Chuyển đến nội dung chính

Lesson 12: LDAP, OIDC and JWT Auth Methods

LDAP Auth Method (configuration of LDAP/Active Directory, group mapping, policies), OIDC Auth Method (configuration with Keycloak, Azure AD, Okta, Google), JWT Auth Method (for CI/CD — GitHub Actions OIDC, GitLab CI JWT), Bound claims, Claim mappings, allowed_redirect_uris.

🔒 DevSecOps — Lesson 12 Lesson 12: LDAP, OIDC and JWT Auth Methods

HashiCorp Vault from Basic to Advanced

Part 3: Auth Methods - Authentication and Authorization

xdev.asia

1. LDAP Auth Method

LDAP Auth Method allows Vault to authenticate users using the LDAP directory (Active Directory, OpenLDAP, FreeIPA). This is the most common method in enterprises to authenticate human users because most organizations already have LDAP/AD infrastructure in place.

Architecture

┌──────────┐   1. Login           ┌──────────────┐
│   User   │ ───────────────────▶ │    Vault     │
│          │                      │  LDAP Auth   │
│          │   4. Vault Token     │              │
│          │ ◀─────────────────── │              │
└──────────┘                      └──────┬───────┘
                                         │
                                2. LDAP Bind (verify password)
                                3. Search groups
                                         │
                                         ▼
                                  ┌──────────────┐
                                  │  LDAP Server │
                                  │  (AD / LDAP) │
                                  └──────────────┘

Configured with Active Directory

# Enable LDAP auth
vault auth enable ldap

# Cấu hình kết nối Active Directory
vault write auth/ldap/config \
  url="ldaps://ad.company.com:636" \
  userdn="OU=Users,DC=company,DC=com" \
  userattr="sAMAccountName" \
  groupdn="OU=Groups,DC=company,DC=com" \
  groupattr="cn" \
  groupfilter="(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={{.UserDN}}))" \
  binddn="CN=vault-svc,OU=ServiceAccounts,DC=company,DC=com" \
  bindpass="VaultServiceP@ss" \
  starttls=false \
  insecure_tls=false \
  certificate=@/etc/vault/ldap-ca.pem \
  token_ttl=8h \
  token_max_ttl=24h

Configure with OpenLDAP

vault write auth/ldap/config \
  url="ldaps://ldap.company.com:636" \
  userdn="ou=people,dc=company,dc=com" \
  userattr="uid" \
  groupdn="ou=groups,dc=company,dc=com" \
  groupattr="cn" \
  groupfilter="(|(memberUid={{.Username}})(member={{.UserDN}}))" \
  binddn="cn=vault,ou=services,dc=company,dc=com" \
  bindpass="LdapBindP@ss" \
  certificate=@/etc/vault/ldap-ca.pem

Group → Policy Mapping

# Map LDAP group "DevOps" → Vault policies
vault write auth/ldap/groups/DevOps \
  policies="devops-admin,kv-devops,pki-issue"

# Map LDAP group "Developers" → Vault policies
vault write auth/ldap/groups/Developers \
  policies="dev-readonly,kv-dev"

# Map LDAP group "DBA" → Vault policies
vault write auth/ldap/groups/DBA \
  policies="db-admin,db-rotate"

# Map specific user → additional policies
vault write auth/ldap/users/john.doe \
  policies="team-lead-extra" \
  groups="DevOps,Developers"

# Liệt kê groups
vault list auth/ldap/groups

Login with LDAP

# CLI login
vault login -method=ldap username=john.doe
# Password (will be hidden): ****

# API login
curl -s --request POST \
  --data '{"password": "userPassword"}' \
  ${VAULT_ADDR}/v1/auth/ldap/login/john.doe | jq .

2. OIDC Auth Method

OIDC (OpenID Connect) Auth Method allows Vault to authenticate via Identity Providers that support OIDC — Keycloak, Azure AD (Entra ID), Okta, Google Workspace, Auth0. This is the most modern method for human authentication because it supports SSO, MFA, and browser-based login.

OIDC Authentication Flow

┌──────────┐   1. vault login       ┌──────────────┐
│   User   │ ─────────────────────▶ │    Vault     │
│ (Browser)│                        │  OIDC Auth   │
│          │   2. Redirect to IdP   │              │
│          │ ◀───────────────────── │              │
│          │                        └──────────────┘
│          │   3. Login at IdP
│          │ ─────────────────────▶ ┌──────────────┐
│          │                        │  Keycloak/   │
│          │   4. Auth code         │  Azure AD    │
│          │ ◀───────────────────── │              │
│          │                        └──────────────┘
│          │   5. Auth code → Vault
│          │ ─────────────────────▶ ┌──────────────┐
│          │                        │    Vault     │
│          │   6. Exchange code     │              │
│          │      for tokens        │              │
│          │   7. Vault Token       │              │
│          │ ◀───────────────────── │              │
└──────────┘                        └──────────────┘

Configure with Keycloak

# Enable OIDC auth
vault auth enable oidc

# Cấu hình OIDC với Keycloak
vault write auth/oidc/config \
  oidc_discovery_url="https://keycloak.company.com/realms/company" \
  oidc_client_id="vault" \
  oidc_client_secret="vault-client-secret" \
  default_role="default"

# Tạo OIDC role
vault write auth/oidc/role/default \
  bound_audiences="vault" \
  allowed_redirect_uris="https://vault.company.com/ui/vault/auth/oidc/oidc/callback" \
  allowed_redirect_uris="http://localhost:8250/oidc/callback" \
  user_claim="preferred_username" \
  groups_claim="groups" \
  token_policies="default" \
  token_ttl=8h \
  token_max_ttl=24h \
  oidc_scopes="openid,profile,email,groups"

# Tạo role cho admin với bound claims
vault write auth/oidc/role/admin \
  bound_audiences="vault" \
  allowed_redirect_uris="https://vault.company.com/ui/vault/auth/oidc/oidc/callback" \
  allowed_redirect_uris="http://localhost:8250/oidc/callback" \
  user_claim="preferred_username" \
  groups_claim="groups" \
  bound_claims='{"department": "IT", "role": "admin"}' \
  claim_mappings='{"email": "email", "department": "department"}' \
  token_policies="admin,kv-admin" \
  token_ttl=4h \
  token_max_ttl=8h

Configure with Azure AD (Entra ID)

vault write auth/oidc/config \
  oidc_discovery_url="https://login.microsoftonline.com/<tenant-id>/v2.0" \
  oidc_client_id="<application-id>" \
  oidc_client_secret="<client-secret>" \
  default_role="azure-default"

vault write auth/oidc/role/azure-default \
  bound_audiences="<application-id>" \
  allowed_redirect_uris="https://vault.company.com/ui/vault/auth/oidc/oidc/callback" \
  allowed_redirect_uris="http://localhost:8250/oidc/callback" \
  user_claim="email" \
  groups_claim="groups" \
  token_policies="default" \
  oidc_scopes="openid,profile,email"

Login with OIDC

# Browser-based login (mở browser tự động)
vault login -method=oidc role=default

# Chỉ định port cho callback
vault login -method=oidc port=8250 role=default

# Qua Vault UI: chọn OIDC → Sign in → redirect đến IdP

3. JWT Auth Method

JWT Auth Method authenticates using JSON Web Tokens. Unlike OIDC (browser-based), JWT auth is suitable for machine authentication when the client already has a JWT token — especially for CI/CD pipelines.

JWT vs OIDC Auth

CriteriaJWT AuthOIDC Auth
Login flowClient sends JWT directlyBrowser-redirectbased
ObjectMachines, CI/CDHuman users
Token sourceClient already has JWTVault taken from IdP
MFA supportNoYes (via IdP)

GitHub Actions OIDC → Vault JWT Auth

GitHub Actions provides OIDC tokens for each workflow run, allowing authentication to Vault without saving secrets:

# Enable JWT auth cho GitHub Actions
vault auth enable -path=github-actions jwt

# Cấu hình JWT auth với GitHub OIDC Provider
vault write auth/github-actions/config \
  oidc_discovery_url="https://token.actions.githubusercontent.com" \
  bound_issuer="https://token.actions.githubusercontent.com"

# Tạo role cho repository cụ thể
vault write auth/github-actions/role/my-app \
  role_type="jwt" \
  bound_audiences="https://github.com/my-org" \
  bound_claims_type="glob" \
  bound_claims='{"repository": "my-org/my-app", "ref": "refs/heads/main"}' \
  user_claim="repository" \
  token_policies="my-app-deploy" \
  token_ttl=10m \
  token_max_ttl=30m

# Tạo role cho toàn bộ organization
vault write auth/github-actions/role/org-readonly \
  role_type="jwt" \
  bound_audiences="https://github.com/my-org" \
  bound_claims_type="glob" \
  bound_claims='{"repository": "my-org/*"}' \
  user_claim="repository" \
  token_policies="org-readonly" \
  token_ttl=5m

GitHub Actions Workflow

# .github/workflows/deploy.yml
name: Deploy with Vault OIDC
on:
  push:
    branches: [main]

permissions:
  id-token: write   # Required cho OIDC token
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Authenticate to Vault
        uses: hashicorp/vault-action@v3
        with:
          url: https://vault.company.com
          method: jwt
          path: github-actions
          role: my-app
          jwtGithubAudience: https://github.com/my-org
          secrets: |
            secret/data/production/db username | DB_USER ;
            secret/data/production/db password | DB_PASS

      - name: Deploy
        run: ./deploy.sh

GitLab CI JWT Auth

# Enable JWT auth cho GitLab CI
vault auth enable -path=gitlab-ci jwt

# Cấu hình
vault write auth/gitlab-ci/config \
  jwks_url="https://gitlab.company.com/-/jwks" \
  bound_issuer="https://gitlab.company.com"

# Tạo role
vault write auth/gitlab-ci/role/deploy \
  role_type="jwt" \
  bound_claims='{"project_id": "42", "ref_protected": "true"}' \
  user_claim="project_path" \
  token_policies="gitlab-deploy" \
  token_ttl=10m
# .gitlab-ci.yml
deploy:
  stage: deploy
  id_tokens:
    VAULT_ID_TOKEN:
      aud: https://vault.company.com
  script:
    - |
      VAULT_TOKEN=$(vault write -field=token auth/gitlab-ci/login \
        role=deploy \
        jwt="${VAULT_ID_TOKEN}")
      export VAULT_TOKEN
      DB_PASS=$(vault kv get -field=password secret/production/db)
      ./deploy.sh

4. Bound Claims and Claim Mappings

Bound Claims

Bound claims limit which JWT tokens are allowed to login to a role:

# Exact match
vault write auth/jwt/role/strict-role \
  bound_claims='{"department": "engineering", "team": "platform"}'

# Glob pattern matching
vault write auth/jwt/role/glob-role \
  bound_claims_type="glob" \
  bound_claims='{"repository": "my-org/*", "ref": "refs/heads/main"}'

# Multiple values (OR logic)
vault write auth/jwt/role/multi-role \
  bound_claims='{"group": ["devops", "sre", "platform"]}'

Claim Mappings

Claim mappings map JWT claims into Vault identity metadata:

vault write auth/oidc/role/mapped-role \
  claim_mappings='{"email": "email", "department": "dept", "employee_id": "emp_id"}'

# Metadata available in policies:
# {{identity.entity.aliases.<mount_accessor>.metadata.email}}
# {{identity.entity.aliases.<mount_accessor>.metadata.dept}}

5. Best Practices

LDAP

  • Always use LDAPS (port 636) or StartTLS

  • Service account for Vault bind should have read-only permission

  • Map groups instead of individual users for ease of management

  • Test LDAP filter configuration carefully before applying production

OIDC

  • Limit allowed_redirect_uris to only Vault actual URL

  • Use bound_claims to restrict access by department/role

  • Enable MFA at IdP (Keycloak, Azure AD)

  • Rotate oidc_client_secret periodically

JWT

  • Prefer OIDC tokens from CI/CD instead of static secrets (AppRole)

  • Bound claims should be as specific as possible (repo, branch, environment)

  • Token Short TTL (5-15 minutes) for CI/CD

  • Use bound_audiences to prevent token misuse

6. Summary

  • LDAP Auth — enterprise choice for human users, taking advantage of existing AD/LDAP infrastructure

  • OIDC Auth — state-of-the-art for human users, SSO, MFA, browser-based login

  • JWT Auth — ideal for CI/CD (GitHub Actions OIDC, GitLab CI JWT), no need to save static secrets

The next article will focus on Kubernetes, AWS and Cloud Auth Methods — authentication based on workload identity.