auth/aws: Enhance AWS authentication with role assumption and custom endpoints. (#2679)

* auth/aws: Enhance AWS authentication with role assumption and custom endpoints.

- Refactor `getLoginData` to support role assumption using STS.
- Introduce custom endpoint resolvers for STS and IAM services.
- Update `getCredentialsConfig` to utilize new options for role ARN and session name.
- Implement `generateLoginData` to create presigned requests for AWS API calls.
- Add unit tests for role assumption logic, session token handling, and custom endpoint configuration.
- Migrate to `awsutil/v2` for improved credential management.

* auth/aws: Update CHANGELOG.

* Refactor AWS credential retrieval in generateLoginData for clear error handling.
This commit is contained in:
Balaji 2025-12-18 09:33:44 +05:30 committed by GitHub
parent 40b17648bc
commit 5f7ef99373
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 595 additions and 57 deletions

View file

@ -10,7 +10,12 @@ IMPROVEMENTS:
* Add support for networking allowlist fields (`allowed_ipv4_addresses`, `allowed_ipv6_addresses`, `allowed_ports`, `disable_strict_networking`) in `vault_secrets_sync_vercel_destination` resource. Requires Vault 1.19+. ([#2681](https://github.com/hashicorp/terraform-provider-vault/pull/2681))
* Add support for `tls_server_name` , `local_datacenter`, `socket_keep_alive`, `consistency` and `username_template` parameters for Cassandra in `vault_database_secret_backend_connection` resource. ([#2677](https://github.com/hashicorp/terraform-provider-vault/pull/2677))
* `vault_secrets_sync_aws_destination`: Add support for networking configuration parameters `allowed_ipv4_addresses`, `allowed_ipv6_addresses`, `allowed_ports`, and `disable_strict_networking` to control outbound connections from Vault to AWS Secrets Manager. Requires Vault 1.19.0+.([#2698](https://github.com/hashicorp/terraform-provider-vault/pull/2698))
* Updated dependencies:
* `github.com/hashicorp/go-secure-stdlib/awsutil` v0.3.0 -> v2.1.1
BUGS:
* `provider/auth_login_aws`: Fix issue where AWS authentication with IAM role assumption (`aws_role_arn`) was not working correctly due to incorrect credential handling ([#2679](https://github.com/hashicorp/terraform-provider-vault/pull/2679))
## 5.6.0 (December 19, 2025)
@ -28,7 +33,6 @@ BUGS:
* Fix LDAP auth tune block read failure caused by extra /tune segment in the API request path ([#2676](https://github.com/hashicorp/terraform-provider-vault/pull/2676))
## 5.5.0 (Nov 19, 2025)
BEHAVIOR CHANGES: With v5.5.0, the default value for `deny_null_bind` in the `vault_ldap_auth_backend` resource has changed from `false` to `true`

16
go.mod
View file

@ -9,6 +9,10 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0
github.com/aws/aws-sdk-go v1.55.8
github.com/aws/aws-sdk-go-v2 v1.32.5
github.com/aws/aws-sdk-go-v2/service/iam v1.38.1
github.com/aws/aws-sdk-go-v2/service/sts v1.33.1
github.com/aws/smithy-go v1.22.1
github.com/cenkalti/backoff/v4 v4.3.0
github.com/coreos/pkg v0.0.0-20230601102743-20bbbf26f4d8
github.com/denisenkom/go-mssqldb v0.12.3
@ -24,7 +28,7 @@ require (
github.com/hashicorp/go-hclog v1.6.3
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-retryablehttp v0.7.8
github.com/hashicorp/go-secure-stdlib/awsutil v0.3.0
github.com/hashicorp/go-secure-stdlib/awsutil/v2 v2.1.1
github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0
github.com/hashicorp/go-version v1.8.0
github.com/hashicorp/terraform-plugin-framework v1.16.1
@ -66,6 +70,16 @@ require (
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
github.com/armon/go-metrics v0.4.1 // indirect
github.com/armon/go-radix v1.0.0 // indirect
github.com/aws/aws-sdk-go-v2/config v1.28.5 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.46 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 // indirect
github.com/cloudflare/circl v1.6.1 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect

42
go.sum
View file

@ -71,9 +71,36 @@ github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aws/aws-sdk-go v1.34.0/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ=
github.com/aws/aws-sdk-go v1.55.8/go.mod h1:ZkViS9AqA6otK+JBBNH2++sx1sgxrPKcSzPPvQkUtXk=
github.com/aws/aws-sdk-go-v2 v1.32.5 h1:U8vdWJuY7ruAkzaOdD7guwJjD06YSKmnKCJs7s3IkIo=
github.com/aws/aws-sdk-go-v2 v1.32.5/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U=
github.com/aws/aws-sdk-go-v2/config v1.28.5 h1:Za41twdCXbuyyWv9LndXxZZv3QhTG1DinqlFsSuvtI0=
github.com/aws/aws-sdk-go-v2/config v1.28.5/go.mod h1:4VsPbHP8JdcdUDmbTVgNL/8w9SqOkM5jyY8ljIxLO3o=
github.com/aws/aws-sdk-go-v2/credentials v1.17.46 h1:AU7RcriIo2lXjUfHFnFKYsLCwgbz1E7Mm95ieIRDNUg=
github.com/aws/aws-sdk-go-v2/credentials v1.17.46/go.mod h1:1FmYyLGL08KQXQ6mcTlifyFXfJVCNJTVGuQP4m0d/UA=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 h1:sDSXIrlsFSFJtWKLQS4PUWRvrT580rrnuLydJrCQ/yA=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20/go.mod h1:WZ/c+w0ofps+/OUqMwWgnfrgzZH1DZO1RIkktICsqnY=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 h1:4usbeaes3yJnCFC7kfeyhkdkPtoRYPa/hTmCqMpKpLI=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24/go.mod h1:5CI1JemjVwde8m2WG3cz23qHKPOxbpkq0HaoreEgLIY=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 h1:N1zsICrQglfzaBnrfM0Ys00860C+QFwu6u/5+LomP+o=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24/go.mod h1:dCn9HbJ8+K31i8IQ8EWmWj0EiIk0+vKiHNMxTTYveAg=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
github.com/aws/aws-sdk-go-v2/service/iam v1.38.1 h1:hfkzDZHBp9jAT4zcd5mtqckpU4E3Ax0LQaEWWk1VgN8=
github.com/aws/aws-sdk-go-v2/service/iam v1.38.1/go.mod h1:u36ahDtZcQHGmVm/r+0L1sfKX4fzLEMdCqiKRKkUMVM=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 h1:wtpJ4zcwrSbwhECWQoI/g6WM9zqCcSpHDJIWSbMLOu4=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5/go.mod h1:qu/W9HXQbbQ4+1+JcZp0ZNPV31ym537ZJN+fiS7Ti8E=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 h1:3zu537oLmsPfDMyjnUS2g+F2vITgy5pB74tHI+JBNoM=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.6/go.mod h1:WJSZH2ZvepM6t6jwu4w/Z45Eoi75lPN7DcydSRtJg6Y=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 h1:K0OQAsDywb0ltlFrZm0JHPY3yZp/S9OaoLU33S7vPS8=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5/go.mod h1:ORITg+fyuMoeiQFiVGoqB3OydVTLkClw/ljbblMq6Cc=
github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 h1:6SZUVRQNvExYlMLbHdlKB48x0fLbc2iVROyaNEwBHbU=
github.com/aws/aws-sdk-go-v2/service/sts v1.33.1/go.mod h1:GqWyYCwLXnlUB1lOAXQyNSPqPLQJvmo8J0DWBzp9mtg=
github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro=
github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
@ -109,7 +136,6 @@ github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7
github.com/coreos/pkg v0.0.0-20230601102743-20bbbf26f4d8 h1:NrLmX9HDyGvQhyZdrDx89zCvPdxQ/EHCo+xGNrjNmHc=
github.com/coreos/pkg v0.0.0-20230601102743-20bbbf26f4d8/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -173,7 +199,6 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
@ -275,7 +300,6 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-cty v1.5.0 h1:EkQ/v+dDNUqnuVpmS5fPqyY71NXVgT5gf32+57xY8g0=
github.com/hashicorp/go-cty v1.5.0/go.mod h1:lFUCG5kd8exDobgSfyj4ONE/dc822kiYMguVKdHGMLM=
github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-hmac-drbg v0.0.0-20210916214228-a6e5a68489f6 h1:kBoJV4Xl5FLtBfnBjDvBxeNSy2IRITSGs73HQsFUEjY=
@ -303,8 +327,8 @@ github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVU
github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw=
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-secure-stdlib/awsutil v0.3.0 h1:I8bynUKMh9I7JdwtW9voJ0xmHvBpxQtLjrMFDYmhOxY=
github.com/hashicorp/go-secure-stdlib/awsutil v0.3.0/go.mod h1:oKHSQs4ivIfZ3fbXGQOop1XuDfdSb8RIsWTGaAanSfg=
github.com/hashicorp/go-secure-stdlib/awsutil/v2 v2.1.1 h1:rXE5JmHT14VYLVm+hHSqBOojPl0rlBqJx6YLikUuCgM=
github.com/hashicorp/go-secure-stdlib/awsutil/v2 v2.1.1/go.mod h1:6+rVulOPNCQbL3Xv2iLCqM0JmU2WO2wRzP1C6hBKeB8=
github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 h1:ET4pqyjiGmY09R5y+rSd70J2w45CtbWDNvGqWp/R3Ng=
github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw=
github.com/hashicorp/go-secure-stdlib/cryptoutil v0.1.1 h1:VaLXp47MqD1Y2K6QVrA9RooQiPyCgAbnfeJg44wKuJk=
@ -456,8 +480,6 @@ github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5Xum
github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8=
github.com/jimlambrt/gldap v0.1.13 h1:jxmVQn0lfmFbM9jglueoau5LLF/IGRti0SKf0vB753M=
github.com/jimlambrt/gldap v0.1.13/go.mod h1:nlC30c7xVphjImg6etk7vg7ZewHCCvl1dfAhO3ZJzPg=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 h1:liMMTbpW34dhU4az1GN0pTPADwNmvoRSeoZ6PItiqnY=
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
@ -486,7 +508,6 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxv
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@ -626,7 +647,6 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
@ -674,7 +694,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
@ -784,7 +803,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=

View file

@ -4,11 +4,22 @@
package provider
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"net/url"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/iam"
"github.com/aws/aws-sdk-go-v2/service/sts"
smithyendpoints "github.com/aws/smithy-go/endpoints"
"github.com/aws/smithy-go/middleware"
smithyhttp "github.com/aws/smithy-go/transport/http"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-secure-stdlib/awsutil"
"github.com/hashicorp/go-secure-stdlib/awsutil/v2"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/vault/api"
@ -184,7 +195,8 @@ func (l *AuthLoginAWS) Login(client *api.Client) (*api.Secret, error) {
return nil, err
}
loginData, err := l.getLoginData(getHCLogger())
ctx := context.Background()
loginData, err := l.getLoginData(ctx, getHCLogger())
if err != nil {
return nil, fmt.Errorf("failed to get AWS credentials required for Vault login, err=%w", err)
}
@ -247,71 +259,225 @@ func (l *AuthLoginAWS) getDefaults() authDefaults {
return defaults
}
func (l *AuthLoginAWS) getLoginData(logger hclog.Logger) (map[string]interface{}, error) {
func (l *AuthLoginAWS) getLoginData(ctx context.Context, logger hclog.Logger) (map[string]interface{}, error) {
// Get credentials configuration
config, err := l.getCredentialsConfig(logger)
if err != nil {
return nil, err
}
creds, err := config.GenerateCredentialChain()
awsConfig, err := config.GenerateCredentialChain(ctx)
if err != nil {
return nil, err
}
// Check if we need to assume a role
var roleARN string
if v, ok := l.params[consts.FieldAWSRoleARN].(string); ok && v != "" {
roleARN = v
// Create STS client with base credentials and custom endpoint if configured
var stsOpts []func(*sts.Options)
if v, ok := l.params[consts.FieldAWSSTSEndpoint].(string); ok && v != "" {
stsOpts = append(stsOpts, sts.WithEndpointResolverV2(&customSTSEndpointResolver{endpointURL: v}))
}
stsClient := sts.NewFromConfig(*awsConfig, stsOpts...)
// Get role session name
roleSessionName := "vault-provider-session"
if v, ok := l.params[consts.FieldAWSRoleSessionName].(string); ok && v != "" {
roleSessionName = v
}
// Call AssumeRole
assumeRoleOutput, err := stsClient.AssumeRole(ctx, &sts.AssumeRoleInput{
RoleArn: aws.String(roleARN),
RoleSessionName: aws.String(roleSessionName),
})
if err != nil {
return nil, fmt.Errorf("failed to assume role %s: %w", roleARN, err)
}
// Create a new config with the assumed role credentials
awsConfig = &aws.Config{
Region: awsConfig.Region,
Credentials: aws.NewCredentialsCache(
aws.CredentialsProviderFunc(func(ctx context.Context) (aws.Credentials, error) {
return aws.Credentials{
AccessKeyID: aws.ToString(assumeRoleOutput.Credentials.AccessKeyId),
SecretAccessKey: aws.ToString(assumeRoleOutput.Credentials.SecretAccessKey),
SessionToken: aws.ToString(assumeRoleOutput.Credentials.SessionToken),
Source: "ManualAssumeRole",
CanExpire: true,
Expires: *assumeRoleOutput.Credentials.Expiration,
}, nil
}),
),
}
}
var headerValue string
if v, ok := l.params[consts.FieldHeaderValue].(string); ok {
headerValue = v
}
return awsutil.GenerateLoginData(creds, headerValue, config.Region, logger)
return generateLoginData(ctx, awsConfig, headerValue, logger)
}
// customSTSEndpointResolver creates an endpoint resolver for STS with a custom endpoint URL
type customSTSEndpointResolver struct {
endpointURL string
}
func (r *customSTSEndpointResolver) ResolveEndpoint(ctx context.Context, params sts.EndpointParameters) (smithyendpoints.Endpoint, error) {
// Parse the custom endpoint URL
uri, err := url.Parse(r.endpointURL)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("failed to parse custom STS endpoint URL: %w", err)
}
// Return custom endpoint
return smithyendpoints.Endpoint{
URI: *uri,
}, nil
}
// customIAMEndpointResolver creates an endpoint resolver for IAM with a custom endpoint URL
type customIAMEndpointResolver struct {
endpointURL string
}
func (r *customIAMEndpointResolver) ResolveEndpoint(ctx context.Context, params iam.EndpointParameters) (smithyendpoints.Endpoint, error) {
// Parse the custom endpoint URL
uri, err := url.Parse(r.endpointURL)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("failed to parse custom IAM endpoint URL: %w", err)
}
// Return custom endpoint
return smithyendpoints.Endpoint{
URI: *uri,
}, nil
}
func (l *AuthLoginAWS) getCredentialsConfig(logger hclog.Logger) (*awsutil.CredentialsConfig, error) {
// we do not leverage awsutil.Options here since awsutil.NewCredentialsConfig
// does not currently support all that we do.
config, err := awsutil.NewCredentialsConfig()
// Build options for NewCredentialsConfig
var opts []awsutil.Option
if v, ok := l.params[consts.FieldAWSAccessKeyID].(string); ok && v != "" {
opts = append(opts, awsutil.WithAccessKey(v))
}
if v, ok := l.params[consts.FieldAWSSecretAccessKey].(string); ok && v != "" {
opts = append(opts, awsutil.WithSecretKey(v))
}
if v, ok := l.params[consts.FieldAWSRegion].(string); ok && v != "" {
opts = append(opts, awsutil.WithRegion(v))
}
if v, ok := l.params[consts.FieldAWSRoleARN].(string); ok && v != "" {
opts = append(opts, awsutil.WithRoleArn(v))
}
if v, ok := l.params[consts.FieldAWSRoleSessionName].(string); ok && v != "" {
opts = append(opts, awsutil.WithRoleSessionName(v))
}
if v, ok := l.params[consts.FieldAWSWebIdentityTokenFile].(string); ok && v != "" {
opts = append(opts, awsutil.WithWebIdentityTokenFile(v))
}
opts = append(opts, awsutil.WithLogger(logger))
config, err := awsutil.NewCredentialsConfig(opts...)
if err != nil {
return nil, err
}
if v, ok := l.params[consts.FieldAWSAccessKeyID].(string); ok && v != "" {
config.AccessKey = v
}
if v, ok := l.params[consts.FieldAWSSecretAccessKey].(string); ok && v != "" {
config.SecretKey = v
}
// Set fields that aren't available through options
if v, ok := l.params[consts.FieldAWSProfile].(string); ok && v != "" {
config.Profile = v
}
if v, ok := l.params[consts.FieldAWSSharedCredentialsFile].(string); ok && v != "" {
config.Filename = v
}
if v, ok := l.params[consts.FieldAWSWebIdentityTokenFile].(string); ok && v != "" {
config.WebIdentityTokenFile = v
}
if v, ok := l.params[consts.FieldAWSRoleARN].(string); ok && v != "" {
config.RoleARN = v
}
if v, ok := l.params[consts.FieldAWSRoleSessionName].(string); ok && v != "" {
config.RoleSessionName = v
}
if v, ok := l.params[consts.FieldAWSRegion].(string); ok && v != "" {
config.Region = v
}
if v, ok := l.params[consts.FieldAWSSessionToken].(string); ok && v != "" {
config.SessionToken = v
}
if v, ok := l.params[consts.FieldAWSSTSEndpoint].(string); ok && v != "" {
config.STSEndpoint = v
config.STSEndpointResolver = &customSTSEndpointResolver{endpointURL: v}
}
if v, ok := l.params[consts.FieldAWSIAMEndpoint].(string); ok && v != "" {
config.IAMEndpoint = v
config.IAMEndpointResolver = &customIAMEndpointResolver{endpointURL: v}
}
return config, nil
}
// generateLoginData generates the necessary login data for Vault AWS authentication
// by creating a presigned STS GetCallerIdentity request.
func generateLoginData(ctx context.Context, awsConfig *aws.Config, headerValue string, logger hclog.Logger) (map[string]interface{}, error) {
const iamServerIdHeader = "X-Vault-AWS-IAM-Server-ID"
loginData := make(map[string]interface{})
// Validate credentials are available before attempting presign
// This catches configuration errors earlier with a clearer error message
if _, err := awsConfig.Credentials.Retrieve(ctx); err != nil {
return nil, fmt.Errorf("failed to retrieve AWS credentials: %w", err)
}
// If a header value is provided, we need to add it to the signed request
// We'll do this by adding middleware to the config
if headerValue != "" {
awsConfig.APIOptions = append(awsConfig.APIOptions, func(stack *middleware.Stack) error {
return stack.Build.Add(middleware.BuildMiddlewareFunc(
"AddVaultHeader",
func(ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler) (middleware.BuildOutput, middleware.Metadata, error) {
req, ok := in.Request.(*smithyhttp.Request)
if ok {
req.Header.Add(iamServerIdHeader, headerValue)
}
return next.HandleBuild(ctx, in)
},
), middleware.After)
})
}
// Create STS client with awsConfig (which already contains the correct credentials)
stsClient := sts.NewFromConfig(*awsConfig)
// Create presigner - credentials will be retrieved automatically during presigning
presignClient := sts.NewPresignClient(stsClient)
// Presign the GetCallerIdentity request
presignedReq, err := presignClient.PresignGetCallerIdentity(ctx, &sts.GetCallerIdentityInput{})
if err != nil {
return nil, fmt.Errorf("failed to presign GetCallerIdentity request: %w", err)
}
// Convert the signed headers map to http.Header for proper marshaling
headers := make(http.Header)
for k, v := range presignedReq.SignedHeader {
headers[k] = v
}
// Marshal headers to JSON
headersJson, err := json.Marshal(headers)
if err != nil {
return nil, fmt.Errorf("failed to marshal request headers: %w", err)
}
// Populate login data with base64-encoded values
// Note: GetCallerIdentity is a POST request with an empty body
loginData[consts.FieldIAMHttpRequestMethod] = presignedReq.Method
loginData[consts.FieldIAMRequestURL] = base64.StdEncoding.EncodeToString([]byte(presignedReq.URL))
loginData[consts.FieldIAMRequestHeaders] = base64.StdEncoding.EncodeToString(headersJson)
loginData[consts.FieldIAMRequestBody] = base64.StdEncoding.EncodeToString([]byte(""))
return loginData, nil
}
// signAWSLogin is for use by the generic auth method
func signAWSLogin(parameters map[string]interface{}, logger hclog.Logger) error {
ctx := context.Background()
var accessKey string
if v, ok := parameters[consts.FieldAWSAccessKeyID].(string); ok {
accessKey = v
@ -331,7 +497,13 @@ func signAWSLogin(parameters map[string]interface{}, logger hclog.Logger) error
sessionToken = v
}
creds, err := awsutil.RetrieveCreds(accessKey, secretKey, sessionToken, logger)
var region string
if v, ok := parameters["sts_region"].(string); ok {
region = v
}
awsConfig, err := awsutil.RetrieveCreds(ctx, accessKey, secretKey, sessionToken, logger,
awsutil.WithRegion(region))
if err != nil {
return fmt.Errorf("failed to retrieve AWS credentials: %s", err)
}
@ -341,12 +513,7 @@ func signAWSLogin(parameters map[string]interface{}, logger hclog.Logger) error
headerValue = v
}
var stsRegion string
if v, ok := parameters["sts_region"].(string); ok {
stsRegion = v
}
loginData, err := awsutil.GenerateLoginData(creds, headerValue, stsRegion, logger)
loginData, err := generateLoginData(ctx, awsConfig, headerValue, logger)
if err != nil {
return fmt.Errorf("failed to generate AWS login data: %s", err)
}

View file

@ -12,7 +12,7 @@ import (
"testing"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-secure-stdlib/awsutil"
"github.com/hashicorp/go-secure-stdlib/awsutil/v2"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/vault/api"
@ -188,6 +188,50 @@ func TestAuthLoginAWS_getCredentialsConfig(t *testing.T) {
},
wantErr: false,
},
{
name: "static-creds-with-role-arn",
fields: fields{
AuthLoginCommon: AuthLoginCommon{
params: map[string]interface{}{
consts.FieldAWSAccessKeyID: "key-id",
consts.FieldAWSSecretAccessKey: "secret-key",
consts.FieldAWSRoleARN: "arn:aws:iam::123456789012:role/test-role",
consts.FieldAWSRoleSessionName: "test-session",
},
},
},
logger: hclog.NewNullLogger(),
want: &awsutil.CredentialsConfig{
Region: "us-east-1",
AccessKey: "key-id",
SecretKey: "secret-key",
RoleARN: "arn:aws:iam::123456789012:role/test-role",
RoleSessionName: "test-session",
},
wantErr: false,
},
{
name: "static-creds-with-session-token-and-role-arn",
fields: fields{
AuthLoginCommon: AuthLoginCommon{
params: map[string]interface{}{
consts.FieldAWSAccessKeyID: "key-id",
consts.FieldAWSSecretAccessKey: "secret-key",
consts.FieldAWSSessionToken: "session-token",
consts.FieldAWSRoleARN: "arn:aws:iam::123456789012:role/test-role",
},
},
},
logger: hclog.NewNullLogger(),
want: &awsutil.CredentialsConfig{
Region: "us-east-1",
AccessKey: "key-id",
SecretKey: "secret-key",
SessionToken: "session-token",
RoleARN: "arn:aws:iam::123456789012:role/test-role",
},
wantErr: false,
},
{
name: "all",
fields: fields{
@ -209,11 +253,11 @@ func TestAuthLoginAWS_getCredentialsConfig(t *testing.T) {
},
logger: hclog.NewNullLogger(),
want: &awsutil.CredentialsConfig{
AccessKey: "key-id",
SecretKey: "sa-key",
SessionToken: "session-token",
IAMEndpoint: "iam.us-east-2.amazonaws.com",
STSEndpoint: "sts.us-east-2.amazonaws.com",
AccessKey: "key-id",
SecretKey: "sa-key",
SessionToken: "session-token",
// Note: IAMEndpoint and STSEndpoint have been replaced with endpoint resolvers in v2
// and are no longer simple string fields
Region: "us-east-2",
Filename: "credentials",
Profile: "profile1",
@ -238,8 +282,41 @@ func TestAuthLoginAWS_getCredentialsConfig(t *testing.T) {
if got.HTTPClient == nil {
t.Errorf("getCredentialsConfig() HTTPClient not initialized")
}
// set HTTPClient to nil
// Verify custom endpoint resolvers are set correctly when endpoints are provided
// We check these explicitly because they're interfaces and can't be compared with DeepEqual
if stsEndpoint, ok := tt.fields.AuthLoginCommon.params[consts.FieldAWSSTSEndpoint].(string); ok && stsEndpoint != "" {
if got.STSEndpointResolver == nil {
t.Error("Expected STSEndpointResolver to be set when aws_sts_endpoint is provided")
} else {
resolver, ok := got.STSEndpointResolver.(*customSTSEndpointResolver)
if !ok {
t.Error("STSEndpointResolver is not of type *customSTSEndpointResolver")
} else if resolver.endpointURL != stsEndpoint {
t.Errorf("STSEndpointResolver endpointURL = %v, want %v", resolver.endpointURL, stsEndpoint)
}
}
}
if iamEndpoint, ok := tt.fields.AuthLoginCommon.params[consts.FieldAWSIAMEndpoint].(string); ok && iamEndpoint != "" {
if got.IAMEndpointResolver == nil {
t.Error("Expected IAMEndpointResolver to be set when aws_iam_endpoint is provided")
} else {
resolver, ok := got.IAMEndpointResolver.(*customIAMEndpointResolver)
if !ok {
t.Error("IAMEndpointResolver is not of type *customIAMEndpointResolver")
} else if resolver.endpointURL != iamEndpoint {
t.Errorf("IAMEndpointResolver endpointURL = %v, want %v", resolver.endpointURL, iamEndpoint)
}
}
}
// Set HTTPClient, Logger, and endpoint resolvers to nil before DeepEqual comparison
// We've already verified endpoint resolvers above
got.HTTPClient = nil
got.Logger = nil
got.STSEndpointResolver = nil
got.IAMEndpointResolver = nil
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("getCredentialsConfig() got = %v, want %v", got, tt.want)
}
@ -247,6 +324,262 @@ func TestAuthLoginAWS_getCredentialsConfig(t *testing.T) {
}
}
// TestAuthLoginAWS_RoleAssumption tests the manual role assumption logic
func TestAuthLoginAWS_RoleAssumption(t *testing.T) {
tests := []struct {
name string
params map[string]interface{}
expectRoleAssumption bool
expectSessionName string
}{
{
name: "with-role-arn-and-session-name",
params: map[string]interface{}{
consts.FieldAWSAccessKeyID: "key-id",
consts.FieldAWSSecretAccessKey: "secret-key",
consts.FieldAWSRoleARN: "arn:aws:iam::123456789012:role/test-role",
consts.FieldAWSRoleSessionName: "custom-session",
},
expectRoleAssumption: true,
expectSessionName: "custom-session",
},
{
name: "with-role-arn-default-session-name",
params: map[string]interface{}{
consts.FieldAWSAccessKeyID: "key-id",
consts.FieldAWSSecretAccessKey: "secret-key",
consts.FieldAWSRoleARN: "arn:aws:iam::123456789012:role/test-role",
},
expectRoleAssumption: true,
expectSessionName: "", // Session name is not set in config when not provided
},
{
name: "without-role-arn",
params: map[string]interface{}{
consts.FieldAWSAccessKeyID: "key-id",
consts.FieldAWSSecretAccessKey: "secret-key",
},
expectRoleAssumption: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
l := &AuthLoginAWS{
AuthLoginCommon: AuthLoginCommon{
params: tt.params,
},
}
// Verify that getCredentialsConfig properly sets role ARN
config, err := l.getCredentialsConfig(hclog.NewNullLogger())
if err != nil {
t.Fatalf("getCredentialsConfig() error = %v", err)
}
if tt.expectRoleAssumption {
if config.RoleARN == "" {
t.Errorf("Expected RoleARN to be set, got empty string")
}
if roleARN, ok := tt.params[consts.FieldAWSRoleARN].(string); ok {
if config.RoleARN != roleARN {
t.Errorf("Expected RoleARN = %v, got %v", roleARN, config.RoleARN)
}
}
// Check session name
expectedSessionName := tt.expectSessionName
if config.RoleSessionName != expectedSessionName {
t.Errorf("Expected RoleSessionName = %v, got %v", expectedSessionName, config.RoleSessionName)
}
} else {
if config.RoleARN != "" {
t.Errorf("Expected RoleARN to be empty, got %v", config.RoleARN)
}
}
})
}
}
// TestAuthLoginAWS_SessionTokenWithRoleARN tests that session token is handled correctly with role assumption
func TestAuthLoginAWS_SessionTokenWithRoleARN(t *testing.T) {
tests := []struct {
name string
params map[string]interface{}
expectSessionTokenSet bool
}{
{
name: "session-token-without-role-arn",
params: map[string]interface{}{
consts.FieldAWSAccessKeyID: "key-id",
consts.FieldAWSSecretAccessKey: "secret-key",
consts.FieldAWSSessionToken: "session-token",
},
expectSessionTokenSet: true,
},
{
name: "session-token-with-role-arn",
params: map[string]interface{}{
consts.FieldAWSAccessKeyID: "key-id",
consts.FieldAWSSecretAccessKey: "secret-key",
consts.FieldAWSSessionToken: "session-token",
consts.FieldAWSRoleARN: "arn:aws:iam::123456789012:role/test-role",
},
expectSessionTokenSet: true,
},
{
name: "no-session-token-with-role-arn",
params: map[string]interface{}{
consts.FieldAWSAccessKeyID: "key-id",
consts.FieldAWSSecretAccessKey: "secret-key",
consts.FieldAWSRoleARN: "arn:aws:iam::123456789012:role/test-role",
},
expectSessionTokenSet: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
l := &AuthLoginAWS{
AuthLoginCommon: AuthLoginCommon{
params: tt.params,
},
}
config, err := l.getCredentialsConfig(hclog.NewNullLogger())
if err != nil {
t.Fatalf("getCredentialsConfig() error = %v", err)
}
hasSessionToken := config.SessionToken != ""
if hasSessionToken != tt.expectSessionTokenSet {
t.Errorf("Expected SessionToken set = %v, got %v", tt.expectSessionTokenSet, hasSessionToken)
}
// Verify session token value matches if it should be set
if tt.expectSessionTokenSet {
if sessionToken, ok := tt.params[consts.FieldAWSSessionToken].(string); ok {
if config.SessionToken != sessionToken {
t.Errorf("Expected SessionToken = %v, got %v", sessionToken, config.SessionToken)
}
}
}
})
}
}
// TestAuthLoginAWS_CustomEndpoints tests that custom STS and IAM endpoints are properly configured
func TestAuthLoginAWS_CustomEndpoints(t *testing.T) {
tests := []struct {
name string
params map[string]interface{}
expectSTSEndpoint bool
expectIAMEndpoint bool
stsEndpoint string
iamEndpoint string
}{
{
name: "with-custom-sts-endpoint",
params: map[string]interface{}{
consts.FieldAWSAccessKeyID: "key-id",
consts.FieldAWSSecretAccessKey: "secret-key",
consts.FieldAWSSTSEndpoint: "https://sts.custom.endpoint.com",
},
expectSTSEndpoint: true,
expectIAMEndpoint: false,
stsEndpoint: "https://sts.custom.endpoint.com",
},
{
name: "with-custom-iam-endpoint",
params: map[string]interface{}{
consts.FieldAWSAccessKeyID: "key-id",
consts.FieldAWSSecretAccessKey: "secret-key",
consts.FieldAWSIAMEndpoint: "https://iam.custom.endpoint.com",
},
expectSTSEndpoint: false,
expectIAMEndpoint: true,
iamEndpoint: "https://iam.custom.endpoint.com",
},
{
name: "with-both-custom-endpoints",
params: map[string]interface{}{
consts.FieldAWSAccessKeyID: "key-id",
consts.FieldAWSSecretAccessKey: "secret-key",
consts.FieldAWSSTSEndpoint: "https://sts.custom.endpoint.com",
consts.FieldAWSIAMEndpoint: "https://iam.custom.endpoint.com",
},
expectSTSEndpoint: true,
expectIAMEndpoint: true,
stsEndpoint: "https://sts.custom.endpoint.com",
iamEndpoint: "https://iam.custom.endpoint.com",
},
{
name: "without-custom-endpoints",
params: map[string]interface{}{
consts.FieldAWSAccessKeyID: "key-id",
consts.FieldAWSSecretAccessKey: "secret-key",
},
expectSTSEndpoint: false,
expectIAMEndpoint: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
l := &AuthLoginAWS{
AuthLoginCommon: AuthLoginCommon{
params: tt.params,
},
}
logger := hclog.NewNullLogger()
config, err := l.getCredentialsConfig(logger)
if err != nil {
t.Errorf("getCredentialsConfig() unexpected error = %v", err)
return
}
// Check STS endpoint resolver
if tt.expectSTSEndpoint {
if config.STSEndpointResolver == nil {
t.Error("Expected STSEndpointResolver to be set, but it was nil")
} else {
// Verify the resolver returns the correct endpoint
resolver, ok := config.STSEndpointResolver.(*customSTSEndpointResolver)
if !ok {
t.Errorf("STSEndpointResolver is not of type *customSTSEndpointResolver")
} else if resolver.endpointURL != tt.stsEndpoint {
t.Errorf("STSEndpointResolver endpointURL = %v, want %v", resolver.endpointURL, tt.stsEndpoint)
}
}
} else {
if config.STSEndpointResolver != nil {
t.Error("Expected STSEndpointResolver to be nil, but it was set")
}
}
// Check IAM endpoint resolver
if tt.expectIAMEndpoint {
if config.IAMEndpointResolver == nil {
t.Error("Expected IAMEndpointResolver to be set, but it was nil")
} else {
// Verify the resolver returns the correct endpoint
resolver, ok := config.IAMEndpointResolver.(*customIAMEndpointResolver)
if !ok {
t.Errorf("IAMEndpointResolver is not of type *customIAMEndpointResolver")
} else if resolver.endpointURL != tt.iamEndpoint {
t.Errorf("IAMEndpointResolver endpointURL = %v, want %v", resolver.endpointURL, tt.iamEndpoint)
}
}
} else {
if config.IAMEndpointResolver != nil {
t.Error("Expected IAMEndpointResolver to be nil, but it was set")
}
}
})
}
}
func TestAuthLoginAWS_Login(t *testing.T) {
handlerFunc := func(t *testLoginHandler, w http.ResponseWriter, req *http.Request) {
role := "default"
@ -295,7 +628,9 @@ func TestAuthLoginAWS_Login(t *testing.T) {
authField: "baz",
mount: "foo",
params: map[string]interface{}{
consts.FieldRole: "bob",
consts.FieldRole: "bob",
consts.FieldAWSAccessKeyID: "test-key",
consts.FieldAWSSecretAccessKey: "test-secret",
},
initialized: true,
},