Keycloak is adding adding port 80 to https urls

Hi,

I have deployed an instance of keycloack (with this chart keycloak 15.1.0 · codecentric/codecentric) in my kubernetes cluster, and it is running behind a reverse-proxy kubernetes ingress.

If I send a request to https://{host}/auth/realms/master/.well-known/openid-configuration to check the config, it’s almost ok, except that all the urls have an added port 80

e.g.
issuer: “https://{host}:80/auth/realms/master”

How can I remove this port?

Did you follow readme keycloak 15.1.0 · codecentric/codecentric ?

Yes
I already set PROXY_ADDRESS_FORWARDING to true, otherwise it would set the urls protocol to http (although it would remove the port)

I have the same problem, doesn’t matter what I do I can’t find anything that will change the port to anything else, seems the problem is if keycloak doesn’t do https termination itself it forces port 80? something like that.

    nginx.ingress.kubernetes.io/configuration-snippet: |
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto: https;
      # proxy_set_header X-Forwarded-Host  $host;

image: quay.io/keycloak/keycloak:18.0.2
args: ["start-dev","--hostname-strict-https=false"]
        - name: KEYCLOAK_ADMIN
          value: "admin"
        - name: KEYCLOAK_ADMIN_PASSWORD
          value: "admin"
        - name: KC_PROXY
          value: "edge"
        - name: PROXY_ADDRESS_FORWARDING
          value: "true"

You have to set approptiate KC_HOSTNAME for the keycloak to know your external hostname to redirect to. Also set KC_PROXY to edge. This is how it works for me

@RbBrDkie did you ever figure this out? I’m at the exact same spot with it forcing port 80 no matter what I do.

You seem to be using Kubernetes. The nginx ingress controller will set X-Forwarded-Host, X-Forwarded-Proto and X-Forwarded-Port so keycloak knows it behind a reverse proxy and can build the external url for the openid connect endpoints.

Problem is: if you have another reverse proxy in front of your nginx ingress controller, out of the box nginx will rewrite those headers sent by the first proxy and the information is lost.

If thats the case for you (a reverse proxy in front of your kubernetes ingress) you’ll need to configure nginx ingress to trust those headers.

CAREFUL: that configuration should only be activated if you really have another proxy in front of your nginx ingress. If not, nginx will trust those headers and a malicious user can set them.

I’m still stuck, I changed my config as follows:
ingress-nginx configmap:

data:
  use-forwarded-headers: “true”

ingress:

    nginx.ingress.kubernetes.io/configuration-snippet: |
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto: https;
      # proxy_set_header X-Forwarded-Host  $host;

And envs

        - name: KEYCLOAK_ADMIN
          value: admin
        - name: KEYCLOAK_ADMIN_PASSWORD
          value: s******y
        - name: KC_PROXY
          value: edge
        - name: KC_HOSTNAME
          value: keycloak.********.com
        - name: KEYCLOAK_LOGLEVEL
          value: DEBUG
        - name: PROXY_ADDRESS_FORWARDING
          value: "true"

You don’t need the nginx.ingress.kubernetes.io/configuration-snippet because nginx already set those headers.

I may suggest you to use a debug pod like daime/http-dump:latest instead of keycloak to see if the headers are correct. http-dump will dump the request it received from the nginx controller so you can inspect it.

Check if all X-Forwarded-XXXX headers are correctly set.

making progress, removed the snippet and running http-dump

GET /admin/ HTTP/1.1
Host: keycloak.*********.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Sec-Ch-Ua: "Chromium";v="104", " Not A;Brand";v="99", "Google Chrome";v="104"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "macOS"
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
Use-Forwarded-Headers: “true”
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36
X-Forwarded-For: 1.2.3.4
X-Forwarded-Host: keycloak.*********.com
X-Forwarded-Port: 80
X-Forwarded-Proto: https
X-Forwarded-Scheme: https
X-Original-Forwarded-For: 1.2.3.4
X-Real-Ip: 1.2.3.4
X-Request-Id: ***********
X-Scheme: https

So Basically what I need is to change X-Forwarded-Port: 80 to X-Forwarded-Port: 443

The tls gets terminated before it hits the ingress which is why I have https but communicating on 443

[quote=“RbBrDkie, post:10, topic:11808”]
I added back the snippet to set the port then it duplicates the port header which is why it didn’t work I guess

GET /admin/ HTTP/1.1
Host: keycloak.*********.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Sec-Ch-Ua: "Chromium";v="104", " Not A;Brand";v="99", "Google Chrome";v="104"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "macOS"
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
Use-Forwarded-Headers: “true”
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36
X-Forwarded-For: 1.2.3.4
X-Forwarded-Host: keycloak.*********.com
X-Forwarded-Port: 80
X-Forwarded-Port: 443
X-Forwarded-Proto: https
X-Forwarded-Scheme: https
X-Original-Forwarded-For: 1.2.3.4
X-Real-Ip: 1.2.3.4
X-Request-Id: ***********
X-Scheme: https

finally got it working.

KC_PROXY=none

I also added tls in the backend with selfsigned crt but don’t think that had an effect