Throughout this series we’ve logged into ArgoCD with the built-in admin account. That’s
fine for a demo, but on a real team you want everyone to sign in with their company
identity and get permissions based on their group — no shared passwords. In this final
post we’ll wire ArgoCD up to Keycloak using OpenID Connect (OIDC) for single sign-on.
How ArgoCD does SSO
ArgoCD authenticates users in one of two ways:
- Local users — accounts defined in
argocd-cm(likeadmin). - SSO via OIDC — delegate login to an identity provider. ArgoCD can talk OIDC directly, or go through its bundled Dex connector for providers that need it.
Keycloak is a first-class OIDC provider, so we’ll use ArgoCD’s direct OIDC integration — no Dex required. The flow is: ArgoCD redirects the user to Keycloak, Keycloak authenticates them and returns an ID token containing their groups, and ArgoCD maps those groups to roles via RBAC.
Configure Keycloak
In your Keycloak realm (say devops), create a new OIDC client for ArgoCD:
- Client ID:
argocd - Client authentication: On (confidential client — we’ll use a secret).
- Valid redirect URIs:
https://argocd.example.com/auth/callback - Web origins:
https://argocd.example.com
Then copy the client secret from the Credentials tab.
The important part is exposing the user’s groups in the token. Add a Group Membership mapper to the client:
- Mapper type: Group Membership
- Token Claim Name:
groups - Full group path: Off (so you get
argocd-admins, not/argocd-admins) - Enable Add to ID token and Add to userinfo.
Finally create a couple of groups in Keycloak — for example argocd-admins and
argocd-developers — and assign your users to them.
Point ArgoCD at Keycloak
ArgoCD reads its OIDC config from the argocd-cm ConfigMap. Add an oidc.config block
with your Keycloak realm URL and client:
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
url: https://argocd.example.com
oidc.config: |
name: Keycloak
issuer: https://keycloak.example.com/realms/devops
clientID: argocd
clientSecret: $oidc.keycloak.clientSecret
requestedScopes:
- openid
- profile
- email
- groups
Notice clientSecret: $oidc.keycloak.clientSecret. The $ tells ArgoCD to read the value
from a key in the argocd-secret Secret rather than storing it in the ConfigMap. Add it
there (sealed, of course):
apiVersion: v1
kind: Secret
metadata:
name: argocd-secret
namespace: argocd
type: Opaque
stringData:
oidc.keycloak.clientSecret: <client-secret-from-keycloak>
Map groups to roles with RBAC
Authentication tells ArgoCD who you are; RBAC decides what you can do. Configure
group-to-role mappings in argocd-rbac-cm:
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-rbac-cm
namespace: argocd
data:
policy.default: role:readonly
policy.csv: |
# Keycloak group -> ArgoCD role
g, argocd-admins, role:admin
# A custom, scoped role for developers
p, role:developer, applications, get, */*, allow
p, role:developer, applications, sync, */*, allow
g, argocd-developers, role:developer
scopes: '[groups]'
Here:
- Members of
argocd-adminsget the built-inrole:admin. - We define a custom
role:developerthat may view and sync Applications but not delete them or change settings, and bind theargocd-developersgroup to it. - Everyone else falls back to
policy.default(role:readonly). scopes: '[groups]'tells the RBAC engine to read thegroupsclaim from the token.
Apply and test
Apply the ConfigMaps and Secret, then restart the API server so it picks up the OIDC config:
kubectl apply -f argocd-cm.yaml -f argocd-rbac-cm.yaml -f argocd-secret.yaml
kubectl -n argocd rollout restart deploy/argocd-server
Open the ArgoCD UI and you’ll now see a “LOG IN VIA KEYCLOAK” button next to the
regular login form. Sign in with a Keycloak user, and ArgoCD applies the role that matches
their group. A member of argocd-developers will be able to sync apps but will find the
delete and settings actions disabled.
Hardening tips
- Once SSO works, disable the local admin account by setting
admin.enabled: "false"inargocd-cm, so there’s no shared password to leak. - Prefer groups over individual users in
policy.csv— access is then managed entirely in Keycloak. - Keep the client secret in a SealedSecret or External Secret, never in plain Git.
- Use AppProjects to further limit which repos, clusters, and namespaces each role can touch.
The manifests are in 11-sso-keycloak.
Wrapping up the series
That completes our ArgoCD journey — from a first Application, through core concepts,
private repos, architecture, Helm and Kustomize, resource hooks, secret management,
ApplicationSet, multi-cluster deployments, and finally single sign-on. You now have the
building blocks to run GitOps continuous delivery for real teams and real clusters. Happy
shipping!