aws.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. package metadata
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "io"
  7. "net"
  8. "net/http"
  9. "github.com/coroot/coroot-node-agent/proc"
  10. "k8s.io/klog/v2"
  11. )
  12. const awsInstanceMetadataURL = "http://169.254.169.254/latest"
  13. func getAwsToken() (string, error) {
  14. // a token must be retrieved using the host net NS because the metadata service sets IP TTL to 1 on all response packets
  15. hostNetNs, err := proc.GetHostNetNs()
  16. if err != nil {
  17. return "", err
  18. }
  19. defer hostNetNs.Close()
  20. agentNetNs, err := proc.GetSelfNetNs()
  21. if err != nil {
  22. return "", err
  23. }
  24. defer agentNetNs.Close()
  25. r, _ := http.NewRequest(http.MethodPut, awsInstanceMetadataURL+"/api/token", nil)
  26. r.Header.Set("X-aws-ec2-metadata-token-ttl-seconds", "21600")
  27. client := http.Client{
  28. Transport: &http.Transport{
  29. DisableKeepAlives: true,
  30. DialContext: func(ctx context.Context, network, addr string) (conn net.Conn, err error) {
  31. err = proc.ExecuteInNetNs(hostNetNs, agentNetNs, func() error {
  32. conn, err = net.DialTimeout(network, addr, metadataServiceTimeout)
  33. return err
  34. })
  35. return conn, err
  36. },
  37. },
  38. }
  39. resp, err := client.Do(r)
  40. if err != nil {
  41. return "", err
  42. }
  43. if resp.StatusCode != 200 {
  44. return "", errors.New(resp.Status)
  45. }
  46. defer resp.Body.Close()
  47. token, err := io.ReadAll(resp.Body)
  48. return string(token), err
  49. }
  50. func getAwsMetadata() *CloudMetadata {
  51. md := &CloudMetadata{Provider: CloudProviderAWS}
  52. token, err := getAwsToken()
  53. if err != nil {
  54. klog.Errorln("failed to get token:", err)
  55. return md
  56. }
  57. md = &CloudMetadata{
  58. Provider: CloudProviderAWS,
  59. InstanceId: getAwsMetadataVariable(token, "instance-id"),
  60. LifeCycle: getAwsMetadataVariable(token, "instance-life-cycle"),
  61. InstanceType: getAwsMetadataVariable(token, "instance-type"),
  62. Region: getAwsMetadataVariable(token, "placement/region"),
  63. AvailabilityZone: getAwsMetadataVariable(token, "placement/availability-zone"),
  64. AvailabilityZoneId: getAwsMetadataVariable(token, "placement/availability-zone-id"),
  65. LocalIPv4: getAwsMetadataVariable(token, "local-ipv4"),
  66. PublicIPv4: getAwsMetadataVariable(token, "public-ipv4"),
  67. }
  68. if infoJson := getAwsMetadataVariable(token, "identity-credentials/ec2/info"); infoJson != "" {
  69. m := map[string]string{}
  70. if err := json.Unmarshal([]byte(infoJson), &m); err != nil {
  71. klog.Errorln(err)
  72. } else {
  73. md.AccountId = m["AccountId"]
  74. }
  75. }
  76. return md
  77. }
  78. func getAwsMetadataVariable(token string, path string) string {
  79. r, _ := http.NewRequest(http.MethodGet, awsInstanceMetadataURL+"/meta-data/"+path, nil)
  80. r.Header.Set("X-aws-ec2-metadata-token", string(token))
  81. resp, err := httpCallWithTimeout(r)
  82. if err != nil {
  83. klog.Errorln(err)
  84. return ""
  85. }
  86. defer resp.Body.Close()
  87. payload, err := io.ReadAll(resp.Body)
  88. if err != nil {
  89. klog.Errorln(path, err)
  90. return ""
  91. }
  92. return string(payload)
  93. }