본문으로 건너뛰기

Keycloak OIDC SSO 여정

증상

Keycloak OIDC에 인프라 서비스를 온보딩하고 다음 오류 클래스 중 하나에 도달할 때 이 가이드를 사용하세요.

  • OAuth 콜백 중 invalid_client
  • 표준 OIDC 범위용 invalid_scope
  • 영역 동기화가 성공했지만 비밀은 해결되지 않은 자리 표시자로 남아 있습니다.
  • RabbitMQ 로그인이 부분적으로 작동하지만 대상자, TLS 또는 관리 역할 확인에서 실패합니다.
  • 서비스가 기술적으로 OIDC를 지원하지만 운영 비용이 가치보다 높습니다.

현재 저장소가 Keycloak GitOps에서 기대하는 것

체크인된 계약은 이제 kc.sh import --override가 아닌 keycloak-config-cli를 기반으로 합니다.

  • lumie-infra/security/keycloak/common-values.yaml
  • lumie-infra/security/keycloak/manifests/realm-sync-job.yaml

현재 영역 동기화 작업은 디자인을 직접 설명합니다.

# kc.sh import writes directly to the DB and bypasses Keycloak's
# realm-creation hooks, so it never creates default scopes.
#
# keycloak-config-cli substitutes secrets on the CLIENT side before
# calling REST, so the DB always contains real values.

출처: lumie-infra/security/keycloak/manifests/realm-sync-job.yaml

현재 infra 영역 정의는 RabbitMQ에 대한 사용자 지정 permissions 클레임 및 명시적인 groups 지원을 포함하여 롤아웃에서 살아남은 클라이언트 범위 결정도 유지합니다.

  • lumie-infra/security/keycloak/common-values.yaml

대부분의 실패를 해결한 아키텍처 결정

2026년 4월 11일 출시는 도구를 전환한 후에야 안정화되었습니다.

  • kc.sh import --override는 일회성 가져오기에는 유용했지만 영역 생성 후크를 우회하고 클라이언트 비밀 자리 표시자 처리를 잘못된 위치에 두었습니다.
  • keycloak-config-cli는 클라이언트 측 대체 및 멱등성 REST 동기화를 수행하여 GitOps와 훨씬 더 잘 일치합니다.

단일 도구 변경으로 여러 가지 초기 증상이 동시에 설명되었습니다.

  • profileemail와 같은 기본 범위가 누락되었습니다.
  • 문자 그대로 데이터베이스에 저장된 해결되지 않은 ${KEY} 자리 표시자
  • 다시 가져올 때마다 수동 수정 사항이 반복적으로 손실됨

롤아웃에서 알려진 실패 클래스

실패 등급의미지속적인 수정
invalid_client저장된 클라이언트 비밀은 확인된 비밀이 아닌 문자 그대로의 자리 표시자였습니다keycloak-oauth-secrets에서 ${KEY} 대체와 함께 keycloak-config-cli 사용
표준 스코프용 invalid_scope일반 Keycloak 영역 생성 후크 없이 영역을 가져왔습니다REST 지원 동기화 작업을 통해 영역 관리
엄격한 클라이언트 범위 오류openid는 실제로 OIDC 프로토콜 마커일 때 Keycloak 클라이언트 범위 개체처럼 처리되었습니다. defaultClientScopes 목록에서 openid를 제거
RabbitMQ 대상 실패Keycloak이 rabbitmqaud에 자동으로 추가하지 않았습니다.명시적인 잠재고객 매퍼 사용
RabbitMQ 관리 역할 실패scope는 예약되었으며 Keycloak에 의해 재구축되었습니다대신 커스텀 permissions 클레임을 내보냅니다
서비스별 막다른 골목헤드램프와 MinIO는 모두 알려져 있지만 비용이 많이 드는 후속 작업값이 변경되지 않는 한 의도적인 비통합으로 유지

현재 저장소가 여전히 증명하는 것

검사된 저장소는 출시의 성공적인 부분을 보존합니다.

  • infra 영역에는 Coder, Vault, Zot 및 RabbitMQ에 대한 저장소 관리 클라이언트가 포함되어 있습니다.
  • RabbitMQ 범위 디자인은 이제 scope를 오버로드하는 대신 permissions를 사용합니다.
  • 영역 동기화 작업은 클라이언트 측에서 자리 표시자 대체가 발생해야 하는 이유를 문서화합니다.
  • Vault에는 lumie-infra/bootstrap/vault/OIDC-SETUP.md에 문서화된 영역 동기화 후에도 여전히 런타임 OIDC 설정 단계가 필요합니다.

또한 두 가지 중요한 경계를 유지합니다.

  • 헤드램프는 lumie-infra/applications/kustomization.yaml의 활성 앱 그래프의 일부가 아닙니다.
  • 리포지토리는 여기에 남아 있는 MinIO OIDC 계약을 문서화하지 않습니다. 이는 장기 통합이 부족하여 중단하기로 한 결정과 일치합니다.

다음 통합을 위한 문제 해결 경로

  1. Keycloak 클라이언트를 생성하기 전에 서비스가 기밀 클라이언트인지 공개 클라이언트인지 확인하세요.
  2. 해당 영역이 DB 가져오기 바로가기가 아닌 keycloak-config-cli에 의해 적용되고 있는지 확인합니다.
  3. 서비스에 ID 토큰, 액세스 토큰 또는 둘 모두에 대한 클레임이 필요한지 확인하십시오.
  4. 서비스가 RabbitMQ와 유사한 경우 인증을 scope로 인코딩하는 대신 전용 클레임을 설계합니다.
  5. 통합에 클러스터 전체 인증 모델 변경이 필요하거나 더 이상 사용되지 않는 업스트림 콘솔 경로에 의존하는 경우 SSO 값이 해당 비용을 정당화하는지 명시적으로 결정합니다.

확인

cd Lumie
rg -n "keycloak-config-cli|IMPORT_VAR_SUBSTITUTION|kc.sh import|invalid_client" \
lumie-infra/security/keycloak/manifests/realm-sync-job.yaml \
lumie-infra/security/keycloak/helm-values.yaml
rg -n "permissions|rabbitmq|defaultClientScopes|clientId" \
lumie-infra/security/keycloak/common-values.yaml
kubectl get job -n keycloak keycloak-realm-sync
kubectl logs -n keycloak job/keycloak-realm-sync --tail=200

성공은 저장소가 여전히 REST 기반 영역 동기화 경로를 사용하고, 영역 정의가 여전히 RabbitMQ 관련 클레임 디자인을 전달하고, 최신 동기화 작업이 자리 표시자 또는 범위 오류 없이 수렴됨을 의미합니다.

원본 사고 세부사항

2026년 4월 11일 원본 기록은 장애가 아니라 하루짜리 SSO 통합 회고입니다. 아키텍처 결정은 Teleport Community Edition을 SSO hub로 보지 않고, 각 서비스를 Keycloak OIDC client로 등록하는 것이었습니다.

세부사항
범위Coder, Vault, Zot, Headlamp, RabbitMQ, MinIO
성공한 경로Coder, Vault, RabbitMQ, Coder-to-Zot chain
의도적으로 보류한 경로Headlamp, MinIO
가장 중요한 도구 결정kc.sh import --overridekeycloak-config-cli로 교체
RabbitMQ 주요 교훈scope를 무리하게 쓰지 말고 permissions 같은 dedicated authorization claim을 둡니다

Rollout은 11개의 벽을 드러냈습니다. 향후 통합에 보존할 가치가 있는 것은 다음입니다.

실패 유형중요했던 이유
file-vault placeholder 한계Keycloak은 일부 config field는 resolve하지만 모든 OAuth secret 비교 경로를 처리하지 못합니다
kc.sh import --overridereimport가 manual change를 지워 GitOps를 불안정하게 만들었습니다
client secret substitutionresolve되지 않은 placeholder가 misleading invalid_client 실패를 만들었습니다
standard scope 생성Service integration이 기대한 claim이 아직 없었습니다
RabbitMQ audienceazp만으로는 broker resource-server check에 충분하지 않았습니다
RabbitMQ TLSErlang TLS behavior가 다른 stack에서의 가정과 달랐습니다
reserved scope behaviorprotocol mapper가 최종 OAuth scope를 안전하게 덮을 수 없었습니다
Headlamp / K3s OIDC해결하려면 cluster auth-model 변경이 필요했습니다
MinIO console / STS당시에는 복잡도 대비 가치가 낮았습니다

지속 운영 규칙은 어떤 서비스를 통합하지 않을지도 명시적으로 결정하는 것입니다. Headlamp와 MinIO는 잊힌 것이 아니라, root cause가 이해됐고 비용/가치 판단상 당시 완료하지 않은 것입니다.