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