Skip to content

feat: add AssumeRole auth type for AWS backends (Lambda + EC2)#14148

Merged
puertomontt merged 7 commits into
kgateway-dev:mainfrom
puertomontt:aws-role
Jun 24, 2026
Merged

feat: add AssumeRole auth type for AWS backends (Lambda + EC2)#14148
puertomontt merged 7 commits into
kgateway-dev:mainfrom
puertomontt:aws-role

Conversation

@puertomontt

@puertomontt puertomontt commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Description

Adds an AssumeRole AWS auth type to the Backend API, enabling per-Backend STS role chaining. The backend's ambient credentials are used to assume a target IAM role, and the resulting temporary credentials are used to sign requests (Lambda) or list instances (EC2).

AwsAuth.Type gains an AssumeRole value alongside the existing Secret. The two are mutually exclusive (discriminated union, enforced via CEL):

spec:
  type: AWS
  aws:
    auth:
      type: AssumeRole
      assumeRole:
        roleArn: arn:aws:iam::123456789012:role/project-invoke-role
    lambda:
      functionName: my-function

The base credentials that sign the STS AssumeRole call come from the default provider chain. In practice that is IRSA (IAM Roles for Service Accounts): on an IRSA-annotated pod the default chain resolves via AssumeRoleWithWebIdentity, and we chain off that to the target role. So AssumeRole is used independently of a credential Secret, not in conjunction with one.

The API is intentionally minimal — roleArn only. sessionName, externalId, and sessionDuration were considered and dropped: the motivating model is IRSA-based chaining within a single org/account, where they add no value (externalId only matters for third-party cross-account trust policies that mandate it; the others are audit/refresh tuning). They can be re-added non-breakingly if a concrete need appears.

How it works

  • Lambda (dataplane): translates to Envoy's AwsRequestSigning.CredentialProvider.AssumeRoleCredentialProvider. The nested base credential_provider is left unset so Envoy resolves the base credentials from its default chain (the gateway proxy pod's IRSA identity).
  • EC2 (control plane): the unified auth.assumeRole.roleArn drives the controller's stscreds.AssumeRoleProvider when calling DescribeInstances, chaining off the controller pod's IRSA identity. This replaces the separate spec.aws.ec2.roleArn field introduced in feat: support for AWS ec2 backends #13961 — role configuration now lives in one place for both backend types.

Note the base identities differ by plane: Lambda signing chains off the gateway proxy ServiceAccount; EC2 discovery chains off the controller ServiceAccount. The target role's trust policy must trust the appropriate principal.

Notable design decision

Secret and AssumeRole are kept mutually exclusive. Consequence: the "static secret base + role chain" combination that #13961's ec2.roleArn technically allowed is no longer expressible — a backend that assumes a role does so off the ambient (IRSA) identity, not a static secret base. This keeps the shared auth block meaning one thing per backend. It can be relaxed later non-breakingly if a use case emerges.

Change Type

/kind feature

Changelog

Added an `AssumeRole` AWS auth type to the Backend API (`spec.aws.auth.assumeRole`) for per-Backend STS role chaining, used for both Lambda request signing and EC2 instance discovery. The previous `spec.aws.ec2.roleArn` field is replaced by `spec.aws.auth.assumeRole.roleArn`.

Additional Notes

  • spec.aws.ec2.roleArn (added in feat: support for AWS ec2 backends #13961, unreleased) is removed in favor of the unified spec.aws.auth.assumeRole.roleArn.
  • Test coverage: golden translator cases for Lambda AssumeRole and EC2; unit tests for configureAWSAuth (default/secret/assume-role paths); the API validation suite covers the roleArn pattern.

Adds an `AssumeRole` AWS auth type to the Backend API, enabling per-Backend
STS role chaining. The gateway's ambient credentials (e.g. the gateway
ServiceAccount's IRSA identity) are used to assume a per-target invoke role
via STS, and the resulting temporary credentials sign requests to the
backend.

`Secret` and `AssumeRole` are mutually exclusive auth types. For AssumeRole,
Envoy's `AssumeRoleCredentialProvider.credential_provider` is left unset so
the base credentials resolve from the default provider chain (IRSA). The
optional `sessionName`, `externalId`, and `sessionDuration` (15m-12h) fields
are supported and CEL-validated.

Signed-off-by: omar <[email protected]>
…block

Reconciles the AssumeRole auth work with the AWS EC2 backend support added
in kgateway-dev#13961. Both features needed STS role assumption (Lambda request signing
in the dataplane; EC2 instance discovery in the control plane), but kgateway-dev#13961
placed its role under spec.aws.ec2.roleArn while this branch added
spec.aws.auth.assumeRole.

Unify on the shared auth block:
- Remove spec.aws.ec2.roleArn; EC2 discovery now sources its role from
  spec.aws.auth.assumeRole.roleArn (the mutually-exclusive AssumeRole auth
  type). buildEc2Ir reads it via assumeRoleArn(in.Auth).
- Keep Secret and AssumeRole as mutually-exclusive auth types.
- For EC2 discovery only RoleArn is honored; sessionName/externalId/
  sessionDuration apply to Lambda request signing.
- Align the AssumeRole roleArn pattern with the partition-tolerant form
  introduced in kgateway-dev#13961 (arn:aws[a-z-]*:...).
- Update EC2 inputs, fixtures, and apivalidation cases accordingly.

Signed-off-by: omar <[email protected]>
EC2 discovery previously consumed only auth.assumeRole.roleArn. Wire the full
AssumeRole config (sessionName, externalId, sessionDuration) through to the
controller's STS AssumeRole call so the unified auth model behaves uniformly
across Lambda request signing and EC2 instance discovery.

externalId is the motivating field: cross-account describe-EC2 roles commonly
require it in their trust policy, and without it the AssumeRole call fails.

- Bundle the role params into a comparable ec2AssumeRole value type and thread
  it through EC2Ir, ec2BackendConfig, ec2CredentialKey/Source, ec2ClientIdentity,
  and ec2BackendStateKey (replacing the bare roleArn string).
- Pass sessionName/externalId/duration into stscreds.NewAssumeRoleProvider.
- Include the session params in the client cache identity (singleflightKey) and
  EC2Ir/stateKey equality so a changed param rebuilds the client instead of
  serving stale credentials.
- Add unit tests for field mapping, KRT-equality, and cache-key distinctness.

Signed-off-by: omar <[email protected]>
Copilot AI review requested due to automatic review settings June 2, 2026 15:32
@puertomontt
puertomontt requested a review from a team as a code owner June 2, 2026 15:32
@gateway-bot gateway-bot added do-not-merge/description-invalid do-not-merge/release-note-invalid Indicates that a PR should not merge because it's missing one of the release note labels. kind/feature Categorizes issue or PR as related to a new feature. labels Jun 2, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new AWS AssumeRole auth mode to the Backend API so both Lambda request signing (dataplane via Envoy) and EC2 instance discovery (control plane via AWS SDK) can chain credentials through STS on a per-Backend basis, replacing the previously EC2-specific spec.aws.ec2.roleArn.

Changes:

  • Extend AwsAuth.Type with AssumeRole and introduce spec.aws.auth.assumeRole (roleArn, sessionName, externalId, sessionDuration) with CEL validation enforcing mutual exclusivity with Secret.
  • Update Lambda translation to emit Envoy AwsRequestSigning config using AssumeRoleCredentialProvider (leaving the base provider unset to use Envoy’s default credential chain).
  • Update EC2 discovery to derive STS assume-role parameters from the shared auth block and incorporate session params into IR equality and client-cache identity to avoid stale credentials.

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated no comments.

Show a summary per file
File Description
test/e2e/tests/apivalidation/apivalidation.go Updates CRD validation e2e coverage to validate auth.assumeRole.roleArn pattern (replacing the removed EC2 roleArn field).
pkg/kgateway/translator/gateway/testutils/outputs/backends/aws_lambda_assume_role.yaml Adds golden output covering Envoy request-signing config for Lambda AssumeRole (full + minimal).
pkg/kgateway/translator/gateway/testutils/inputs/backends/aws_lambda_assume_role.yaml Adds translator input fixtures for Lambda backends using AssumeRole auth.
pkg/kgateway/translator/gateway/testutils/inputs/backends/aws_ec2.yaml Updates EC2 fixture to use the unified auth.assumeRole configuration (removing embedded Secret + ec2.roleArn).
pkg/kgateway/translator/gateway/gateway_translator_test.go Registers a new translator golden test case for Lambda + AssumeRole.
pkg/kgateway/extensions2/plugins/backend/plugin.go Threads AwsAuth through Lambda filter construction and keeps secret loading scoped to Secret auth only.
pkg/kgateway/extensions2/plugins/backend/ec2.go Replaces EC2 roleArn plumbing with a comparable AssumeRole value object, uses it in equality/cache keys, and applies all session params to the AWS SDK STS provider.
pkg/kgateway/extensions2/plugins/backend/ec2_test.go Updates EC2 tests for the new auth shape and adds unit tests ensuring AssumeRole session params affect IR equality and client cache keys.
pkg/kgateway/extensions2/plugins/backend/aws.go Implements configureAWSAuth support for default chain, Secret inline creds, and Envoy AssumeRole credential provider.
pkg/kgateway/extensions2/plugins/backend/aws_test.go Adds unit coverage for configureAWSAuth across default/secret/assume-role paths, including minimal AssumeRole config.
install/helm/kgateway-crds/templates/gateway.kgateway.dev_backends.yaml Updates CRD OpenAPI schema: adds assumeRole, adds AssumeRole enum value, adds CEL validations, removes spec.aws.ec2.roleArn.
api/v1alpha1/kgateway/zz_generated.deepcopy.go Adds deepcopy support for the new AwsAssumeRole type and the new AwsAuth.AssumeRole field.
api/v1alpha1/kgateway/backend_types.go Adds the API types/validation tags for AwsAuthTypeAssumeRole and the AwsAssumeRole struct; removes AwsEc2.RoleArn.
Files not reviewed (1)
  • api/v1alpha1/kgateway/zz_generated.deepcopy.go: Language not supported

@gateway-bot gateway-bot added release-note and removed do-not-merge/description-invalid do-not-merge/release-note-invalid Indicates that a PR should not merge because it's missing one of the release note labels. labels Jun 2, 2026
Drop sessionName, externalId, and sessionDuration from the AssumeRole API.
The motivating use case is IRSA-based role chaining within a single org/account
(gateway/controller ambient identity assumes a per-target role), where these
parameters add no value: externalId only matters for third-party cross-account
trust policies that mandate it, and sessionName/sessionDuration are audit/refresh
tuning knobs. Keep the surface minimal; any of these can be re-added
non-breakingly if a concrete need appears.

- API: AwsAssumeRole now has only RoleArn.
- Lambda: AssumeRoleCredentialProvider sets only RoleArn.
- EC2: revert the ec2AssumeRole bundle back to a plain roleArn string sourced
  from auth.assumeRole.roleArn.
- Regenerate CRD/deepcopy/goldens; simplify the Lambda AssumeRole fixture to a
  single backend now that the minimal/full variants are identical.

Signed-off-by: omar <[email protected]>

@andy-fong andy-fong left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good in general but because there is no e2e test (probably not easy to do) can we at least do strict validation on the generated cluster config so we know for sure our config won't be rejected by envoy?

@puertomontt
puertomontt enabled auto-merge June 23, 2026 23:11
@puertomontt
puertomontt added this pull request to the merge queue Jun 23, 2026
Merged via the queue into kgateway-dev:main with commit cae5471 Jun 24, 2026
32 checks passed
@puertomontt
puertomontt deleted the aws-role branch June 24, 2026 00:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/feature Categorizes issue or PR as related to a new feature. release-note

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants