ci: keyless Harbor robot + K8s creds via GitHub OIDC->Vault (retire admin HARBOR_* + KUBECONFIG_PROD) - #16
Conversation
…dmin HARBOR_* + KUBECONFIG_PROD) Retire org-admin HARBOR_USERNAME/HARBOR_PASSWORD and KUBECONFIG_PROD. Authenticate via GitHub OIDC -> Vault (jwt mount github-actions, role gha-kubetty) for the repo-scoped Harbor robot and a runtime-minted, namespace-scoped Kubernetes deploy token. Build/push/deploy logic unchanged; deploy-production moves to the in-cluster self-hosted-linux runner. Refs: cluster-services-secret-scoping
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d5c4773539
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| echo "${{ secrets.KUBECONFIG_PROD }}" | base64 -d > $HOME/.kube/config | ||
| chmod 600 $HOME/.kube/config | ||
| KUBE_TOKEN=$(curl -sf -H "X-Vault-Token: ${VAULT_TOKEN}" \ | ||
| -X PUT -d '{"kubernetes_namespace":"arc-runners-supporttools"}' \ |
There was a problem hiding this comment.
Generate the deploy token in the target namespace
The deploy job mints Vault Kubernetes credentials for arc-runners-supporttools, but every subsequent Helm/kubectl operation targets kubetty-gateway-prd. HashiCorp documents kubernetes_namespace as the namespace where the credentials are generated (and the response reports that service account namespace), so with the namespace-scoped token described here this job will authenticate as a service account scoped to the runner namespace and fail to deploy into kubetty-gateway-prd; request credentials for kubetty-gateway-prd instead, or explicitly use a cluster-wide binding if that is intended. See https://developer.hashicorp.com/vault/api-docs/secret/kubernetes#generate-credentials.
Useful? React with 👍 / 👎.
Keyless CI: GitHub OIDC -> Vault (retire org-admin secrets)
Converts
.github/workflows/pipeline.ymlfrom long-lived org-admin GitHub secretsto keyless, short-lived credentials minted at deploy time from HashiCorp Vault
(
vault.support.tools) via the GitHub OIDC token. Auth mechanism only — build,push, helm-upgrade, and rollout/verify logic are unchanged.
Removed (org-admin secrets, no longer referenced anywhere)
secrets.HARBOR_USERNAMEsecrets.HARBOR_PASSWORDsecrets.KUBECONFIG_PRODHow auth works now
Vault jwt mount
github-actions, rolegha-kubetty(audiencehttps://github.com/SupportTools):buildjob, and the disabledsecurity-scanjob):hashicorp/vault-action@v3exchanges the OIDC token for the repo-scoped Harbor robot at
secret/data/harbor/kubetty-ci-robot(username/password->HARBOR_ROBOT_USER/HARBOR_ROBOT_TOKEN);docker/login-actionnow uses those env vars. Robot is scopedto kubetty push / cache push / dockerhub pull.
deploy-productionjob):vault-actionlogs in withexportToken: true,then a mint step does
PUT kubernetes-onprem/creds/kubetty(
kubernetes_namespace: arc-runners-supporttools) to obtain a 1-hour SA token forkubetty-ci-deployer(CRUD inkubetty-gateway-prdonly). The token is guarded(non-empty / not
null),::add-mask::ed, and written into a kubeconfig at the samepath the deploy steps already use (
$HOME/.kube/config), pointing at the in-clusterapiserver (
https://kubernetes.default.svc:443) with the in-cluster CA. The existinghelm upgrade --install kubetty-gateway ... -n kubetty-gateway-prd, rollout, andkubectl get pods/svcsteps are untouched.Permissions
build: addedpermissions: { contents: read, id-token: write }.security-scan(disabled,if: false): addedid-token: writeto its existing block;converted to keyless so no
secrets.HARBOR_*remain anywhere.deploy-production: addedpermissions: { contents: read, id-token: write }.runs-on change (please note)
deploy-productionmovesubuntu-latest->self-hosted-linux. The keyless K8s pathtargets the in-cluster apiserver via the pod's ServiceAccount CA
(
/var/run/secrets/kubernetes.io/serviceaccount/ca.crt), which only exists on thein-cluster ARC runner (
arc-runners-supporttools). A GitHub-hostedubuntu-latestrunnercannot reach
kubernetes.default.svcor read that CA. Thebuild/security-scanHarborjobs stay on
ubuntu-latest.Triggers unchanged
on:is untouched (pushtomain+ tagsv*,pull_requesttomain,workflow_dispatch).deploy-productionkeeps itsif: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')guard, sothis PR branch push does not deploy. The Harbor/Vault steps in
buildare guarded byif: github.event_name != 'pull_request', so the PR'spull_requestrun does not attempta keyless login either.
Verification
yaml.safe_load), all 7 jobs preserved.grep -E 'secrets\.(HARBOR|KUBECONFIG)' pipeline.ymlreturns nothing.secrets.*references were touched (there were none besides the three removed).Draft — backend (Vault jwt role, Harbor robot, kubernetes-onprem role) is already
provisioned and verified; open as draft for review before merge.