Enabling SSL to secure the HTTP traffic of the Keycloak Server with existing certificate (avoid self-signed certificate)

Hi everyone,

i tried to secure the traffic of my keycloak instance behind my proxy with SSL but unfortunately without success so far.

Is there any way to follow the described way in the keycloak documentation Keycloak Docu if you already have a certificate and don’t want to use a self signed certificate?

The traffic from the web to the proxy is encrypted correctly only the way from the proxy to Keycloak does not seem to use SSL correctly yet.

Maybe someone here has a tip and can help me with my problem

Thanks for your help

I am using Keycloak 12.0.4 (distribution powered by WildFly) on Cent OS 7

Yes, you can follow documentation same way, just skip part of certificate creation.

Personally, i recommend that you use reverse proxy with nginx in front of keycloak, and configure nginx to use your certficate in ssl.

1 Like

@claudioweiler thanks for your quick reply, i tried to run nginx in front of keycloak but I’m getting nowhere with my current nginx configuration for keycloak and am stuck at this point

At the moment i’m using apache proxy

Keycloak alone runs without problems

The current configuration of nginx (/etc/nginx/nginx.conf) on its own runs also without problems

As soon as I start both in a row, there are problems because ports 80, 443, 8080 and 8443 are already in use (Keycloak or Nginx).

Do you have a working nginx config that runs in parallel with keycloak (bare metal)?

Do I necessarily need a reverse proxy before Keycloak?

Currently Keycloak communicates via 8443 but still without SSL/TLS, where to store/configure that with existing purchased certificates?

At the moment i’m using apache proxy

You can use apache, no problem.

As soon as I start both in a row, there are problems because ports 80, 443, 8080 and 8443 are already in use

Right, nginx or apache will run in 80 and 443, keycloak will run in 8080 (no need for 8443). If you have ports conflict you need to check what is using those ports and close processes or change ports (for 80/443, better close).
Maybe you already have apache running, so nginx will conflict.

Do you have a working nginx config that runs in parallel with keycloak (bare metal)?

Sorry, nope, we use kubernetes here, but google it, test, and post your results here, we will try to help.

Do I necessarily need a reverse proxy before Keycloak?

No, definitely. You can configure SSL on keycloak without problems. I would dare to say that a reverse proxy is just a recommended approach.

Currently Keycloak communicates via 8443 but still without SSL/TLS, where to store/configure that with existing purchased certificates?

Do it how it says in documentation, just skip certificate creation steps.

1 Like

nginx and apache at the same time and both for port 80 & 443 is not possible.
Take one program and remove the other one, or at least do not use the same ports again.

Just one process can listen on a specific socket, here the https 443

On my setup, an Apache reverse proxy works fine.
The Apache is the TLS-endpoint and forwards the traffic to Keycloak without encryption.
Used ports are 443 on Apache for https and 8080 for Keycloak for http.

On Linux you can check its usage by
netstat -tulpena | grep 443

Check for port 8080
netstat -tulpena | grep 8080

If there is already another program on you port, you can move your keycloak to another port, e.g. 8088
by passing the option in ./bin/standalone.conf
JAVA_OPTS="$JAVA_OPTS -Djboss.http.port=8088"

1 Like

Hi @claudioweiler and @psytester many thanks for your replies.

I tried in my first attempt to get nginx running with keycloak as upstream proxy

And now in my second try apache with keycloak

apache has to run in parallel because this proxy already exists and has many services to serve

My problem with nginx was that it can’t communicate on 80 and 443 because apache is running and also can’t use ports 8080, 8443, 9990 and 9993 because of keycloak
Is it correct to change the configuration file “/etc/nginx/nginx.conf” or to create configurations for each service in “/etc/nginx/conf.d/*”?

I will post my configurations for nginx and apache tomorrow morning , maybe you can advise me to fix my problem/misconfiguration

@claudioweiler & @psytester

My current Apache config:

<VirtualHost *:80>
      ServerName keycloak.example.com
     ServerAdmin keycloak@example.com
    ServerSignature Off

	Redirect / https://keycloak.example.com
</VirtualHost>


<VirtualHost *:443>
	ServerName keycloak.example.com
	ServerAdmin keycloak@example.com
	ServerSignature Off
	
	ErrorLog logs/ssl_error_log
	TransferLog logs/ssl_access_log
	LogLevel info

	CustomLog logs/ssl_request_log \
	          "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

	SSLEngine on
	SSLProtocol all 
	SSLCipherSuite HIGH:3DES:!aNULL:!MD5:!SEED:!IDEA
	SSLCertificateFile "*.cert-file"
	SSLCertificateKeyFile "*.key-file"
	SSLCertificateChainFile "*.cert-file"



	ProxyPreserveHost On
	ProxyRequests Off
	RequestHeader add "X-forwarded-proto" "https"

	RequestHeader set x-ssl-client-cert "%{SSL_CLIENT_CERT}s"
	
	SSLProxyEngine On
	SSLProxyCheckPeerCN on
	SSLProxyCheckPeerExpire on
	RequestHeader set X-Forwarded-Proto "https"
	RequestHeader set X-Forwarded-Port "443"

	ProxyPass "/auth" "https://127.0.0.1:8443"
    ProxyPassReverse "/auth" "https://127.0.0.1:8443"

</VirtualHost>

My current Nginx config:

   events {
}

http {

  upstream keycloak {
    # Use IP Hash for session persistence
    ip_hash;
  
    # List of Keycloak servers
    server 127.0.0.1:8443;
  }


  server {
    listen 8443;
    server_name keycloak.example.com;

    #server_name keycloak.example.com;
    #return 301 https://$host$request_uri;

    # Redirect all HTTP to HTTPS
    location / {   
      return 301 https://\$server_name\$request_uri;
    }
  }

  server {
 
    include       /etc/nginx/mime.types;
   
    listen 8443 ssl http2;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_certificate "*.cert-file";
    ssl_certificate_key "*.key-file";

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header Content-Security-Policy "default-src 'self'; frame-ancestors 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src http://example.com;";   
    add_header X-XSS-Protection: "1; mode=block";

    proxy_set_header X-Forwarded-For $proxy_protocol_addr; # To forward the original client's IP address 
    proxy_set_header X-Forwarded-Proto $scheme; # to forward the  original protocol (HTTP or HTTPS)
    proxy_set_header Host $host; # to forward the original host requested by the client
    
    location /auth {
      proxy_pass http://127.0.0.1:8443;
    }
  }
}

Hope you can help me on this

If you already has apache, stick with apache.

My comments on your config:

ProxyRequests Off
RequestHeader add “X-forwarded-proto” “https”

Exclude this.

ProxyPass “/auth” “https://127.0.0.1:8080
ProxyPassReverse “/auth” “https://127.0.0.1:8080

You are pointing to https on keycloak, just use http. Please, confirm that you keycloak is running on 8080.
It depends much on setup, but I recommend you to use a virtual host, and reverse proxy root ("/"). If you need to proxy only “auth” context, than it should be something like this:

ProxyPass "/auth" "http://127.0.0.1:8080/auth"
ProxyPassReverse "/auth" "http://127.0.0.1:8080/auth"
1 Like

I’ll try this changes in my current config :+1:t4:

Is there a fundamental difference/advantage of Nginx instead of Apache, since most of the info on Keycloak refers to Nginx as a proxy?

Is there a fundamental difference/advantage of Nginx instead of Apache

1 Like

Unfortunately the adjustments to the apache proxy config did not solve the problem

In my current instance keycloak runs on 8443 after the first start.

Here I have at the moment problems to activate an existing certificate, at the beginning keycloak was started on 8080 and after that keys were generated automatically directly at restart “Generated self signed certificate”, “stored in the keystore → …/keycloak/standalone/configuration/application.keystore” and keycloak was only available on port 8443 which changed

I have been able to import the existing certificate into the keystore and now have the problem that when I try to add the new security-realm element using the CLI via the commands:

$ /core-service=management/security-realm=UndertowRealm:add()

$ /core-service=management/security-realm=UndertowRealm/server-identity=ssl:add(keystore-path=keycloak.jks, keystore-relative-to=jboss.server.config.dir, keystore-password=secret)

, this is not possible or is not executed.

What is the syntax or directory for executing the command here?

I never tested this, but it looks odd. Simply enabling server identity should not disable a entire interface.

But, you can always just start over!

Wildfly cli always return a message indicating the problem.
Guessing: Probably because these configurations is already added, so you can’t add it again.

1 Like

@claudioweiler many thanks for your fast replies

I’m really struggling with keycloak at the moment and point of configuration

It’s very weird that keycloak has generated a self signed certificate on it’s own and as i read this is only usable for the local test env, an active certificate is already available and can’t be used right away

And in this case also the default communication port has turned off

I’ve already checked the file “…/standalone/configuration/standalone.xml” for this

You need to connect to server, first, as noted in second line. Just type ‘connect’ and enter.

Or use ./bin/jboss-cli.sh -c

1 Like

Many thanks @claudioweiler
Was my fault because the keycloak service has to be already running and available to connect to it.

I was wondering because when i prepared the configuration to use my own database with for example “mysql-connector-java” i used

./bin/jboss-cli.sh
module add --name=org.mysql --dependencies=javax.api,javax.transaction.api --resources=/opt/mysql-connector-java-5.1.47/mysql-connector-java-5.1.47.jar
exit

**OR**

./bin/jboss-cli.sh 'embed-server,/subsystem=datasources/jdbc-driver=org.mysql:add(driver-name=org.mysql,driver-module-name=org.mysql,driver-class-name=com.mysql.jdbc.Driver)'
-> {"outcome" => "success"}

and it worked fine as i could see/check afterwards in the file “standalone.xml”