Skip to content

Commit

Permalink
Merge pull request #54 from 9rnt/main
Browse files Browse the repository at this point in the history
Allow provider to use the external ID when assuming the role in the p…
  • Loading branch information
phillbaker authored Jul 24, 2023
2 parents cfbbefd + 63bdd48 commit 7555b94
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 41 deletions.
7 changes: 5 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ EOF

- `aws_access_key` (String) The access key for use with AWS opensearch Service domains
- `aws_assume_role_arn` (String) Amazon Resource Name of an IAM Role to assume prior to making AWS API calls.
- `aws_assume_role_external_id` (Optional) - External ID configured in the role to assume prior to making AWS API calls.
- `aws_profile` (String) The AWS profile for use with AWS opensearch Service domains
- `aws_region` (String) The AWS region for use in signing of AWS opensearch requests. Must be specified in order to use AWS URL signing with AWS OpenSearch endpoint exposed on a custom DNS domain.
- `aws_secret_key` (String) The secret key for use with AWS opensearch Service domains
Expand Down Expand Up @@ -115,13 +116,15 @@ provider "opensearch" {
#### Assume role configuration

You can instruct the provider to assume a role in AWS before interacting with the cluster by setting the `aws_assume_role_arn` variable.
When necessary, use the aws_assume_role_external_id to pass the extenral ID configured in the policy of the role for the provider to assume the role.

Example usage:

```tf
provider "opensearch" {
url = "https://search-foo-bar-pqrhr4w3u4dzervg41frow4mmy.us-east-1.es.amazonaws.com"
aws_assume_role_arn = "arn:aws:iam::012345678901:role/rolename"
url = "https://search-foo-bar-pqrhr4w3u4dzervg41frow4mmy.us-east-1.es.amazonaws.com"
aws_assume_role_arn = "arn:aws:iam::012345678901:role/rolename"
aws_assume_role_external_id = "SecretID"
}
```

Expand Down
82 changes: 47 additions & 35 deletions provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,29 +40,30 @@ const (
var awsUrlRegexp = regexp.MustCompile(`([a-z0-9-]+).es.amazonaws.com$`)

type ProviderConf struct {
rawUrl string
insecure bool
sniffing bool
healthchecking bool
cacertFile string
username string
password string
token string
tokenName string
parsedUrl *url.URL
signAWSRequests bool
osVersion string
pingTimeoutSeconds int
awsRegion string
awsAssumeRoleArn string
awsAccessKeyId string
awsSecretAccessKey string
awsSessionToken string
awsSig4Service string
awsProfile string
certPemPath string
keyPemPath string
hostOverride string
rawUrl string
insecure bool
sniffing bool
healthchecking bool
cacertFile string
username string
password string
token string
tokenName string
parsedUrl *url.URL
signAWSRequests bool
osVersion string
pingTimeoutSeconds int
awsRegion string
awsAssumeRoleArn string
awsAssumeRoleExternalID string
awsAccessKeyId string
awsSecretAccessKey string
awsSessionToken string
awsSig4Service string
awsProfile string
certPemPath string
keyPemPath string
hostOverride string
// determined after connecting to the server
flavor ServerFlavor
}
Expand Down Expand Up @@ -118,6 +119,12 @@ func Provider() *schema.Provider {
Default: "",
Description: "Amazon Resource Name of an IAM Role to assume prior to making AWS API calls.",
},
"aws_assume_role_external_id": {
Type: schema.TypeString,
Optional: true,
Default: "",
Description: "External ID configured in the IAM policy of the IAM Role to assume prior to making AWS API calls.",
},
"aws_access_key": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -264,14 +271,15 @@ func providerConfigure(c context.Context, d *schema.ResourceData) (interface{},
pingTimeoutSeconds: d.Get("version_ping_timeout").(int),
awsRegion: d.Get("aws_region").(string),

awsAssumeRoleArn: d.Get("aws_assume_role_arn").(string),
awsAccessKeyId: d.Get("aws_access_key").(string),
awsSecretAccessKey: d.Get("aws_secret_key").(string),
awsSessionToken: d.Get("aws_token").(string),
awsProfile: d.Get("aws_profile").(string),
certPemPath: d.Get("client_cert_path").(string),
keyPemPath: d.Get("client_key_path").(string),
hostOverride: d.Get("host_override").(string),
awsAssumeRoleArn: d.Get("aws_assume_role_arn").(string),
awsAssumeRoleExternalID: d.Get("aws_assume_role_external_id").(string),
awsAccessKeyId: d.Get("aws_access_key").(string),
awsSecretAccessKey: d.Get("aws_secret_key").(string),
awsSessionToken: d.Get("aws_token").(string),
awsProfile: d.Get("aws_profile").(string),
certPemPath: d.Get("client_cert_path").(string),
keyPemPath: d.Get("client_key_path").(string),
hostOverride: d.Get("host_override").(string),
}, nil
}

Expand Down Expand Up @@ -457,15 +465,16 @@ func getClient(conf *ProviderConf) (interface{}, error) {
return relevantClient, nil
}

func assumeRoleCredentials(region, roleARN, profile string) *awscredentials.Credentials {
func assumeRoleCredentials(region, roleARN, roleExternalID, profile string) *awscredentials.Credentials {
sessOpts := awsSessionOptions(region)
sessOpts.Profile = profile

sess := awssession.Must(awssession.NewSessionWithOptions(sessOpts))
stsClient := awssts.New(sess)
assumeRoleProvider := &awsstscreds.AssumeRoleProvider{
Client: stsClient,
RoleARN: roleARN,
Client: stsClient,
RoleARN: roleARN,
ExternalID: aws.String(roleExternalID),
}

return awscredentials.NewChainCredentials([]awscredentials.Provider{assumeRoleProvider})
Expand Down Expand Up @@ -503,7 +512,10 @@ func awsSession(region string, conf *ProviderConf) *awssession.Session {
if conf.awsAccessKeyId != "" {
sessOpts.Config.Credentials = awscredentials.NewStaticCredentials(conf.awsAccessKeyId, conf.awsSecretAccessKey, conf.awsSessionToken)
} else if conf.awsAssumeRoleArn != "" {
sessOpts.Config.Credentials = assumeRoleCredentials(region, conf.awsAssumeRoleArn, conf.awsProfile)
if conf.awsAssumeRoleExternalID == "" {
conf.awsAssumeRoleExternalID = ""
}
sessOpts.Config.Credentials = assumeRoleCredentials(region, conf.awsAssumeRoleArn, conf.awsAssumeRoleExternalID, conf.awsProfile)
} else if conf.awsProfile != "" {
sessOpts.Profile = conf.awsProfile
}
Expand Down
6 changes: 4 additions & 2 deletions provider/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,13 +182,15 @@ func TestAWSCredsAssumeRole(t *testing.T) {
testRegion := "us-east-1"

testConfig := map[string]interface{}{
"aws_assume_role_arn": "test_arn",
"aws_assume_role_arn": "test_arn",
"aws_assume_role_external_id": "secret_id",
}

testConfigData := schema.TestResourceDataRaw(t, Provider().Schema, testConfig)

conf := &ProviderConf{
awsAssumeRoleArn: testConfigData.Get("aws_assume_role_arn").(string),
awsAssumeRoleArn: testConfigData.Get("aws_assume_role_arn").(string),
awsAssumeRoleExternalID: testConfigData.Get("aws_assume_role_external_id").(string),
}
s := awsSession(testRegion, conf)
if s == nil {
Expand Down
6 changes: 4 additions & 2 deletions templates/index.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,15 @@ provider "opensearch" {
#### Assume role configuration

You can instruct the provider to assume a role in AWS before interacting with the cluster by setting the `aws_assume_role_arn` variable.
When necessary, use the aws_assume_role_external_id to pass the extenral ID configured in the policy of the role for the provider to assume the role.

Example usage:

```tf
provider "opensearch" {
url = "https://search-foo-bar-pqrhr4w3u4dzervg41frow4mmy.us-east-1.es.amazonaws.com"
aws_assume_role_arn = "arn:aws:iam::012345678901:role/rolename"
url = "https://search-foo-bar-pqrhr4w3u4dzervg41frow4mmy.us-east-1.es.amazonaws.com"
aws_assume_role_arn = "arn:aws:iam::012345678901:role/rolename"
aws_assume_role_external_id = "SecretID"
}
```

Expand Down

0 comments on commit 7555b94

Please sign in to comment.