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 &currentEnv{
   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  `