1. Prerequisite for configuring gatekeeper for a specific application:
create a client, called my-app in Keycloak. In the creation step select access-type: confidential
once created you will see a credentials tab for the newly created client with the secret. You will need that for the gatekeeper.yaml config file
create Realm role for that application my-app-role
create a group my-group and add the role my-app-role in role-mappings of the group
go to your user and add it to the my-group. This user will be authorized to access the secured application, once we configure it
2. Create a gatekeeper configuration file, gatekeeper.yaml, as a secret
client-id: my-app client-secret: my-app-secret-from-credentials discovery-url: https://my-keycloak-server.com/auth/realms/my-realm skip-upstream-tls-verify: false skip-openid-provider-tls-verify: true encryption-key: random-secret-value-of-16-or-32-characters listen: 0.0.0.0:3000 secure-cookie: false enable-logging: true enable-json-logging: true enable-default-deny: true enable-refresh-tokens: true enable-session-cookies: true debug: true ingress.enabled: true resources: - uri: /favicon white-listed: true
Values to be replaced and set in the above config file:
client-secret set from the client credentials tab
encryption-key random hash value 16 or 32 characters
discovery-url keycloak endpoint
Some of the important values explained:
discovery-url is keycloak's realm url that the my-app client resides in
skip-openid-provider-tls-verify ignores Keycloak's self-signed certificate warning for gatekeeper client request
enable-default-deny - all resources are by default secured unless explicitly allowed in resources
listen - port where the gatekeeper will start and listen on
redirection-url - where the successful login will be redirected to
upstream-url - where gatekeeper will forward the request after successful authorization
resources configures which resources can be accessed (white-listed) without authentication.
The configuration values are needed by the gatekeeper to communicate with Keycloak. So with the endpoint, we tell gatekeeper where to find the Keycloak server to talk to, with the client-id and client-secret gatekeeper can authenticate itself with Keycloak to make requests to it.
kubectl create secret generic gatekeeper --from-file= ./gatekeeper.yaml -n my-namespace
Now that you have set up all the necessary configuration, you need to deploy gatekeeper container inside the pod where the application you want to secure is running. SO gatekeeper will be a side-car container to your actual app, acting as a... well, gatekeeper to all incoming requests.
So to deploy both containers inside one pod, you need to configure it like this:
apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: template: ... spec: containers: - image: keycloak/keycloak-gatekeeper:7.0.0 name: gatekeeper ports: - containerPort: 3000 args: - --config=/etc/secrets/gatekeeper.yaml - --redirection-url=https://my-app-server-url - --upstream-url=http://127.0.0.1:8080 - --resources=uri=/*|roles=my-app-role volumeMounts: - name: gatekeeper-secrets mountPath: /etc/secrets - image: my-app-image name: my-app ports: - containerPort: 8080 volumes: - name: gatekeeper-secrets secret: secretName: gatekeeper
So with the above configuration, a pod will be created with the application and gatekeeper containers and the gatekeeper.yaml file that we created above will be mounted inside the gatekeeper container.
As you see in the deployment config, gatekeeper container has args configured.
redirection-url is where the successful login will be redirected to. This points to the url of the my-app, which will also land with the gatekeeper
upstream-url - after the redirect-url is called for the authenticated user, gatekeeper will allow access to my-app, by forwarding the request to it on
http://127.0.0.1:8080? because both my-app and gatekeeper run in the same pod, they can communicate via localhost.
So, now we need to configure the service for my-app to forward the incoming requests NOT to my-app, but to the gatekeeper container. As you see from above my-app and gatekeeper are running on different ports (8080 and 3000), so we just need to tell the service to forward the request to gatekeeper's port 3000.
apiVersion: v1 kind: Service metadata: name: my-service spec: selector: service: my-service type: ClusterIP ports: - port: 32111 targetPort: 3000
► Get 30% off - with this code: UDEMY_NANA_OCT2020: Udemy course here
► Kubernetes 101: Compact and easy-to-read ebook bundle 🚀
It's a handy way to quickly look something up or refresh your knowledge at work and use it as your cheatsheet 😎
Like, share and follow me 😍 for more content:
Top comments (9)
Hi! Just a quick note that Keycloak Gatekeeper sadly has reach its end-of-life and is no longer supported and no longer receiving security updates. That's really a shame because I used to have the exact same pattern as you to secure some of my application. I'll have a look into Authelia to see if that can be a replacement. Let me know your findings as well.
For anyone reading my above comment, I found an actively maintained fork here: github.com/gogatekeeper/gatekeeper
I hope you are fine!
I'm currently trying to protect a Django application using Keycloak and I recently discovered gatekeeper, so I was just starting to understand how it works, and then I found the EOL announcement, and that is why your comment was sooo welcome!
Do you think this could be a right tool to do it? (Keycloak/Gatekeeper/Django App)
From the few things I've read, I understand gatekeeper is language agnostic, but I'm not sure if it will require some sort of configuration on the Django side.
Thank you again!!
@nana Very nice article!
Hi Ricardo, Gatekeeper is a great tool to secure access to an application. However, it acts like a proxy. It sits in "front" of your app and forwards traffic to it. For any unauthenticated users, it prompts them to authenticate before forwarding their traffic to the app.
That it to say, it's easy to use gatekeeper to secure access to a Django website or part of it (eg: the admin), but Django won't be aware that Gatekeeper is sitting in front of it.
There's a few PyPy package if you want to logging in Django using Keycloak as your identity provider.
Thank you very much for your answer!
Ok understood (I think).
Let me summarize to see if I really did understand:
So Gatekeeper would be your let's say "root url" the one users will point to when they try to log in to your app.
Then Gatekeeper will communicate with Keycloak to authenticate/authorize the user.
Keycloak will send Gatekeeper the corresponding tokens and Gatekeeper will redirect the user to your app url.
Gatekeeper will also send the tokens to your app, so you can use them in your code to protect your resources using the roles/permissions you have defined for that user in Keycloak. (if this last part really happens, how do you handle those roles once in Django?)
Is this how it works, or I'm not even close to it?
If you want to handle "tokens" in Django, I recommend using a Django app designed to do this. Search for "Django auth" and you should have quite a few options.
I don't know if Gatekeeper sends token to the backend (Django) when it forwards an authenticated requests. Perhaps it adds a header or a cookie. I don't know.
Ok. I'll do my research on that and let you know if I find anything interesting.
What I want to do in the end is to delegate as much as possible of the security handling to Keycloak , and get the Django code to the minimum, that is, just check if the user has the permission to access the given resource (view, model, etc.).
I'm no expert, but I'm wondering if there are some typos in the last code block. What is "my-service"? It's not referenced elsewhere in the article. Same for port "32111", what's running there? Anyhow, I'm very unfamiliar with Kubernetes so perhaps this is all correct.
Thanks for sharing this. I'm trying to use Gatekeeper and this cleared up a few things.
There is no typo, "my-service" is a k8s object that abstracts a set of pods. Port "32111" is where this k8s objects is receiving traffic. Every application which was calling the pod directly, now call the service on that port, and the service routes the traffic for one of its pods, like a load-balance. As you said, those are k8s specific matters, and I suggest you reading kubernetes.io/docs/concepts/servic...