2015-12-10 22:43:13 +01:00
|
|
|
package aws
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2016-01-11 16:22:09 +01:00
|
|
|
"io/ioutil"
|
2015-12-10 22:43:13 +01:00
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
|
|
|
"os"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestAWSConfig_shouldError(t *testing.T) {
|
|
|
|
resetEnv := unsetEnv(t)
|
|
|
|
defer resetEnv()
|
|
|
|
cfg := Config{}
|
|
|
|
|
2016-01-11 16:22:09 +01:00
|
|
|
c := getCreds(cfg.AccessKey, cfg.SecretKey, cfg.Token, cfg.Profile, cfg.CredsFilename)
|
2015-12-10 22:43:13 +01:00
|
|
|
_, err := c.Get()
|
|
|
|
if awsErr, ok := err.(awserr.Error); ok {
|
|
|
|
if awsErr.Code() != "NoCredentialProviders" {
|
|
|
|
t.Fatalf("Expected NoCredentialProviders error")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("Expected an error with empty env, keys, and IAM in AWS Config")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAWSConfig_shouldBeStatic(t *testing.T) {
|
|
|
|
simple := []struct {
|
|
|
|
Key, Secret, Token string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
Key: "test",
|
|
|
|
Secret: "secret",
|
|
|
|
}, {
|
|
|
|
Key: "test",
|
|
|
|
Secret: "test",
|
|
|
|
Token: "test",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range simple {
|
|
|
|
cfg := Config{
|
|
|
|
AccessKey: c.Key,
|
|
|
|
SecretKey: c.Secret,
|
|
|
|
Token: c.Token,
|
|
|
|
}
|
|
|
|
|
2016-01-11 16:22:09 +01:00
|
|
|
creds := getCreds(cfg.AccessKey, cfg.SecretKey, cfg.Token, cfg.Profile, cfg.CredsFilename)
|
2015-12-10 22:43:13 +01:00
|
|
|
if creds == nil {
|
|
|
|
t.Fatalf("Expected a static creds provider to be returned")
|
|
|
|
}
|
|
|
|
v, err := creds.Get()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Error gettings creds: %s", err)
|
|
|
|
}
|
|
|
|
if v.AccessKeyID != c.Key {
|
|
|
|
t.Fatalf("AccessKeyID mismatch, expected: (%s), got (%s)", c.Key, v.AccessKeyID)
|
|
|
|
}
|
|
|
|
if v.SecretAccessKey != c.Secret {
|
|
|
|
t.Fatalf("SecretAccessKey mismatch, expected: (%s), got (%s)", c.Secret, v.SecretAccessKey)
|
|
|
|
}
|
|
|
|
if v.SessionToken != c.Token {
|
|
|
|
t.Fatalf("SessionToken mismatch, expected: (%s), got (%s)", c.Token, v.SessionToken)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestAWSConfig_shouldIAM is designed to test the scenario of running Terraform
|
|
|
|
// from an EC2 instance, without environment variables or manually supplied
|
|
|
|
// credentials.
|
|
|
|
func TestAWSConfig_shouldIAM(t *testing.T) {
|
|
|
|
// clear AWS_* environment variables
|
|
|
|
resetEnv := unsetEnv(t)
|
|
|
|
defer resetEnv()
|
|
|
|
|
|
|
|
// capture the test server's close method, to call after the test returns
|
|
|
|
ts := awsEnv(t)
|
|
|
|
defer ts()
|
|
|
|
|
|
|
|
// An empty config, no key supplied
|
|
|
|
cfg := Config{}
|
|
|
|
|
2016-01-11 16:22:09 +01:00
|
|
|
creds := getCreds(cfg.AccessKey, cfg.SecretKey, cfg.Token, cfg.Profile, cfg.CredsFilename)
|
2015-12-10 22:43:13 +01:00
|
|
|
if creds == nil {
|
|
|
|
t.Fatalf("Expected a static creds provider to be returned")
|
|
|
|
}
|
|
|
|
|
|
|
|
v, err := creds.Get()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Error gettings creds: %s", err)
|
|
|
|
}
|
|
|
|
if v.AccessKeyID != "somekey" {
|
|
|
|
t.Fatalf("AccessKeyID mismatch, expected: (somekey), got (%s)", v.AccessKeyID)
|
|
|
|
}
|
|
|
|
if v.SecretAccessKey != "somesecret" {
|
|
|
|
t.Fatalf("SecretAccessKey mismatch, expected: (somesecret), got (%s)", v.SecretAccessKey)
|
|
|
|
}
|
|
|
|
if v.SessionToken != "sometoken" {
|
|
|
|
t.Fatalf("SessionToken mismatch, expected: (sometoken), got (%s)", v.SessionToken)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestAWSConfig_shouldIAM is designed to test the scenario of running Terraform
|
|
|
|
// from an EC2 instance, without environment variables or manually supplied
|
|
|
|
// credentials.
|
|
|
|
func TestAWSConfig_shouldIgnoreIAM(t *testing.T) {
|
|
|
|
resetEnv := unsetEnv(t)
|
|
|
|
defer resetEnv()
|
|
|
|
// capture the test server's close method, to call after the test returns
|
|
|
|
ts := awsEnv(t)
|
|
|
|
defer ts()
|
|
|
|
simple := []struct {
|
|
|
|
Key, Secret, Token string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
Key: "test",
|
|
|
|
Secret: "secret",
|
|
|
|
}, {
|
|
|
|
Key: "test",
|
|
|
|
Secret: "test",
|
|
|
|
Token: "test",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range simple {
|
|
|
|
cfg := Config{
|
|
|
|
AccessKey: c.Key,
|
|
|
|
SecretKey: c.Secret,
|
|
|
|
Token: c.Token,
|
|
|
|
}
|
|
|
|
|
2016-01-11 16:22:09 +01:00
|
|
|
creds := getCreds(cfg.AccessKey, cfg.SecretKey, cfg.Token, cfg.Profile, cfg.CredsFilename)
|
2015-12-10 22:43:13 +01:00
|
|
|
if creds == nil {
|
|
|
|
t.Fatalf("Expected a static creds provider to be returned")
|
|
|
|
}
|
|
|
|
v, err := creds.Get()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Error gettings creds: %s", err)
|
|
|
|
}
|
|
|
|
if v.AccessKeyID != c.Key {
|
|
|
|
t.Fatalf("AccessKeyID mismatch, expected: (%s), got (%s)", c.Key, v.AccessKeyID)
|
|
|
|
}
|
|
|
|
if v.SecretAccessKey != c.Secret {
|
|
|
|
t.Fatalf("SecretAccessKey mismatch, expected: (%s), got (%s)", c.Secret, v.SecretAccessKey)
|
|
|
|
}
|
|
|
|
if v.SessionToken != c.Token {
|
|
|
|
t.Fatalf("SessionToken mismatch, expected: (%s), got (%s)", c.Token, v.SessionToken)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-11 16:22:09 +01:00
|
|
|
var credentialsFileContents = `[myprofile]
|
|
|
|
aws_access_key_id = accesskey
|
|
|
|
aws_secret_access_key = secretkey
|
|
|
|
`
|
|
|
|
|
|
|
|
func TestAWSConfig_shouldBeShared(t *testing.T) {
|
|
|
|
file, err := ioutil.TempFile(os.TempDir(), "terraform_aws_cred")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Error writing temporary credentials file: %s", err)
|
|
|
|
}
|
|
|
|
_, err = file.WriteString(credentialsFileContents)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Error writing temporary credentials to file: %s", err)
|
|
|
|
}
|
|
|
|
err = file.Close()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Error closing temporary credentials file: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
defer os.Remove(file.Name())
|
|
|
|
|
|
|
|
resetEnv := unsetEnv(t)
|
|
|
|
defer resetEnv()
|
|
|
|
|
|
|
|
if err := os.Setenv("AWS_PROFILE", "myprofile"); err != nil {
|
|
|
|
t.Fatalf("Error resetting env var AWS_PROFILE: %s", err)
|
|
|
|
}
|
|
|
|
if err := os.Setenv("AWS_SHARED_CREDENTIALS_FILE", file.Name()); err != nil {
|
|
|
|
t.Fatalf("Error resetting env var AWS_SHARED_CREDENTIALS_FILE: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
creds := getCreds("", "", "", "myprofile", file.Name())
|
|
|
|
if creds == nil {
|
|
|
|
t.Fatalf("Expected a provider chain to be returned")
|
|
|
|
}
|
|
|
|
v, err := creds.Get()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Error gettings creds: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if v.AccessKeyID != "accesskey" {
|
|
|
|
t.Fatalf("AccessKeyID mismatch, expected (%s), got (%s)", "accesskey", v.AccessKeyID)
|
|
|
|
}
|
|
|
|
|
|
|
|
if v.SecretAccessKey != "secretkey" {
|
|
|
|
t.Fatalf("SecretAccessKey mismatch, expected (%s), got (%s)", "accesskey", v.AccessKeyID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-10 22:43:13 +01:00
|
|
|
func TestAWSConfig_shouldBeENV(t *testing.T) {
|
|
|
|
// need to set the environment variables to a dummy string, as we don't know
|
|
|
|
// what they may be at runtime without hardcoding here
|
|
|
|
s := "some_env"
|
|
|
|
resetEnv := setEnv(s, t)
|
2016-01-11 16:22:09 +01:00
|
|
|
|
2015-12-10 22:43:13 +01:00
|
|
|
defer resetEnv()
|
|
|
|
|
|
|
|
cfg := Config{}
|
2016-01-11 16:22:09 +01:00
|
|
|
creds := getCreds(cfg.AccessKey, cfg.SecretKey, cfg.Token, cfg.Profile, cfg.CredsFilename)
|
2015-12-10 22:43:13 +01:00
|
|
|
if creds == nil {
|
|
|
|
t.Fatalf("Expected a static creds provider to be returned")
|
|
|
|
}
|
|
|
|
v, err := creds.Get()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Error gettings creds: %s", err)
|
|
|
|
}
|
|
|
|
if v.AccessKeyID != s {
|
|
|
|
t.Fatalf("AccessKeyID mismatch, expected: (%s), got (%s)", s, v.AccessKeyID)
|
|
|
|
}
|
|
|
|
if v.SecretAccessKey != s {
|
|
|
|
t.Fatalf("SecretAccessKey mismatch, expected: (%s), got (%s)", s, v.SecretAccessKey)
|
|
|
|
}
|
|
|
|
if v.SessionToken != s {
|
|
|
|
t.Fatalf("SessionToken mismatch, expected: (%s), got (%s)", s, v.SessionToken)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// unsetEnv unsets enviornment variables for testing a "clean slate" with no
|
|
|
|
// credentials in the environment
|
|
|
|
func unsetEnv(t *testing.T) func() {
|
|
|
|
// Grab any existing AWS keys and preserve. In some tests we'll unset these, so
|
|
|
|
// we need to have them and restore them after
|
|
|
|
e := getEnv()
|
|
|
|
if err := os.Unsetenv("AWS_ACCESS_KEY_ID"); err != nil {
|
|
|
|
t.Fatalf("Error unsetting env var AWS_ACCESS_KEY_ID: %s", err)
|
|
|
|
}
|
|
|
|
if err := os.Unsetenv("AWS_SECRET_ACCESS_KEY"); err != nil {
|
|
|
|
t.Fatalf("Error unsetting env var AWS_SECRET_ACCESS_KEY: %s", err)
|
|
|
|
}
|
|
|
|
if err := os.Unsetenv("AWS_SESSION_TOKEN"); err != nil {
|
|
|
|
t.Fatalf("Error unsetting env var AWS_SESSION_TOKEN: %s", err)
|
|
|
|
}
|
2016-01-11 16:22:09 +01:00
|
|
|
if err := os.Unsetenv("AWS_PROFILE"); err != nil {
|
|
|
|
t.Fatalf("Error unsetting env var AWS_TOKEN: %s", err)
|
|
|
|
}
|
|
|
|
if err := os.Unsetenv("AWS_SHARED_CREDENTIALS_FILE"); err != nil {
|
|
|
|
t.Fatalf("Error unsetting env var AWS_SHARED_CREDENTIALS_FILE: %s", err)
|
|
|
|
}
|
2015-12-10 22:43:13 +01:00
|
|
|
|
|
|
|
return func() {
|
|
|
|
// re-set all the envs we unset above
|
|
|
|
if err := os.Setenv("AWS_ACCESS_KEY_ID", e.Key); err != nil {
|
|
|
|
t.Fatalf("Error resetting env var AWS_ACCESS_KEY_ID: %s", err)
|
|
|
|
}
|
|
|
|
if err := os.Setenv("AWS_SECRET_ACCESS_KEY", e.Secret); err != nil {
|
|
|
|
t.Fatalf("Error resetting env var AWS_SECRET_ACCESS_KEY: %s", err)
|
|
|
|
}
|
|
|
|
if err := os.Setenv("AWS_SESSION_TOKEN", e.Token); err != nil {
|
|
|
|
t.Fatalf("Error resetting env var AWS_SESSION_TOKEN: %s", err)
|
|
|
|
}
|
2016-01-11 16:22:09 +01:00
|
|
|
if err := os.Setenv("AWS_PROFILE", e.Profile); err != nil {
|
|
|
|
t.Fatalf("Error resetting env var AWS_PROFILE: %s", err)
|
|
|
|
}
|
|
|
|
if err := os.Setenv("AWS_SHARED_CREDENTIALS_FILE", e.CredsFilename); err != nil {
|
|
|
|
t.Fatalf("Error resetting env var AWS_SHARED_CREDENTIALS_FILE: %s", err)
|
|
|
|
}
|
2015-12-10 22:43:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func setEnv(s string, t *testing.T) func() {
|
|
|
|
e := getEnv()
|
|
|
|
// Set all the envs to a dummy value
|
|
|
|
if err := os.Setenv("AWS_ACCESS_KEY_ID", s); err != nil {
|
|
|
|
t.Fatalf("Error setting env var AWS_ACCESS_KEY_ID: %s", err)
|
|
|
|
}
|
|
|
|
if err := os.Setenv("AWS_SECRET_ACCESS_KEY", s); err != nil {
|
|
|
|
t.Fatalf("Error setting env var AWS_SECRET_ACCESS_KEY: %s", err)
|
|
|
|
}
|
|
|
|
if err := os.Setenv("AWS_SESSION_TOKEN", s); err != nil {
|
|
|
|
t.Fatalf("Error setting env var AWS_SESSION_TOKEN: %s", err)
|
|
|
|
}
|
2016-01-11 16:22:09 +01:00
|
|
|
if err := os.Setenv("AWS_PROFILE", s); err != nil {
|
|
|
|
t.Fatalf("Error setting env var AWS_PROFILE: %s", err)
|
|
|
|
}
|
|
|
|
if err := os.Setenv("AWS_SHARED_CREDENTIALS_FILE", s); err != nil {
|
|
|
|
t.Fatalf("Error setting env var AWS_SHARED_CREDENTIALS_FLE: %s", err)
|
|
|
|
}
|
2015-12-10 22:43:13 +01:00
|
|
|
|
|
|
|
return func() {
|
|
|
|
// re-set all the envs we unset above
|
|
|
|
if err := os.Setenv("AWS_ACCESS_KEY_ID", e.Key); err != nil {
|
|
|
|
t.Fatalf("Error resetting env var AWS_ACCESS_KEY_ID: %s", err)
|
|
|
|
}
|
|
|
|
if err := os.Setenv("AWS_SECRET_ACCESS_KEY", e.Secret); err != nil {
|
|
|
|
t.Fatalf("Error resetting env var AWS_SECRET_ACCESS_KEY: %s", err)
|
|
|
|
}
|
|
|
|
if err := os.Setenv("AWS_SESSION_TOKEN", e.Token); err != nil {
|
|
|
|
t.Fatalf("Error resetting env var AWS_SESSION_TOKEN: %s", err)
|
|
|
|
}
|
2016-01-11 16:22:09 +01:00
|
|
|
if err := os.Setenv("AWS_PROFILE", e.Profile); err != nil {
|
|
|
|
t.Fatalf("Error setting env var AWS_PROFILE: %s", err)
|
|
|
|
}
|
|
|
|
if err := os.Setenv("AWS_SHARED_CREDENTIALS_FILE", s); err != nil {
|
|
|
|
t.Fatalf("Error setting env var AWS_SHARED_CREDENTIALS_FLE: %s", err)
|
|
|
|
}
|
2015-12-10 22:43:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// awsEnv establishes a httptest server to mock out the internal AWS Metadata
|
|
|
|
// service. IAM Credentials are retrieved by the EC2RoleProvider, which makes
|
|
|
|
// API calls to this internal URL. By replacing the server with a test server,
|
|
|
|
// we can simulate an AWS environment
|
|
|
|
func awsEnv(t *testing.T) func() {
|
|
|
|
routes := routes{}
|
|
|
|
if err := json.Unmarshal([]byte(aws_routes), &routes); err != nil {
|
|
|
|
t.Fatalf("Failed to unmarshal JSON in AWS ENV test: %s", err)
|
|
|
|
}
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
w.Header().Set("Content-Type", "text/plain")
|
|
|
|
w.Header().Add("Server", "MockEC2")
|
|
|
|
for _, e := range routes.Endpoints {
|
|
|
|
if r.RequestURI == e.Uri {
|
|
|
|
fmt.Fprintln(w, e.Body)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}))
|
|
|
|
|
|
|
|
os.Setenv("AWS_METADATA_URL", ts.URL+"/latest")
|
|
|
|
return ts.Close
|
|
|
|
}
|
|
|
|
|
|
|
|
func getEnv() *currentEnv {
|
|
|
|
// Grab any existing AWS keys and preserve. In some tests we'll unset these, so
|
|
|
|
// we need to have them and restore them after
|
|
|
|
return ¤tEnv{
|
2016-01-11 16:22:09 +01:00
|
|
|
Key: os.Getenv("AWS_ACCESS_KEY_ID"),
|
|
|
|
Secret: os.Getenv("AWS_SECRET_ACCESS_KEY"),
|
|
|
|
Token: os.Getenv("AWS_SESSION_TOKEN"),
|
|
|
|
Profile: os.Getenv("AWS_TOKEN"),
|
|
|
|
CredsFilename: os.Getenv("AWS_SHARED_CREDENTIALS_FILE"),
|
2015-12-10 22:43:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// struct to preserve the current environment
|
|
|
|
type currentEnv struct {
|
2016-01-11 16:22:09 +01:00
|
|
|
Key, Secret, Token, Profile, CredsFilename string
|
2015-12-10 22:43:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
type routes struct {
|
|
|
|
Endpoints []*endpoint `json:"endpoints"`
|
|
|
|
}
|
|
|
|
type endpoint struct {
|
|
|
|
Uri string `json:"uri"`
|
|
|
|
Body string `json:"body"`
|
|
|
|
}
|
|
|
|
|
|
|
|
const aws_routes = `
|
|
|
|
{
|
|
|
|
"endpoints": [
|
|
|
|
{
|
|
|
|
"uri": "/latest/meta-data/iam/security-credentials",
|
|
|
|
"body": "test_role"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"uri": "/latest/meta-data/iam/security-credentials/test_role",
|
|
|
|
"body": "{\"Code\":\"Success\",\"LastUpdated\":\"2015-12-11T17:17:25Z\",\"Type\":\"AWS-HMAC\",\"AccessKeyId\":\"somekey\",\"SecretAccessKey\":\"somesecret\",\"Token\":\"sometoken\"}"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
`
|