github.com/erriapo/terraform@v0.6.12-0.20160203182612-0340ea72354f/builtin/providers/aws/config_test.go (about)

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