harness-keycloak-auth

Harness Keycloak Auth Skill

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "harness-keycloak-auth" with this command: npx skills add lobbi-docs/claude/lobbi-docs-claude-harness-keycloak-auth

Harness Keycloak Auth Skill

Integrate Keycloak OIDC with Harness pipelines and EKS deployments.

Use For

  • Keycloak client management in pipelines, OIDC for EKS authentication

  • Realm-as-code patterns, service account provisioning

Keycloak Helm Values for EKS

charts/keycloak/values.yaml

keycloak: replicas: 2

image: repository: quay.io/keycloak/keycloak tag: "24.0.1"

command: - "/opt/keycloak/bin/kc.sh" - "start" - "--optimized"

extraEnv: | - name: KC_HOSTNAME value: "keycloak.{{ .Values.global.domain }}" - name: KC_PROXY value: "edge" - name: KC_DB value: "postgres" - name: KC_DB_URL valueFrom: secretKeyRef: name: keycloak-db key: url - name: KC_DB_USERNAME valueFrom: secretKeyRef: name: keycloak-db key: username - name: KC_DB_PASSWORD valueFrom: secretKeyRef: name: keycloak-db key: password - name: KEYCLOAK_ADMIN valueFrom: secretKeyRef: name: keycloak-admin key: username - name: KEYCLOAK_ADMIN_PASSWORD valueFrom: secretKeyRef: name: keycloak-admin key: password

ingress: enabled: true ingressClassName: nginx annotations: cert-manager.io/cluster-issuer: letsencrypt-prod rules: - host: keycloak.{{ .Values.global.domain }} paths: - path: / pathType: Prefix tls: - secretName: keycloak-tls hosts: - keycloak.{{ .Values.global.domain }}

serviceAccount: create: true annotations: eks.amazonaws.com/role-arn: arn:aws:iam::{{ .Values.aws.accountId }}:role/keycloak-role

Realm-as-Code Configuration

Realm Export Template

{ "realm": "{{ .Values.keycloak.realm }}", "enabled": true, "sslRequired": "external", "registrationAllowed": false, "loginWithEmailAllowed": true, "duplicateEmailsAllowed": false, "resetPasswordAllowed": true, "editUsernameAllowed": false, "bruteForceProtected": true, "permanentLockout": false, "maxFailureWaitSeconds": 900, "minimumQuickLoginWaitSeconds": 60, "waitIncrementSeconds": 60, "quickLoginCheckMilliSeconds": 1000, "maxDeltaTimeSeconds": 43200, "failureFactor": 5, "roles": { "realm": [ { "name": "admin", "description": "Administrator" }, { "name": "user", "description": "Standard user" } ] }, "clients": [], "users": [], "browserSecurityHeaders": { "contentSecurityPolicyReportOnly": "", "xContentTypeOptions": "nosniff", "xRobotsTag": "none", "xFrameOptions": "SAMEORIGIN", "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", "xXSSProtection": "1; mode=block", "strictTransportSecurity": "max-age=31536000; includeSubDomains" } }

Client Configuration Template

{ "clientId": "{{ .Values.service.name }}-client", "name": "{{ .Values.service.name }} Service", "enabled": true, "clientAuthenticatorType": "client-secret", "secret": "{{ .Values.keycloak.clientSecret }}", "redirectUris": [ "https://{{ .Values.service.name }}.{{ .Values.global.domain }}/*" ], "webOrigins": [ "https://{{ .Values.service.name }}.{{ .Values.global.domain }}" ], "standardFlowEnabled": true, "implicitFlowEnabled": false, "directAccessGrantsEnabled": true, "serviceAccountsEnabled": true, "publicClient": false, "protocol": "openid-connect", "attributes": { "pkce.code.challenge.method": "S256", "access.token.lifespan": "300", "client.session.idle.timeout": "1800" }, "defaultClientScopes": [ "web-origins", "profile", "roles", "email" ], "optionalClientScopes": [ "address", "phone", "offline_access" ] }

Harness Pipeline Steps for Keycloak

Create/Update Keycloak Client

  • step: type: Run name: Configure Keycloak Client identifier: configure_keycloak spec: shell: Bash command: | # Get admin token TOKEN=$(curl -s -X POST
    "${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token"
    -H "Content-Type: application/x-www-form-urlencoded"
    -d "username=${KEYCLOAK_ADMIN}"
    -d "password=${KEYCLOAK_ADMIN_PASSWORD}"
    -d "grant_type=password"
    -d "client_id=admin-cli" | jq -r '.access_token')

      # Check if client exists
      CLIENT_ID="<+service.name>-client"
      EXISTING=$(curl -s -X GET \
        "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients?clientId=${CLIENT_ID}" \
        -H "Authorization: Bearer ${TOKEN}" | jq -r '.[0].id // empty')
    
      # Prepare client config
      cat > /tmp/client.json << 'EOF'
      {
        "clientId": "<+service.name>-client",
        "name": "<+service.name>",
        "enabled": true,
        "clientAuthenticatorType": "client-secret",
        "redirectUris": ["https://<+service.name>.<+pipeline.variables.domain>/*"],
        "webOrigins": ["https://<+service.name>.<+pipeline.variables.domain>"],
        "standardFlowEnabled": true,
        "serviceAccountsEnabled": true,
        "publicClient": false,
        "protocol": "openid-connect"
      }
      EOF
    
      if [ -n "$EXISTING" ]; then
        # Update existing client
        curl -s -X PUT \
          "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${EXISTING}" \
          -H "Authorization: Bearer ${TOKEN}" \
          -H "Content-Type: application/json" \
          -d @/tmp/client.json
        echo "Updated client: ${CLIENT_ID}"
      else
        # Create new client
        curl -s -X POST \
          "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients" \
          -H "Authorization: Bearer ${TOKEN}" \
          -H "Content-Type: application/json" \
          -d @/tmp/client.json
        echo "Created client: ${CLIENT_ID}"
      fi
    
      # Get client secret
      CLIENT_UUID=$(curl -s -X GET \
        "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients?clientId=${CLIENT_ID}" \
        -H "Authorization: Bearer ${TOKEN}" | jq -r '.[0].id')
    
      SECRET=$(curl -s -X GET \
        "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${CLIENT_UUID}/client-secret" \
        -H "Authorization: Bearer ${TOKEN}" | jq -r '.value')
    
      # Store in AWS Secrets Manager
      aws secretsmanager put-secret-value \
        --secret-id "<+service.name>/keycloak-client-secret" \
        --secret-string "${SECRET}"
    envVariables:
      KEYCLOAK_URL: <+pipeline.variables.keycloak_url>
      KEYCLOAK_REALM: <+pipeline.variables.keycloak_realm>
      KEYCLOAK_ADMIN: <+secrets.getValue("keycloak_admin_user")>
      KEYCLOAK_ADMIN_PASSWORD: <+secrets.getValue("keycloak_admin_password")>
    

Realm Import Step

  • step: type: Run name: Import Keycloak Realm identifier: import_realm spec: shell: Bash command: | # Get admin token TOKEN=$(curl -s -X POST
    "${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token"
    -H "Content-Type: application/x-www-form-urlencoded"
    -d "username=${KEYCLOAK_ADMIN}"
    -d "password=${KEYCLOAK_ADMIN_PASSWORD}"
    -d "grant_type=password"
    -d "client_id=admin-cli" | jq -r '.access_token')

      # Import realm from repo
      curl -s -X POST \
        "${KEYCLOAK_URL}/admin/realms" \
        -H "Authorization: Bearer ${TOKEN}" \
        -H "Content-Type: application/json" \
        -d @keycloak/realm-export.json
    
      echo "Realm imported successfully"
    

EKS OIDC Integration with Keycloak

IRSA for Keycloak-Authenticated Pods

ServiceAccount with Keycloak token injection

apiVersion: v1 kind: ServiceAccount metadata: name: {{ .Values.service.name }} annotations: eks.amazonaws.com/role-arn: arn:aws:iam::{{ .Values.aws.accountId }}:role/{{ .Values.service.name }}-role

apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Values.service.name }} spec: template: spec: serviceAccountName: {{ .Values.service.name }} containers: - name: app env: - name: KEYCLOAK_URL value: "https://keycloak.{{ .Values.global.domain }}" - name: KEYCLOAK_REALM value: "{{ .Values.keycloak.realm }}" - name: KEYCLOAK_CLIENT_ID value: "{{ .Values.service.name }}-client" - name: KEYCLOAK_CLIENT_SECRET valueFrom: secretKeyRef: name: {{ .Values.service.name }}-keycloak key: client-secret

External Secrets for Keycloak Credentials

apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: {{ .Values.service.name }}-keycloak spec: refreshInterval: 1h secretStoreRef: name: aws-secrets-manager kind: ClusterSecretStore target: name: {{ .Values.service.name }}-keycloak creationPolicy: Owner data: - secretKey: client-secret remoteRef: key: {{ .Values.service.name }}/keycloak-client-secret

Helm Values for Keycloak-Enabled Service

values.yaml for a service with Keycloak auth

service: name: api-gateway

keycloak: enabled: true realm: production clientId: api-gateway-client

Client secret fetched from AWS Secrets Manager

clientSecretRef: name: api-gateway-keycloak key: client-secret

OIDC configuration

oidc: issuerUri: https://keycloak.example.com/realms/production jwksUri: https://keycloak.example.com/realms/production/protocol/openid-connect/certs tokenEndpoint: https://keycloak.example.com/realms/production/protocol/openid-connect/token authorizationEndpoint: https://keycloak.example.com/realms/production/protocol/openid-connect/auth userInfoEndpoint: https://keycloak.example.com/realms/production/protocol/openid-connect/userinfo

Role mappings

roles: admin: ROLE_ADMIN user: ROLE_USER

Pipeline Variables for Keycloak

pipeline: variables: - name: keycloak_url type: String default: "https://keycloak.example.com" description: "Keycloak server URL" - name: keycloak_realm type: String default: "production" description: "Keycloak realm name" - name: domain type: String default: "example.com" description: "Base domain for services"

Verification Steps

  • step: type: Run name: Verify Keycloak Integration identifier: verify_keycloak spec: shell: Bash command: | # Test token endpoint RESPONSE=$(curl -s -o /dev/null -w "%{http_code}"
    "${KEYCLOAK_URL}/realms/${KEYCLOAK_REALM}/.well-known/openid-configuration")

      if [ "$RESPONSE" != "200" ]; then
        echo "Keycloak realm not accessible"
        exit 1
      fi
    
      # Test client authentication
      TOKEN_RESPONSE=$(curl -s -X POST \
        "${KEYCLOAK_URL}/realms/${KEYCLOAK_REALM}/protocol/openid-connect/token" \
        -H "Content-Type: application/x-www-form-urlencoded" \
        -d "client_id=${CLIENT_ID}" \
        -d "client_secret=${CLIENT_SECRET}" \
        -d "grant_type=client_credentials")
    
      if echo "$TOKEN_RESPONSE" | jq -e '.access_token' > /dev/null; then
        echo "Keycloak client authentication successful"
      else
        echo "Keycloak client authentication failed"
        exit 1
      fi
    

Troubleshooting

Issue Solution

Token endpoint unreachable Check Keycloak ingress, verify realm exists

Invalid client credentials Regenerate client secret, update secrets

CORS errors Configure web origins in client settings

Token validation failed Check JWKS endpoint, verify issuer URI

Realm import failed Validate JSON syntax, check for conflicts

References

  • Keycloak Admin REST API

  • EKS OIDC Provider

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

vision-multimodal

No summary provided by upstream source.

Repository SourceNeeds Review
General

design-system

No summary provided by upstream source.

Repository SourceNeeds Review
General

kanban

No summary provided by upstream source.

Repository SourceNeeds Review
General

complex-reasoning

No summary provided by upstream source.

Repository SourceNeeds Review