In modern enterprise environments, user entitlements are often managed through LDAP (Lightweight Directory Access Protocol) directories like Active Directory. On the other hand, Kubernetes (K8s) is the de facto container orchestration platform. Ensuring that users have the correct Kubernetes RoleBindings based on LDAP entitlements is critical for security, compliance, and productivity.

This article explains how to write and automate a Python script that syncs LDAP entitlements with Kubernetes RoleBindings, scheduled using a Kubernetes CronJob. We’ll also cover how to structure the Python script, access both LDAP and Kubernetes APIs, and automate the sync process reliably.

Understanding the Architecture

Before diving into the implementation, let’s understand the components:

  1. LDAP Server: Stores user groups and entitlements.

  2. Kubernetes Cluster: Requires proper RBAC bindings (RoleBinding or ClusterRoleBinding).

  3. Python Sync Script: Queries LDAP and updates Kubernetes resources.

  4. Kubernetes CronJob: Schedules the script to run periodically.

Prerequisites

  • Access to an LDAP server.

  • A running Kubernetes cluster with access to kubectl or Kubernetes API.

  • Python 3.x installed with necessary libraries.

  • ServiceAccount in Kubernetes with appropriate permissions to manage RoleBindings.

Required Python Libraries

Install the required libraries using pip:

bash
pip install ldap3 kubernetes pyyaml
  • ldap3 for connecting and querying LDAP.

  • kubernetes for interacting with the K8s API.

  • pyyaml for config parsing (optional for external configs).

Connect to the LDAP Server

Let’s define a function to connect and query LDAP groups.

python

from ldap3 import Server, Connection, ALL

def get_ldap_group_members(ldap_host, base_dn, group_cn, bind_user, bind_password):
server = Server(ldap_host, get_info=ALL)
conn = Connection(server, user=bind_user, password=bind_password, auto_bind=True)

search_filter = f”(&(objectClass=group)(cn={group_cn}))”
conn.search(search_base=base_dn, search_filter=search_filter, attributes=[“member”])

members = []
if conn.entries:
group = conn.entries[0]
for member_dn in group.member.values:
conn.search(search_base=member_dn, search_filter=‘(objectClass=person)’, attributes=[‘sAMAccountName’])
if conn.entries:
members.append(conn.entries[0].sAMAccountName.value)

conn.unbind()
return members

This function authenticates with the LDAP server, retrieves members of a specified group, and returns their usernames.

Authenticate With Kubernetes API

Use the Kubernetes Python client to authenticate and configure access.

python

from kubernetes import client, config

def load_k8s_config():
try:
config.load_incluster_config() # For use inside a cluster
except:
config.load_kube_config() # For local development

This function makes the script flexible to run both locally and as a CronJob inside the cluster.

Create or Update RoleBindings

Now, create or update Kubernetes RoleBindings based on LDAP group members.

python
def create_role_binding(namespace, role_name, group_members):
rbac_api = client.RbacAuthorizationV1Api()
subjects = [{
“kind”: “User”,
“name”: member,
“apiGroup”: “rbac.authorization.k8s.io”
} for member in group_members]role_binding = client.V1RoleBinding(
metadata=client.V1ObjectMeta(name=f”{role_name}-binding”),
role_ref=client.V1RoleRef(
api_group=“rbac.authorization.k8s.io”,
kind=“Role”,
name=role_name
),
subjects=subjects
)try:
rbac_api.replace_namespaced_role_binding(name=f”{role_name}-binding”, namespace=namespace, body=role_binding)
print(f”Updated RoleBinding in namespace ‘{namespace}‘.”)
except client.exceptions.ApiException as e:
if e.status == 404:
rbac_api.create_namespaced_role_binding(namespace=namespace, body=role_binding)
print(f”Created new RoleBinding in namespace ‘{namespace}‘.”)
else:
raise

This function will ensure that the correct users have the desired role in the specified namespace.

Sync Function – The Glue

This function will orchestrate the whole flow.

python
def sync_ldap_to_k8s():
ldap_host = "ldap://ldap.example.com"
base_dn = "dc=example,dc=com"
group_cn = "k8s-developers"
bind_user = "CN=ldap-read,CN=Users,DC=example,DC=com"
bind_password = "secret"
namespace = “development”
role_name = “developer”print(“Fetching LDAP users…”)
ldap_users = get_ldap_group_members(ldap_host, base_dn, group_cn, bind_user, bind_password)print(f”LDAP group ‘{group_cn}‘ has members: {ldap_users}“)print(“Loading Kubernetes config…”)
load_k8s_config()print(“Syncing RoleBinding…”)
create_role_binding(namespace, role_name, ldap_users)

This central function connects to LDAP, retrieves group members, connects to Kubernetes, and applies the correct RoleBinding.

Kubernetes CronJob YAML

To automate the script, containerize it and run it via a CronJob.

Dockerfile:

dockerfile

FROM python:3.10-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY sync.py .

CMD [“python”, “sync.py”]

requirements.txt:

nginx
ldap3
kubernetes
pyyaml

CronJob YAML:

yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: ldap-sync-job
spec:
schedule: "0 * * * *" # Every hour
jobTemplate:
spec:
template:
spec:
containers:
- name: ldap-sync
image: your-registry/ldap-sync:latest
env:
- name: LDAP_PASSWORD
valueFrom:
secretKeyRef:
name: ldap-secret
key: password
restartPolicy: OnFailure
serviceAccountName: ldap-sync-sa

Secret and ServiceAccount:

Create a Kubernetes Secret and ServiceAccount:

bash
kubectl create secret generic ldap-secret --from-literal=password='secret'
kubectl apply -f ldap-sync-sa.yaml

Role-Based Access Control (RBAC)

You must give the ServiceAccount permission to manage RoleBindings:

ldap-sync-sa.yaml:

yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: ldap-sync-sa
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: ldap-sync-role
rules:
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["rolebindings"]
verbs: ["get", "list", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: ldap-sync-role-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ldap-sync-role
subjects:
- kind: ServiceAccount
name: ldap-sync-sa
namespace: default

Logging and Error Handling

You should enhance the script with logging and proper error handling for production use.

python

import logging

logging.basicConfig(level=logging.INFO, format=‘%(asctime)s – %(levelname)s – %(message)s’)

Replace print() statements with logging.info() or logging.error() accordingly.

Test Locally Before Deployment

You can run the script locally for testing:

bash
export KUBECONFIG=~/.kube/config
python sync.py

This allows you to verify LDAP connectivity and Kubernetes access before deploying the automation in-cluster.

Conclusion

Synchronizing LDAP entitlements with Kubernetes RBAC policies is essential for secure, scalable user access management. Manual handling is error-prone and inefficient, especially in dynamic or large-scale environments. By building and automating a Python script with LDAP and Kubernetes integrations, you can:

  • Automatically reflect LDAP group changes in Kubernetes access.

  • Reduce administrative overhead and human error.

  • Improve compliance with audit trails via logging.

  • Enhance security by ensuring least-privilege access is always up-to-date.

This solution can be extended further with enhancements like:

  • Multiple group-role mappings via a config file (YAML or JSON).

  • Dry-run mode for testing changes.

  • Email or Slack alerts on errors or access changes.

  • Integration with GitOps tools like ArgoCD for full infrastructure as code.

By leveraging Kubernetes CronJob, you achieve continuous synchronization, enabling your infrastructure to remain in lockstep with corporate directory structures and policies. This architecture is flexible, cloud-agnostic, and can be adapted to various enterprise scenarios.