fix: enable Vault JWT auth without Spire for KMS signing#1616
fix: enable Vault JWT auth without Spire for KMS signing#1616infernus01 wants to merge 1 commit into
Conversation
|
/kind bug |
|
Core fix looks good, the priority chain (Spire → static token → K8s SA JWT) preserves backward compatibility. /lgtm |
|
Please add a release note |
When signers.kms.auth.oidc.path and signers.kms.auth.oidc.role are set in the Chains ConfigMap without Spire, the controller now reads the Kubernetes service account token from the pod filesystem and uses it for Vault JWT auth login. Previously, the OIDC token field was only populated by Spire, causing the code to fall through to VAULT_TOKEN lookup and fail with "read .vault-token file: no such file or directory". Signed-off-by: Shubham Bhardwaj <shubbhar@redhat.com>
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
| if tokenPath == "" { | ||
| tokenPath = defaultOIDCTokenPath | ||
| } | ||
| token, err := os.ReadFile(tokenPath) |
There was a problem hiding this comment.
can we reuse the existing getKMSAuthToken function here instead of calling os.ReadFile directly
There was a problem hiding this comment.
Ah yes that is intentional, since getKMSAuthToken uses TrimSuffix("\n") which only strips a single trailing newline. That's fine for static Vault tokens, but for the OIDC JWT path I used TrimSpace because for example if someone has a token file with just whitespaces like " \n \n", TrimSuffix would leave " \n " (looks non-empty, gets sent to Vault, confusing error), while TrimSpace correctly gives us "" which we then catch with the empty file check.
The empty file check itself is the other difference, since getKMSAuthToken might return "" without error, but here an empty token might cause the code to drop the entire OIDC config and fall back to VAULT_TOKEN, which is the exact bug this PR is fixing.
So same os.ReadFile, but different post-processing needs.
|
/lgtm |
There was a problem hiding this comment.
Pull request overview
This PR fixes Vault KMS JWT (OIDC) auth when running Tekton Chains without Spire by adding a fallback that reads the Kubernetes service account token from a file and passes it as the Vault JWT for login.
Changes:
- Add
signers.kms.auth.oidc.token-pathconfig to specify a JWT file for Vault OIDC auth (defaulting to the K8s SA token path). - Update KMS signer initialization to load the JWT from file when OIDC is configured and no Spire/static token is present.
- Add unit tests and docs coverage for the new configuration behavior.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/config/config.go | Adds KMSAuthOIDC.TokenPath and parses the new config key. |
| pkg/config/config_test.go | Adds a test ensuring the new OIDC token-path config is parsed correctly. |
| pkg/chains/signing/kms/kms.go | Implements OIDC JWT file fallback (default K8s SA token path). |
| pkg/chains/signing/kms/kms_test.go | Adds tests for the OIDC JWT file behavior and precedence. |
| docs/config.md | Documents signers.kms.auth.oidc.token-path and its default. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| rpcAuth.OIDC.Token = token | ||
| } | ||
|
|
||
| if rpcAuth.OIDC.Token == "" && rpcAuth.Token == "" && (cfg.Auth.OIDC.Path != "" || cfg.Auth.OIDC.Role != "") { |
| "github.com/tektoncd/chains/pkg/chains/signing" | ||
| ) | ||
|
|
||
| const defaultOIDCTokenPath = "/var/run/secrets/kubernetes.io/serviceaccount/token" //nolint:gosec // Not a credential, this is the path to read the K8s SA token file from |
| switch { | ||
| case r.URL.Path == "/v1/auth/jwt/login" && r.Method == http.MethodPut: | ||
| loginCalled = true | ||
| receivedPath = "jwt" | ||
|
|
| assert.Equal(t, "jwt", receivedPath, | ||
| "auth path must match the configured OIDC path") |
| if err == nil { | ||
| t.Fatal("expected error when default SA token path does not exist") | ||
| } | ||
| assert.Contains(t, err.Error(), "reading OIDC token") | ||
| assert.Contains(t, err.Error(), defaultOIDCTokenPath, | ||
| "error must reference the default K8s SA token path") | ||
| } |
| rpcAuth.OIDC.Token = token | ||
| } | ||
|
|
||
| if rpcAuth.OIDC.Token == "" && rpcAuth.Token == "" && (cfg.Auth.OIDC.Path != "" || cfg.Auth.OIDC.Role != "") { |
| } | ||
|
|
||
| if rpcAuth.OIDC.Token == "" && rpcAuth.Token == "" && (cfg.Auth.OIDC.Path != "" || cfg.Auth.OIDC.Role != "") { | ||
| tokenPath := cfg.Auth.OIDC.TokenPath |
There was a problem hiding this comment.
add debug
logger.Debug("OIDC token path for Vault JWT auth", "path", tokenPath)
Changes
Setting
signers.kms.auth.oidc.pathandsigners.kms.auth.oidc.rolein the Chains ConfigMap without Spire does nothing. The OIDC path and role are parsed correctly but never used — the code falls through toVAULT_TOKEN/~/.vault-tokenand fails:error configuring kms signer with config {hashivault://supply-chain {http://vault.vault:8200/ {jwt tekton-chains} { }}}: read .vault-token file: open /home/nonroot/.vault-token: no such file or directoryNow with this PR, when OIDC path/role are configured and no Spire or static token is present, read the Kubernetes service account token from
/var/run/secrets/kubernetes.io/serviceaccount/tokenand use it for Vault JWT auth. A new config keysigners.kms.auth.oidc.token-pathallows overriding the default path.Priority order: Spire → static token → K8s SA token
fixes: #1479
Submitter Checklist
As the author of this PR, please check off the items in this checklist:
functionality, content, code)
Release Notes