-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
158 lines (130 loc) · 4.13 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package main
import (
"encoding/json"
"errors"
"flag"
"fmt"
"net/http"
"os"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sts"
)
const TaskMetaDataBase = "http://169.254.170.2"
type taskCredentialResp struct {
RoleARN string `json:"RoleArn"`
AccessKeyID string `json:"AccessKeyId"`
SecretAccessKey string `json:"SecretAccessKey"`
Token string `json:"Token"`
Expiration time.Time `json:"Expiration"`
}
func getCredentialsFromSts() (export *exported, expires time.Time, _ error) {
svc := sts.New(session.New())
input := &sts.GetSessionTokenInput{
DurationSeconds: aws.Int64(7200),
}
result, err := svc.GetSessionToken(input)
if err != nil {
return nil, expires, err
}
return &exported{
AccessKeyID: *result.Credentials.AccessKeyId,
SecretAccessKey: *result.Credentials.SecretAccessKey,
Token: *result.Credentials.SessionToken,
}, *result.Credentials.Expiration, nil
}
func getCredentialsFromTask(httpClient *http.Client) (export *exported, expires time.Time, _ error) {
relativeURI := os.Getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI")
if len(relativeURI) < 1 {
return nil, expires, errors.New("missing AWS_CONTAINER_CREDENTIALS_RELATIVE_URI environment variable")
}
address := fmt.Sprintf("%s/%s", TaskMetaDataBase, relativeURI)
r, err := httpClient.Get(address)
if err != nil {
return nil, expires, err
}
var creds taskCredentialResp
json.NewDecoder(r.Body).Decode(&creds)
r.Body.Close()
if len(creds.AccessKeyID) < 1 {
return nil, expires, errors.New("missing credentials in response")
}
return &exported{
AccessKeyID: creds.AccessKeyID,
SecretAccessKey: creds.SecretAccessKey,
Token: creds.Token,
}, creds.Expiration, nil
}
const InstanceMetaDataBase = "http://169.254.169.254/latest/meta-data/iam/security-credentials"
type instanceCredentialResp struct {
Code string `json:"Code"`
LastUpdated time.Time `json:"LastUpdated"`
Type string `json:"Type"`
AccessKeyID string `json:"AccessKeyId"`
SecretAccessKey string `json:"SecretAccessKey"`
Token string `json:"Token"`
Expiration time.Time `json:"Expiration"`
}
func getCredentialsFromInstance(httpClient *http.Client, roleName string) (export *exported, expires time.Time, _ error) {
if len(roleName) < 1 {
return nil, expires, errors.New("missing roleName")
}
address := fmt.Sprintf("%s/%s", InstanceMetaDataBase, roleName)
r, err := httpClient.Get(address)
if err != nil {
return nil, expires, err
}
var creds instanceCredentialResp
json.NewDecoder(r.Body).Decode(&creds)
r.Body.Close()
if len(creds.AccessKeyID) < 1 {
return nil, expires, errors.New("missing credentials in response")
}
return &exported{
AccessKeyID: creds.AccessKeyID,
SecretAccessKey: creds.SecretAccessKey,
Token: creds.Token,
}, creds.Expiration, nil
}
func main() {
roleName := flag.String("roleName", "", "AWS IAM role name to get credentials for")
flag.Parse()
httpClient := &http.Client{
Timeout: 1 * time.Second,
}
out := output{
Secret: true,
}
if creds, expires, err := getCredentialsFromSts(); err == nil {
out.Exports = creds
out.Expires = expires
out.State = "success"
} else if creds, expires, err := getCredentialsFromTask(httpClient); err == nil {
out.Exports = creds
out.Expires = expires
out.State = "success"
} else if creds, expires, err := getCredentialsFromInstance(httpClient, *roleName); err == nil {
out.Exports = creds
out.Expires = expires
out.State = "success"
} else {
out.State = "critical"
out.Error = "no valid response from metadata endpoints"
out.Exports = &exported{}
}
o, _ := json.Marshal(out)
fmt.Printf("%s\n", o)
}
type output struct {
Secret bool `json:"secret"`
Exports *exported `json:"exports"`
Expires time.Time `json:"expires"`
Error string `json:"error"`
State string `json:"state"`
}
type exported struct {
AccessKeyID string `json:"AWS_ACCESS_KEY_ID"`
SecretAccessKey string `json:"AWS_SECRET_ACCESS_KEY"`
Token string `json:"AWS_SESSION_TOKEN"`
}