Category: IAM

Integrating Keycloak and Harbor Registry with OpenID Connect

The documentation for setting up an OpenIDC identity provider / authentication method for Harbor Registry can be found in the harbor docs.

Harbor has supported OIDC since version 1.8.


You can change the authentication mode from database to OIDC only if no local users have been added to the database. If there is at least one user other than admin in the Harbor database, you cannot change the authentication mode.

So if you have existing local users, you will need to remove them - unfortunately doing this from the admin frontend does not actually delete them. you have to enter the postgres db and delete associated projects and then the users.

Information for setting up the client on keycloak side can be found on the red hat docs page

Getting Started

Having said all that...

  1. As Admin, go to Administration -> Configuration -> Authentication

  2. Select Auth mode as OIDC

  3. Fill in the required information as per the below screenshot:

  4. Click Test Configuration

OIDC Endpoint

For keycloak you can get your realm's OIDC details by going to:


But for the OIDC configuration you remove everthing up to /.well-known... including the back slash.
So the OIDC endpoint should be:


Deleting Existing Harbor Users

If you are using harbor on kubernetes - you can enter the postgres pod and execute in the shell:

docker exec -it harbor-db bash
psql -U postgres
\c registry
select * from harbor_user
delete from harbor_user where user_id > 2


Setting up Keycloak on Kubernetes

First thing to do is get familiar with keycloak. once you are happy it might be useful take a look at the keycloak quickstarts.
They seem to have all the examples and samples on getting going with keycloak.

In particular you want to look at the keycloak examples

For posterity I will show the contents of keycloak.yaml:

apiVersion: v1
kind: Service
  name: keycloak
    app: keycloak
  - name: http
    port: 8080
    targetPort: 8080
    app: keycloak
  type: LoadBalancer
apiVersion: apps/v1
kind: Deployment
  name: keycloak
  namespace: default
    app: keycloak
  replicas: 1
      app: keycloak
        app: keycloak
      - name: keycloak
        - name: KEYCLOAK_USER
          value: "admin"
        - name: KEYCLOAK_PASSWORD
          value: "admin"
          value: "true"
        - name: http
          containerPort: 8080
        - name: https
          containerPort: 8443
            path: /auth/realms/master
            port: 8080

and keycloak-ingress.yaml:

apiVersion: extensions/v1beta1
kind: Ingress
  name: keycloak
    - hosts:
      - backend:
          serviceName: keycloak
          servicePort: 8080

Environment Variables

We want to customise a few things about how keycloak runs and we do this by updating the environment variables.
So let us find what environment variabels are available and which we need to change.

We know the image beind used it:

So lets see what the readme of that container image says

It is rather dissapointing that when we check on quay for keycloak, there is an empty readme. So our princess is in another castle.

The best readme I could find was on keycloak-containers.

So the list of available environment variables I could find were:

  • DB_VENDOR - h2, postgres, mysql, mariadb, oracle, mssql
  • DB_ADDR - database hostname
  • DB_PORT - optoinal defaults to vendor port
  • DB_DATABASE - database name
  • DB_SCHEMA - only postgres uses this
  • DB_USER - user to auth with db
  • DB_PASSWORD - user password to auth with db
  • KEYCLOAK_FRONTEND_URL - A set fixed url for frontend requests
  • KEYCLOAK_STATISTICS - db,http or all

Oh I found an even more exhaustive list of environment variables in the docker entrypoint

Creating a K8s service as a reference to an external servie

As per kubernetes up and running, it is worthwhile to represent an external service in kubernetes. That way you get built in naming, service discovery and it looks like the database is a k8s service.

It also helps when replacing a service or switching between prod and test.


kind: Service
apiVersion: v1
  name: external-database
  namespace: prod
  type: ExternalName

If you just have an ip you need to create the service and the endpoint with:

kind: Service
apiVersion: v1
  name: keycloak-external-db-ip
    - protocol: TCP
      port: 3306
      targetPort: 3306
kind: Endpoints
apiVersion: v1
  name: keycloak-external-db-ip
  - addresses:
    - ip:
    - port: 3306

now the actual service dns name will be:

so in this case:


Set that as DB_ADDR with the other credentials and we should be good to go.

So updarte that and the other environment variables and deploy:

Create the deployment:

kubectl create -f keycloak-deployment.yml -n keycloak

create the service and the ingress:

kubectl apply -f keycloak-service.yml -n keycloak
kubectl apply -f keycloak-ingress.yml -n keycloak

Boom and you should be up and running


Using Keycloak Identity Provider for Rancher SSO

In Rancher 2.1.0 they added support for SAML authentication with Keycloak. What this means is Rancher will use a Keycloak realm to authenticate users.

This means that there is one place to manage users for a host of your applications. It also means that if they have logged on to the realm with their browser they can have single sign on to rancher - ie. they will already be logged into rancher.

The documentation on Rancher setting up Keycloak auth is already pretty good, however certain things can get tricky espescially if you are using Keycloak 7 and up.

So let's jump in and set it up...


  • A Keycloak Identity Provider Setup
  • A Rancher Instance

Setting up the Rancher Client on Keycloak

In keycloak you already have a realm and user's eith local or federated from LDAP.

So now we need to create the client for Rancher.

Go to Clients -> Create:


Now add the following extra settings (replace the white box with your Rancher URL):

keycloak-saml-client-for-rancher-config-1keycloak-saml-client-for-rancher-config-2Boom, we've setup the keycloak side. Now we just need to export this config to load onto the rancher side.

Usually this would be done on the Installation tab of the client. However rancher wants the SAML Metadata IDPSSODescriptor but Keycloak 7 does not provide that.

The way to get it is to go to this URL:


and save that XML to a file.

You then need to copy all the properties of EntitiesDescriptor and add them to the first EntityDescriptor.  Then delete the EntitiesDescriptor element.

Now save that and it will be the config to import.

Setting up Keycloak Auth on Rancher

Open Rancher on the Global scope and select Security -> Authentication:


You will get a few authentication / identity provider options:


Select Keycloak and you will need the following information.

Field Description
Display Name Field The AD attribute that contains the display name of users.
User Name Field The AD attribute that contains the user name/given name.
UID Field An AD attribute that is unique to every user.
Groups Field Make entries for managing group memberships.
Rancher API Host The URL for your Rancher Server.
Private Key / Certificate A key/certificate pair to create a secure shell between Rancher and your IdP.
IDP-metadata The metadata.xml file that you exported from your IdP server.

These AD Attributes are set on the Keycloak side at Client -> Mappers, the best thing to do is add builtin on the rancher side:

That will add the defualt attributes and it is best to add those, however for access to the groups of the user you need to map a group list attribute.


You would use the protocol mapper below, to map the member attribute on rancher side to a user's group list.



So to view the SAML attribute name just open one of the mappers and use the Friendly Name.

In my case:

Display Name Field: givenName
User Name Field: email
UID Field: email
Rancher API Host: https://yourRancherHostURL:5443
Groups Field: member


If successful you will be presented with this screen. If you are not successful and you have the invalid SAML attributes error, then you need to fix your attribute names.

If you only want to allow members of certain groups on the keycloak realm then you can change the options below:


So How has Our Lives Improved Since Implementing SSO

  • A central place for authentication, you don't need to manage much about auth on your application side.
  • Deletage auth and turn Time-based One Time Pin, Add terms and conditions and giving access with a simple button switch.
  • You get SSO (single sign on): sign on to the realm and now you can simply press the login button on any other linked client and you will be logged in.
  • Single sign off - I tested this and it did not work. Logging out of one client kept you in the other client.

Single Sign Out

During my testing single sign out was not working. However I must mention my setup was 3 parts:

  • Keycloak on a VM accessible only on the local network
  • A Django App in a docker container on my local machine
  • Rancher also accessible on the local network

So my guess is that when using the front channel (browser) for the authentication step on the django client, it works because the redirect from the client goes to the docker container.

However when the logout is sent on the backchannel, it can't access as there isn't a proper DNS entry.

What I am going to do is deploy the docker container on Openshift (god bless my soul)...and set an ip or dns so that keycloak can access it on the back channel.