github.com/gwilym/terraform@v0.3.8-0.20151231151641-c7573de75b19/builtin/providers/aws/config_test.go (about) 1 package aws 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "net/http/httptest" 8 "os" 9 "testing" 10 11 "github.com/aws/aws-sdk-go/aws/awserr" 12 ) 13 14 func TestAWSConfig_shouldError(t *testing.T) { 15 resetEnv := unsetEnv(t) 16 defer resetEnv() 17 cfg := Config{} 18 19 c := getCreds(cfg.AccessKey, cfg.SecretKey, cfg.Token) 20 _, err := c.Get() 21 if awsErr, ok := err.(awserr.Error); ok { 22 if awsErr.Code() != "NoCredentialProviders" { 23 t.Fatalf("Expected NoCredentialProviders error") 24 } 25 } 26 if err == nil { 27 t.Fatalf("Expected an error with empty env, keys, and IAM in AWS Config") 28 } 29 } 30 31 func TestAWSConfig_shouldBeStatic(t *testing.T) { 32 simple := []struct { 33 Key, Secret, Token string 34 }{ 35 { 36 Key: "test", 37 Secret: "secret", 38 }, { 39 Key: "test", 40 Secret: "test", 41 Token: "test", 42 }, 43 } 44 45 for _, c := range simple { 46 cfg := Config{ 47 AccessKey: c.Key, 48 SecretKey: c.Secret, 49 Token: c.Token, 50 } 51 52 creds := getCreds(cfg.AccessKey, cfg.SecretKey, cfg.Token) 53 if creds == nil { 54 t.Fatalf("Expected a static creds provider to be returned") 55 } 56 v, err := creds.Get() 57 if err != nil { 58 t.Fatalf("Error gettings creds: %s", err) 59 } 60 if v.AccessKeyID != c.Key { 61 t.Fatalf("AccessKeyID mismatch, expected: (%s), got (%s)", c.Key, v.AccessKeyID) 62 } 63 if v.SecretAccessKey != c.Secret { 64 t.Fatalf("SecretAccessKey mismatch, expected: (%s), got (%s)", c.Secret, v.SecretAccessKey) 65 } 66 if v.SessionToken != c.Token { 67 t.Fatalf("SessionToken mismatch, expected: (%s), got (%s)", c.Token, v.SessionToken) 68 } 69 } 70 } 71 72 // TestAWSConfig_shouldIAM is designed to test the scenario of running Terraform 73 // from an EC2 instance, without environment variables or manually supplied 74 // credentials. 75 func TestAWSConfig_shouldIAM(t *testing.T) { 76 // clear AWS_* environment variables 77 resetEnv := unsetEnv(t) 78 defer resetEnv() 79 80 // capture the test server's close method, to call after the test returns 81 ts := awsEnv(t) 82 defer ts() 83 84 // An empty config, no key supplied 85 cfg := Config{} 86 87 creds := getCreds(cfg.AccessKey, cfg.SecretKey, cfg.Token) 88 if creds == nil { 89 t.Fatalf("Expected a static creds provider to be returned") 90 } 91 92 v, err := creds.Get() 93 if err != nil { 94 t.Fatalf("Error gettings creds: %s", err) 95 } 96 if v.AccessKeyID != "somekey" { 97 t.Fatalf("AccessKeyID mismatch, expected: (somekey), got (%s)", v.AccessKeyID) 98 } 99 if v.SecretAccessKey != "somesecret" { 100 t.Fatalf("SecretAccessKey mismatch, expected: (somesecret), got (%s)", v.SecretAccessKey) 101 } 102 if v.SessionToken != "sometoken" { 103 t.Fatalf("SessionToken mismatch, expected: (sometoken), got (%s)", v.SessionToken) 104 } 105 } 106 107 // TestAWSConfig_shouldIAM is designed to test the scenario of running Terraform 108 // from an EC2 instance, without environment variables or manually supplied 109 // credentials. 110 func TestAWSConfig_shouldIgnoreIAM(t *testing.T) { 111 resetEnv := unsetEnv(t) 112 defer resetEnv() 113 // capture the test server's close method, to call after the test returns 114 ts := awsEnv(t) 115 defer ts() 116 simple := []struct { 117 Key, Secret, Token string 118 }{ 119 { 120 Key: "test", 121 Secret: "secret", 122 }, { 123 Key: "test", 124 Secret: "test", 125 Token: "test", 126 }, 127 } 128 129 for _, c := range simple { 130 cfg := Config{ 131 AccessKey: c.Key, 132 SecretKey: c.Secret, 133 Token: c.Token, 134 } 135 136 creds := getCreds(cfg.AccessKey, cfg.SecretKey, cfg.Token) 137 if creds == nil { 138 t.Fatalf("Expected a static creds provider to be returned") 139 } 140 v, err := creds.Get() 141 if err != nil { 142 t.Fatalf("Error gettings creds: %s", err) 143 } 144 if v.AccessKeyID != c.Key { 145 t.Fatalf("AccessKeyID mismatch, expected: (%s), got (%s)", c.Key, v.AccessKeyID) 146 } 147 if v.SecretAccessKey != c.Secret { 148 t.Fatalf("SecretAccessKey mismatch, expected: (%s), got (%s)", c.Secret, v.SecretAccessKey) 149 } 150 if v.SessionToken != c.Token { 151 t.Fatalf("SessionToken mismatch, expected: (%s), got (%s)", c.Token, v.SessionToken) 152 } 153 } 154 } 155 156 func TestAWSConfig_shouldBeENV(t *testing.T) { 157 // need to set the environment variables to a dummy string, as we don't know 158 // what they may be at runtime without hardcoding here 159 s := "some_env" 160 resetEnv := setEnv(s, t) 161 defer resetEnv() 162 163 cfg := Config{} 164 creds := getCreds(cfg.AccessKey, cfg.SecretKey, cfg.Token) 165 if creds == nil { 166 t.Fatalf("Expected a static creds provider to be returned") 167 } 168 v, err := creds.Get() 169 if err != nil { 170 t.Fatalf("Error gettings creds: %s", err) 171 } 172 if v.AccessKeyID != s { 173 t.Fatalf("AccessKeyID mismatch, expected: (%s), got (%s)", s, v.AccessKeyID) 174 } 175 if v.SecretAccessKey != s { 176 t.Fatalf("SecretAccessKey mismatch, expected: (%s), got (%s)", s, v.SecretAccessKey) 177 } 178 if v.SessionToken != s { 179 t.Fatalf("SessionToken mismatch, expected: (%s), got (%s)", s, v.SessionToken) 180 } 181 } 182 183 // unsetEnv unsets enviornment variables for testing a "clean slate" with no 184 // credentials in the environment 185 func unsetEnv(t *testing.T) func() { 186 // Grab any existing AWS keys and preserve. In some tests we'll unset these, so 187 // we need to have them and restore them after 188 e := getEnv() 189 if err := os.Unsetenv("AWS_ACCESS_KEY_ID"); err != nil { 190 t.Fatalf("Error unsetting env var AWS_ACCESS_KEY_ID: %s", err) 191 } 192 if err := os.Unsetenv("AWS_SECRET_ACCESS_KEY"); err != nil { 193 t.Fatalf("Error unsetting env var AWS_SECRET_ACCESS_KEY: %s", err) 194 } 195 if err := os.Unsetenv("AWS_SESSION_TOKEN"); err != nil { 196 t.Fatalf("Error unsetting env var AWS_SESSION_TOKEN: %s", err) 197 } 198 199 return func() { 200 // re-set all the envs we unset above 201 if err := os.Setenv("AWS_ACCESS_KEY_ID", e.Key); err != nil { 202 t.Fatalf("Error resetting env var AWS_ACCESS_KEY_ID: %s", err) 203 } 204 if err := os.Setenv("AWS_SECRET_ACCESS_KEY", e.Secret); err != nil { 205 t.Fatalf("Error resetting env var AWS_SECRET_ACCESS_KEY: %s", err) 206 } 207 if err := os.Setenv("AWS_SESSION_TOKEN", e.Token); err != nil { 208 t.Fatalf("Error resetting env var AWS_SESSION_TOKEN: %s", err) 209 } 210 } 211 } 212 213 func setEnv(s string, t *testing.T) func() { 214 e := getEnv() 215 // Set all the envs to a dummy value 216 if err := os.Setenv("AWS_ACCESS_KEY_ID", s); err != nil { 217 t.Fatalf("Error setting env var AWS_ACCESS_KEY_ID: %s", err) 218 } 219 if err := os.Setenv("AWS_SECRET_ACCESS_KEY", s); err != nil { 220 t.Fatalf("Error setting env var AWS_SECRET_ACCESS_KEY: %s", err) 221 } 222 if err := os.Setenv("AWS_SESSION_TOKEN", s); err != nil { 223 t.Fatalf("Error setting env var AWS_SESSION_TOKEN: %s", err) 224 } 225 226 return func() { 227 // re-set all the envs we unset above 228 if err := os.Setenv("AWS_ACCESS_KEY_ID", e.Key); err != nil { 229 t.Fatalf("Error resetting env var AWS_ACCESS_KEY_ID: %s", err) 230 } 231 if err := os.Setenv("AWS_SECRET_ACCESS_KEY", e.Secret); err != nil { 232 t.Fatalf("Error resetting env var AWS_SECRET_ACCESS_KEY: %s", err) 233 } 234 if err := os.Setenv("AWS_SESSION_TOKEN", e.Token); err != nil { 235 t.Fatalf("Error resetting env var AWS_SESSION_TOKEN: %s", err) 236 } 237 } 238 } 239 240 // awsEnv establishes a httptest server to mock out the internal AWS Metadata 241 // service. IAM Credentials are retrieved by the EC2RoleProvider, which makes 242 // API calls to this internal URL. By replacing the server with a test server, 243 // we can simulate an AWS environment 244 func awsEnv(t *testing.T) func() { 245 routes := routes{} 246 if err := json.Unmarshal([]byte(aws_routes), &routes); err != nil { 247 t.Fatalf("Failed to unmarshal JSON in AWS ENV test: %s", err) 248 } 249 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 250 w.Header().Set("Content-Type", "text/plain") 251 w.Header().Add("Server", "MockEC2") 252 for _, e := range routes.Endpoints { 253 if r.RequestURI == e.Uri { 254 fmt.Fprintln(w, e.Body) 255 } 256 } 257 })) 258 259 os.Setenv("AWS_METADATA_URL", ts.URL+"/latest") 260 return ts.Close 261 } 262 263 func getEnv() *currentEnv { 264 // Grab any existing AWS keys and preserve. In some tests we'll unset these, so 265 // we need to have them and restore them after 266 return ¤tEnv{ 267 Key: os.Getenv("AWS_ACCESS_KEY_ID"), 268 Secret: os.Getenv("AWS_SECRET_ACCESS_KEY"), 269 Token: os.Getenv("AWS_SESSION_TOKEN"), 270 } 271 } 272 273 // struct to preserve the current environment 274 type currentEnv struct { 275 Key, Secret, Token string 276 } 277 278 type routes struct { 279 Endpoints []*endpoint `json:"endpoints"` 280 } 281 type endpoint struct { 282 Uri string `json:"uri"` 283 Body string `json:"body"` 284 } 285 286 const aws_routes = ` 287 { 288 "endpoints": [ 289 { 290 "uri": "/latest/meta-data/iam/security-credentials", 291 "body": "test_role" 292 }, 293 { 294 "uri": "/latest/meta-data/iam/security-credentials/test_role", 295 "body": "{\"Code\":\"Success\",\"LastUpdated\":\"2015-12-11T17:17:25Z\",\"Type\":\"AWS-HMAC\",\"AccessKeyId\":\"somekey\",\"SecretAccessKey\":\"somesecret\",\"Token\":\"sometoken\"}" 296 } 297 ] 298 } 299 `