Deploy Production Mode Keycloak 21.1.1 on Azure Kubernetes Multinode

Hi Everyone!

This time I bring to the table a particular situation where I couldn’t find any cleaner documentation (nor office neither on several blogs).

I am trying to deploy the following scenario.

We have an Angular application that use many API written on PHP Laravel 9. Just like a microservice architecture.

Everything fine so far, so we decided to use Keycloak as our Identity Provider to serve as an authentication on the front end as well the backend services.

At this point we mounted everything on several dockers and deploy Keycloak version 19 with MySQL as database support.

Now, we decided to move forward and go to a kubernetes solution on Azure.

We have our cluster with 3 nodes, and deployed Keycloak on one Pod (replicated on the 3 nodes) using also nginx-ingress with tls.

So far so good. But we are facing an issue that I was unable to find a solution in anywhere on the internet. :frowning:

Debbuging from the front end, we saw that after the user login through the Keycloak UI the token (step 2 in the authorization flow) is giving us an invalid grant type…

code: e18b5ae9-3cae-4840-830d-08d542779b17.aacdc750-2dfe-4dc6-951c-46b649340170.640029e6-b41c-4b92-89fb-21b636725b42
grant_type: authorization_code
client_id: xxxx
redirect_uri: http://xxxx/

{error: “invalid_grant”, error_description: “Code not valid”}

I don´t know if someone had faced the same scenario because I couldn´t find really nothing and now I was wondering if this scenario is supported at all.

Well, here are all my configurations:

odi-keycloak-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: odi-keycloak
  namespace: odi-ns
  labels:
    app: odi-keycloak
  annotations:
    service.beta.kubernetes.io/azure-load-balancer-resource-group: allresources-rg
    service.beta.kubernetes.io/azure-load-balancer-ipv4: xx.xx.xx.xx  
spec:
  type: LoadBalancer
  ports:
    - name: https
      port: 443 
      targetPort: 8443
  selector:
    app: odi-keycloak

odi-keycloak-ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: odi-keycloak-ingress
  namespace: odi-ns
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: "https"
    nginx.ingress.kubernetes.io/proxy-buffer-size: "128k"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /$1    
    nginx.ingress.kubernetes.io/affinity: cookie
    nginx.ingress.kubernetes.io/configuration-snippet: |
      proxy_set_header X-Real-IP          $remote_addr;
      proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Host   $host;
      proxy_set_header X-Forwarded-Server $host;
      proxy_set_header X-Forwarded-Port   $server_port;
      proxy_set_header X-Forwarded-Proto  $scheme;
    nginx.ingress.kubernetes.io/session-cookie-path: /    
spec:
  tls:
  - hosts: 
    - myhost.com
    secretName: keycloak-test-tls
  ingressClassName: nginx
  rules:
  - host: "myhost.com"
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: odi-keycloak
            port:
              number: 443

odi-keycloak-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: odi-keycloak
  labels:
    app: odi-keycloak
  namespace: odi-ns

spec:
  replicas: 3
  selector:
    matchLabels:
      app: odi-keycloak
  template:
    metadata:
      labels:
        app: odi-keycloak

    spec:
      volumes:
        - name: odi-keycloak-mnt
          persistentVolumeClaim:
            claimName: odi-keycloak-pvc
        - name: odi-keycloak-tls-mnt
          persistentVolumeClaim:
            claimName: odi-keycloak-tls-pvc
      containers:
        - name: odi-keycloak
          image: quay.io/keycloak/keycloak:latest
          args: ["start"]          
          volumeMounts:
            - mountPath: /opt/keycloak/providers
              name: odi-keycloak-mnt     
            - mountPath: /etc/ssl
              name: odi-keycloak-tls-mnt                     
          env:
            #- name: KC_CACHE_STACK
            #  value: "azure"
            - name: KEYCLOAK_PRODUCTION
              value: "true"
            - name: KEYCLOAK_JDBC_PARAMS
              value: "sslmode=disable&connectTimeout=40000"
            - name: KEYCLOAK_EXTRA_ARGS
              value: "-Dkeycloak.profile.feature.scripts=enabled"
            - name: KEYCLOAK_ENABLE_HTTPS
              value: "true"
            - name: KEYCLOAK_HTTPS_USE_PEM
              value: "true"
            - name: KEYCLOAK_ADMIN
              value: "admin"
            - name: KEYCLOAK_ADMIN_PASSWORD
              value: "admin"
            - name: KC_PROXY
              value: "edge"  
            - name: KC_HOSTNAME
              value: "myhost.com"
            - name: KC_HTTPS_CERTIFICATE_FILE
              value: "/etc/ssl/odi-keycloak-cert.pem"              
            - name: KC_HTTPS_CERTIFICATE_KEY_FILE
              value: "/etc/ssl/odi-keycloak-cert-key.pem"
            - name: KC_LOG_LEVEL
              value: "info"       
            - name: KC_DB
              value: "mysql"
            - name: KC_DB_VENDOR
              value: "mysql"              
            - name: KC_DB_URL
              value: "jdbc:mysql://IP:PORT/database"
            - name: KC_DB_USERNAME
              value: "kcdbuser"
            - name: KC_DB_PASSWORD
              value: "mypassword"
            - name: KC_DB_SCHEMA
              value: "kcdbprod"
            - name: KC_HEALTH_ENABLED
              value: "true"
            - name: KC_METRICS_ENABLED
              value: "true"          
          ports:
            - name: http
              containerPort: 8080      
          readinessProbe:
            httpGet:
              scheme: HTTP
              path: /realms/master
              port: 8080              
            initialDelaySeconds: 60
            periodSeconds: 1        
      restartPolicy: Always

Thanks for the time for reading my issue and hope someone could give me a light.

Cheers!
Javier.