Keycloak 은 17 버전부터 WildFly 대신 Quarkus 위에서 돈다. 기동 방식과 설정 키가 통째로 바뀌었기 때문에, 예전 문서를 보고 올리면 기동 단계에서 막히는 일이 많다. 여기 모은 것은 RHEL 계열에 압축 배포판을 풀어 올릴 때 실제로 부딪히는 메시지들이다.
설정은 conf/keycloak.conf 에 두거나 실행 인자로 준다. 같은 항목이 양쪽에 있으면 실행 인자가 이긴다.
Key material not provided to setup HTTPS. Please configure your keys/certificates
or start the server in development mode.
start 는 운영 모드라 HTTPS 를 기본으로 요구한다. 인증서를 주지 않으면 기동이 멈춘다. 앞단에 리버스 프록시를 두고 Keycloak 은 평문으로 받을 것이라면 HTTP 를 명시적으로 켠다.
# conf/keycloak.conf
http-enabled=true
proxy-headers=xforwarded
hostname=https://auth.example.com
proxy-headers 를 주지 않으면 Keycloak 이 자기 주소를 http:// 로 알고 있어 리다이렉트 URL 이 깨진다. 예전 문서의 proxy=edge 는 최근 버전에서 proxy-headers 로 바뀌었다.
Keycloak 이 직접 TLS 를 종단할 것이라면 인증서를 준다.
https-certificate-file=/etc/pki/tls/certs/keycloak.crt
https-certificate-key-file=/etc/pki/tls/private/keycloak.key
https-port=8443
http-enabled=false
hostname=https://auth.example.com
start-dev 로 넘기면 오류는 사라지지만 캐시가 로컬 전용으로 바뀌고 hostname 검증이 꺼진다. 운영에 쓰지 않는다.
WARN [org.keycloak.encoding.ResourceEncodingProvider] Failed to encode resource:
java.io.IOException: 그런 파일이나 디렉터리가 없습니다
at java.io.File.createTempFile(File.java:2184)
at org.keycloak.encoding.GzipResourceEncodingProvider.createEncodedFile(...)
테마 리소스를 gzip 으로 만들어 캐시하려는데 임시 파일을 못 만든 것이다. 로그인 화면의 CSS · JS 가 압축 없이 나가므로 동작은 하지만 매 요청마다 경고가 쌓인다.
java.io.tmpdir 이 가리키는 곳을 확인한다.
ls -ld /tmp
df -h /tmp
셋 중 하나다 — 디렉터리가 없거나, 퍼미션이 1777 이 아니거나, 가득 찼다.
chmod 1777 /tmp
systemd 로 띄우면서 PrivateTmp=true 를 걸어 두었다면 서비스 전용 /tmp 가 쓰인다. 이때는 서비스 계정이 그 안에 쓸 수 있는지 본다. 아예 별도 경로를 지정하는 편이 확실하다.
# /etc/systemd/system/keycloak.service
Environment=JAVA_OPTS_APPEND=-Djava.io.tmpdir=/opt/keycloak/tmp
mkdir -p /opt/keycloak/tmp
chown keycloak:keycloak /opt/keycloak/tmp
chmod 700 /opt/keycloak/tmp
컨테이너로 돌리면서 루트 파일시스템을 읽기 전용으로 잠갔다면 /tmp 를 tmpfs 로 마운트해 준다.
WARNING: Usage of the default value for the db option in the production profile is deprecated.
Please explicitly set the db instead.
운영 모드에서 DB 를 명시하지 않으면 내장 H2 로 뜬다. H2 는 개발용이고 재기동이나 다중 노드를 견디지 못한다. 실제로 쓸 DB 를 적는다.
db=postgres
db-url=jdbc:postgresql://db.example.com:5432/keycloak
db-username=keycloak
db-password=${KC_DB_PASSWORD}
비밀번호를 파일에 적지 말고 환경변수로 넘긴다. Keycloak 은 KC_ 접두어 환경변수를 설정 키로 읽는다 — db-password 는 KC_DB_PASSWORD 다.
start 는 매번 설정을 다시 빌드한다. 설정이 확정되면 한 번 빌드해 두고 그 결과로 띄운다.
bin/kc.sh build
bin/kc.sh start --optimized
--optimized 로 띄운 뒤 빌드 단계 옵션(db, features, health-enabled 등)을 바꾸면 반영되지 않는다. 그 항목을 고쳤으면 build 를 다시 돌린다.
ERROR [org.jgroups.protocols.TCP] auth-18492: failed sending message to auth-22653:
java.net.ConnectException: 연결이 거부됨
두 대 이상을 묶으면 Infinispan 이 JGroups 로 서로를 찾는다. 노드 간 통신 포트(기본 7800 계열)가 막혀 있으면 이 메시지가 반복된다.
firewall-cmd --permanent --add-port=7800/tcp
firewall-cmd --permanent --add-port=7800/udp
firewall-cmd --reload
노드가 서로의 주소를 잘못 알고 있는 경우도 같은 증상이다. 멀티캐스트가 막힌 망에서는 기본 검색 방식이 동작하지 않으므로 DB 기반 또는 정적 목록 기반 검색으로 바꾼다. Kubernetes 라면 kubernetes.KUBE_PING 을 쓰고 헤드리스 서비스를 붙인다.
노드 하나만 쓸 것이라면 클러스터링을 꺼 버리는 것이 간단하다.
bin/kc.sh start --optimized --cache=local
부트스트랩 관리자 계정은 첫 기동 때 환경변수로 만든다. 최근 버전은 KEYCLOAK_ADMIN 대신 KC_BOOTSTRAP_ADMIN_USERNAME 계열을 쓴다 (버전별로 다르므로 쓰는 배포판 문서를 확인한다).
export KC_BOOTSTRAP_ADMIN_USERNAME=admin
export KC_BOOTSTRAP_ADMIN_PASSWORD=${KEYCLOAK_ADMIN_PASSWORD}
bin/kc.sh start --optimized
이미 떠 있는 서버에 계정을 추가하려면 admin CLI 로 붙는다.
bin/kcadm.sh config credentials --server http://localhost:8080 \
--realm master --user admin
bin/kcadm.sh create users -r master -s username=operator -s enabled=true