Skip IAM/STS validation and metadata check (#7874)
* Skip IAM/STS validation and metadata check * Skip IAM/STS identity validation - For environments or other api implementations where there are no IAM/STS endpoints available, this option lets you opt out from that provider initialization step. * Skip metdata api check - For environments in which you know ahead of time there isn't going to be a metadta api endpoint, this option lets you opt out from that check to save time. * Allow iam/sts initialization even if skipping account/cred validation (#7874) * Split out skip of IAM validation into credentials and account id (#7874)
This commit is contained in:
parent
6b477e888a
commit
c2bcb5fbe5
|
@ -86,18 +86,18 @@ func parseAccountIdFromArn(arn string) (string, error) {
|
|||
// This function is responsible for reading credentials from the
|
||||
// environment in the case that they're not explicitly specified
|
||||
// in the Terraform configuration.
|
||||
func GetCredentials(key, secret, token, profile, credsfile string) *awsCredentials.Credentials {
|
||||
func GetCredentials(c *Config) *awsCredentials.Credentials {
|
||||
// build a chain provider, lazy-evaulated by aws-sdk
|
||||
providers := []awsCredentials.Provider{
|
||||
&awsCredentials.StaticProvider{Value: awsCredentials.Value{
|
||||
AccessKeyID: key,
|
||||
SecretAccessKey: secret,
|
||||
SessionToken: token,
|
||||
AccessKeyID: c.AccessKey,
|
||||
SecretAccessKey: c.SecretKey,
|
||||
SessionToken: c.Token,
|
||||
}},
|
||||
&awsCredentials.EnvProvider{},
|
||||
&awsCredentials.SharedCredentialsProvider{
|
||||
Filename: credsfile,
|
||||
Profile: profile,
|
||||
Filename: c.CredsFilename,
|
||||
Profile: c.Profile,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -114,19 +114,21 @@ func GetCredentials(key, secret, token, profile, credsfile string) *awsCredentia
|
|||
// Real AWS should reply to a simple metadata request.
|
||||
// We check it actually does to ensure something else didn't just
|
||||
// happen to be listening on the same IP:Port
|
||||
metadataClient := ec2metadata.New(session.New(cfg))
|
||||
if metadataClient.Available() {
|
||||
providers = append(providers, &ec2rolecreds.EC2RoleProvider{
|
||||
Client: metadataClient,
|
||||
})
|
||||
log.Printf("[INFO] AWS EC2 instance detected via default metadata" +
|
||||
" API endpoint, EC2RoleProvider added to the auth chain")
|
||||
} else {
|
||||
if usedEndpoint == "" {
|
||||
usedEndpoint = "default location"
|
||||
if c.SkipMetadataApiCheck == false {
|
||||
metadataClient := ec2metadata.New(session.New(cfg))
|
||||
if metadataClient.Available() {
|
||||
providers = append(providers, &ec2rolecreds.EC2RoleProvider{
|
||||
Client: metadataClient,
|
||||
})
|
||||
log.Printf("[INFO] AWS EC2 instance detected via default metadata" +
|
||||
" API endpoint, EC2RoleProvider added to the auth chain")
|
||||
} else {
|
||||
if usedEndpoint == "" {
|
||||
usedEndpoint = "default location"
|
||||
}
|
||||
log.Printf("[WARN] Ignoring AWS metadata API endpoint at %s "+
|
||||
"as it doesn't return any instance-id", usedEndpoint)
|
||||
}
|
||||
log.Printf("[WARN] Ignoring AWS metadata API endpoint at %s "+
|
||||
"as it doesn't return any instance-id", usedEndpoint)
|
||||
}
|
||||
|
||||
return awsCredentials.NewChainCredentials(providers)
|
||||
|
|
|
@ -218,7 +218,7 @@ func TestAWSGetCredentials_shouldError(t *testing.T) {
|
|||
defer resetEnv()
|
||||
cfg := Config{}
|
||||
|
||||
c := GetCredentials(cfg.AccessKey, cfg.SecretKey, cfg.Token, cfg.Profile, cfg.CredsFilename)
|
||||
c := GetCredentials(&cfg)
|
||||
_, err := c.Get()
|
||||
if awsErr, ok := err.(awserr.Error); ok {
|
||||
if awsErr.Code() != "NoCredentialProviders" {
|
||||
|
@ -251,7 +251,7 @@ func TestAWSGetCredentials_shouldBeStatic(t *testing.T) {
|
|||
Token: c.Token,
|
||||
}
|
||||
|
||||
creds := GetCredentials(cfg.AccessKey, cfg.SecretKey, cfg.Token, cfg.Profile, cfg.CredsFilename)
|
||||
creds := GetCredentials(&cfg)
|
||||
if creds == nil {
|
||||
t.Fatalf("Expected a static creds provider to be returned")
|
||||
}
|
||||
|
@ -286,7 +286,7 @@ func TestAWSGetCredentials_shouldIAM(t *testing.T) {
|
|||
// An empty config, no key supplied
|
||||
cfg := Config{}
|
||||
|
||||
creds := GetCredentials(cfg.AccessKey, cfg.SecretKey, cfg.Token, cfg.Profile, cfg.CredsFilename)
|
||||
creds := GetCredentials(&cfg)
|
||||
if creds == nil {
|
||||
t.Fatalf("Expected a static creds provider to be returned")
|
||||
}
|
||||
|
@ -335,7 +335,7 @@ func TestAWSGetCredentials_shouldIgnoreIAM(t *testing.T) {
|
|||
Token: c.Token,
|
||||
}
|
||||
|
||||
creds := GetCredentials(cfg.AccessKey, cfg.SecretKey, cfg.Token, cfg.Profile, cfg.CredsFilename)
|
||||
creds := GetCredentials(&cfg)
|
||||
if creds == nil {
|
||||
t.Fatalf("Expected a static creds provider to be returned")
|
||||
}
|
||||
|
@ -362,7 +362,7 @@ func TestAWSGetCredentials_shouldErrorWithInvalidEndpoint(t *testing.T) {
|
|||
ts := invalidAwsEnv(t)
|
||||
defer ts()
|
||||
|
||||
creds := GetCredentials("", "", "", "", "")
|
||||
creds := GetCredentials(&Config{})
|
||||
v, err := creds.Get()
|
||||
if err == nil {
|
||||
t.Fatal("Expected error returned when getting creds w/ invalid EC2 endpoint")
|
||||
|
@ -380,7 +380,7 @@ func TestAWSGetCredentials_shouldIgnoreInvalidEndpoint(t *testing.T) {
|
|||
ts := invalidAwsEnv(t)
|
||||
defer ts()
|
||||
|
||||
creds := GetCredentials("accessKey", "secretKey", "", "", "")
|
||||
creds := GetCredentials(&Config{AccessKey: "accessKey", SecretKey: "secretKey"})
|
||||
v, err := creds.Get()
|
||||
if err != nil {
|
||||
t.Fatalf("Getting static credentials w/ invalid EC2 endpoint failed: %s", err)
|
||||
|
@ -406,7 +406,7 @@ func TestAWSGetCredentials_shouldCatchEC2RoleProvider(t *testing.T) {
|
|||
ts := awsEnv(t)
|
||||
defer ts()
|
||||
|
||||
creds := GetCredentials("", "", "", "", "")
|
||||
creds := GetCredentials(&Config{})
|
||||
if creds == nil {
|
||||
t.Fatalf("Expected an EC2Role creds provider to be returned")
|
||||
}
|
||||
|
@ -452,7 +452,7 @@ func TestAWSGetCredentials_shouldBeShared(t *testing.T) {
|
|||
t.Fatalf("Error resetting env var AWS_SHARED_CREDENTIALS_FILE: %s", err)
|
||||
}
|
||||
|
||||
creds := GetCredentials("", "", "", "myprofile", file.Name())
|
||||
creds := GetCredentials(&Config{Profile: "myprofile", CredsFilename: file.Name()})
|
||||
if creds == nil {
|
||||
t.Fatalf("Expected a provider chain to be returned")
|
||||
}
|
||||
|
@ -479,7 +479,7 @@ func TestAWSGetCredentials_shouldBeENV(t *testing.T) {
|
|||
defer resetEnv()
|
||||
|
||||
cfg := Config{}
|
||||
creds := GetCredentials(cfg.AccessKey, cfg.SecretKey, cfg.Token, cfg.Profile, cfg.CredsFilename)
|
||||
creds := GetCredentials(&cfg)
|
||||
if creds == nil {
|
||||
t.Fatalf("Expected a static creds provider to be returned")
|
||||
}
|
||||
|
|
|
@ -70,12 +70,16 @@ type Config struct {
|
|||
AllowedAccountIds []interface{}
|
||||
ForbiddenAccountIds []interface{}
|
||||
|
||||
DynamoDBEndpoint string
|
||||
KinesisEndpoint string
|
||||
Ec2Endpoint string
|
||||
IamEndpoint string
|
||||
ElbEndpoint string
|
||||
Insecure bool
|
||||
DynamoDBEndpoint string
|
||||
KinesisEndpoint string
|
||||
Ec2Endpoint string
|
||||
IamEndpoint string
|
||||
ElbEndpoint string
|
||||
S3Endpoint string
|
||||
Insecure bool
|
||||
SkipIamCredsValidation bool
|
||||
SkipIamAccountId bool
|
||||
SkipMetadataApiCheck bool
|
||||
}
|
||||
|
||||
type AWSClient struct {
|
||||
|
@ -141,7 +145,7 @@ func (c *Config) Client() (interface{}, error) {
|
|||
client.region = c.Region
|
||||
|
||||
log.Println("[INFO] Building AWS auth structure")
|
||||
creds := GetCredentials(c.AccessKey, c.SecretKey, c.Token, c.Profile, c.CredsFilename)
|
||||
creds := GetCredentials(c)
|
||||
// Call Get to check for credential provider. If nothing found, we'll get an
|
||||
// error, and we can present it nicely to the user
|
||||
cp, err := creds.Get()
|
||||
|
@ -199,19 +203,24 @@ func (c *Config) Client() (interface{}, error) {
|
|||
client.iamconn = iam.New(awsIamSess)
|
||||
client.stsconn = sts.New(sess)
|
||||
|
||||
err = c.ValidateCredentials(client.stsconn)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
return nil, &multierror.Error{Errors: errs}
|
||||
}
|
||||
accountId, err := GetAccountId(client.iamconn, client.stsconn, cp.ProviderName)
|
||||
if err == nil {
|
||||
client.accountid = accountId
|
||||
if c.SkipIamCredsValidation == false {
|
||||
err = c.ValidateCredentials(client.stsconn)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
return nil, &multierror.Error{Errors: errs}
|
||||
}
|
||||
}
|
||||
|
||||
authErr := c.ValidateAccountId(client.accountid)
|
||||
if authErr != nil {
|
||||
errs = append(errs, authErr)
|
||||
if c.SkipIamAccountId == false {
|
||||
accountId, err := GetAccountId(client.iamconn, client.stsconn, cp.ProviderName)
|
||||
if err == nil {
|
||||
client.accountid = accountId
|
||||
}
|
||||
|
||||
authErr := c.ValidateAccountId(client.accountid)
|
||||
if authErr != nil {
|
||||
errs = append(errs, authErr)
|
||||
}
|
||||
}
|
||||
|
||||
client.apigateway = apigateway.New(sess)
|
||||
|
|
|
@ -100,6 +100,7 @@ func Provider() terraform.ResourceProvider {
|
|||
Default: "",
|
||||
Description: descriptions["kinesis_endpoint"],
|
||||
},
|
||||
|
||||
"endpoints": endpointsSchema(),
|
||||
|
||||
"insecure": &schema.Schema{
|
||||
|
@ -108,6 +109,27 @@ func Provider() terraform.ResourceProvider {
|
|||
Default: false,
|
||||
Description: descriptions["insecure"],
|
||||
},
|
||||
|
||||
"skip_iam_creds_validation": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
Description: descriptions["skip_iam_creds_validation"],
|
||||
},
|
||||
|
||||
"skip_iam_account_id": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
Description: descriptions["skip_iam_account_id"],
|
||||
},
|
||||
|
||||
"skip_metadata_api_check": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
Description: descriptions["skip_metadata_api_check"],
|
||||
},
|
||||
},
|
||||
|
||||
DataSourcesMap: map[string]*schema.Resource{
|
||||
|
@ -332,21 +354,33 @@ func init() {
|
|||
|
||||
"insecure": "Explicitly allow the provider to perform \"insecure\" SSL requests. If omitted," +
|
||||
"default value is `false`",
|
||||
|
||||
"skip_iam_creds_validation": "Skip the IAM/STS credentials validation. " +
|
||||
"Used for AWS API implementations that do not use IAM.",
|
||||
|
||||
"skip_iam_account_id": "Skip the request of account id to IAM/STS. " +
|
||||
"Used for AWS API implementations that do not use IAM.",
|
||||
|
||||
"skip_medatadata_api_check": "Skip the AWS Metadata API check. " +
|
||||
"Used for AWS API implementations that do not have a metadata api endpoint.",
|
||||
}
|
||||
}
|
||||
|
||||
func providerConfigure(d *schema.ResourceData) (interface{}, error) {
|
||||
config := Config{
|
||||
AccessKey: d.Get("access_key").(string),
|
||||
SecretKey: d.Get("secret_key").(string),
|
||||
Profile: d.Get("profile").(string),
|
||||
CredsFilename: d.Get("shared_credentials_file").(string),
|
||||
Token: d.Get("token").(string),
|
||||
Region: d.Get("region").(string),
|
||||
MaxRetries: d.Get("max_retries").(int),
|
||||
DynamoDBEndpoint: d.Get("dynamodb_endpoint").(string),
|
||||
KinesisEndpoint: d.Get("kinesis_endpoint").(string),
|
||||
Insecure: d.Get("insecure").(bool),
|
||||
AccessKey: d.Get("access_key").(string),
|
||||
SecretKey: d.Get("secret_key").(string),
|
||||
Profile: d.Get("profile").(string),
|
||||
CredsFilename: d.Get("shared_credentials_file").(string),
|
||||
Token: d.Get("token").(string),
|
||||
Region: d.Get("region").(string),
|
||||
MaxRetries: d.Get("max_retries").(int),
|
||||
DynamoDBEndpoint: d.Get("dynamodb_endpoint").(string),
|
||||
KinesisEndpoint: d.Get("kinesis_endpoint").(string),
|
||||
Insecure: d.Get("insecure").(bool),
|
||||
SkipIamCredsValidation: d.Get("skip_iam_creds_validation").(bool),
|
||||
SkipIamAccountId: d.Get("skip_iam_account_id").(bool),
|
||||
SkipMetadataApiCheck: d.Get("skip_metadata_api_check").(bool),
|
||||
}
|
||||
|
||||
endpointsSet := d.Get("endpoints").(*schema.Set)
|
||||
|
|
|
@ -60,7 +60,13 @@ func s3Factory(conf map[string]string) (Client, error) {
|
|||
kmsKeyID := conf["kms_key_id"]
|
||||
|
||||
var errs []error
|
||||
creds := terraformAws.GetCredentials(conf["access_key"], conf["secret_key"], conf["token"], conf["profile"], conf["shared_credentials_file"])
|
||||
creds := terraformAws.GetCredentials(&terraformAws.Config{
|
||||
AccessKey: conf["access_key"],
|
||||
SecretKey: conf["secret_key"],
|
||||
Token: conf["token"],
|
||||
Profile: conf["profile"],
|
||||
CredsFilename: conf["shared_credentials_file"],
|
||||
})
|
||||
// Call Get to check for credential provider. If nothing found, we'll get an
|
||||
// error, and we can present it nicely to the user
|
||||
_, err := creds.Get()
|
||||
|
|
Loading…
Reference in New Issue