K8s-AD Integration using Keycloak
Q:
How to integrate keycloak on K8s on RHEL 8 with AD, given RHEL 8 is integrated with AD via Kerberos and password auth.
A:
Integrating Keycloak on Kubernetes (K8s) running on RHEL 8 with Active Directory (AD), especially when RHEL 8 is already integrated with AD via Kerberos and password authentication, involves several steps. Below is a high-level guide to achieve this integration:
Prerequisites
- Kubernetes Cluster: Ensure you have a running Kubernetes cluster on RHEL 8.
- Keycloak Deployment: Keycloak should be deployed on your Kubernetes cluster.
- AD Integration on RHEL: Confirm that RHEL 8 is successfully integrated with AD using SSSD for Kerberos and password authentication.
LDAP : Lightweight Directory Access Protocol
Successor to DAP (Directory Access Protocol) of switched-based telecoms era, and is origin of X.500 series standards.
Port(s):
- LDAP :
389 TCP and UDP
- LDAPS :
636 TCP and UDP
(TLS)
Both schemes use TCP mostly, but for Connectionless LDAP (CLDAP) protocol, which is a lightweight version of LDAP that uses UDP for simple, stateless queries, such as when a client needs to locate a domain controller in a Microsoft Active Directory environment. This is commonly seen in the initial stages of authentication, such as during a "ping" to locate domain controllers.
Terminology
CN=ldap-reader,OU=Service Accounts,DC=example,DC=com
- DC : Domain Component
- DN : Distinguished Name: a name that uniquely identifies an entry and its position in the DIT. It is comprised of a series of zero or more relative distinguished names (RDNs) separated by commas.
- RDN : Relative Distinguished Name: one or more attribute name-value pairs. DNs are comprised of zero or more RDNs, but it is common to use the term RDN to refer to the leftmost component of a DN because the attribute values included in the leftmost RDN component for a DN must also be present in the entry referenced by that DN.
- DIT : Directory Information Tree: the hierarchy of entries contained in a directory server.
LDAP Security Objects
- OU : Organizational Unit (OU): similar to a Window directory. For LDAP, it typically holds either Group objects or User objects.
- CN : Common Name
- Group : object containing a member attribute that is a list of Distinguished Names that define the users in that group.
- User : object describing a single person within the LDAP structure. Unlike a Group, a User does not contain a list. Instead, its attributes describe a user in as much detail as necessary.
Step 1: Deploy Keycloak on Kubernetes
Create a Namespace for Keycloak:
kubectl create namespace keycloak
Deploy Keycloak: You can deploy Keycloak using a Helm chart or a custom deployment. Here's an example using a Helm chart:
helm repo add codecentric https://codecentric.github.io/helm-charts helm install keycloak codecentric/keycloak --namespace keycloak
Expose Keycloak: Use an Ingress or a LoadBalancer service to expose Keycloak externally. Example:
apiVersion: v1 kind: Service metadata: name: keycloak namespace: keycloak spec: ports: - port: 80 targetPort: 8080 protocol: TCP selector: app: keycloak type: LoadBalancer
Step 2: Integrate Keycloak with Active Directory
- Access Keycloak Admin Console:
- Access the Keycloak admin console using the external IP or DNS name provided by the LoadBalancer or Ingress.
- Log in using the default admin credentials (which should be set during deployment).
- Create a New Realm:
- In the Keycloak admin console, create a new realm that will be used for AD integration.
- Add LDAP/AD as a User Federation Provider: Allowing Keycloak to connect to, and synch with, other IdP/IdM such as Active Directory Domain Services (AD DS), and otherwise act as an intermediary IdP. Implementing such Federated Identity allows users to quickly move between systems securely.
- Navigate to User Federation in the Keycloak admin console.
- Click on Add provider and select LDAP.
- Configure LDAP settings as follows:
- Vendor: Active Directory
- Connection URL:
ldap://<AD_SERVER_IP>:389
orldaps://<AD_SERVER_IP>:636
(for LDAPS) - Users DN: The base DN where your users are located, e.g.,
OU=Users,DC=example,DC=com
- Bind DN: The DN of an AD service account that has read access to the user data, e.g.,
CN=ldap-reader,OU=Service Accounts,DC=example,DC=com
- Bind Credential: The password for the Bind DN account.
- Kerberos Integration: Set Allow Kerberos Authentication to ON if Keycloak is to delegate authentication to AD using Kerberos.
- Sync Settings: Configure how and when to synchronize user data from AD to Keycloak.
- Test the connection to ensure that Keycloak can communicate with the AD server.
- Configure Kerberos Authentication (Optional):
- If you want Keycloak to use Kerberos for authentication, additional configuration is required:
- Kerberos Realm: Set the Kerberos realm, which should match your AD domain.
- Server Principal: The principal name Keycloak will use,
usually something like
HTTP/<keycloak-hostname>@EXAMPLE.COM
. - Keytab File: Upload the keytab file for the Keycloak service principal, which should be generated and exported from AD.
- If you want Keycloak to use Kerberos for authentication, additional configuration is required:
- Sync Users:
- After configuring the LDAP provider, trigger a full sync to import AD users into Keycloak.
Step 3: Integrate Kubernetes with Keycloak
UPDATE: OIDC v. SAML
- Enable OIDC Authentication on Kubernetes :
Update your Kubernetes API server configuration (
kube-apiserver.yaml
) to use Keycloak as the OIDC provider. This involves adding flags to the API server configuration:--oidc-issuer-url=https://<keycloak-url>/auth/realms/<realm-name> --oidc-client-id=<client-id> --oidc-username-claim=preferred_username --oidc-groups-claim=groups
Create a Keycloak Client for Kubernetes:
- In the Keycloak admin console, create a new client for Kubernetes within your realm.
- Set the Client ID to match the
--oidc-client-id
configured in Kubernetes. - Set the Access Type to
confidential
. - Configure the Valid Redirect URIs to include the Kubernetes API server URL.
- See
kubelogin
Configure RBAC in Kubernetes:
- Map the Keycloak roles/groups to Kubernetes RBAC roles.
You can use a
ClusterRoleBinding
orRoleBinding
to grant appropriate permissions to the users authenticating via Keycloak.
- Map the Keycloak roles/groups to Kubernetes RBAC roles.
You can use a
Step 4: Testing and Verification
- Login to Kubernetes using Keycloak:
- Use a Kubernetes client (like
kubectl
) with an OIDC plugin or a custom script to obtain an OIDC token from Keycloak. - Test the login and ensure users can authenticate to Kubernetes via Keycloak using their AD credentials.
- Use a Kubernetes client (like
- Monitor Logs and Debug:
- Check the Keycloak and Kubernetes logs to ensure that the integration is working correctly and troubleshoot any issues.
Step 5: Optionally Refactor Groups/Roles
In environment having AD DS as the domain-level IdP, both K8s and its workloads (application services) have the option of abiding AD groups exclusively or refactoring to better fit upstream services.
@ AD DS (Domain IdP)
AD's org-based groups (having users);
are all synchronized with RHEL clients,
providing realm-level (domain) Authn:
team_1_*
⋮team_3_members
u11
u33
u5
u44
team_3_leaders
u11
u33
⋮
team_11_*
⋮
@ Keycloak (OIDC / User-Federation IdP)
- Authn : LDAP Realm has AD Groups. That is the coupling.
The resulting OIDC identity may match nothing but upstream (containerized) application(s).- Groups and Users synched with AD
- Requires AD service-account credentials.
- Groups may be refactored (per application) for better fit.
- Groups and Users synched with AD
- Authz is per role(s) bound to OIDC Group(s)
- OAuth2 Role(s)
- Realm-level
- Client-level
- OAuth2 Role(s)
Example @ Unchanged:
team_3_members
- Role-B
team_3_leaders
- Role-A
- Role-B
⋮
team_11_*
⋮
Example @ Refractored:
App-X
TestRack-B-Leaders
- Role-8
- Role-4
- Role-9
POSTGRESQL_DB_OWNER
- Role-3
- Role-7
⋮
App-Y
team_3_members
- Role-N
- Role-R
⋮
An authenticated subject (identity) is issued a bearer token (JWT) having claims including
id: <UUID>
,groups:[]
androles:[]
. Such claims scope all upstream API access (Authz) regardless (K8s API, App-X API, Web UI SSO, …).
@ K8s API Authn modes for Authz
- Bearer token
groups: []
- Has
Role
s viaRoleBinding
s
- Has
user: <UUID>
HasRole
s viaRoleBinding
s- Okay, but rather not.
roles: []
- K8s API ignores this.
ServiceAccount
token- Has
Role
s viaRoleBinding
s
- Has
- X.509 Certificate
- groups from
/OU=team_3_members /OU=TestRack-B-Leaders
- Has
Role
s viaRoleBinding
s
- Has
- user from
/CN=u33
HasRole
s viaRoleBinding
s- Okay, but rather not.
- groups from
Role
andRoleBinding
are objects of K8s API, whereasgroup
anduser
are merely concepts of K8s API, known only as token subjects. The latter map toRole
only byRoleBinding
.
ClusterRole
and ClusterRoleBinding
objects are ommitted here for clarity.
Where Role
and RoleBinding
are scoped to a Namespace
, the Cluster*
versions apply cluster-wide.
So, the lone coupling is the map from domain IdP (AD DS) user/group to DevOps-controlled IdP (Keycloak) group/role.
User/Group (Authn) is otherwise decoupled from roles (Authz). Moreover, access to K8s API endpoints is entirely decoupled from that of applications. Though decoupled, these may be configured identically, entirely refactored, or any mix thereof, all at the discretion of cluster/application administrators, and that separation too (cluster admin vs teams/apps admin) is discretionary and maintains its flexibility.
Summary
- Keycloak serves as the OIDC provider for Kubernetes, integrating with AD via LDAP and optionally Kerberos.
- RHEL 8 acts as the underlying OS for Kubernetes and is already integrated with AD, which facilitates secure communication and authentication.
- Kerberos can be configured in Keycloak if you require Kerberos-based SSO for users, although it's optional.
This setup provides a secure and centralized authentication mechanism for Kubernetes users, leveraging existing AD infrastructure and using Keycloak as a flexible and powerful identity broker.