Skip to content

Commit ef682e2

Browse files
committed
feat(aws): support keyless authentication (IRSA / instance profile)
Make aws_access_key/aws_secret_key optional. When omitted, fall back to the AWS SDK default credential chain so IRSA, EC2/ECS instance profiles, env vars and shared config work without injecting static creds into the provider config.
1 parent c3dc404 commit ef682e2

3 files changed

Lines changed: 38 additions & 10 deletions

File tree

PROVIDERS.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ Amazon Web Services can be integrated by using the following configuration block
99
provider: aws
1010
# id is the name defined by user for filtering (optional)
1111
id: staging
12-
# aws_access_key is the access key for AWS account
12+
# aws_access_key is the access key for AWS account (optional - see "Keyless Authentication" below)
1313
aws_access_key: $AWS_ACCESS_KEY
14-
# aws_secret_key is the secret key for AWS account
14+
# aws_secret_key is the secret key for AWS account (optional - see "Keyless Authentication" below)
1515
aws_secret_key: $AWS_SECRET_KEY
1616
# aws_session_token session token for temporary security credentials retrieved via STS (optional)
1717
aws_session_token: $AWS_SESSION_TOKEN
@@ -31,6 +31,24 @@ Amazon Web Services can be integrated by using the following configuration block
3131
3232
`aws_access_key` and `aws_secret_key` can be generated in the IAM console. We recommend creating a new IAM user with `Read Only` permissions and providing the access token for the user.
3333

34+
#### Keyless Authentication (IRSA / Instance Profile / Environment)
35+
36+
`aws_access_key` and `aws_secret_key` are **optional**. When both are omitted, the provider falls back to the AWS SDK default credential chain, so no secrets need to be injected into the config file. This enables:
37+
38+
- **IRSA (IAM Roles for Service Accounts)** on EKS — credentials are picked up automatically from the `AWS_WEB_IDENTITY_TOKEN_FILE` and `AWS_ROLE_ARN` environment variables injected by the pod identity webhook.
39+
- **EC2 / ECS instance profiles** — credentials are resolved from the instance/task metadata endpoint.
40+
- **Environment variables** — `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`.
41+
- **Shared config / profile** — `~/.aws/credentials` and `~/.aws/config`.
42+
43+
```yaml
44+
# Zero-key config relying on IRSA / instance profile / environment
45+
- provider: aws
46+
id: keyless-discovery
47+
# no aws_access_key / aws_secret_key — credentials resolved by the SDK default chain
48+
```
49+
50+
> Note: if you provide one of `aws_access_key` / `aws_secret_key`, you must provide both. `assume_role_arn`, `assume_role_name` and `org_discovery_role_arn` all work on top of keyless base credentials too.
51+
3452
Scopes Required -
3553
1. EC2
3654
2. Route53

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Cloudlist is a multi-cloud tool for getting Assets from Cloud Providers. This is
3838

3939
- List Cloud assets with multiple configurations
4040
- Multiple Cloud providers support
41+
- Keyless authentication support (AWS IRSA / instance profiles, GCP workload identity)
4142
- Multiple output format support
4243
- Multiple filters support
4344
- Highly extensible making adding new providers a breeze

pkg/providers/aws/aws.go

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,16 @@ type ProviderOptions struct {
4949

5050
func (p *ProviderOptions) ParseOptionBlock(block schema.OptionBlock) error {
5151
p.Id, _ = block.GetMetadata("id")
52-
accessKey, ok := block.GetMetadata(apiAccessKey)
53-
if !ok {
54-
return &schema.ErrNoSuchKey{Name: apiAccessKey}
55-
}
56-
accessToken, ok := block.GetMetadata(apiSecretKey)
57-
if !ok {
58-
return &schema.ErrNoSuchKey{Name: apiSecretKey}
52+
// aws_access_key/aws_secret_key are optional. When both are omitted the
53+
// provider falls back to the AWS SDK default credential chain, which
54+
// supports keyless auth such as IRSA (IAM Roles for Service Accounts),
55+
// EC2/ECS instance profiles and AWS_* environment variables.
56+
accessKey, _ := block.GetMetadata(apiAccessKey)
57+
accessToken, _ := block.GetMetadata(apiSecretKey)
58+
// If one of the static-credential pair is set, both must be set;
59+
// a half-configured pair is almost always a mistake.
60+
if (accessKey == "") != (accessToken == "") {
61+
return errors.Errorf("both %s and %s must be provided together", apiAccessKey, apiSecretKey)
5962
}
6063
p.Token, _ = block.GetMetadata(sessionToken)
6164
p.AccessKey = accessKey
@@ -156,7 +159,13 @@ func New(block schema.OptionBlock) (*Provider, error) {
156159
provider := &Provider{options: options}
157160
config := aws.NewConfig()
158161
config.WithRegion("us-east-1")
159-
config.WithCredentials(credentials.NewStaticCredentials(options.AccessKey, options.SecretKey, options.Token))
162+
// Only set static credentials when explicitly provided. Otherwise leave
163+
// config.Credentials nil so session.NewSession resolves credentials via the
164+
// SDK default chain (env vars, shared config, IRSA web identity, EC2/ECS
165+
// instance profile), enabling keyless authentication.
166+
if options.AccessKey != "" && options.SecretKey != "" {
167+
config.WithCredentials(credentials.NewStaticCredentials(options.AccessKey, options.SecretKey, options.Token))
168+
}
160169

161170
var sess *session.Session
162171
var err error

0 commit comments

Comments
 (0)