Keycloak

개요

오픈소스 인증 권한 관리 툴.
여러 어플리케이션을 운용하거나 활용할 때, 각각 여러 개의 계정을 두게 된다면 사용자도 불편하고 관리자도 불편하다.
그래서 이를 한꺼번에 통합하여 관리할 수 있는, SSO가 필요하게 되는 것이다.
그리고 이러한 툴로서 오픈소스로 sso를 구축할 수 있도록 도와주는 툴이 바로 키클록이다.

OIDC, OAuth, SAML 3가지의 보안 프로토콜을 지원한다.
이 모두 외부의 인증 공급자를 두고, 클라이언트가 서비스에 접근할 때 필요한 토큰을 제공하는 방식의 프로토콜들로, 키클록이 바로 여기에서 인증 공급자 역할을 해준다.

레드햇에서 주도하여 만드는 중인데 그래서 그런지 설치하는 것도 레드햇 관련 사이트들에서 많이 지원하는 것 같더라.

특징

아키텍처


크게 봤을 때 키클록은 웹 3티어 아키텍쳐의 구조를 가지고 있다.[1]

설치

요구 스펙

사용환경에 따라 어떤 정도의 사양을 생각하면 될지 매우 상세하게 나와있다![2]
아무래도 인증 서버들은 많은 트래픽을 감당해야 하는 경우가 많다.
내용량이 많다기 보다는, 정말 단순하게 요청 개수가 많을 수밖에 없다.
그래서 이렇게 상세하게 알려주는 것이라고 생각한다.

쿠버네티스 설치

일단 쿠버네티스 클러스터에 설치를 하는 방법도 있다.
그러나, 나는 쿠버네티스 인증을 위해 사용하는 입장이라면 이 방식이 좋다고 생각하지 않는다.
유저의 인증이 클러스터의 라이프사이클과 함께 하게 된다면 유사시에 클러스터 상태를 제대로 추적하지 못하는 상태가 될 수도 있다고 생각한다.
그래서 최소한 이렇게 운영할 것이라면, 관리자는 해당 인증 모듈로부터 독립된 별도의 인증 방식을 마련해야만 할 것이다.

kubectl create -f https://raw.githubusercontent.com/keycloak/keycloak-quickstarts/refs/heads/main/kubernetes/keycloak.yaml

문서에서는 이러한 방식으로 minikube에 세팅하는 방법을 알려준다.

helm repo add bitnami https://charts.bitnami.com/bitnami


이번에도 헬름을 먼저 써보자.
최소한 순수 양식 파일로 설치하는 것은 지양하고자 하는 것이, 나중에 지울 때 귀찮다..
받을 때 사용했던 웹 주소를 가지고 있던가, 아니면 따로 양식 파일을 저장해놔야 하는데, 그럴거면 잘 포장된 헬름을 쓰는 것이 더 나은 것이 아닌가 하는 생각이다.

일단 어드민 정보를 넣었다.

나중에 브라우저로 접근하기 위해 이 정보도 미리 확인해둔다.

helm install --generate-name --create-namespace -n keycloak bitnami/keycloak -f keycloak-helm.yaml    

이런 식으로 해줬다.

본격적으로 이슈 모니터링을 해보자.

디비로 사용되는 포스트그레에 문제가 있어서 봤다.
스테이트풀셋으로 만들어지는 놈인데 마운팅에 문제가 생긴다.

과거에도 봤던 에러가 또 나온다.
그런데 해당 노드에서 마운팅이 가능하다는 것은 이미 확인을 거쳤다.

또한 같은 노드의 다른 파드가 동적 프로비저닝을 잘 받는 것도 확인했다.
같은 스토리지 클래스를 사용하기까지 했다.
그런데 이 놈은 왜 이럴까?

아예 나스에 들어가서 확인해봤는데, 이것도 이제 보니 상태가 이상하다.
각 pvc에 대해서 디렉토리가 만들어지지 않았고, 한 pvc에 대한 디렉토리만 만들어진 상태이다.

다시 보니까 worker2에 배치된 파드들이 문제가 생기기 시작했다.
문제가 생긴 이후 나스를 보니 디렉토리들이 사라졌다.
이건 회수정책을 그리 설정해놔서 그런 거긴 한데..
문제는 한 노드에서 발생하는 것이라 일축해볼 수도 있을 것 같다.

조금 더 확장시켜보니, 확실히 두번째 노드에서 문제가 발생하긴 한다.
다만 또 놀라웠던 것은 한놈이 문제가 생기는 순간 모든 파드가 재시작을 했다는 것이다.
내 생각에는 스토리지 드라이버의 이슈일 수도 있다.

NFS를 다시금 활용해봐야겠다.
Pasted image 20250129193234.png
확실히, nfs로 하니까 바로 성공했다.
자료들을 조금 찾아봤는데 관련한 에러가 윈도우에 3년전쯤에 발생했던 것이 있다.
그런데 같은 에러가 리눅스에서 갑자기 발생하고 있다라..
nfs는 조금도 문제 없이 잘 돌아가는데, 여태 smb는 멀쩡하던 컨테이너가 주기적으로 재시작하기도 하는 등의 문제들이 많았다.
한가지 감안해야 할 것은, 지금의 nfs는 그냥 내 로컬에서 구동한 서버를 활용하고 있다는 것이다.
나스에 nfs를 세팅하고 사용하면 또 비슷한 상황이 나올 수도 있을 것이다.

Did you know there are enterprise versions of the Bitnami catalog? For enhanced secure software supply chain features, unlimited pulls from Docker, LTS support, or a
pplication customization, see Bitnami Premium or Tanzu Application Catalog. See https://www.arrow.com/globalecs/na/vendors/bitnami for more information.

** Please be patient while the chart is being deployed **

Keycloak can be accessed through the following DNS name from within your cluster:

    keycloak-1738032521.keycloak.svc.cluster.local (port 80)

To access Keycloak from outside the cluster execute the following commands:

1. Get the Keycloak URL by running these commands:

    export HTTP_SERVICE_PORT=$(kubectl get --namespace keycloak -o jsonpath="{.spec.ports[?(@.name=='http')].port}" services keycloak-1738032521)
    kubectl port-forward --namespace keycloak svc/keycloak-1738032521 ${HTTP_SERVICE_PORT}:${HTTP_SERVICE_PORT} &

    echo "http://127.0.0.1:${HTTP_SERVICE_PORT}/"

2. Access Keycloak using the obtained URL.
3. Access the Administration Console using the following credentials:

  echo Username: admin
  echo Password: $(kubectl get secret --namespace keycloak keycloak-1738032521 -o jsonpath="{.data.admin-password}" | base64 -d)

WARNING: There are "resources" sections in the chart not set. Using "resourcesPreset" is not recommended for production. For production installations, please set the
 following values according to your workload needs:
  - resources
+info https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/

설치할 때, 이렇게 친절하게 사용법을 알려준다.
한번 시도해보자.
Pasted image 20250129193826.png
드디어 성공..
설치될 때 나오는 문구로는 kubectl 포트포워딩을 예시로 들어주지만, vm에 클러스터를 올리고 있으면서 도메인을 정확하게 지정해보고 싶은 나는 조금 다른 방법을 썼다.
Pasted image 20250130145150.png
현재 내 클러스터는 MetalLB로드밸런서로 활용하고 있다.
L2 레이어 모드이기에 붙어있는 인터페이스만 있다면 모든 기기가 해당 주소를 알 수 있다.
Pasted image 20250130145255.png
여기에 단순하게 호스트에서 해당 대역은 vm과 연결된 인터페이스로 빠지도록 테이블만 수정해주면 사용되고 있는 외부 ip를 통해 접근하는 것이 가능해진다.

tls 인증

쿠버네티스 인증에 키클록을 oidc로 사용하려면 https로 통신하는 것이 보장돼야 한다.
헬름 차트에서도 TLS 세팅 관련 필드가 있었는데, 나는 Gateway API를 써서 윗단에서 tls 터미네이션을 시키고 통신을 하기로 마음 먹었다.
이유는 이렇다.

일단 게아를 설치해야 하는데, T-gateway api 설치 및 간단 테스트에서 기본 설정을 진행했다.
근데 브라우저에서는 리디렉션 이슈로 http를 받을 수 없었다..
구체적으로는 https로 들어가도 http로 리디렉션되는데, 이건 키클록 내부 로직에 의한 것으로 보인다.
그래서 진정으로 tls을 하고 싶다면 키클록을 처음부터 다시 세팅해야 한다는 말이 되시겠다.

그렇지만 oidc의 discoveryurl로서는 가능할수도 있다고 생각해서 계속 진행해본다.

사용법

E-쿠버네티스 인증 실습을 위한 세팅이기도 하고, 아직 잘은 몰라서 빠르게 글을 보면서 진행한다.
Pasted image 20250129195534.png
내 realm을 먼저 만든다.
Pasted image 20250129195723.png
그 다음, 키클록 입장에서 클라이언트가 되어줄 서버 세팅을 한다.[3]

기본으로 존재하는 클라도 상당히 많은 것이 보인다.

여기에서 direct access grants가 있으면 비밀번호로 토큰을 받을 수 있다.

스코프 정의하는 부분인데, 사실 아직 내가 잘 알지는 못해서 하라는 대로 한다.
그룹에 롤을 할당하고 유저를 넣는 작업, 그리고 이걸 매핑하는 작업까지 완료했다.

그런데 왜인지 이상하게 계속 세팅이 덜 됐다고 나왔다.
하도 안 되길래 뭔가 했는데, 그냥 유저 정보를 다 안 채워둔 상태로 진행하면 세팅인 안 됐다고 뜬다.
이메일이나 이런 것 안 채워도 되게 세팅을 했는데, 그래도 이름을 안 채워서 계정을 만들게 되면 결국 세팅하지 않으면 안 되는 듯하다.
아무래도 이런 방식을 취하는 것은, 관리자의 입장에서 운영의 편의성을 더하기 위함인 것 같다.
어떤 유저를 인증해야 할지, 그 사람이 누군지 모르는 상태에서 관련한 역할과 자리를 먼저 마련하고, 나중에 실제 유저가 해당 자리를 채울 수 있게 미리 세팅을 해두는 것이다.

curl -X POST http://localhost:8889/realms/test-realm/protocol/openid-connect/token \
-d grant_type=password -d client_id=kubernetes-auth -d username=test-ua -d password="1234qwer" -d \
scope=openid -d client_secret=y4NyeVOiCkMXySD7wVSskL1htkaPekiF
| jq -r '.id_token'

이렇게 해서 나와준다면 성공이다.

클라이언트를 인증할지도 정할 수 있는데 이건 세팅을 하는 게 좋을 것 같다.

대충 진행은 하는데, 결국 클러스터 입장에서 중요한 건 발행자 url, 관련 클라이언트 정보 정도.

초기 세팅해둔 유저로 로그인하면 이런 문구가 뜬다.
이에 맞춰서 일단 세팅을 진행한다.

다시 세팅..

Pasted image 20250129195534.png
내 realm을 먼저 만든다.
Pasted image 20250129195723.png
한 realm 안에는 여러 클라이언트를 둘 수 있는데, 이 클라이언트가 각각 인증을 수행하는 큰 단위가 된다.
키클록을 통해 여러 서비스의 인증을 수행하고 싶다면 여러 클라이언트를 만드는 식으로 세팅하면 되는 것이다.
그래서 이 클라이언트를 이제 만들어준다.
기본으로 존재하는 클라도 상당히 많은 것이 보인다.

OIDC로 사용하기 위해서는 Client Authentication을 활성화해줘야 한다.
여기에서 direct access grants가 있으면 비밀번호로 토큰을 받을 수 있다.
image.png
만들어지면 바로 credential에서 client secret 값을 메모해둔다.
이 값은 나중에 이 클라이언트를 이용해 토큰을 발급받을 때 사용하게 될 것이다.
image.png
그 다음에는 바로 옆 탭 roles를 들어가 롤을 하나 만든다.
image.png
다음으로는 인증을 할 때 사용할 scope 설정이다.
상단의 kubernetes-auth-dedicated는에 설정된 모든 스코프를 포괄하는 스코프로, 실제 인증을 수행할 때 이 친구를 사용하게 된다.

일단 full scope allowed를 비활성화하여, 토큰을 받기 위해 세팅돼야 하는 스코프를 최소화해준다.
image.png
다시 scope에서 해당 기능을 비활성화한 후, mapper 부분에서 매핑을 시킬 것이다.
이 부분에서는 토큰에 어떤 것들을 넣을지 매핑을 시키는 설정을 한다.
위에서 만든 롤을 넣을 수 있도록 세팅을 해주었다.
image.png
토큰 클레임 이름은 나중에 jwt 토큰에 들어갈 이름이 된다.
image.png
다음은 유저를 하나 만든다.
여기에서 username만 필수라고 해서 다른 부분을 세팅하지 않으면 유저가 완전히 세팅되지 않았다는 에러를 보게 되므로, 미리 세팅을 해두자.
image.png
비번도 만들어준다.
image.png
이후에 위에서 만든 롤이 처음 만든 scope 속에 들어있는 것을 확인할 수 있다.
이걸 바로 붙여준다.

curl -k -X POST https://localhost/realms/test-realm/protocol/openid-connect/token \
-d grant_type=password -d client_id=kubernetes-auth -d username=zerotay -d password="1234" -d \
scope=openid -d client_secret=f4n2pYSsjOr3Epfh04ASwHPCU9tIrXXD  | jq -r '.id_token'

이렇게 해서 나와준다면 성공이다!

관련 문서

이름 noteType created
Keycloak knowledge 2025-01-27

참고


  1. https://devocean.sk.com/blog/techBoardDetail.do?ID=165131&boardType=techBlog ↩︎

  2. https://www.keycloak.org/high-availability/concepts-memory-and-cpu-sizing ↩︎

  3. https://wlsdn3004.tistory.com/62 ↩︎