← Back to blog
KeycloakSecuritySSODevOps

One Login to Rule Them All: Keycloak as Your Infrastructure SSO Provider

· 6 min read

You have five tools. Each one has its own user database. Each one has its own password policy. Each one requires a separate login. When someone leaves the team, you spend an afternoon clicking through admin panels hoping you did not miss one. This is not security. This is a liability.

Keycloak fixes this. One identity provider, one login, one place to disable access. Here is how to wire it into the tools that actually run your infrastructure.

The problem nobody talks about

Most infrastructure teams accumulate authentication debt the same way they accumulate technical debt — slowly, then all at once. GitLab has local accounts. Grafana has its own user store. Vault has userpass backends. ArgoCD has a local admin password that three people know. Kubernetes uses client certificates that never expire.

The consequences are predictable:

  • Offboarding is incomplete. Someone leaves, and their Grafana account sits active for months.
  • No MFA consistency. Maybe GitLab enforces it. Vault probably does not.
  • No audit trail. You cannot answer “who accessed what and when” across tools.
  • Password fatigue. People reuse passwords or store them in plaintext notes.

The fix is not another password manager. The fix is removing passwords from the equation entirely.

graph TD
    KC[Keycloak] --> V[Vault]
    KC --> K8S[Kubernetes]
    KC --> ARGO[ArgoCD]
    KC --> GL[GitLab]
    KC --> GRAF[Grafana]
    KC --> LDAP[LDAP / AD]
    KC --> MFA[MFA / 2FA]

Keycloak as your central identity provider

Keycloak is an open-source identity and access management solution that speaks both OIDC and SAML. It gives you a single place to manage users, groups, MFA policies, and session lifetimes. Every tool in your stack authenticates against Keycloak instead of maintaining its own user database.

The architecture is straightforward: Keycloak holds the users and groups. Each tool becomes an OIDC or SAML client. Group memberships in Keycloak map to roles and permissions in each tool. One user record, one password (or no password if you use social login or certificate auth), one MFA policy.

Create a Keycloak realm for your infrastructure, define groups like infra-admins, developers, and readonly, and start connecting tools.

Vault: OIDC auth with group-based policies

If you have followed our guide on managing secrets with Vault, you know that access control is everything. Keycloak makes it centralized.

Enable the OIDC auth method and point it at your Keycloak realm:

vault auth enable oidc

vault write auth/oidc/config \
  oidc_discovery_url="https://keycloak.example.com/realms/infrastructure" \
  oidc_client_id="vault" \
  oidc_client_secret="$VAULT_CLIENT_SECRET" \
  default_role="default"

vault write auth/oidc/role/default \
  bound_audiences="vault" \
  allowed_redirect_uris="https://vault.example.com/ui/vault/auth/oidc/oidc/callback" \
  user_claim="sub" \
  groups_claim="groups" \
  policies="default"

Then map Keycloak groups to Vault policies:

vault write identity/group-alias name="infra-admins" \
  mount_accessor=$(vault auth list -format=json | jq -r '.["oidc/"].accessor') \
  canonical_id=$(vault read -field=id identity/group/name/vault-admins)

Users log into Vault through the browser, Keycloak handles authentication and MFA, and Vault assigns policies based on group membership.

Kubernetes: OIDC authentication with kubelogin

Kubernetes API server supports OIDC natively. Configure it to trust your Keycloak realm as described in our Kubernetes security post:

# kube-apiserver flags
--oidc-issuer-url=https://keycloak.example.com/realms/infrastructure
--oidc-client-id=kubernetes
--oidc-username-claim=preferred_username
--oidc-groups-claim=groups

On the client side, use kubelogin to handle the OIDC flow:

# kubeconfig
users:
  - name: oidc-user
    user:
      exec:
        apiVersion: client.authentication.k8s.io/v1beta1
        command: kubectl
        args:
          - oidc-login
          - get-token
          - --oidc-issuer-url=https://keycloak.example.com/realms/infrastructure
          - --oidc-client-id=kubernetes
          - --oidc-client-secret=kubernetes-secret

Bind Keycloak groups to Kubernetes RBAC:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: keycloak-admins
subjects:
  - kind: Group
    name: infra-admins
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

No more long-lived client certificates. No more shared kubeconfigs.

ArgoCD: OIDC in the ConfigMap

ArgoCD integrates with OIDC directly. As we covered in our ArgoCD and GitOps post, access control matters when your CD tool can modify production. Configure it in the argocd-cm ConfigMap:

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/infrastructure
    clientID: argocd
    clientSecret: $oidc.keycloak.clientSecret
    requestedScopes:
      - openid
      - profile
      - email
      - groups

Map Keycloak groups to ArgoCD roles in argocd-rbac-cm:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-rbac-cm
  namespace: argocd
data:
  policy.csv: |
    g, infra-admins, role:admin
    g, developers, role:readonly

Disable the local admin account once SSO is working. You do not need it.

GitLab: SAML or OIDC provider

GitLab supports both protocols. OIDC is simpler for most setups. Add this to gitlab.rb:

gitlab_rails['omniauth_providers'] = [
  {
    name: "openid_connect",
    label: "Keycloak",
    args: {
      name: "openid_connect",
      scope: ["openid", "profile", "email"],
      response_type: "code",
      issuer: "https://keycloak.example.com/realms/infrastructure",
      discovery: true,
      client_auth_method: "query",
      uid_field: "preferred_username",
      client_options: {
        identifier: "gitlab",
        secret: "gitlab-client-secret",
        redirect_uri: "https://gitlab.example.com/users/auth/openid_connect/callback"
      }
    }
  }
]

gitlab_rails['omniauth_block_auto_created_users'] = false
gitlab_rails['omniauth_allow_single_sign_on'] = ['openid_connect']

Consider disabling password-based login entirely once SSO is verified. One less attack surface.

Grafana: OAuth with role mapping

Grafana’s OAuth integration is clean. Add this to grafana.ini:

[auth.generic_oauth]
enabled = true
name = Keycloak
allow_sign_up = true
client_id = grafana
client_secret = grafana-client-secret
scopes = openid profile email groups
auth_url = https://keycloak.example.com/realms/infrastructure/protocol/openid-connect/auth
token_url = https://keycloak.example.com/realms/infrastructure/protocol/openid-connect/token
api_url = https://keycloak.example.com/realms/infrastructure/protocol/openid-connect/userinfo
role_attribute_path = contains(groups[*], 'infra-admins') && 'Admin' || contains(groups[*], 'developers') && 'Editor' || 'Viewer'

The role_attribute_path uses JMESPath to map Keycloak groups to Grafana roles. Infra admins get Admin, developers get Editor, everyone else gets Viewer. No manual role assignment in Grafana.

What you actually gain

Once all five tools authenticate against Keycloak, the operational benefits are immediate:

  • Offboarding in one click. Disable a user in Keycloak. They lose access to Vault, Kubernetes, ArgoCD, GitLab, and Grafana simultaneously. No tool-hopping, no forgotten accounts.
  • MFA everywhere. Enable MFA in Keycloak once. Every tool inherits it. No per-tool MFA configuration.
  • Centralized audit trail. Keycloak logs every authentication event. Combined with each tool’s own audit logs, you get a complete picture of who accessed what.
  • Group-based RBAC. Move a user from developers to infra-admins in Keycloak. Their permissions update across all tools. No need to touch five different admin panels.
  • Reduced attack surface. Fewer passwords means fewer credentials to leak. OIDC tokens are short-lived by default.

Getting started

Start with the tool that causes the most authentication pain — usually it is the one with the most stale accounts. Get Keycloak running (a simple Docker Compose setup works for evaluation), connect one tool, verify the flow, and expand from there.

The order we recommend: Vault first (because secrets are the highest-risk surface), then Kubernetes, then ArgoCD, GitLab, and Grafana. Each integration takes an afternoon at most.

If wiring SSO across your infrastructure stack sounds like a project you would rather not do alone, reach out to us. We have done this for teams ranging from five engineers to fifty, and the result is always the same — less operational overhead, better security posture, and one fewer spreadsheet tracking who has access to what.