From ee7cb6a6c2249087f534bf58b64be8ecebe6b6a3 Mon Sep 17 00:00:00 2001 From: Kay Craig Date: Wed, 17 Apr 2024 13:32:34 -0400 Subject: [PATCH 1/7] add basic external id support to aws auth sts configuration --- builtin/credential/aws/client.go | 20 ++++++++--------- builtin/credential/aws/path_config_sts.go | 26 +++++++++++++++++++---- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/builtin/credential/aws/client.go b/builtin/credential/aws/client.go index bed15bb6a491..a1a6a391c323 100644 --- a/builtin/credential/aws/client.go +++ b/builtin/credential/aws/client.go @@ -84,7 +84,7 @@ func (b *backend) getRawClientConfig(ctx context.Context, s logical.Storage, reg // It uses getRawClientConfig to obtain config for the runtime environment, and if // stsRole is a non-empty string, it will use AssumeRole to obtain a set of assumed // credentials. The credentials will expire after 15 minutes but will auto-refresh. -func (b *backend) getClientConfig(ctx context.Context, s logical.Storage, region, stsRole, accountID, clientType string) (*aws.Config, error) { +func (b *backend) getClientConfig(ctx context.Context, s logical.Storage, region, stsRole, externalID, accountID, clientType string) (*aws.Config, error) { config, err := b.getRawClientConfig(ctx, s, region, clientType) if err != nil { return nil, err @@ -105,7 +105,7 @@ func (b *backend) getClientConfig(ctx context.Context, s logical.Storage, region if err != nil { return nil, err } - assumedCredentials := stscreds.NewCredentials(sess, stsRole) + assumedCredentials := stscreds.NewCredentials(sess, stsRole, func(p *stscreds.AssumeRoleProvider) { p.ExternalID = aws.String(externalID) }) // Test that we actually have permissions to assume the role if _, err = assumedCredentials.Get(); err != nil { return nil, err @@ -180,22 +180,22 @@ func (b *backend) setCachedUserId(userId, arn string) { } } -func (b *backend) stsRoleForAccount(ctx context.Context, s logical.Storage, accountID string) (string, error) { +func (b *backend) stsRoleForAccount(ctx context.Context, s logical.Storage, accountID string) (string, string, error) { // Check if an STS configuration exists for the AWS account sts, err := b.lockedAwsStsEntry(ctx, s, accountID) if err != nil { - return "", fmt.Errorf("error fetching STS config for account ID %q: %w", accountID, err) + return "", "", fmt.Errorf("error fetching STS config for account ID %q: %w", accountID, err) } // An empty STS role signifies the master account if sts != nil { - return sts.StsRole, nil + return sts.StsRole, sts.ExternalID, nil } - return "", nil + return "", "", nil } // clientEC2 creates a client to interact with AWS EC2 API func (b *backend) clientEC2(ctx context.Context, s logical.Storage, region, accountID string) (*ec2.EC2, error) { - stsRole, err := b.stsRoleForAccount(ctx, s, accountID) + stsRole, stsExternalID, err := b.stsRoleForAccount(ctx, s, accountID) if err != nil { return nil, err } @@ -218,7 +218,7 @@ func (b *backend) clientEC2(ctx context.Context, s logical.Storage, region, acco // Create an AWS config object using a chain of providers var awsConfig *aws.Config - awsConfig, err = b.getClientConfig(ctx, s, region, stsRole, accountID, "ec2") + awsConfig, err = b.getClientConfig(ctx, s, region, stsRole, stsExternalID, accountID, "ec2") if err != nil { return nil, err } @@ -247,7 +247,7 @@ func (b *backend) clientEC2(ctx context.Context, s logical.Storage, region, acco // clientIAM creates a client to interact with AWS IAM API func (b *backend) clientIAM(ctx context.Context, s logical.Storage, region, accountID string) (*iam.IAM, error) { - stsRole, err := b.stsRoleForAccount(ctx, s, accountID) + stsRole, stsExternalID, err := b.stsRoleForAccount(ctx, s, accountID) if err != nil { return nil, err } @@ -277,7 +277,7 @@ func (b *backend) clientIAM(ctx context.Context, s logical.Storage, region, acco // Create an AWS config object using a chain of providers var awsConfig *aws.Config - awsConfig, err = b.getClientConfig(ctx, s, region, stsRole, accountID, "iam") + awsConfig, err = b.getClientConfig(ctx, s, region, stsRole, stsExternalID, accountID, "iam") if err != nil { return nil, err } diff --git a/builtin/credential/aws/path_config_sts.go b/builtin/credential/aws/path_config_sts.go index 21034f69feff..d2ff2d15a3f5 100644 --- a/builtin/credential/aws/path_config_sts.go +++ b/builtin/credential/aws/path_config_sts.go @@ -13,7 +13,8 @@ import ( // awsStsEntry is used to store details of an STS role for assumption type awsStsEntry struct { - StsRole string `json:"sts_role"` + StsRole string `json:"sts_role"` + ExternalID string `json:"external_id,omitempty"` // optional, but recommended } func (b *backend) pathListSts() *framework.Path { @@ -57,6 +58,11 @@ instances in this account.`, Description: `AWS ARN for STS role to be assumed when interacting with the account specified. The Vault server must have permissions to assume this role.`, }, + "external_id": { + Type: framework.TypeString, + Description: `AWS external ID to be used when assuming the STS role.`, + Required: false, + }, }, ExistenceCheck: b.pathConfigStsExistenceCheck, @@ -192,10 +198,15 @@ func (b *backend) pathConfigStsRead(ctx context.Context, req *logical.Request, d return nil, nil } + dt := map[string]interface{}{ + "sts_role": stsEntry.StsRole, + } + if stsEntry.ExternalID != "" { + dt["external_id"] = stsEntry.ExternalID + } + return &logical.Response{ - Data: map[string]interface{}{ - "sts_role": stsEntry.StsRole, - }, + Data: dt, }, nil } @@ -230,6 +241,13 @@ func (b *backend) pathConfigStsCreateUpdate(ctx context.Context, req *logical.Re return logical.ErrorResponse("sts role cannot be empty"), nil } + stsExternalID, ok := data.GetOk("external_id") + if ok { + stsEntry.ExternalID = stsExternalID.(string) + } + + b.Logger().Info("setting sts", "account_id", accountID, "sts_role", stsEntry.StsRole, "external_id", stsEntry.ExternalID) + // save the provided STS role if err := b.nonLockedSetAwsStsEntry(ctx, req.Storage, accountID, stsEntry); err != nil { return nil, err From 36420834759914dda26d8c2cdaabc10a05d20619 Mon Sep 17 00:00:00 2001 From: Kay Craig Date: Wed, 24 Apr 2024 13:00:38 -0400 Subject: [PATCH 2/7] documentation --- website/content/api-docs/auth/aws.mdx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/website/content/api-docs/auth/aws.mdx b/website/content/api-docs/auth/aws.mdx index 2a490c150845..6baea2cdec0c 100644 --- a/website/content/api-docs/auth/aws.mdx +++ b/website/content/api-docs/auth/aws.mdx @@ -437,6 +437,9 @@ when validating IAM principals or EC2 instances in the particular AWS account. - `sts_role` `(string: )` - AWS ARN for STS role to be assumed when interacting with the account specified. The Vault server must have permissions to assume this role. +- `external_id` `(string: "")` - External ID to be used when assuming + the STS role. If set, the STS role must be configured to require this + external ID. ### Sample payload From df9010b8abf694ae6038a0c43bd1ead553384edc Mon Sep 17 00:00:00 2001 From: Kay Craig Date: Wed, 24 Apr 2024 13:04:14 -0400 Subject: [PATCH 3/7] add changelog --- changelog/26628.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelog/26628.txt diff --git a/changelog/26628.txt b/changelog/26628.txt new file mode 100644 index 000000000000..2ab067f3ef09 --- /dev/null +++ b/changelog/26628.txt @@ -0,0 +1,3 @@ +```release-note:improvement +auth/aws: add support for external_ids in AWS assume-role +``` \ No newline at end of file From ea95bc0f2fc8791694b616132736cc91679039d3 Mon Sep 17 00:00:00 2001 From: Kay Craig Date: Tue, 30 Apr 2024 11:36:34 -0400 Subject: [PATCH 4/7] add external id to tests --- builtin/credential/aws/backend_test.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/builtin/credential/aws/backend_test.go b/builtin/credential/aws/backend_test.go index d56478266d9a..5d4a1760b60d 100644 --- a/builtin/credential/aws/backend_test.go +++ b/builtin/credential/aws/backend_test.go @@ -1046,6 +1046,7 @@ This is an acceptance test. export TEST_AWS_EC2_IAM_ROLE_ARN=$(aws iam get-role --role-name $(curl -q http://169.254.169.254/latest/meta-data/iam/security-credentials/ -S -s) --query Role.Arn --output text) export TEST_AWS_EC2_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) + If the test is not being run on an EC2 instance that has access to credentials using EC2RoleProvider, on top of the above vars, following needs to be set: @@ -1407,6 +1408,11 @@ func TestBackend_pathStsConfig(t *testing.T) { "sts_role": "arn:aws:iam:account1:role/myRole", } + data2 := map[string]interface{}{ + "sts_role": "arn:aws:iam:account1:role/myRole", + "external_id": "fake_id", + } + stsReq.Data = data // test create operation resp, err := b.HandleRequest(context.Background(), stsReq) @@ -1440,8 +1446,8 @@ func TestBackend_pathStsConfig(t *testing.T) { stsReq.Operation = logical.CreateOperation stsReq.Path = "config/sts/account2" - stsReq.Data = data - // create another entry to test the list operation + stsReq.Data = data2 + // create another entry with alternate data to test ExternalID and LIST resp, err = b.HandleRequest(context.Background(), stsReq) if err != nil || (resp != nil && resp.IsError()) { t.Fatal(err) From 1e118e2ac2519b82ab6e28e5c481539cfec4faf8 Mon Sep 17 00:00:00 2001 From: Kay Craig Date: Tue, 30 Apr 2024 11:47:07 -0400 Subject: [PATCH 5/7] fix proto --- helper/forwarding/types.pb.go | 2 +- helper/identity/mfa/types.pb.go | 2 +- helper/identity/types.pb.go | 2 +- helper/storagepacker/types.pb.go | 2 +- physical/raft/types.pb.go | 2 +- sdk/database/dbplugin/database.pb.go | 2 +- sdk/database/dbplugin/v5/proto/database.pb.go | 2 +- sdk/helper/clientcountutil/generation/generate_data.pb.go | 2 +- sdk/helper/pluginutil/multiplexing.pb.go | 2 +- sdk/logical/event.pb.go | 2 +- sdk/logical/identity.pb.go | 2 +- sdk/logical/plugin.pb.go | 2 +- sdk/logical/version.pb.go | 2 +- sdk/plugin/pb/backend.pb.go | 2 +- vault/activity/activity_log.pb.go | 2 +- vault/hcp_link/proto/link_control/link_control.pb.go | 2 +- vault/hcp_link/proto/meta/meta.pb.go | 2 +- vault/hcp_link/proto/node_status/status.pb.go | 2 +- vault/request_forwarding_service.pb.go | 2 +- vault/seal/multi_wrap_value.pb.go | 2 +- vault/tokens/token.pb.go | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/helper/forwarding/types.pb.go b/helper/forwarding/types.pb.go index 68cd1c47be73..de839a50df66 100644 --- a/helper/forwarding/types.pb.go +++ b/helper/forwarding/types.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: helper/forwarding/types.proto diff --git a/helper/identity/mfa/types.pb.go b/helper/identity/mfa/types.pb.go index c309215e82c3..90ad0fee921d 100644 --- a/helper/identity/mfa/types.pb.go +++ b/helper/identity/mfa/types.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: helper/identity/mfa/types.proto diff --git a/helper/identity/types.pb.go b/helper/identity/types.pb.go index 037f63e894e4..18570f33a008 100644 --- a/helper/identity/types.pb.go +++ b/helper/identity/types.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: helper/identity/types.proto diff --git a/helper/storagepacker/types.pb.go b/helper/storagepacker/types.pb.go index b4767746f2cc..292f849fbdea 100644 --- a/helper/storagepacker/types.pb.go +++ b/helper/storagepacker/types.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: helper/storagepacker/types.proto diff --git a/physical/raft/types.pb.go b/physical/raft/types.pb.go index 8f94eee83cbf..8388bafeec1f 100644 --- a/physical/raft/types.pb.go +++ b/physical/raft/types.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: physical/raft/types.proto diff --git a/sdk/database/dbplugin/database.pb.go b/sdk/database/dbplugin/database.pb.go index 6a2bacb0b513..5859109d0413 100644 --- a/sdk/database/dbplugin/database.pb.go +++ b/sdk/database/dbplugin/database.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: sdk/database/dbplugin/database.proto diff --git a/sdk/database/dbplugin/v5/proto/database.pb.go b/sdk/database/dbplugin/v5/proto/database.pb.go index e5986a5804ea..fec68c53b83c 100644 --- a/sdk/database/dbplugin/v5/proto/database.pb.go +++ b/sdk/database/dbplugin/v5/proto/database.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: sdk/database/dbplugin/v5/proto/database.proto diff --git a/sdk/helper/clientcountutil/generation/generate_data.pb.go b/sdk/helper/clientcountutil/generation/generate_data.pb.go index 25174d5de4ea..4df3957532ec 100644 --- a/sdk/helper/clientcountutil/generation/generate_data.pb.go +++ b/sdk/helper/clientcountutil/generation/generate_data.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: sdk/helper/clientcountutil/generation/generate_data.proto diff --git a/sdk/helper/pluginutil/multiplexing.pb.go b/sdk/helper/pluginutil/multiplexing.pb.go index 2327b2fbef3c..a4a3db5e82bf 100644 --- a/sdk/helper/pluginutil/multiplexing.pb.go +++ b/sdk/helper/pluginutil/multiplexing.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: sdk/helper/pluginutil/multiplexing.proto diff --git a/sdk/logical/event.pb.go b/sdk/logical/event.pb.go index 9198e8100bf6..6d7f28cee973 100644 --- a/sdk/logical/event.pb.go +++ b/sdk/logical/event.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: sdk/logical/event.proto diff --git a/sdk/logical/identity.pb.go b/sdk/logical/identity.pb.go index f2d81ba0630e..71a63d0d6a07 100644 --- a/sdk/logical/identity.pb.go +++ b/sdk/logical/identity.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: sdk/logical/identity.proto diff --git a/sdk/logical/plugin.pb.go b/sdk/logical/plugin.pb.go index 9669eaecf361..379eaf7e9a82 100644 --- a/sdk/logical/plugin.pb.go +++ b/sdk/logical/plugin.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: sdk/logical/plugin.proto diff --git a/sdk/logical/version.pb.go b/sdk/logical/version.pb.go index 3139a93bdf89..6076009afe31 100644 --- a/sdk/logical/version.pb.go +++ b/sdk/logical/version.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: sdk/logical/version.proto diff --git a/sdk/plugin/pb/backend.pb.go b/sdk/plugin/pb/backend.pb.go index 4b7df7060fda..76828cf24026 100644 --- a/sdk/plugin/pb/backend.pb.go +++ b/sdk/plugin/pb/backend.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: sdk/plugin/pb/backend.proto diff --git a/vault/activity/activity_log.pb.go b/vault/activity/activity_log.pb.go index 81f0b58248d4..0ff9230166f2 100644 --- a/vault/activity/activity_log.pb.go +++ b/vault/activity/activity_log.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: vault/activity/activity_log.proto diff --git a/vault/hcp_link/proto/link_control/link_control.pb.go b/vault/hcp_link/proto/link_control/link_control.pb.go index dd5565fa3f62..acaa9fa306cd 100644 --- a/vault/hcp_link/proto/link_control/link_control.pb.go +++ b/vault/hcp_link/proto/link_control/link_control.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: vault/hcp_link/proto/link_control/link_control.proto diff --git a/vault/hcp_link/proto/meta/meta.pb.go b/vault/hcp_link/proto/meta/meta.pb.go index 321b2c669dc0..03e5b9e73d3a 100644 --- a/vault/hcp_link/proto/meta/meta.pb.go +++ b/vault/hcp_link/proto/meta/meta.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: vault/hcp_link/proto/meta/meta.proto diff --git a/vault/hcp_link/proto/node_status/status.pb.go b/vault/hcp_link/proto/node_status/status.pb.go index 1e29dc2a0c20..afc0de15cd6c 100644 --- a/vault/hcp_link/proto/node_status/status.pb.go +++ b/vault/hcp_link/proto/node_status/status.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: vault/hcp_link/proto/node_status/status.proto diff --git a/vault/request_forwarding_service.pb.go b/vault/request_forwarding_service.pb.go index eb1b4110fcad..511b1049084d 100644 --- a/vault/request_forwarding_service.pb.go +++ b/vault/request_forwarding_service.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: vault/request_forwarding_service.proto diff --git a/vault/seal/multi_wrap_value.pb.go b/vault/seal/multi_wrap_value.pb.go index c61426582429..0709b5d8f7ac 100644 --- a/vault/seal/multi_wrap_value.pb.go +++ b/vault/seal/multi_wrap_value.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: vault/seal/multi_wrap_value.proto diff --git a/vault/tokens/token.pb.go b/vault/tokens/token.pb.go index a53dd665effd..696366b4e748 100644 --- a/vault/tokens/token.pb.go +++ b/vault/tokens/token.pb.go @@ -3,7 +3,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.0 // protoc (unknown) // source: vault/tokens/token.proto From 1944160765447020fd13666c04a7b19e4566aa1f Mon Sep 17 00:00:00 2001 From: kpcraig <3031348+kpcraig@users.noreply.github.com> Date: Tue, 30 Apr 2024 16:16:51 -0400 Subject: [PATCH 6/7] Update website/content/api-docs/auth/aws.mdx Co-authored-by: Sarah Chavis <62406755+schavis@users.noreply.github.com> --- website/content/api-docs/auth/aws.mdx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/website/content/api-docs/auth/aws.mdx b/website/content/api-docs/auth/aws.mdx index b1c15eef346a..450afadec3ed 100644 --- a/website/content/api-docs/auth/aws.mdx +++ b/website/content/api-docs/auth/aws.mdx @@ -438,9 +438,8 @@ when validating IAM principals or EC2 instances in the particular AWS account. - `sts_role` `(string: )` - AWS ARN for STS role to be assumed when interacting with the account specified. The Vault server must have permissions to assume this role. -- `external_id` `(string: "")` - External ID to be used when assuming - the STS role. If set, the STS role must be configured to require this - external ID. +- `external_id` `(string: "")` - The external ID expected by the STS role. The + associated STS role **must** be configured to require the external ID. ### Sample payload From 750ced2b49337eb988292d7fbbe820b82d85ec11 Mon Sep 17 00:00:00 2001 From: Kay Craig Date: Thu, 2 May 2024 12:35:04 -0400 Subject: [PATCH 7/7] verify second entry data in test --- builtin/credential/aws/backend_test.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/builtin/credential/aws/backend_test.go b/builtin/credential/aws/backend_test.go index 5d4a1760b60d..771dc0e31140 100644 --- a/builtin/credential/aws/backend_test.go +++ b/builtin/credential/aws/backend_test.go @@ -1409,7 +1409,7 @@ func TestBackend_pathStsConfig(t *testing.T) { } data2 := map[string]interface{}{ - "sts_role": "arn:aws:iam:account1:role/myRole", + "sts_role": "arn:aws:iam:account2:role/myRole2", "external_id": "fake_id", } @@ -1453,6 +1453,21 @@ func TestBackend_pathStsConfig(t *testing.T) { t.Fatal(err) } + // test second read + stsReq.Operation = logical.ReadOperation + resp, err = b.HandleRequest(context.Background(), stsReq) + if err != nil { + t.Fatal(err) + } + expectedStsRole = "arn:aws:iam:account2:role/myRole2" + expectedExternalID := "fake_id" + if resp.Data["sts_role"].(string) != expectedStsRole { + t.Fatalf("bad: expected:%s\n got:%s\n", expectedStsRole, resp.Data["sts_role"].(string)) + } + if resp.Data["external_id"].(string) != expectedExternalID { + t.Fatalf("bad: expected:%s\n got:%s\n", expectedExternalID, resp.Data["external_id"].(string)) + } + stsReq.Operation = logical.ListOperation stsReq.Path = "config/sts" // test list operation