Keycloak. Configuration as Code

Posted by bubnovd on Wednesday, November 22, 2023

Представленная конфигурация keycloak создает федерацию LDAP для подключения к Active Directory и клиента k8s-client для взаимодействия с kubernetes по OIDC. В федерацию добавлен маппинг групп AD.

Конфигурацию производит job keycloak-config-cli после деплоя хелм чарта (post-install hook). Детальное описание, примеры конфигурации

В kube-apiserver нужно добавить аргументы:

--oidc-client-id=k8s-client
--oidc-issuer-url=https://your.keycloak.url/realms/realmWithLdap
--oidc-groups-claim=groups
--oidc-username-claim=name

следующие аргументы необязательны
--oidc-username-prefix="keycloak:"
--oidc-groups-prefix="keycloak:"

Конфигурация работает с чартом https://github.com/bitnami/charts/tree/main/bitnami/keycloak версии 17.1.0

  • Secret keycloak-config-cli must contain CLIENT_SECRET and LDAP_BIND_CREDS
  • IMPORT_VARSUBSTITUTION_ENABLED needs for substitute data from secret like "$(env:LDAP_BIND_CREDS)"
keycloakConfigCli:
    enabled: true
    image:
      registry: docker.io
      repository: bitnami/keycloak-config-cli
      tag: 5.9.0-debian-11-r0
  
    extraEnvVars:
     - name: IMPORT_VARSUBSTITUTION_ENABLED
       value: 'true'
  
    # secret must contain: CLIENT_SECRET and LDAP_BIND_CREDS
    extraEnvVarsSecret: "keycloak-config-cli"
    configuration:
      realm1.json: |
        {
          "enabled": true,
          "realm": "realmWithLdap",
          "components": {
            "org.keycloak.storage.UserStorageProvider": [
              {
                "id": "ldap",
                "name": "ldap",
                "providerId": "ldap",
                "subComponents": {
                  "org.keycloak.storage.ldap.mappers.LDAPStorageMapper": [
                    {
                      "name": "last name",
                      "providerId": "user-attribute-ldap-mapper",
                      "subComponents": {},
                      "config": {
                        "is.mandatory.in.ldap": [
                          "true"
                        ],
                        "read.only": [
                          "true"
                        ],
                        "always.read.value.from.ldap": [
                          "true"
                        ],
                        "user.model.attribute": [
                          "lastName"
                        ]
                      }
                    },
                    {
                      "name": "first name",
                      "providerId": "user-attribute-ldap-mapper",
                      "subComponents": {},
                      "config": {
                        "ldap.attribute": [
                          "cn"
                        ],
                        "is.mandatory.in.ldap": [
                          "true"
                        ],
                        "always.read.value.from.ldap": [
                          "true"
                        ],
                        "read.only": [
                          "true"
                        ],
                        "user.model.attribute": [
                          "firstName"
                        ]
                      }
                    },
                    {
                      "name": "creation date",
                      "providerId": "user-attribute-ldap-mapper",
                      "subComponents": {},
                      "config": {
                        "ldap.attribute": [
                          "createTimestamp"
                        ],
                        "is.mandatory.in.ldap": [
                          "false"
                        ],
                        "always.read.value.from.ldap": [
                          "true"
                        ],
                        "read.only": [
                          "true"
                        ],
                        "user.model.attribute": [
                          "createTimestamp"
                        ]
                      }
                    },
                    {
                      "name": "username",
                      "providerId": "user-attribute-ldap-mapper",
                      "subComponents": {},
                      "config": {
                        "ldap.attribute": [
                          "cn"
                        ],
                        "is.mandatory.in.ldap": [
                          "true"
                        ],
                        "always.read.value.from.ldap": [
                          "false"
                        ],
                        "read.only": [
                          "true"
                        ],
                        "user.model.attribute": [
                          "username"
                        ]
                      }
                    },
                    {
                      "name": "modify date",
                      "providerId": "user-attribute-ldap-mapper",
                      "subComponents": {},
                      "config": {
                        "ldap.attribute": [
                          "modifyTimestamp"
                        ],
                        "is.mandatory.in.ldap": [
                          "false"
                        ],
                        "read.only": [
                          "true"
                        ],
                        "always.read.value.from.ldap": [
                          "true"
                        ],
                        "user.model.attribute": [
                          "modifyTimestamp"
                        ]
                      }
                    },
                    {
                      "name": "email",
                      "providerId": "user-attribute-ldap-mapper",
                      "subComponents": {},
                      "config": {
                        "ldap.attribute": [
                          "mail"
                        ],
                        "is.mandatory.in.ldap": [
                          "false"
                        ],
                        "always.read.value.from.ldap": [
                          "false"
                        ],
                        "read.only": [
                          "true"
                        ],
                        "user.model.attribute": [
                          "email"
                        ]
                      }
                    },
                    {
                      "name": "ldap-groups",
                      "providerId": "group-ldap-mapper",
                      "subComponents": {},
                      "config": {
                        "membership.attribute.type": [
                          "DN"
                        ],
                        "group.name.ldap.attribute": [
                          "cn"
                        ],
                        "membership.user.ldap.attribute": [
                          "cn"
                        ],
                        "preserve.group.inheritance": [
                          "false"
                        ],
                        "groups.dn": [
                          "ou=YOUR_GROUPS_DN,dc=YOUR_DOMAIN,dc=YOUR_LOCAL"
                        ],
                        "mode": [
                          "READ_ONLY"
                        ],
                        "user.roles.retrieve.strategy": [
                          "GET_GROUPS_FROM_USER_MEMBEROF_ATTRIBUTE"
                        ],
                        "membership.ldap.attribute": [
                          "member"
                        ],
                        "ignore.missing.groups": [
                          "true"
                        ],
                        "group.object.classes": [
                          "group"
                        ],
                        "memberof.ldap.attribute": [
                          "memberOf"
                        ],
                        "groups.path": [
                          "/"
                        ],
                        "drop.non.existing.groups.during.sync": [
                          "true"
                        ]
                      }
                    }
                  ]
                },
                "config": {
                  "pagination": [
                    "false"
                  ],
                  "fullSyncPeriod": [
                    "30000"
                  ],
                  "connectionPooling": [
                    "true"
                  ],
                  "usersDn": [
                    "ou=YOUR_USERS_DN,dc=YOUR_DOMAIN,dc=YOUR_LOCAL"
                  ],
                  "cachePolicy": [
                    "DEFAULT"
                  ],
                  "useKerberosForPasswordAuthentication": [
                    "false"
                  ],
                  "importEnabled": [
                    "true"
                  ],
                  "enabled": [
                    "true"
                  ],
                  "usernameLDAPAttribute": [
                    "cn"
                  ],
                  "bindDn": [
                    "cn=YOUR_CN,ou=YOUR_SERVICE_ACCOUNT_OU,dc=YOUR_DOMAIN,dc=YOUR_LOCAL"
                  ],
                  "bindCredential": [
                    "$(env:LDAP_BIND_CREDS)"
                  ],
                  "changedSyncPeriod": [
                    "-1"
                  ],
                  "lastSync": [
                    "1622010092"
                  ],
                  "vendor": [
                    "ad"
                  ],
                  "uuidLDAPAttribute": [
                    "objectGUID"
                  ],
                  "connectionUrl": [
                    "ldaps://LDAPS.YOUR.DOMAIN"
                  ],
                  "allowKerberosAuthentication": [
                    "false"
                  ],
                  "syncRegistrations": [
                    "true"
                  ],
                  "authType": [
                    "simple"
                  ],
                  "debug": [
                    "false"
                  ],
                  "searchScope": [
                    "2"
                  ],
                  "useTruststoreSpi": [
                    "always"
                  ],
                  "priority": [
                    "0"
                  ],
                  "trustEmail": [
                    "false"
                  ],
                  "userObjectClasses": [
                    "person, organizationalPerson, user"
                  ],
                  "rdnLDAPAttribute": [
                    "cn"
                  ],
                  "editMode": [
                    "READ_ONLY"
                  ],
                  "validatePasswordPolicy": [
                    "false"
                  ],
                  "batchSizeForSync": [
                    "0"
                  ]
                }
              }
            ]
          },
          "clients": [
            {
              "clientId": "k8s-client",
              "name": "k8s-client",
              "description": "k8s-Client",
              "enabled": true,
              "protocol": "openid-connect",
              "clientAuthenticatorType": "client-secret",
              "secret": "$(env:CLIENT_SECRET)",
              "directAccessGrantsEnabled": true,
              "authorizationServicesEnabled": true,
              "serviceAccountsEnabled": true,
              "protocolMappers": [
                {
                  "name": "Client IP Address",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-usersessionmodel-note-mapper",
                  "consentRequired": false,
                  "config": {
                    "user.session.note": "clientAddress",
                    "id.token.claim": "true",
                    "access.token.claim": "true",
                    "claim.name": "clientAddress",
                    "jsonType.label": "String"
                  }
                },
                {
                  "name": "Client ID",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-usersessionmodel-note-mapper",
                  "consentRequired": false,
                  "config": {
                    "user.session.note": "clientId",
                    "id.token.claim": "true",
                    "access.token.claim": "true",
                    "claim.name": "clientId",
                    "jsonType.label": "String"
                  }
                },
                {
                  "name": "groups",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-group-membership-mapper",
                  "consentRequired": false,
                  "config": {
                    "full.path": "true",
                    "id.token.claim": "true",
                    "access.token.claim": "true",
                    "claim.name": "groups",
                    "userinfo.token.claim": "true"
                  }
                },
                {
                  "name": "Client Host",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-usersessionmodel-note-mapper",
                  "consentRequired": false,
                  "config": {
                    "user.session.note": "clientHost",
                    "id.token.claim": "true",
                    "access.token.claim": "true",
                    "claim.name": "clientHost",
                    "jsonType.label": "String"
                  }
                }
              ],
              "authorizationSettings": {
                "allowRemoteResourceManagement": true,
                "policyEnforcementMode": "ENFORCING",
                "resources": [
                  {
                    "name": "Default Resource",
                    "type": "urn:k8s-client:resources:default",
                    "ownerManagedAccess": false,
                    "attributes": {},
                    "uris": [
                      "/*"
                    ]
                  }
                ],
                "policies": [
                  {
                    "name": "Default Policy",
                    "description": "A policy that grants access only for users within this realm",
                    "type": "js",
                    "logic": "POSITIVE",
                    "decisionStrategy": "AFFIRMATIVE",
                    "config": {
                      "code": "// by default, grants any permission associated with this policy\n$evaluation.grant();\n"
                    }
                  },
                  {
                    "name": "Default Permission",
                    "description": "A permission that applies to the default resource type",
                    "type": "resource",
                    "logic": "POSITIVE",
                    "decisionStrategy": "UNANIMOUS",
                    "config": {
                      "defaultResourceType": "urn:k8s-client:resources:default",
                      "applyPolicies": "[\"Default Policy\"]"
                    }
                  }
                ],
                "scopes": [],
                "decisionStrategy": "UNANIMOUS"
              },
              "redirectUris": [
                "*"
              ],
              "webOrigins": [
                "*"
              ]
            }
          ]
        }

comments powered by Disqus