diff options
Diffstat (limited to 'vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go')
-rw-r--r-- | vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go b/vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go new file mode 100644 index 0000000..c397495 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go | |||
@@ -0,0 +1,178 @@ | |||
1 | package ec2rolecreds | ||
2 | |||
3 | import ( | ||
4 | "bufio" | ||
5 | "encoding/json" | ||
6 | "fmt" | ||
7 | "path" | ||
8 | "strings" | ||
9 | "time" | ||
10 | |||
11 | "github.com/aws/aws-sdk-go/aws/awserr" | ||
12 | "github.com/aws/aws-sdk-go/aws/client" | ||
13 | "github.com/aws/aws-sdk-go/aws/credentials" | ||
14 | "github.com/aws/aws-sdk-go/aws/ec2metadata" | ||
15 | ) | ||
16 | |||
17 | // ProviderName provides a name of EC2Role provider | ||
18 | const ProviderName = "EC2RoleProvider" | ||
19 | |||
20 | // A EC2RoleProvider retrieves credentials from the EC2 service, and keeps track if | ||
21 | // those credentials are expired. | ||
22 | // | ||
23 | // Example how to configure the EC2RoleProvider with custom http Client, Endpoint | ||
24 | // or ExpiryWindow | ||
25 | // | ||
26 | // p := &ec2rolecreds.EC2RoleProvider{ | ||
27 | // // Pass in a custom timeout to be used when requesting | ||
28 | // // IAM EC2 Role credentials. | ||
29 | // Client: ec2metadata.New(sess, aws.Config{ | ||
30 | // HTTPClient: &http.Client{Timeout: 10 * time.Second}, | ||
31 | // }), | ||
32 | // | ||
33 | // // Do not use early expiry of credentials. If a non zero value is | ||
34 | // // specified the credentials will be expired early | ||
35 | // ExpiryWindow: 0, | ||
36 | // } | ||
37 | type EC2RoleProvider struct { | ||
38 | credentials.Expiry | ||
39 | |||
40 | // Required EC2Metadata client to use when connecting to EC2 metadata service. | ||
41 | Client *ec2metadata.EC2Metadata | ||
42 | |||
43 | // ExpiryWindow will allow the credentials to trigger refreshing prior to | ||
44 | // the credentials actually expiring. This is beneficial so race conditions | ||
45 | // with expiring credentials do not cause request to fail unexpectedly | ||
46 | // due to ExpiredTokenException exceptions. | ||
47 | // | ||
48 | // So a ExpiryWindow of 10s would cause calls to IsExpired() to return true | ||
49 | // 10 seconds before the credentials are actually expired. | ||
50 | // | ||
51 | // If ExpiryWindow is 0 or less it will be ignored. | ||
52 | ExpiryWindow time.Duration | ||
53 | } | ||
54 | |||
55 | // NewCredentials returns a pointer to a new Credentials object wrapping | ||
56 | // the EC2RoleProvider. Takes a ConfigProvider to create a EC2Metadata client. | ||
57 | // The ConfigProvider is satisfied by the session.Session type. | ||
58 | func NewCredentials(c client.ConfigProvider, options ...func(*EC2RoleProvider)) *credentials.Credentials { | ||
59 | p := &EC2RoleProvider{ | ||
60 | Client: ec2metadata.New(c), | ||
61 | } | ||
62 | |||
63 | for _, option := range options { | ||
64 | option(p) | ||
65 | } | ||
66 | |||
67 | return credentials.NewCredentials(p) | ||
68 | } | ||
69 | |||
70 | // NewCredentialsWithClient returns a pointer to a new Credentials object wrapping | ||
71 | // the EC2RoleProvider. Takes a EC2Metadata client to use when connecting to EC2 | ||
72 | // metadata service. | ||
73 | func NewCredentialsWithClient(client *ec2metadata.EC2Metadata, options ...func(*EC2RoleProvider)) *credentials.Credentials { | ||
74 | p := &EC2RoleProvider{ | ||
75 | Client: client, | ||
76 | } | ||
77 | |||
78 | for _, option := range options { | ||
79 | option(p) | ||
80 | } | ||
81 | |||
82 | return credentials.NewCredentials(p) | ||
83 | } | ||
84 | |||
85 | // Retrieve retrieves credentials from the EC2 service. | ||
86 | // Error will be returned if the request fails, or unable to extract | ||
87 | // the desired credentials. | ||
88 | func (m *EC2RoleProvider) Retrieve() (credentials.Value, error) { | ||
89 | credsList, err := requestCredList(m.Client) | ||
90 | if err != nil { | ||
91 | return credentials.Value{ProviderName: ProviderName}, err | ||
92 | } | ||
93 | |||
94 | if len(credsList) == 0 { | ||
95 | return credentials.Value{ProviderName: ProviderName}, awserr.New("EmptyEC2RoleList", "empty EC2 Role list", nil) | ||
96 | } | ||
97 | credsName := credsList[0] | ||
98 | |||
99 | roleCreds, err := requestCred(m.Client, credsName) | ||
100 | if err != nil { | ||
101 | return credentials.Value{ProviderName: ProviderName}, err | ||
102 | } | ||
103 | |||
104 | m.SetExpiration(roleCreds.Expiration, m.ExpiryWindow) | ||
105 | |||
106 | return credentials.Value{ | ||
107 | AccessKeyID: roleCreds.AccessKeyID, | ||
108 | SecretAccessKey: roleCreds.SecretAccessKey, | ||
109 | SessionToken: roleCreds.Token, | ||
110 | ProviderName: ProviderName, | ||
111 | }, nil | ||
112 | } | ||
113 | |||
114 | // A ec2RoleCredRespBody provides the shape for unmarshaling credential | ||
115 | // request responses. | ||
116 | type ec2RoleCredRespBody struct { | ||
117 | // Success State | ||
118 | Expiration time.Time | ||
119 | AccessKeyID string | ||
120 | SecretAccessKey string | ||
121 | Token string | ||
122 | |||
123 | // Error state | ||
124 | Code string | ||
125 | Message string | ||
126 | } | ||
127 | |||
128 | const iamSecurityCredsPath = "/iam/security-credentials" | ||
129 | |||
130 | // requestCredList requests a list of credentials from the EC2 service. | ||
131 | // If there are no credentials, or there is an error making or receiving the request | ||
132 | func requestCredList(client *ec2metadata.EC2Metadata) ([]string, error) { | ||
133 | resp, err := client.GetMetadata(iamSecurityCredsPath) | ||
134 | if err != nil { | ||
135 | return nil, awserr.New("EC2RoleRequestError", "no EC2 instance role found", err) | ||
136 | } | ||
137 | |||
138 | credsList := []string{} | ||
139 | s := bufio.NewScanner(strings.NewReader(resp)) | ||
140 | for s.Scan() { | ||
141 | credsList = append(credsList, s.Text()) | ||
142 | } | ||
143 | |||
144 | if err := s.Err(); err != nil { | ||
145 | return nil, awserr.New("SerializationError", "failed to read EC2 instance role from metadata service", err) | ||
146 | } | ||
147 | |||
148 | return credsList, nil | ||
149 | } | ||
150 | |||
151 | // requestCred requests the credentials for a specific credentials from the EC2 service. | ||
152 | // | ||
153 | // If the credentials cannot be found, or there is an error reading the response | ||
154 | // and error will be returned. | ||
155 | func requestCred(client *ec2metadata.EC2Metadata, credsName string) (ec2RoleCredRespBody, error) { | ||
156 | resp, err := client.GetMetadata(path.Join(iamSecurityCredsPath, credsName)) | ||
157 | if err != nil { | ||
158 | return ec2RoleCredRespBody{}, | ||
159 | awserr.New("EC2RoleRequestError", | ||
160 | fmt.Sprintf("failed to get %s EC2 instance role credentials", credsName), | ||
161 | err) | ||
162 | } | ||
163 | |||
164 | respCreds := ec2RoleCredRespBody{} | ||
165 | if err := json.NewDecoder(strings.NewReader(resp)).Decode(&respCreds); err != nil { | ||
166 | return ec2RoleCredRespBody{}, | ||
167 | awserr.New("SerializationError", | ||
168 | fmt.Sprintf("failed to decode %s EC2 instance role credentials", credsName), | ||
169 | err) | ||
170 | } | ||
171 | |||
172 | if respCreds.Code != "Success" { | ||
173 | // If an error code was returned something failed requesting the role. | ||
174 | return ec2RoleCredRespBody{}, awserr.New(respCreds.Code, respCreds.Message, nil) | ||
175 | } | ||
176 | |||
177 | return respCreds, nil | ||
178 | } | ||