Skip to content

Commit

Permalink
Merge pull request #19 from coroot/aws_metadata_service_v2
Browse files Browse the repository at this point in the history
using IMDSv2 to retrieve AWS instance metadata
  • Loading branch information
def authored May 30, 2023
2 parents 98b9e46 + 06edf01 commit 0fb14e3
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 71 deletions.
14 changes: 1 addition & 13 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ go 1.19

require (
cloud.google.com/go/compute/metadata v0.2.3
github.com/aws/aws-sdk-go-v2/config v1.18.3
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19
github.com/cilium/cilium v1.13.0
github.com/cilium/ebpf v0.9.4-0.20221102092914-a9cf21df64c2
github.com/containerd/cgroups v1.0.1
Expand All @@ -30,6 +28,7 @@ require (
golang.org/x/mod v0.7.0
golang.org/x/net v0.7.0
golang.org/x/sys v0.6.0
golang.org/x/time v0.3.0
gopkg.in/alecthomas/kingpin.v2 v2.2.6
gopkg.in/yaml.v2 v2.4.0
inet.af/netaddr v0.0.0-20210903134321-85fa6c94624e
Expand All @@ -43,16 +42,6 @@ require (
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
github.com/aws/aws-sdk-go-v2 v1.17.1 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.13.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.11.25 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.17.5 // indirect
github.com/aws/smithy-go v1.13.4 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.2.0 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
Expand Down Expand Up @@ -138,7 +127,6 @@ require (
golang.org/x/exp v0.0.0-20221106115401-f9659909a136 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/text v0.7.0 // indirect
golang.org/x/time v0.3.0 // indirect
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
google.golang.org/grpc v1.53.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
Expand Down
29 changes: 0 additions & 29 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -95,30 +95,6 @@ github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:W
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ=
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
github.com/aws/aws-sdk-go-v2 v1.17.1 h1:02c72fDJr87N8RAC2s3Qu0YuvMRZKNZJ9F+lAehCazk=
github.com/aws/aws-sdk-go-v2 v1.17.1/go.mod h1:JLnGeGONAyi2lWXI1p0PCIOIy333JMVK1U7Hf0aRFLw=
github.com/aws/aws-sdk-go-v2/config v1.18.3 h1:3kfBKcX3votFX84dm00U8RGA1sCCh3eRMOGzg5dCWfU=
github.com/aws/aws-sdk-go-v2/config v1.18.3/go.mod h1:BYdrbeCse3ZnOD5+2/VE/nATOK8fEUpBtmPMdKSyhMU=
github.com/aws/aws-sdk-go-v2/credentials v1.13.3 h1:ur+FHdp4NbVIv/49bUjBW+FE7e57HOo03ELodttmagk=
github.com/aws/aws-sdk-go-v2/credentials v1.13.3/go.mod h1:/rOMmqYBcFfNbRPU0iN9IgGqD5+V2yp3iWNmIlz0wI4=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 h1:E3PXZSI3F2bzyj6XxUXdTIfvp425HHhwKsFvmzBwHgs=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19/go.mod h1:VihW95zQpeKQWVPGkwT+2+WJNQV8UXFfMTWdU6VErL8=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25 h1:nBO/RFxeq/IS5G9Of+ZrgucRciie2qpLy++3UGZ+q2E=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25/go.mod h1:Zb29PYkf42vVYQY6pvSyJCJcFHlPIiY+YKdPtwnvMkY=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19 h1:oRHDrwCTVT8ZXi4sr9Ld+EXk7N/KGssOr2ygNeojEhw=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19/go.mod h1:6Q0546uHDp421okhmmGfbxzq2hBqbXFNpi4k+Q1JnQA=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 h1:Mza+vlnZr+fPKFKRq/lKGVvM6B/8ZZmNdEopOwSQLms=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26/go.mod h1:Y2OJ+P+MC1u1VKnavT+PshiEuGPyh/7DqxoDNij4/bg=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19 h1:GE25AWCdNUPh9AOJzI9KIJnja7IwUc1WyUqz/JTyJ/I=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19/go.mod h1:02CP6iuYP+IVnBX5HULVdSAku/85eHB2Y9EsFhrkEwU=
github.com/aws/aws-sdk-go-v2/service/sso v1.11.25 h1:GFZitO48N/7EsFDt8fMa5iYdmWqkUDDB3Eje6z3kbG0=
github.com/aws/aws-sdk-go-v2/service/sso v1.11.25/go.mod h1:IARHuzTXmj1C0KS35vboR0FeJ89OkEy1M9mWbK2ifCI=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 h1:jcw6kKZrtNfBPJkaHrscDOZoe5gvi9wjudnxvozYFJo=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8/go.mod h1:er2JHN+kBY6FcMfcBBKNGCT3CarImmdFzishsqBmSRI=
github.com/aws/aws-sdk-go-v2/service/sts v1.17.5 h1:60SJ4lhvn///8ygCzYy2l53bFW/Q15bVfyjyAWo6zuw=
github.com/aws/aws-sdk-go-v2/service/sts v1.17.5/go.mod h1:bXcN3koeVYiJcdDU89n3kCYILob7Y34AeLopUbZgLT4=
github.com/aws/smithy-go v1.13.4 h1:/RN2z1txIJWeXeOkzX+Hk/4Uuvv7dWtCjbmVJcrskyk=
github.com/aws/smithy-go v1.13.4/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
Expand Down Expand Up @@ -487,7 +463,6 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
Expand Down Expand Up @@ -552,8 +527,6 @@ github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLf
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
Expand Down Expand Up @@ -1209,8 +1182,6 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE=
golang.org/x/time v0.2.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
Expand Down
93 changes: 69 additions & 24 deletions node/metadata/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,76 @@ package metadata
import (
"context"
"encoding/json"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
"errors"
"github.com/coroot/coroot-node-agent/proc"
"io"
"k8s.io/klog/v2"
"net"
"net/http"
)

const awsInstanceMetadataURL = "http://169.254.169.254/latest"

func getAwsToken() (string, error) {
// a token must be retrieved using the host net NS because the metadata service sets IP TTL to 1 on all response packets
hostNetNs, err := proc.GetHostNetNs()
if err != nil {
return "", err
}
defer hostNetNs.Close()
agentNetNs, err := proc.GetSelfNetNs()
if err != nil {
return "", err
}
defer agentNetNs.Close()

r, _ := http.NewRequest(http.MethodPut, awsInstanceMetadataURL+"/api/token", nil)
r.Header.Set("X-aws-ec2-metadata-token-ttl-seconds", "21600")

client := http.Client{
Transport: &http.Transport{
DisableKeepAlives: true,
DialContext: func(ctx context.Context, network, addr string) (conn net.Conn, err error) {
err = proc.ExecuteInNetNs(hostNetNs, agentNetNs, func() error {
conn, err = net.DialTimeout(network, addr, metadataServiceTimeout)
return err
})
return conn, err
},
},
}
resp, err := client.Do(r)
if err != nil {
return "", err
}
if resp.StatusCode != 200 {
return "", errors.New(resp.Status)
}
defer resp.Body.Close()
token, err := io.ReadAll(resp.Body)
return string(token), err
}

func getAwsMetadata() *CloudMetadata {
ctx, cancel := context.WithTimeout(context.Background(), metadataServiceTimeout)
defer cancel()
cfg, err := config.LoadDefaultConfig(ctx)
md := &CloudMetadata{Provider: CloudProviderAWS}
token, err := getAwsToken()
if err != nil {
klog.Errorln(err)
return nil
klog.Errorln("failed to get token:", err)
return md
}
c := imds.NewFromConfig(cfg)
md := &CloudMetadata{

md = &CloudMetadata{
Provider: CloudProviderAWS,
InstanceId: getAwsMetadataVariable(ctx, c, "instance-id"),
LifeCycle: getAwsMetadataVariable(ctx, c, "instance-life-cycle"),
InstanceType: getAwsMetadataVariable(ctx, c, "instance-type"),
Region: getAwsMetadataVariable(ctx, c, "placement/region"),
AvailabilityZone: getAwsMetadataVariable(ctx, c, "placement/availability-zone"),
AvailabilityZoneId: getAwsMetadataVariable(ctx, c, "placement/availability-zone-id"),
LocalIPv4: getAwsMetadataVariable(ctx, c, "local-ipv4"),
PublicIPv4: getAwsMetadataVariable(ctx, c, "public-ipv4"),
}
if infoJson := getAwsMetadataVariable(ctx, c, "identity-credentials/ec2/info"); infoJson != "" {
InstanceId: getAwsMetadataVariable(token, "instance-id"),
LifeCycle: getAwsMetadataVariable(token, "instance-life-cycle"),
InstanceType: getAwsMetadataVariable(token, "instance-type"),
Region: getAwsMetadataVariable(token, "placement/region"),
AvailabilityZone: getAwsMetadataVariable(token, "placement/availability-zone"),
AvailabilityZoneId: getAwsMetadataVariable(token, "placement/availability-zone-id"),
LocalIPv4: getAwsMetadataVariable(token, "local-ipv4"),
PublicIPv4: getAwsMetadataVariable(token, "public-ipv4"),
}
if infoJson := getAwsMetadataVariable(token, "identity-credentials/ec2/info"); infoJson != "" {
m := map[string]string{}
if err := json.Unmarshal([]byte(infoJson), &m); err != nil {
klog.Errorln(err)
Expand All @@ -40,14 +83,16 @@ func getAwsMetadata() *CloudMetadata {
return md
}

func getAwsMetadataVariable(ctx context.Context, client *imds.Client, path string) string {
res, err := client.GetMetadata(ctx, &imds.GetMetadataInput{Path: path})
func getAwsMetadataVariable(token string, path string) string {
r, _ := http.NewRequest(http.MethodGet, awsInstanceMetadataURL+"/meta-data/"+path, nil)
r.Header.Set("X-aws-ec2-metadata-token", string(token))
resp, err := httpCallWithTimeout(r)
if err != nil {
klog.Errorln(path, err)
klog.Errorln(err)
return ""
}
defer res.Content.Close()
payload, err := io.ReadAll(res.Content)
defer resp.Body.Close()
payload, err := io.ReadAll(resp.Body)
if err != nil {
klog.Errorln(path, err)
return ""
Expand Down
2 changes: 1 addition & 1 deletion node/metadata/azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func getAzureMetadata() *CloudMetadata {
q.Add("api-version", "2021-05-01")
r.URL.RawQuery = q.Encode()

resp, err := httpGetWithTimeout(r)
resp, err := httpCallWithTimeout(r)
if err != nil {
klog.Errorln(err)
return nil
Expand Down
2 changes: 1 addition & 1 deletion node/metadata/digital_ocean.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func getDigitalOceanMetadata() *CloudMetadata {
var lastErr error
getVar := func(path string) string {
r, _ := http.NewRequest(http.MethodGet, doInstanceMetadataURL+path, nil)
resp, err := httpGetWithTimeout(r)
resp, err := httpCallWithTimeout(r)
if err != nil {
lastErr = err
return ""
Expand Down
2 changes: 1 addition & 1 deletion node/metadata/hetzner.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type hetznerInstanceMetadata struct {

func getHetznerMetadata() *CloudMetadata {
r, _ := http.NewRequest(http.MethodGet, hetznerInstanceMetadataURL, nil)
resp, err := httpGetWithTimeout(r)
resp, err := httpCallWithTimeout(r)
if err != nil {
klog.Errorln(err)
return nil
Expand Down
3 changes: 1 addition & 2 deletions node/metadata/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,14 @@ func GetInstanceMetadata() *CloudMetadata {
return nil
}

func httpGetWithTimeout(r *http.Request) (*http.Response, error) {
func httpCallWithTimeout(r *http.Request) (*http.Response, error) {
client := http.DefaultClient
client.Timeout = metadataServiceTimeout
resp, err := client.Do(r)
if err != nil {
return nil, err
}
if resp.StatusCode != 200 {
klog.Errorln()
return nil, fmt.Errorf("metadata service response: %s", resp.Status)
}
return resp, nil
Expand Down

0 comments on commit 0fb14e3

Please sign in to comment.