Runbook: Provisioning Backstage Access to ArgoCD¶
Status: Active — implemented for the 7kgroup canary (hub ArgoCD)
Purpose¶
Provision a dedicated, least-privilege ArgoCD account for the Backstage portal
(roadie argo-cd plugin), so the portal reads Applications without the admin
password. This is a one-time, hub-level step against the shared
management-plane ArgoCD (configured in 7k-inari-fleet). Every client's
Backstage instance reuses this account — repeat the steps with a different
account name only if per-client isolation is required.
The account is token-only (apiKey, no interactive login) and scoped to
role:backstage = applications, get, */* (read-only: no create/update/delete,
sync, repositories, clusters, or accounts).
Prerequisites¶
- Write access to
github.com/7k-group/7k-inari-fleet. kubectlaccess to the management-plane cluster (theargocdnamespace).- ArgoCD admin credentials — only to mint the account token; discarded after.
- Vault write access (
backstage/argocd).
Background: where ArgoCD config lives¶
The hub ArgoCD is Helm argo-cd (chart 9.5.14), self-managed by the argocd
Application with two sources:
- chart
argo-cd, values from$values/fleet/bootstrap/values.yaml fleet/bootstrap(applied as manifests;extras/argocd-cm.yamlholds account config)
Therefore:
argocd-cmaccount config → editfleet/bootstrap/extras/argocd-cm.yamlargocd-rbac-cmpolicy → editfleet/bootstrap/values.yaml(configs.rbac)
Both are reconciled by ArgoCD self-heal — edit the repo, never patch live (a live edit is reverted within seconds).
Steps¶
1. Declare the account (fleet repo)¶
In fleet/bootstrap/extras/argocd-cm.yaml, under data:, add:
accounts.backstage: apiKey
accounts.backstage.enabled: "true"
2. Add least-privilege RBAC (fleet repo)¶
In fleet/bootstrap/values.yaml, append to configs.rbac.policy.csv:
g, backstage, role:backstage
p, role:backstage, applications, get, */*, allow
Commit both files. The self-managing argocd app syncs within a few minutes, or
force it:
kubectl -n argocd annotate application argocd argocd.argoproj.io/refresh=hard --overwrite
3. Verify the account + role landed¶
kubectl -n argocd get cm argocd-cm -o jsonpath='{.data.accounts\.backstage}'
kubectl -n argocd get cm argocd-rbac-cm -o jsonpath='{.data.policy\.csv}' | grep backstage
4. Mint the account token¶
Exec into argocd-server, authenticate as admin, and generate a token. The
command below sources the admin password from the backstage-env-vars secret;
if provisioning before Backstage exists, use argocd-initial-admin-secret
({.data.password}) instead.
ADMIN_PW_B64=$(kubectl -n backstage get secret backstage-env-vars -o jsonpath='{.data.ARGOCD_PASSWORD}')
kubectl -n argocd exec deploy/argocd-server -- sh -c \
"PW=\$(printf '%s' $ADMIN_PW_B64 | base64 -d); \
argocd login localhost:8080 --username admin --password \"\$PW\" --plaintext >/dev/null 2>&1 && \
argocd account generate-token --account backstage --id backstage-portal"
The token is a JWT (sub: backstage:apiKey, jti: backstage-portal) with no
expiry. It is revocable via its jti (see Rotation below).
5. Store the token in Vault¶
vault kv put backstage/argocd token="<jwt>"
This replaces the legacy admin password key — the portal no longer needs it.
6. Point the Backstage addon at the token¶
Already done in the golden template (clients/_templates/cnoe/backstage/):
manifests/external-secrets.yamlmaps Vaultbackstage/argocd:token→ARGOCD_TOKENvalues.yamlsetsargocd.appLocatorMethods[].instances[].token: ${ARGOCD_TOKEN}
Sync the backstage-<client> app; the ExternalSecret pulls the token and the pod
restarts with it.
7. Verify¶
Token-level (run inside argocd-server, --auth-token <jwt>):
argocd account can-i get applications 'default/test' # -> yes
argocd account can-i create applications 'default/test' # -> no
argocd app list # -> lists applications
can-ineeds aproject/appobject (e.g.default/test). Testing with a bare*false-negatives because the policy object*/*requires a/.
Portal-level: the backstage pod logs show
Plugin initialization complete ... 'argocd' with no 401/403, and ArgoCD data
loads on catalog entities.
Rotation / revocation¶
- Rotate: generate a new token with a fresh id
(
--id backstage-portal-<date>), update Vault, let ESO refresh (or restart the backstage pod), then delete the old id. - Revoke:
argocd account delete-token --account backstage --id backstage-portal
TODO¶
- Automate account + token provisioning (currently a manual admin step).
- Decide whether each client gets a dedicated ArgoCD account (isolation) or all
share the single hub
backstageaccount.