This article has been written to expand on the already
In this article I will tell you how to install and configure:
- keycloak is an open source project. Which provides a single point of entry for applications. Works with a variety of protocols, including LDAP and OpenID which we are interested in.
- keycloak gatekeeper - reverse proxy application that allows you to integrate authorization through Keycloak.
- Gangways - an application that generates a config for kubectl with which you can log in and connect to the Kubernetes API through OpenID.
How permissions work in Kubernetes.
We can manage user / group rights using RBAC, a bunch of articles have already been created about this, I will not dwell on this in detail. The problem is that you can use RBAC to restrict user rights, but Kubernetes doesn't know anything about users. It turns out that we need a user delivery mechanism in Kubernetes. To do this, we will add a provider to Kuberntes OpenID, which will say that such a user really exists, and Kubernetes itself will give him the rights.
Prepare
- You will need a Kubernetes cluster or minikube
- Active Directory
- Domains:
keycloak.example.org
kubernetes-dashboard.example.org
gangway.example.org - Certificate for domains or self-signed certificate
I will not dwell on how to create a self-signed certificate, you need to create 2 certificates, this is the root (Certificate Authority) and wildcard client for the *.example.org domain
After you receive / issue certificates, the client must be added to Kubernetes, for this we create a secret for it:
kubectl create secret tls tls-keycloak --cert=example.org.crt --key=example.org.pem
Next, we will use it for our Ingress controller.
Keycloak Installation
I decided that the easiest way is to use ready-made solutions for this, namely helm charts.
Install the repository and update it:
helm repo add codecentric https://codecentric.github.io/helm-charts
helm repo update
Create a keycloak.yml file with the following content:
keycloak.yml
keycloak:
# ΠΠΌΡ Π°Π΄ΠΌΠΈΠ½ΠΈΡΡΡΠ°ΡΠΎΡΠ°
username: "test_admin"
# ΠΠ°ΡΠΎΠ»Ρ Π°Π΄ΠΌΠΈΠ½ΠΈΡΡΡΠ°ΡΠΎΡ
password: "admin"
# ΠΡΠΈ ΡΠ»Π°Π³ΠΈ Π½ΡΠΆΠ½Ρ ΡΡΠΎ Π±Ρ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΡΡ Π·Π°Π³ΡΡΠΆΠ°ΡΡ Π² Keycloak ΡΠΊΡΠΈΠΏΡΡ ΠΏΡΡΠΌΠΎ ΡΠ΅ΡΠ΅Π· web ΠΌΠΎΡΠ΄Ρ. ΠΡΠΎ Π½Π°ΠΌ
ΠΏΠΎΠ½Π°Π΄ΠΎΠ±ΠΈΡΡΡΡ ΡΡΠΎ Π±Ρ ΠΏΠΎΡΠΈΠ½ΠΈΡΡ ΠΎΠ΄ΠΈΠ½ Π±Π°Π³, ΠΎ ΠΊΠΎΡΠΎΡΠΎΠΌ Π½ΠΈΠΆΠ΅.
extraArgs: "-Dkeycloak.profile.feature.script=enabled -Dkeycloak.profile.feature.upload_scripts=enabled"
# ΠΠΊΠ»ΡΡΠ°Π΅ΠΌ ingress, ΡΠΊΠ°Π·ΡΠ²Π°Π΅ΠΌ ΠΈΠΌΡ Ρ
ΠΎΡΡΠ° ΠΈ ΡΠ΅ΡΡΠΈΡΠΈΠΊΠ°Ρ ΠΊΠΎΡΠΎΡΡΠΉ ΠΌΡ ΠΏΡΠ΅Π΄Π²Π°ΡΠΈΡΠ΅Π»ΡΠ½ΠΎ ΡΠΎΡ
ΡΠ°Π½ΠΈΠ»ΠΈ Π² secrets
ingress:
enabled: true
path: /
annotations:
kubernetes.io/ingress.class: nginx
ingress.kubernetes.io/affinity: cookie
hosts:
- keycloak.example.org
tls:
- hosts:
- keycloak.example.org
secretName: tls-keycloak
# Keycloak Π΄Π»Ρ ΡΠ²ΠΎΠ΅ΠΉ ΡΠ°Π±ΠΎΡΡ ΡΡΠ΅Π±ΡΠ΅Ρ Π±Π°Π·Ρ Π΄Π°Π½Π½ΡΡ
, Π² ΡΠ΅ΡΡΠΎΠ²ΡΡ
ΡΠ΅Π»ΡΡ
Ρ ΡΠ°Π·Π²ΠΎΡΠ°ΡΠΈΠ²Π°Ρ Postgresql ΠΏΡΡΠΌΠΎ Π² Kuberntes, Π² ΠΏΡΠΎΠ΄Π°ΠΊΡΠ΅Π½Π΅ ΡΠ°ΠΊ Π»ΡΡΡΠ΅ Π½Π΅ Π΄Π΅Π»Π°ΡΡ!
persistence:
deployPostgres: true
dbVendor: postgres
postgresql:
postgresUser: keycloak
postgresPassword: ""
postgresDatabase: keycloak
persistence:
enabled: true
Federation setup
Next, go to the web interface
Click in the left corner add realm
Key
Value
Name
kubernetes
Display Name
Kubernetes
Disable user email verification:
Client scopes β> Email β> Mappers β> Email verified (Delete)
We set up federation to import users from ActiveDirectory, I will leave screenshots below, I think it will be clearer.
User federation β> Add providerβ¦ β> ldap
Federation setup
If all is well, then after pressing the button Synchronize all users you will see a message about the successful import of users.
Next we need to map our groups
User federation --> ldap_localhost --> Mappers --> Create
Creating a mapper
Client setup
It is necessary to create a client, in terms of Keycloak, this is an application that will be authorized from him. I will highlight the important points in the screenshot in red.
Clients β> Create
Client setup
Let's create scoupe for groups:
Client Scopes β> Create
Create scope
And set up a mapper for them:
Client Scopes β> groups β> Mappers β> Create
Mapper
Add the mapping of our groups to the Default Client Scopes:
Clients β> kubernetes β> Client Scopes β> Default Client Scopes
Choosing groups Π² Available Client Scopespush Add selected
We get the secret (and write it to the thread) which we will use for authorization in Keycloak:
Clients β> kubernetes β> Credentials β> Secret
This completes the setup, but I had an error when, after successful authorization, I received an error 403.
Fix:
Client Scopes β> roles β> Mappers β> Create
Mapper
Script code
// add current client-id to token audience
token.addAudience(token.getIssuedFor());
// return token issuer as dummy result assigned to iss again
token.getIssuer();
Configuring Kubernetes
We need to specify where our root certificate from the site lies, and where the OIDC provider is located.
To do this, edit the file /etc/kubernetes/manifests/kube-apiserver.yaml
kube-apiserver.yaml
...
spec:
containers:
- command:
- kube-apiserver
...
- --oidc-ca-file=/var/lib/minikube/certs/My_Root.crt
- --oidc-client-id=kubernetes
- --oidc-groups-claim=groups
- --oidc-issuer-url=https://keycloak.example.org/auth/realms/kubernetes
- --oidc-username-claim=email
...
Update kubeadm config in the cluster:
kubeadmconfig
kubectl edit -n kube-system configmaps kubeadm-config
...
data:
ClusterConfiguration: |
apiServer:
extraArgs:
oidc-ca-file: /var/lib/minikube/certs/My_Root.crt
oidc-client-id: kubernetes
oidc-groups-claim: groups
oidc-issuer-url: https://keycloak.example.org/auth/realms/kubernetes
oidc-username-claim: email
...
Setting auth-proxy
You can use keycloak gatekeeper to protect your web application. In addition to the fact that this reverse proxy will authorize the user before showing the page, it will also pass information about you to the end application in the headers. Thus, if your application supports OpenID, then the user is immediately authorized. Consider the example of Kubernetes Dashboard
Installing Kubernetes Dashboard
helm install stable/kubernetes-dashboard --name dashboard -f values_dashboard.yaml
values_dashboard.yaml
enableInsecureLogin: true
service:
externalPort: 80
rbac:
clusterAdminRole: true
create: true
serviceAccount:
create: true
name: 'dashboard-test'
Setting access rights:
Let's create a ClusterRoleBinding that will give cluster admin rights (standard ClusterRole cluster-admin) for users in the DataOPS group.
kubectl apply -f rbac.yaml
rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: dataops_group
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: DataOPS
Install keycloak gatekeeper:
helm repo add gabibbo97 https://gabibbo97.github.io/charts/
helm repo update
helm install gabibbo97/keycloak-gatekeeper --version 2.1.0 --name keycloak-gatekeeper -f values_proxy.yaml
values_proxy.yaml
# ΠΠΊΠ»ΡΡΠ°Π΅ΠΌ ingress
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: nginx
path: /
hosts:
- kubernetes-dashboard.example.org
tls:
- secretName: tls-keycloak
hosts:
- kubernetes-dashboard.example.org
# ΠΠΎΠ²ΠΎΡΠΈΠΌ Π³Π΄Π΅ ΠΌΡ Π±ΡΠ΄Π΅ΠΌ Π°Π²ΡΠΎΡΠΈΠ·ΠΎΠ²ΡΠ²Π°ΡΡΡΡ Ρ OIDC ΠΏΡΠΎΠ²Π°ΠΉΠ΄Π΅ΡΠ°
discoveryURL: "https://keycloak.example.org/auth/realms/kubernetes"
# ΠΠΌΡ ΠΊΠ»ΠΈΠ΅Π½ΡΠ° ΠΊΠΎΡΠΎΡΠΎΠ³ΠΎ ΠΌΡ ΡΠΎΠ·Π΄Π°Π»ΠΈ Π² Keycloak
ClientID: "kubernetes"
# Secret ΠΊΠΎΡΠΎΡΡΠΉ Ρ ΠΏΡΠΎΡΠΈΠ» Π·Π°ΠΏΠΈΡΠ°ΡΡ
ClientSecret: "c6ec03b8-d0b8-4cb6-97a0-03becba1d727"
# ΠΡΠ΄Π° ΠΏΠ΅ΡΠ΅Π½Π°ΠΏΡΠ°Π²ΠΈΡΡ Π² ΡΠ»ΡΡΠ°Π΅ ΡΡΠΏΠ΅ΡΠ½ΠΎΠΉ Π°Π²ΡΠΎΡΠΈΠ·Π°ΡΠΈΠΈ. Π€ΠΎΡΠΌΠ°Ρ <SCHEMA>://<SERVICE_NAME>.><NAMESAPCE>.<CLUSTER_NAME>
upstreamURL: "http://dashboard-kubernetes-dashboard.default.svc.cluster.local"
# ΠΡΠΎΠΏΡΡΠΊΠ°Π΅ΠΌ ΠΏΡΠΎΠ²Π΅ΡΠΊΡ ΡΠ΅ΡΡΠΈΡΠΈΠΊΠ°ΡΠ°, Π΅ΡΠ»ΠΈ Ρ Π½Π°Ρ ΡΠ°ΠΌΠΎΠΏΠΎΠ΄ΠΏΠΈΡΠ°Π½Π½ΡΠΉ
skipOpenidProviderTlsVerify: true
# ΠΠ°ΡΡΡΠΎΠΉΠΊΠ° ΠΏΡΠ°Π² Π΄ΠΎΡΡΡΠΏΠ°, ΠΏΡΡΠΊΠ°Π΅ΠΌ Π½Π° Π²ΡΠ΅ path Π΅ΡΠ»ΠΈ ΠΌΡ Π² Π³ΡΡΠΏΠΏΠ΅ DataOPS
rules:
- "uri=/*|groups=DataOPS"
After that, when you try to go to
gangway installation
For convenience, you can add a gangway that will generate a config file for kubectl, with the help of which we will get into Kubernetes under our user.
helm install --name gangway stable/gangway -f values_gangway.yaml
values_gangway.yaml
gangway:
# ΠΡΠΎΠΈΠ·Π²ΠΎΠ»ΡΠ½ΠΎΠ΅ ΠΈΠΌΡ ΠΊΠ»Π°ΡΡΠ΅ΡΠ°
clusterName: "my-k8s"
# ΠΠ΄Π΅ Ρ Π½Π°Ρ OIDC ΠΏΡΠΎΠ²Π°ΠΉΠ΄Π΅Ρ
authorizeURL: "https://keycloak.example.org/auth/realms/kubernetes/protocol/openid-connect/auth"
tokenURL: "https://keycloak.example.org/auth/realms/kubernetes/protocol/openid-connect/token"
audience: "https://keycloak.example.org/auth/realms/kubernetes/protocol/openid-connect/userinfo"
# Π’Π΅ΠΎΡΠΈΡΠΈΡΠ΅ΡΠΊΠΈ ΡΡΠ΄Π° ΠΌΠΎΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡΡ groups ΠΊΠΎΡΠΎΡΡΠ΅ ΠΌΡ Π·Π°ΠΌΠ°ΠΏΠΈΠ»ΠΈ
scopes: ["openid", "profile", "email", "offline_access"]
redirectURL: "https://gangway.example.org/callback"
# ΠΠΌΡ ΠΊΠ»ΠΈΠ΅Π½ΡΠ°
clientID: "kubernetes"
# Π‘Π΅ΠΊΡΠ΅Ρ
clientSecret: "c6ec03b8-d0b8-4cb6-97a0-03becba1d727"
# ΠΡΠ»ΠΈ ΠΎΡΡΠ°Π²ΠΈΡΡ Π΄Π΅ΡΠΎΠ»ΡΠ½ΠΎΠ΅ Π·Π½Π°ΡΠ½ΠΈΠ΅, ΡΠΎ Π·Π° ΠΈΠΌΡ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ Π±ΡΠ΄Π΅Ρ Π±ΡΠ°ΡΡΡ <b>Frist name</b> <b>Second name</b>, Π° ΠΏΡΠΈ "sub" Π΅Π³ΠΎ Π»ΠΎΠ³ΠΈΠ½
usernameClaim: "sub"
# ΠΠΎΠΌΠ΅Π½Π½ΠΎΠ΅ ΠΈΠΌΡ ΠΈΠ»ΠΈ IP Π°Π΄ΡΠ΅ΡΡ API ΡΠ΅ΡΠ²Π΅ΡΠ°
apiServerURL: "https://192.168.99.111:8443"
# ΠΠΊΠ»ΡΡΠ°Π΅ΠΌ Ingress
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/proxy-buffer-size: "64k"
path: /
hosts:
- gangway.example.org
tls:
- secretName: tls-keycloak
hosts:
- gangway.example.org
# ΠΡΠ»ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌ ΡΠ°ΠΌΠΎΠΏΠΎΠ΄ΠΏΠΈΡΠ°Π½Π½ΡΠΉ ΡΠ΅ΡΡΠΈΡΠΈΠΊΠ°Ρ, ΡΠΎ Π΅Π³ΠΎ(ΠΎΡΠΊΡΡΡΡΠΉ ΠΊΠΎΡΠ½Π΅Π²ΠΎΠΉ ΡΠ΅ΡΡΠΈΡΠΈΠΊΠ°Ρ) Π½Π°Π΄ΠΎ ΡΠΊΠ°Π·Π°ΡΡ.
trustedCACert: |-
-----BEGIN CERTIFICATE-----
MIIDVzCCAj+gAwIBAgIBATANBgkqhkiG9w0BAQsFADA1MQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRGF0YU9QUzEUMBIGA1UEAxMLbXkgcm9vdCBrZXkwHhcNMjAwMjE0MDkxODAwWhcNMzAwMjE0MDkxODAwWjA1MQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRGF0YU9QUzEUMBIGA1UEAxMLbXkgcm9vdCBrZXkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDyP749PqqIRwNSqaK6qr0Zsi03G4PTCUlgaYTPZuMrwUVPK8xX2dWWs9MPRMOdXpgr8aSTZnVfmelIlVz4D7o2vK5rfmAe9GPcK0WbwKwXyhFU0flS9sU/g46ogHFrk03SZxQAeJhMLfEmAJm8LF5HghtGDs3t4uwGsB95o+lqPLiBvxRB8ZS3jSpYpvPgXAuZWKdZUQ3UUZf0X3hGLp7uIcIwJ7i4MduOGaQEO4cePeEJy9aDAO6qV78YmHbyh9kaW+1DL/Sgq8NmTgHGV6UOnAPKHTnMKXl6KkyUz8uLBGIdVhPxrlzG1EzXresJbJenSZ+FZqm3oLqZbw54Yp5hAgMBAAGjcjBwMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHISTOU/6BQqqnOZj+1xJfxpjiG0MAsGA1UdDwQEAwIBBjARBglghkgBhvhCAQEEBAMCAAcwHgYJYIZIAYb4QgENBBEWD3hjYSBjZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsFAAOCAQEAj7HC8ObibwOLT4ZYmISJZwub9lcE0AZ5cWkPW39j/syhdbbqjK/6jy2D3WUEbR+s1Vson5Ov7JhN5In2yfZ/ByDvBnoj7CP8Q/ZMjTJgwN7j0rgmEb3CTZvnDPAz8Ijw3FP0cjxfoZ1Z0V2F44Ry7gtLJWr06+MztXVyto3aIz1/XbMQnXYlzc3c3B5yUQIy44Ce5aLRVsAjmXNqVRmDJ2QPNLicvrhnUJsO0zFWI+zZ2hc4Ge1RotCrjfOc9hQY63jZJ17myCZ6QCD7yzMzAob4vrgmkD4q7tpGrhPY/gDcE+lUNhC7DO3l0oPy2wsnT2TEn87eyWmDiTFG9zWDew==
-----END CERTIFICATE-----
Looks like this. Allows you to immediately download the config file and generate it using a set of commands:
Source: habr.com