Ver código fonte

using IMDSv2 to retrieve AWS instance metadata

Nikolay Sivko 3 anos atrás
pai
commit
06edf01e60

+ 1 - 13
go.mod

@@ -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
@@ -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
@@ -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
@@ -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

+ 0 - 29
go.sum

@@ -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=
@@ -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=
@@ -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=
@@ -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=

+ 69 - 24
node/metadata/aws.go

@@ -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)
@@ -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 ""

+ 1 - 1
node/metadata/azure.go

@@ -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

+ 1 - 1
node/metadata/digital_ocean.go

@@ -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 ""

+ 1 - 1
node/metadata/hetzner.go

@@ -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

+ 1 - 2
node/metadata/metadata.go

@@ -79,7 +79,7 @@ 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)
@@ -87,7 +87,6 @@ func httpGetWithTimeout(r *http.Request) (*http.Response, error) {
 		return nil, err
 	}
 	if resp.StatusCode != 200 {
-		klog.Errorln()
 		return nil, fmt.Errorf("metadata service response: %s", resp.Status)
 	}
 	return resp, nil