/kubi

A set of tools to authenticaticate through LDAP and AD LDS backend

Primary LanguageGoApache License 2.0Apache-2.0

Kubi

Build Status

Kubi is the missing tool for Active Directory or LDAP driven company. It handles OpenLDAP or Active Directory LDS authentication for Kubernetes clusters. It acts as a Kubernetes Token Server, authenticating user through LDAP, AD LDS and assigns permissions dynamically using a predefined naming convention (LDAP Group).

Kubi is a webhook for the server part and has a cli for linux and windows users.

Index

General

Namespaces and Rolebindings are automatically created and managed by Kubi. Kubi parse the LDAP group and find the namespace and the role. The first part (from the right) is the role, and the second is the namespace.

The _ is used to split Role and Namespace, the pattern is <whatever>_<namespace>_<role>. Namespace must be DNS1123 compatible and can´t exceed 63 characters ( kubernetes constraint ).

For example:

  • a ldap group named: WHATYOUWANT_DEMO_ADMIN give cluster role binding admin permissions to the namespace DEMO.
  • a ldap group named: WHATYOUWANT_PROJECT-IN-PRODUCTION_ADMIN give cluster role binding admin permissions to the namespace PROJECT-IN-PRODUCTION.

If the namespace is missing, it will be automatically created at startup. You can refresh it by calling /refresh. Some namespace are protected: kube-system, kube-public, default. Kubi can generate NetworkPolicy if PROVISIONING_NETWORK_POLICIES flag is enabled. In this case, it create a Networpolicy that create something like a bubble.

The network policy works like this principle:

  • Every pods can communicate inside the namespace
  • Pods cannot communicate with external resources ( outside cluster )
  • Dns is not filtered

You can customize PROVISIONING_EGRESS_ALLOWED_PORTS, PROVISIONING_EGRESS_ALLOWED_CIDR, PROVISIONING_INGRESS_ALLOWED_NAMESPACES to add default rules. For specific exceptions, add another network policy.

Parameters

Name Description Example Mandatory Default
PUBLIC_APISERVER_URL Api server url (public) https://k8s.macompany.com yes -
LDAP_USERBASE BaseDn for user base search ou=People,dc=example,dc=org yes -
LDAP_GROUPBASE BaseDn for group base search ou=CONTAINER,dc=example,dc=org yes -
LDAP_APP_GROUPBASE BaseDn for group base search ou=CONTAINER,dc=example,dc=org yes -
LDAP_OPS_GROUPBASE BaseDn for group base search ou=CONTAINER,dc=example,dc=org yes -
LDAP_ADMIN_USERBASE BaseDn for admin base search ou=Admin,dc=example,dc=org yes -
LDAP_ADMIN_GROUPBASE BaseDn for admin group base search ou=AdminGroup,dc=example,dc=org yes -
LDAP_SERVER LDAP server ip address "192.168.2.1" yes -
LDAP_PORT LDAP server port 389, 636... 389 no 389
LDAP_USE_SSL Use SSL or no true no false
LDAP_START_TLS Use StartTLS ( use with 389 port) true false false
LDAP_SKIP_TLS_VERIFICATION Skip TLS verification true false true
LDAP_BINDDN LDAP bind account DN "CN=admin,DC=example,DC=ORG" yes -
LDAP_PASSWD LDAP bind account password "password" yes -
LDAP_USERFILTER LDAP filter for user search "(userPrincipalName=%s)" no (cn=%s)
TOKEN_LIFETIME Duration for the JWT token "4h" no 4h
LOCATOR Locator: must be internet or extranet "intranet" no intranet

Client

For Windows users

  1. Download the cli: download here
  2. Open Cmd
# Get help
.\kubi.exe --help
# Connect and generate config file
.\kubi.exe --kubi-url <kubi-server-fqdn-or-ip>:30003 --generate-config --username <user_cn>
# Connect with your password and generate config file
.\kubi.exe --kubi-url <kubi-server-fqdn-or-ip>:30003 --generate-config --username <user_cn> --password your_pwd

For Linux

With kubi cli

# Install the kubi cli
sudo wget https://github.com/ca-gip/kubi/releases/download/v1.2.4/kubi -P /usr/local/bin
sudo chmod a+x /usr/local/bin/kubi

# Connect to the cluster
kubi --kubi-url <kubi-server-fqdn-or-ip>:30003 --generate-config --username <user_cn>
# Connect with your password and generate config file
.\kubi.exe --kubi-url <kubi-server-fqdn-or-ip>:30003 --generate-config --username <user_cn> --password your_pwd

With curl

  curl -v -k --user <user_cn> https://<kubi-server-fqdn-or-ip>:30003/config

It is not recommended to use curl, because it is used with -k parameter ( insecure mode).

Installation

Prerequisites

Create a crt signed by Kubernetes CA

Change kubi.devops.managed.kvm to an existing kubernetes node ip, vip, or fqdn that point to an existing Kubernetes Cluster node. Eg: 10.56.221.4, kubernetes.<my_domain>...

cat <<EOF | cfssl genkey - | cfssljson -bare server
{
  "hosts": [
    "kubi.devops.managed.kvm",
    "kubi-svc.kube-system.svc.cluster.local"
  ],
  "CN": "kubi-svc.kube-system.svc.cluster.local",
  "key": {
    "algo": "ecdsa",
    "size": 256
  }
}
EOF

Create the signing request

cat <<EOF | kubectl create -f -
apiVersion: certificates.k8s.io/v1beta1
kind: CertificateSigningRequest
metadata:
  name: kubi-svc.kube-system
spec:
  groups:
  - system:authenticated
  request: $(cat server.csr | base64 | tr -d '\n')
  usages:
  - digital signature
  - key encipherment
  - server auth
EOF

Approve the csr

kubectl certificate approve kubi-svc.kube-system

Retrieve the crt

kubectl get csr kubi-svc.kube-system -o jsonpath='{.status.certificate}'     | base64 --decode > server.crt

Create a secret for the deployment

kubectl -n kube-system create secret tls kubi --key server-key.pem --cert server.crt

Create a secret for LDAP Bind password

kubectl -n kube-system create secret generic kubi-secret \
  --from-literal ldap_passwd='changethispasswordnow!'

Deploy the config map

** YOU MUST CHANGE VALUE WITH YOUR OWN **

cat <<EOF | kubectl -n kube-system create -f -
apiVersion: v1
kind: ConfigMap
data:
  LDAP_USERBASE: "ou=People,dc=kubi,dc=fr"
  LDAP_GROUPBASE: "ou=local_platform,ou=Groups,dc=kubi,dc=fr"
  LDAP_SERVER: "192.168.2.1"
  LDAP_PORT: "389"
  LDAP_BINDDN: "cn=admin,dc=kubi,dc=fr"
  LDAP_ADMIN_USERBASE: "ou=People,dc=kubi,dc=fr"
  LDAP_ADMIN_GROUPBASE: "ou=Administrators,ou=Groups,dc=kubi,dc=fr"
  PUBLIC_APISERVER_URL: https://api.devops.managed.kvm
metadata:
  name: kubi-config
EOF

Deploy the Custom Resource Definitions

kubectl apply -f https://raw.githubusercontent.com/ca-gip/kubi/master/deployments/kube-crds.yml

Deploy the Kubi components

kubectl apply -f https://raw.githubusercontent.com/ca-gip/kubi/master/deployments/kube-deployment.yml

Customize the default network policy

You can customize the default network policy named kubi-default, for example:

apiVersion: "ca-gip.github.com/v1"
kind: NetworkPolicyConfig
metadata:
  name: kubi-default
spec:
  egress:
    # ports allowed for egress
    ports:
      - 636
      - 389
      - 123
      - 53
    # cidrs allowed for egress 
    # for ipvs, add the network used by calico, for kubernetes svc in default ns
    cidrs:
      - 192.168.2.0/24
      - 172.10.0.0/24
  ingress:
    # namespaces allowed for ingress rules ( here only nginx )
    namespaces:
      - ingress-nginx

** Deploy the example : **

kubectl apply -f https://raw.githubusercontent.com/ca-gip/kubi/master/deployments/kube-example-netpolconf.yml

Basic Webhook configuration

Kubi is installed as a Kubernetes webhook.

For more information about webhook: https://kubernetes.io/docs/reference/access-authn-authz/authentication/#webhook-token-authentication

  1. On each master node in /etc/kubernetes/pki/webhook
# Kubernetes API version
apiVersion: v1
# kind of the API object
kind: Config
# clusters refers to the remote service.
clusters:
  - name: kubi
    cluster:
      certificate-authority: /etc/kubernetes/pki/ca.crt
      server: https://api.devops.managed.kvm:30003/authenticate   
users:
  - name: apiserver
    user:
      client-certificate: /etc/kubernetes/pki/apiserver.crt
      client-key: /etc/kubernetes/pki/apiserver.key
current-context: kubi
contexts:
- context:
    cluster:  kubi
    user: apiserver
  name: webhook
# vim /etc/kubernetes/manifests/kube-apiserver.yaml
- --authentication-token-webhook-config-file=/etc/kubernetes/pki/webhook.yml

Api servers reboot automatically, check logs kubectl logs -f kube-apiserver-master-01 -n kube-system.

Advanced Webhook configuration

You could change apiserver mount and create an aditionnal folder. Here we use /etc/kubernetes/pki which is automatically mounted.

  1. Add these params to kubeadm config in ClusterConfiguration:
# Before, create the additionnals folder in all master nodes
mkdir /etc/kubernetes/additionnals
  1. And edit your kubeadm-config.yml file with the following values:
extraArgs:
  authentication-token-webhook-config-file: /etc/kubernetes/additionnals/webhook.yml
extraVolumes:
  - name: additionnals
    hostPath: /etc/kubernetes/additionnals
    mountPath: /etc/kubernetes/additionnals
  1. Copy the webhook file to /etc/kubernetes/additionnals folder.

Roadmap

The following features should be available soon.

  • Allow usage of static mapping ( a json file mapping with LDAP group and Kubernetes namespaces)
  • Expose /metrics

Additionnals

Local LDAP Server

The server need to have memberof overlay

docker run -d -p 389:389 \
  --hostname localhost \
  -e SLAPD_PASSWORD=password  \
  -e SLAPD_DOMAIN=kubi.fr  \
  -e SLAPD_ADDITIONAL_MODULES=memberof  \
  -e SLAPD_CONFIG_PASSWORD=config \
  -e SLAPD_PASSWORD=password \
  --hostname localhost \
  dinkel/openldap

Admin connection string: cn=admin,dc=kubi,dc=fr