Skip to content

eks: ServiceAccount (IdentityType.POD_IDENTITY) should accept an existing IAM role via optional role prop #37299

@letsgomeow

Description

@letsgomeow

Describe the feature

When using ServiceAccount with IdentityType.POD_IDENTITY, the CDK automatically
creates an IAM role internally. There is currently no way to pass a pre-existing IAM
role (e.g., created via iam.Role, iam.Role.fromRoleArn(), or iam.Role.fromLookup())
to be used in the underlying PodIdentityAssociation.

Use Case

1. Centralized IAM role management

Projects that consolidate all IAM role definitions in a dedicated construct
(e.g., IamConstruct) cannot use ServiceAccount with IdentityType.POD_IDENTITY,
because the auto-generated role falls outside that construct's control.
This makes it impossible to call grantRead() or attach policies in one place.

2. Reusing an existing IAM role

When an IAM role already exists (imported via Role.fromRoleArn() or
Role.fromLookup()), there is no L2 way to associate it with a Pod Identity.
Developers are forced to fall back to the L1 construct CfnPodIdentityAssociation.

Proposed Solution

Add an optional role property to ServiceAccountOptions:

export interface ServiceAccountOptions {
  // ... existing props ...

  /**
   * An existing IAM role to associate with this service account via Pod Identity.
   * Only valid when `identityType` is `IdentityType.POD_IDENTITY`.
   *
   * When specified, the provided role is used instead of auto-generating one.
   * When omitted, the current behavior (auto-generating an IAM role) is preserved.
   *
   * @default - a new IAM role is created automatically
   */
  readonly role?: iam.IRole;
}

Example usage:

// IAM role defined and managed separately
const appRole = new iam.Role(this, 'AppRole', {
  assumedBy: new iam.SessionTagsPrincipal(
    new iam.ServicePrincipal('pods.eks.amazonaws.com'),
  ),
});
appRole.addManagedPolicy(...);

// Pass the existing role to ServiceAccount
new eks.ServiceAccount(this, 'AppSA', {
  cluster: this.cluster,
  name: 'app-sa',
  namespace: 'production',
  identityType: IdentityType.POD_IDENTITY,
  role: appRole,  // use pre-existing role instead of auto-generating
});

Backward Compatibility

This change is fully backward compatible:
- If role is not specified, behavior remains unchanged (IAM role is auto-generated).
- If role is specified, the provided role is used instead.
- A validation error should be thrown if role is specified when
identityType is not IdentityType.POD_IDENTITY.

Current Workaround

Using the L1 construct directly:

const pia = new CfnPodIdentityAssociation(this, 'AppPIA', {
  clusterName: cluster.clusterName,
  namespace: 'production',
  serviceAccount: 'app-sa',
  roleArn: appRole.roleArn,
});

This works but loses the ergonomics and CDK-level dependency management
that the L2 ServiceAccount construct provides.


### Other Information

Related

- #30519  original Pod Identity L2 support issue (closed)

### Acknowledgements

- [x] I may be able to implement this feature request
- [ ] This feature might incur a breaking change

### AWS CDK Library version (aws-cdk-lib)

2.243.0

### AWS CDK CLI version

2.1111.0 (build 69089a7)

### Environment details (OS name and version, etc.)

Ubuntu 24.04

Metadata

Metadata

Assignees

No one assigned

    Labels

    @aws-cdk/aws-iamRelated to AWS Identity and Access Managementfeature-requestA feature should be added or improved.needs-triageThis issue or PR still needs to be triaged.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions