Repository navigation
Allow the egress gateway to use more than one credential provider - #3409
Open
Max Thompson (thompsonmax) wants to merge 8 commits into
Open
Max Thompson (thompsonmax) wants to merge 8 commits into
Max Thompson (thompsonmax) wants to merge 8 commits into
Conversation
2 tasks done
Max Thompson (thompsonmax)
force-pushed
the
multi-credential-providers
branch
from
October 28, 2026 22:09
897ba77 to
34328e9
Compare
Max Thompson (thompsonmax)
marked this pull request as ready for review
October 28, 2026 22:12
The egress gateway dialed one credential provider and refused any credential URI naming another. Make the provider name, address and server name flags repeatable, dial each provider, and send each URI to the provider its host names. One of each flag behaves as before. Signed-off-by: Max Thompson <maxthomp@google.com>
--credential-provider also takes a JSON array of provider objects. ate-setup renders one set of egress flags, or one agentgateway credentialProviders entry, per provider, and deploys the bundled Kubernetes Secrets provider when k8s.io is among them. Signed-off-by: Max Thompson <maxthomp@google.com>
Max Thompson (thompsonmax)
requested review from
Bowei Du (bowei) and
Tim Hockin (thockin)
October 28, 2026 22:12
Max Thompson (thompsonmax)
force-pushed
the
multi-credential-providers
branch
from
October 28, 2026 22:14
34328e9 to
40c9cea
Compare
Decode --credential-provider once and switch on whether it is an object or an array, instead of looking for a leading bracket, and document the three accepted forms. Signed-off-by: Max Thompson <maxthomp@google.com>
Signed-off-by: Max Thompson <maxthomp@google.com>
Bowei Du (bowei)
left a comment
Collaborator
There was a problem hiding this comment.
otherwise LG, some comments
With the repeatable flag, --credential-provider-address= became one provider with an empty dial target instead of turning injection off. Refuse it at startup, and correct the comments on what happens with no provider: a request that needs an injection is denied. Signed-off-by: Max Thompson <maxthomp@google.com>
An entry such as null reported "name is required". Reject a non-object entry by its JSON type, and handle the error from re-encoding each entry. Signed-off-by: Max Thompson <maxthomp@google.com>
Document the providers map on the Handler field and point New at it. The catch-all now applies only when "" is the sole entry, as the field says, instead of whenever a "" key is present. Signed-off-by: Max Thompson <maxthomp@google.com>
Signed-off-by: Max Thompson <maxthomp@google.com>
Tim Hockin (thockin)
approved these changes
Oct 29, 2026
Tim Hockin (thockin)
left a comment
Collaborator
There was a problem hiding this comment.
I'm going to approve but seek a response, especially on the repeated flag question
| const credentialProviderUsage = `{"name":"k8s.io"} for the bundled Kubernetes Secrets provider, ` + | ||
| `{"enabled":false} to turn egress credential injection off, ` + | ||
| `or {"name":"<provider>","address":"<host>:<port>"} for a provider you deploy` | ||
| `or {"name":"<provider>","address":"<host>:<port>"} for a provider you deploy; ` + |
Collaborator
There was a problem hiding this comment.
Wouldn't this be better as a repeated flag, rather than a JSON list?
--credential-provider '{...}' --credential-provider value '{...}'
?
Collaborator
There was a problem hiding this comment.
yep, plus one
| fs.StringVar(&cfg.CredentialProvider.CAFile, "credential-provider-ca-file", "", "CA the credential provider's serving certificate must chain to; required unless --credential-provider-insecure is set") | ||
| fs.StringVar(&cfg.CredentialProvider.ClientCert, "credential-provider-client-cert", "", "Credential bundle presented to the credential provider as the client certificate; required unless --credential-provider-insecure is set") | ||
| fs.StringVar(&cfg.CredentialProvider.ServerName, "credential-provider-server-name", "", "SAN/SNI expected on the credential provider's serving certificate") | ||
| fs.StringArrayVar(&cfg.CredentialProvider.ServerNames, "credential-provider-server-name", nil, "SAN/SNI expected on a credential provider's serving certificate. Repeat once per --credential-provider-address, in the same order, or omit") |
Collaborator
There was a problem hiding this comment.
FTR: multiple parallel repeated flags are almost always the wrong choice
| func (h *Handler) providerCredential(ctx context.Context, ref resources.ActorRef, dest egresspolicy.Destination, uri string) ([]byte, error) { | ||
| if h.provider == nil { | ||
| if len(h.providers) == 0 { | ||
| slog.ErrorContext(ctx, "egress denied: policy requires credential injection but no credential provider is configured", |
Collaborator
There was a problem hiding this comment.
Is this case not covered by the names a provider this gateway does not serve error below? Seems like a better error, too?
Candidate for cleanup
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.
Part of #1661.
We plan an out-of-tree credential provider that exchanges an actor's JWT for a cloud access token (RFC 8693), so actors can call Google Cloud APIs as themselves. Clusters will also run Secret Manager or Kubernetes Secrets providers. Today the egress gateway dials one provider and refuses URIs naming any other, which prevents us from supporting multiple credential providers.
--credential-provider-name,-addressand-server-namerepeat once per provider. The gateway sends eachate-secret://URI to the provider its host names, and still fails closed on any other.--credential-provideralso takes a JSON array, rendered for both the Envoy and agentgateway dataplanes.The single-object JSON and single flags behave as before, except that atenet now rejects an empty
--credential-provider-address, which used to turn injection off, and an address without a--credential-provider-name(ate-setup always passes both;--credential-provider-name=keeps the unchecked dev mode). Providers share one CA and client certificate, as they do today. Docs follow in #3410.Tested with unit tests. Not run: kind e2e with two providers, which is worth a follow-up, or agentgateway with more than one entry.
AI use: AI-assisted, I reviewed and tested it.