Links#
https://www.keycloak.org/server/enabletls
https://www.keycloak.org/server/hostname
https://www.keycloak.org/server/reverseproxy
https://www.keycloak.org/server/db
https://www.keycloak.org/server/all-config1. Important Points#
Keycloak 企业部署里 TLS 不只是浏览器访问 HTTPS。至少有 4 条链路要明确:
browser / app -> Keycloak:
public HTTPS endpoint
reverse proxy / ingress -> Keycloak:
edge termination or re-encrypt
Keycloak -> PostgreSQL:
JDBC TLS and CA verification
Keycloak -> LDAP / AD / upstream IdP / SMTP:
LDAPS / HTTPS / SMTP TLSproduction principles:
use trusted CA certificates
keep hostname stable
verify certificates and hostnames
monitor certificate expiry
rotate certs before expiry
do not use insecure TLS flags in production2. Server Configuration#
TLS terminated at Keycloak#
hostname=sso.example.com
http-enabled=false
https-certificate-file=/etc/keycloak/tls/tls.crt
https-certificate-key-file=/etc/keycloak/tls/tls.key
health-enabled=true
metrics-enabled=trueFile layout:
/etc/keycloak/tls/
tls.crt
tls.key
ca.crt
permissions:
tls.key readable only by keycloak user
certificate files managed by cert-manager / ACME / secret managerTLS terminated at reverse proxy#
hostname=sso.example.com
http-enabled=true
proxy-headers=xforwardedreverse proxy checklist:
edge:
TLS certificate belongs to sso.example.com
redirect HTTP to HTTPS
set X-Forwarded-For
set X-Forwarded-Proto=https
set X-Forwarded-Host=sso.example.com
Keycloak:
trusts forwarded headers only from controlled proxy
hostname matches external URL
admin console tested behind proxyDo not expose the internal HTTP port directly to users when TLS is terminated at the proxy.
3. Client Configuration / Verify#
OIDC discovery:
curl -fsS https://sso.example.com/realms/prod/.well-known/openid-configurationCertificate verify:
openssl s_client -connect sso.example.com:443 -servername sso.example.com </dev/nullExpected:
Verify return code: 0 (ok)
issuer is expected company/public CA
subject/SAN contains sso.example.com
certificate expires later than rotation windowDatabase TLS:
db=postgres
db-url=jdbc:postgresql://postgres.example.com:5432/keycloak?sslmode=verify-full&sslrootcert=/etc/keycloak/db-ca/ca.crt
db-username=keycloak
db-password=${KC_DB_PASSWORD}LDAP TLS:
LDAP URL:
ldaps://ad.example.com:636
trust:
AD server certificate chains to trusted CA
hostname matches certificate SAN
bind account has least privilege4. Java#
Spring Security OIDC resource server example:
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://sso.example.com/realms/prodCustom CA:
keytool -importcert \
-alias company-root-ca \
-file company-root-ca.crt \
-keystore truststore.p12 \
-storetype PKCS12
java \
-Djavax.net.ssl.trustStore=truststore.p12 \
-Djavax.net.ssl.trustStorePassword=changeit \
-jar order-api.jarDo not disable hostname verification in production.
5. Python#
Python requests with CA bundle:
import requests
issuer = "https://sso.example.com/realms/prod"
resp = requests.get(
f"{issuer}/.well-known/openid-configuration",
timeout=5,
verify="/etc/ssl/company-ca.pem",
)
resp.raise_for_status()
print(resp.json()["issuer"])Runtime:
export SSL_CERT_FILE=/etc/ssl/company-ca.pem
export REQUESTS_CA_BUNDLE=/etc/ssl/company-ca.pemNever use verify=False in production.
6. Go#
Go custom CA:
package main
import (
"crypto/tls"
"crypto/x509"
"net/http"
"os"
)
func clientWithCA(caPath string) (*http.Client, error) {
pem, err := os.ReadFile(caPath)
if err != nil {
return nil, err
}
roots := x509.NewCertPool()
roots.AppendCertsFromPEM(pem)
return &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
RootCAs: roots,
},
},
}, nil
}Do not set InsecureSkipVerify: true in production.
7. Node.js#
Node.js with custom CA:
export NODE_EXTRA_CA_CERTS=/etc/ssl/company-ca.pem
node server.jsFetch OIDC discovery:
const issuer = "https://sso.example.com/realms/prod";
const resp = await fetch(`${issuer}/.well-known/openid-configuration`);
if (!resp.ok) {
throw new Error(`OIDC discovery failed: ${resp.status}`);
}
const discovery = await resp.json();
console.log(discovery.issuer);Never use NODE_TLS_REJECT_UNAUTHORIZED=0 or rejectUnauthorized: false in production.
8. Rotation Checklist#
before rotation:
check all clients trust the new CA/intermediate
update Keycloak TLS secret or certificate files
update DB / LDAP CA bundles if needed
confirm certificate SAN includes hostname
during rotation:
apply secret/certificate
restart or reload component if needed
verify OIDC discovery
verify browser login
verify app token validation
after rotation:
monitor login failures and TLS errors
remove old cert after overlap window
update expiry dashboard