Skip to content

Commit 1807e97

Browse files
committed
add support for AWS IMDSv2
Signed-off-by: Dmitry Shmulevich <[email protected]>
1 parent 524efe2 commit 1807e97

File tree

1 file changed

+55
-13
lines changed

1 file changed

+55
-13
lines changed

pkg/providers/aws/imds.go

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import (
2121
"context"
2222
"encoding/json"
2323
"fmt"
24-
"io"
2524
"net/http"
25+
"path"
2626
"strings"
2727
"time"
2828

@@ -32,7 +32,9 @@ import (
3232
)
3333

3434
const (
35-
IMDSURL = "http://169.254.169.254/latest/meta-data/"
35+
IMDS = "http://169.254.169.254"
36+
IMDS_TOKEN_URL = IMDS + "/latest/api/token"
37+
IMDS_URL = IMDS + "/latest/meta-data"
3638

3739
tokenTimeDelay = 15 * time.Second
3840
)
@@ -45,20 +47,59 @@ type Creds struct {
4547
Expiration string `json:"Expiration"`
4648
}
4749

48-
func getMetadata(path string) ([]byte, error) {
49-
url := IMDSURL + path
50+
func getToken() (string, error) {
51+
req, err := http.NewRequest("PUT", IMDS_TOKEN_URL, nil)
52+
if err != nil {
53+
return "", fmt.Errorf("failed to create HTTP request: %v", err)
54+
}
55+
56+
req.Header.Add("X-aws-ec2-metadata-token-ttl-seconds", "21600")
57+
58+
_, data, err := utils.HttpRequest(req)
59+
if err != nil {
60+
return "", fmt.Errorf("failed to send HTTP request: %v", err)
61+
}
5062

51-
resp, err := http.Get(url)
63+
return string(data), nil
64+
}
65+
66+
func addToken(req *http.Request) error {
67+
token, err := getToken()
68+
if err != nil {
69+
return err
70+
}
71+
72+
if len(token) != 0 {
73+
req.Header.Add("X-aws-ec2-metadata-token", token)
74+
}
75+
76+
return nil
77+
}
78+
79+
func getMetadata(route string) ([]byte, error) {
80+
url := path.Join(IMDS_URL, route)
81+
klog.V(4).Infof("Requesting URL %s", url)
82+
83+
req, err := http.NewRequest("GET", url, nil)
84+
if err != nil {
85+
return nil, fmt.Errorf("failed to create HTTP request: %v", err)
86+
}
87+
88+
err = addToken(req)
5289
if err != nil {
5390
return nil, err
5491
}
55-
defer func() { _ = resp.Body.Close() }()
92+
93+
resp, data, err := utils.HttpRequest(req)
94+
if err != nil {
95+
return nil, fmt.Errorf("failed to send HTTP request: %v", err)
96+
}
5697

5798
if resp.StatusCode != http.StatusOK {
5899
return nil, fmt.Errorf("HTTP status: %s", resp.Status)
59100
}
60101

61-
return io.ReadAll(resp.Body)
102+
return data, nil
62103
}
63104

64105
func GetRegion() (string, error) {
@@ -71,22 +112,22 @@ func GetRegion() (string, error) {
71112
}
72113

73114
func GetCredentials() (*Creds, error) {
74-
path := "iam/security-credentials"
75-
data, err := getMetadata(path)
115+
route := "iam/security-credentials"
116+
data, err := getMetadata(route)
76117
if err != nil {
77118
return nil, err
78119
}
79120

80121
lines := strings.Split(string(data), "\n")
81122
for _, line := range lines {
82-
path = fmt.Sprintf("%s/%s", path, line)
123+
route = path.Join(route, line)
83124
break
84125
}
85126

86127
// ensure the credentials remain valid for at least the next tokenTimeDelay
87128
for {
88-
klog.V(4).Infof("Getting credentials from path %s", path)
89-
data, err = getMetadata(path)
129+
klog.V(4).Infof("Getting credentials from %s", route)
130+
data, err = getMetadata(route)
90131
if err != nil {
91132
return nil, err
92133
}
@@ -114,7 +155,8 @@ func GetCredentials() (*Creds, error) {
114155
}
115156

116157
func Instance2NodeMap(ctx context.Context, nodes []string) (map[string]string, error) {
117-
args := []string{"-w", strings.Join(nodes, ","), fmt.Sprintf("echo $(curl -s %s/instance-id)", IMDSURL)}
158+
args := []string{"-w", strings.Join(nodes, ","),
159+
fmt.Sprintf("TOKEN=$(curl -s -X PUT -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\" %s); echo $(curl -s -H \"X-aws-ec2-metadata-token: $TOKEN\" %s)", IMDS_TOKEN_URL, path.Join(IMDS_URL, "instance-id"))}
118160

119161
stdout, err := utils.Exec(ctx, "pdsh", args, nil)
120162
if err != nil {

0 commit comments

Comments
 (0)