Skip to content

fdk

Securing Kubernetes Apps with Keycloak and Gatekeeper

k8s, keycloak, oidc, minikube4 min read

Today there are many ways to secure applications. With the rise of Kubernetes you might search for a self hosted open source solution for Identity Management. One of the most popular and powerful candidates is Keycloak. Lets explore how these both work together.

For my sample scenario I am going to use minikube to setup a local Kubernetes cluster to work with. My goal is to protect an application running in this cluster without the need of adding any code to it. Additionally it should be a scaling solution that can be easily added to any other application running inside the cluster. As sample application to protect, I chose httpbin.

Setting up Keycloak with persistence

At the very first I need a running keycloak instance to authenticate to. Even though the keycloak-operator seems to be in a pretty early stage and might not work perfectly yet, I decided to give it a try. Lets clone the git repo and checkout the latest release.

In order to use the custom keycloak resource definitions coming from the operator, they need to be applied to the cluster. There is a Makefile target that can be used for this. Along with CRDs it also deploys some roles, bindings, service accounts etc. When these basic cluster preparations are done, the keycloak-operator can be deployed into the newly created keycloak namespace.

Since I do not want to lose my configured keycloak data every time I restart my minikube kubernetes cluster, I want to setup keycloak with persistence. Before proceeding with the installation of keycloak it is necessary to setup a PersistentVolume, that can be used for the underlying postgres database.

Finally keycloak can be installed by using the keycloaks.keycloak.org CRD. It is going to deploy a postgresql database using our persistence volume, that then can get picked up by keycloak.

Keycloak is running and ready to be used. To setup an easy accessible address for the keycloak instance the minikube ingress addon together with a hostname entry can be used. While I am at adding hostnames, I already add another one that I need for resolving my sample httpbin application later on.

Of course the corresponding Kubernetes ingress resource needs to be created as well. This resource could also be created by the keycloak operator by passing externalAccess.enabled: True to the keycloak spec, but it did not work for me due to some missing annotation for telling nginx to use https for the upstream service. So I created an ingress resource by myself.

If everything is set up correctly, the keycloak instance should be accessible now.

Configuring Keycloak for the client application

Now, after keycloak was successfully installed to the cluster, it is time to prepare the instance for the client application. The easiest way might be to use the adminstration console UI from keycloak. It can be accessed via browser at http://keycloak.local/auth/admin/. The necessary admin credentials have been initially created as kubernetes secrets by the keycloak operator while installing.

Taking the credentials to login to the adminstration console UI, the client configuration can be started. Following steps have to be done:

  1. Create a new realm. To not run into trouble with login later on, since I have not set up proper certificates for tls, I am setting an insecure "Frontend URL" to http://keycloak.local/auth for this realm.
  2. Add a client with protocol openid-connect and access type confidential. Add http://httpbin.local/oauth/callback to valid Redirect URIs.
  3. Goto to the "Client Scopes" menu and add a new client scope. Create new protocol with mapper type audience, select your client in "Included Client Audience" and set "Add to access token" to "On".
  4. In client settings go to client scopes and add your created client scope containing the audience mapper.
  5. Add a user and set a password in the "Credentials" tab.

I called my realm test and my client httpbin. By setting the client access-type to confidential a client-secret has been generated by keycloak. It is needed for the upcoming gatekeeper configuration and can be found at the credentials tab of the client configuration.

Deploying Client Application along with Keycloak Gatekeeper

By having a running keycloak instance configured with proper client settings and a test user, everything is in place to protect the sample httbin application. As mentioned in the introduction I would like to secure the application without adding code. Here comes Keycloak Gatekeeper into play, which is an OIDC proxy service, handling authentication for an upstream application. The idea of gatekeeper is to have it as close as possible to the upstream application, thats why I am going to deploy it as sidecar to the httpbin application. But before proceeding with the deployment, the client-secret (from keycloak client configuration) needs to be accessible in the cluster.

Having the secret in place, finally the sample application along with gatekeeper can be deployed.

To make the OIDC discovery of gatekeeper work with the internal Keycloak Kubernetes service URL, it is necessary to pass it as argument to the --openid-provider-proxy parameter. I found a related issue here.

Is my Application protected now?

To verify the protection of my httpbin application, I am going to use a couple of curl commands. First of all, what happens when I try to access my httpbin application?

Cool, I get redirected to the keycloak login page. Lets use the credentials of the test-user I created earlier. To use the received access token for further commands, I am storing it inside a shell variable by using the command-line JSON processor jq for grabbing it from the JSON response.

Et Voilà! After getting an access token for my test-user, I can finally pass through gatekeeper to my httpbin application, showing that I am authenticated. Goal reached! :) For upstream services it might be necessary to get some user information as well. These can be obtained from custom headers forwarded by gatekeeper.

For having a better and more insightful reading experience I used curl here. Of course it is easier to verify the protection by navigate to http://httpbin.local in browser and go through the flow there.

Conclusion

I think keycloak is a wonderful piece of software for handling user identity. It might be not the easiest to setup with Kubernetes yet, but I am confident that especially the keycloak-operator will improve quick and constantly. Using gatekeeper deployed as sidecar to the application you want to protect by providing a little configuration seems to me like a very scalable and consistent solution. At the time of microservices you want to focus as much as possible on business logic. This solution could save you from implementing same authentication layer over and over again. Additionally it can be applied to protect third-party applications, that do not support any auth flows by themselves, like dashboards etc.

Happy authenticating and authorizing!

References