feat: add AssumeRole auth type for AWS backends (Lambda + EC2)#14148
Merged
Conversation
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]>
Contributor
There was a problem hiding this comment.
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.TypewithAssumeRoleand introducespec.aws.auth.assumeRole(roleArn, sessionName, externalId, sessionDuration) with CEL validation enforcing mutual exclusivity withSecret. - Update Lambda translation to emit Envoy
AwsRequestSigningconfig usingAssumeRoleCredentialProvider(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
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
reviewed
Jun 23, 2026
andy-fong
left a comment
Contributor
There was a problem hiding this comment.
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?
Signed-off-by: omar <[email protected]>
puertomontt
enabled auto-merge
June 23, 2026 23:11
andy-fong
approved these changes
Jun 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds an
AssumeRoleAWS auth type to theBackendAPI, 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.Typegains anAssumeRolevalue alongside the existingSecret. The two are mutually exclusive (discriminated union, enforced via CEL):The base credentials that sign the STS
AssumeRolecall 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 viaAssumeRoleWithWebIdentity, and we chain off that to the target role. SoAssumeRoleis used independently of a credentialSecret, not in conjunction with one.The API is intentionally minimal —
roleArnonly.sessionName,externalId, andsessionDurationwere 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
AwsRequestSigning.CredentialProvider.AssumeRoleCredentialProvider. The nested basecredential_provideris left unset so Envoy resolves the base credentials from its default chain (the gateway proxy pod's IRSA identity).auth.assumeRole.roleArndrives the controller'sstscreds.AssumeRoleProviderwhen callingDescribeInstances, chaining off the controller pod's IRSA identity. This replaces the separatespec.aws.ec2.roleArnfield 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
SecretandAssumeRoleare kept mutually exclusive. Consequence: the "static secret base + role chain" combination that #13961'sec2.roleArntechnically 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 sharedauthblock meaning one thing per backend. It can be relaxed later non-breakingly if a use case emerges.Change Type
/kind feature
Changelog
Additional Notes
spec.aws.ec2.roleArn(added in feat: support for AWS ec2 backends #13961, unreleased) is removed in favor of the unifiedspec.aws.auth.assumeRole.roleArn.configureAWSAuth(default/secret/assume-role paths); the API validation suite covers theroleArnpattern.