I’m currently in the process of setting up a home k3s cluster. As part of that I want to use Keycloak as an OIDC provider for managing authorization and authentication in a couple of apps that I’m hosting.

Because I’m hosting the cluster at home and my ISP users a CGNAT which prevents me from forwarding ports from my home router I am using Cloudflare Tunnels to allow access (as described here).

The problem is that although the Keycloak admin console is available internally via IP address when accessing via the exposed domain ingress route the site refuses to load with mixed content errors in the browser.

Mixed Content: The page at ‘<URL>’ was loaded over HTTPS, but requested an insecure resource ‘<URL>’

After a lot of trial and error the solution to this was to explicitly state the hostname and admin hostname in the container environment variables which seems to get the console to realise that it should be running on https rather than http.

apiVersion: v1
kind: Service
metadata:
  name: keycloak
  namespace: keycloak
  labels:
    app: keycloak
spec:
  ports:
    - name: http
      port: 8080
      targetPort: 8080
  selector:
    app: keycloak
  type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: keycloak
  namespace: keycloak
  labels:
    app: keycloak
spec:
  replicas: 1
  selector:
    matchLabels:
      app: keycloak
  template:
    metadata:
      labels:
        app: keycloak
    spec:
      containers:
        - name: keycloak
          image: quay.io/keycloak/keycloak:26.0.7
          args: ["start-dev"]
          env:
            - name: KC_BOOTSTRAP_ADMIN_USERNAME
              valueFrom:
                secretKeyRef:
                  name: keycloak-secrets
                  key: bootstrap_admin_username
            - name: KC_BOOTSTRAP_ADMIN_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: keycloak-secrets
                  key: bootstrap_admin_password
            - name: KC_PROXY_ADDRESS_FORWARDING
              value: "true"
            - name: KC_HEALTH_ENABLED
              value: "true"
            - name: KC_PROXY
              value: "edge"
            - name: KC_HOSTNAME_STRICT
              value: "false"
            - name: KC_HTTP_ENABLED
              value: "true"
            - name: KC_HOSTNAME_STRICT_BACKCHANNEL
              value: "false"
            - name: KC_HOSTNAME
              value: "https://sub.domain.com"
            - name: KC_HOSTNAME_ADMIN
              value: "https://sub.domain.com"
            - name: KC_HOSTNAME_STRICT_HTTPS
              value: "true"
          ports:
            - name: http
              containerPort: 8080
          readinessProbe:
            httpGet:
              path: /health/ready
              port: 9000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: keycloak-ingress
  namespace: keycloak
  annotations:
    kubernetes.io/ingress.class: traefik
    traefik.ingress.kubernetes.io/router.entrypoints: web
    cert-manager.io/cluster-issuer: cert-manager-cluster-issuer
    external-dns.alpha.kubernetes.io/cloudflare-proxied: "true"
    external-dns.alpha.kubernetes.io/hostname: sub.domain.com
    external-dns.alpha.kubernetes.io/target: TUNNEL-ID.cfargotunnel.com
spec:
  tls:
  - hosts:
    - sub.domain.com
    secretName: keycloak-tls
  rules:
  - host: sub.domain.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: keycloak
            port:
              number: 8080

In order to get this working just replace the “TUNNEL-ID” and “sub.domain” placeholders with the actual values for your Cloudflare tunnel and external domain.


0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *