Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ RUN echo "Running on ${BUILDPLATFORM}, building for ${TARGETPLATFORM}."

WORKDIR /workdir

RUN apk add git build-base
RUN apk add --no-cache git build-base
RUN go env -w GOPROXY=direct

COPY go.mod .
Expand Down
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,41 @@ The primary objects field of the SecretProviderClass can contain the following s
You may pass an additional sub-field to specify the file permission:
* filePermission: This optional field expects a 4 digit string which specifies the file permission for the secret that will be mounted. When not specified this will default to the parent object's file permission.

## Assume Role parameters

The provider supports an optional assume-role flow where the base credentials (from IRSA or Pod Identity) are used to call STS AssumeRole and obtain short-lived credentials for a different role.

Add the following parameters to the `parameters:` block in your `SecretProviderClass` to enable assume-role behavior:

- `assumeRoleArn`: The ARN of the IAM role to assume. When provided, the provider will call STS AssumeRole and use the resulting credentials for subsequent AWS API calls.
- `assumeRoleDurationSeconds`: Optional. The requested session duration in seconds for the assumed role. The provider accepts a numeric string and validates it; out-of-range or invalid values are ignored and a warning is emitted. A sensible upper bound is applied by the provider (12 hours / 43200s).
- `assumeRoleExternalId`: Optional. An external ID string to pass to STS AssumeRole for additional cross-account security.

Example `SecretProviderClass` snippet enabling assume-role (Pod Identity mode):

```yaml
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: example-assume-role
spec:
provider: aws
parameters:
region: us-west-2
usePodIdentity: "true"
assumeRoleArn: "arn:aws:iam::123456789012:role/MyAssumedRole"
assumeRoleDurationSeconds: "3600"
assumeRoleExternalId: "external-id-value"
objects: |
- objectName: "MySecret"
objectType: "secretsmanager"
```

Notes:
- Ensure the base credentials obtained via Pod Identity or IRSA have permission to call `sts:AssumeRole` on the target role.
- For Pod Identity, ensure the pod-identity agent is deployed and reachable from your pods.
- If using cross-account assume-role, confirm the target role's trust policy allows the principal used by the base credentials.

## Additional Considerations

### Rotation
Expand Down
48 changes: 38 additions & 10 deletions auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ type Auth struct {
podIdentityHttpTimeout *time.Duration
k8sClient k8sv1.CoreV1Interface
stsClient stscreds.AssumeRoleWithWebIdentityAPIClient
assumeRoleArn string
assumeRoleDurationSeconds time.Duration
assumeRoleExternalId string
}

// NewAuth creates an Auth object for an incoming mount request.
Expand All @@ -49,6 +52,9 @@ func NewAuth(
usePodIdentity bool,
podIdentityHttpTimeout *time.Duration,
k8sClient k8sv1.CoreV1Interface,
assumeRoleArn string,
assumeRoleDurationSeconds time.Duration,
assumeRoleExternalId string,
) (auth *Auth, e error) {
var stsClient *sts.Client

Expand All @@ -65,16 +71,19 @@ func NewAuth(
}

return &Auth{
region: region,
nameSpace: nameSpace,
svcAcc: svcAcc,
podName: podName,
preferredAddressType: preferredAddressType,
eksAddonVersion: eksAddonVersion,
usePodIdentity: usePodIdentity,
podIdentityHttpTimeout: podIdentityHttpTimeout,
k8sClient: k8sClient,
stsClient: stsClient,
region: region,
nameSpace: nameSpace,
svcAcc: svcAcc,
podName: podName,
preferredAddressType: preferredAddressType,
eksAddonVersion: eksAddonVersion,
usePodIdentity: usePodIdentity,
podIdentityHttpTimeout: podIdentityHttpTimeout,
k8sClient: k8sClient,
stsClient: stsClient,
assumeRoleArn: assumeRoleArn,
assumeRoleDurationSeconds: assumeRoleDurationSeconds,
assumeRoleExternalId: assumeRoleExternalId,
}, nil

}
Expand Down Expand Up @@ -105,6 +114,25 @@ func (p Auth) GetAWSConfig(ctx context.Context) (aws.Config, error) {
return aws.Config{}, err
}

// If an assumeRoleArn was provided, create an AssumeRole provider using the
// base credentials (from cfg) and wrap the config's Credentials with the
// resulting credentials cache so subsequent AWS calls use the assumed role.
if p.assumeRoleArn != "" {
stsClient := sts.NewFromConfig(cfg)
var optFns []func(*stscreds.AssumeRoleOptions)
if p.assumeRoleDurationSeconds > 0 {
optFns = append(optFns, func(o *stscreds.AssumeRoleOptions) { o.Duration = p.assumeRoleDurationSeconds })
}
if p.assumeRoleExternalId != "" {
external := p.assumeRoleExternalId
optFns = append(optFns, func(o *stscreds.AssumeRoleOptions) { o.ExternalID = &external })
}

assumeProv := stscreds.NewAssumeRoleProvider(stsClient, p.assumeRoleArn, optFns...)
cfg.Credentials = aws.NewCredentialsCache(assumeProv)
klog.Infof("Using assumed role %s for AWS calls", p.assumeRoleArn)
}

// Add the user agent to the config
cfg.APIOptions = append(cfg.APIOptions, func(stack *middleware.Stack) error {
return stack.Build.Add(&userAgentMiddleware{
Expand Down
Loading