]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go
Initial transfer of provider code
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / aws / aws-sdk-go / aws / credentials / ec2rolecreds / ec2_role_provider.go
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 }