본문으로 건너뛰기

RabbitMQ 키클로크 OAuth2 401

증상

RabbitMQ 관리 UI가 Keycloak으로 성공적으로 리디렉션되었지만 RabbitMQ가 로그인 직후 401 Unauthorized를 반환하는 경우(주로 /api/whoami에서) 이 가이드를 사용하세요.

이 실패 모드의 과거 신호에는 다음이 포함됩니다.

  • 브라우저가 정상적으로 Keycloak 로그인 페이지에 도달했습니다.
  • RabbitMQ로 다시 리디렉션이 성공했습니다.
  • 처음으로 인증된 관리 API 요청에서 401가 반환되었습니다.
  • RabbitMQ 로그에 user 'rabbitmq' - invalid credentials와 같은 잘못된 폴백 메시지가 표시되었습니다.

먼저 알아야 할 현재 Repo 드리프트

현재 저장소는 여전히 통합의 Keycloak 측면을 입증합니다.

  • lumie-infra/security/keycloak/common-values.yaml는 공개 rabbitmq 클라이언트를 정의합니다.
  • 동일한 파일이 rabbitmq-admin 클라이언트 범위를 정의합니다.
  • 이제 해당 범위에는 rabbitmq에 대한 oidc-audience-mapper가 포함됩니다.

현재 저장소는 RabbitMQ가 여전히 Git에서 OAuth2 백엔드를 활성화한다는 것을 증명하지 않습니다. 검사된 RabbitMQ 매니페스트는 현재 lumie-infra/platform/rabbitmq/ 아래에 렌더링된 additionalConfigauth_backends.1 = internal만 표시되며 체크인된 auth_oauth2.* 설정은 발견되지 않았습니다.

즉, 이 페이지는 기록 401에 대한 유효한 트러블슈팅 가이드로 남아 있지만 지금 디버깅하는 경우 먼저 OAuth2가 라이브 브로커 또는 현재 저장소 트리 외부의 구성 경로에서 여전히 활성화되어 있는지 확인해야 합니다.

가능한 원인

두 개의 독립적인 오류로 인해 동일한 401이 생성되었습니다.

  1. Keycloak 액세스 토큰에 aud: rabbitmq가 누락되어 RabbitMQ가 대상 확인 단계에서 토큰을 거부했습니다.
  2. Erlang TLS가 auth.lumie-edu.com에 대한 와일드카드 인증서 일치를 거부했기 때문에 RabbitMQ는 JWKS 끝점을 가져오거나 유효성을 검사할 수 없습니다.

중요한 교훈은 하나의 401이 하나의 근본 원인을 암시하지 않는다는 것입니다. 청중 매퍼를 수정하는 것만으로도 여전히 TLS 오류가 발생했습니다.

진단 경로

먼저 액세스 토큰을 디코딩합니다.

Keycloak 액세스 토큰을 검사하고 대상 클레임에 rabbitmq가 포함되어 있는지 확인하세요. 현재 저장소의 고정 Keycloak 범위는 이를 lumie-infra/security/keycloak/common-values.yaml로 표현합니다.

대표적인 형태:

{
"aud": "rabbitmq",
"azp": "rabbitmq",
"preferred_username": "bluemayne"
}

azp가 있지만 aud가 누락된 경우 RabbitMQ 대상 확인에 실패하더라도 토큰은 표면적으로는 여전히 올바르게 보일 수 있습니다.

OAuth 키워드뿐만 아니라 TLS 실패에 대한 RabbitMQ 로그 검색

원래 JWKS 오류는 다음과 같은 Erlang TLS 로그 줄로 나타났습니다.

  • bad_cert
  • hostname_check_failed
  • ssl_handshake
  • Handshake Failure

oauth 또는 whoami만 검색하는 경우 실제 브로커 측 확인 실패를 놓칠 수 있습니다.

브로커에 OAuth2가 아직 활성화되어 있는지 확인하세요.

현재 저장소에는 더 이상 체크인된 auth_oauth2.* 설정이 표시되지 않으므로 이 페이지가 올바른 수정 경로라고 가정하기 전에 라이브 브로커 구성을 확인하십시오. 라이브 구성이 내부 인증 전용인 경우 Keycloak 리디렉션 후 401이 완전히 다른 액세스 경로에서 발생할 수 있습니다.

수정

  1. lumie-infra/security/keycloak/common-values.yaml의 현재 상태인 rabbitmq에 대한 대상 매퍼로 구성된 Keycloak rabbitmq-admin 범위를 유지합니다.
  2. 라이브 브로커에서 RabbitMQ OAuth2가 여전히 활성화되어 있는 경우 auth.lumie-edu.com에 필요한 와일드카드 호스트 이름 일치를 허용하도록 HTTPS JWKS 클라이언트를 구성합니다.

대표적인 형태:

auth_oauth2.resource_server_id = rabbitmq
auth_oauth2.issuer = https://auth.lumie-edu.com/realms/infra
auth_oauth2.https.hostname_verification = wildcard
  1. 대상 클레임과 TLS 경로가 모두 확인된 후에만 유효한 전달자 토큰을 사용하여 /api/whoami를 다시 테스트합니다.

예방

  • 최초 SSO 출시 중에 RabbitMQ OAuth2 401을 잠재적인 다중 원인으로 처리합니다.
  • Erlang 기반 서비스 디버깅 시 TLS 로그를 애플리케이션 수준 OAuth 로그와 별도로 검색합니다.
  • 와일드카드 인증서가 Go, Java, Python 및 Erlang TLS 스택에서 동일하게 작동한다고 가정하지 마십시오.
  • Keycloak 클라이언트 범위 계약을 명시적으로 유지하세요. RabbitMQ의 경우 azp만으로는 충분하지 않습니다. aud에는 리소스 서버 식별자가 포함되어야 합니다.

확인

cd Lumie
rg -n "rabbitmq-admin|oidc-audience-mapper|included.custom.audience|clientId\": \"rabbitmq\"" \
lumie-infra/security/keycloak/common-values.yaml
rg -n "auth_oauth2|rabbitmq_auth_backend_oauth2|hostname_verification" \
lumie-infra/platform/rabbitmq

성공은 Keycloak 대상 매퍼가 여전히 Git에 선언되어 있음을 의미합니다. 두 번째 명령은 RabbitMQ OAuth2 브로커 설정이 저장소에서 확인 가능한지, 아니면 라이브 배포에서 직접 확인해야 하는지 알려줍니다.

원본 사고 세부사항

2026년 4월 11일 원본 사고는 Keycloak SSO rollout 중 RabbitMQ에 해당하는 부분을 기록합니다. RabbitMQ management UI의 401은 하나의 bug가 아니었습니다. OAuth2 claim, audience, TLS, broker setting mismatch가 이어진 결과였습니다.

세부사항
영향 componentRabbitMQ management OAuth2 login
Identity providerKeycloak infra realm
주요 증상Keycloak authentication이 성공한 것처럼 보여도 login이 401을 반환했습니다
지속 수정 방향명시적인 RabbitMQ audience와 dedicated authorization claim
중요한 함정RabbitMQ/Erlang TLS log와 OAuth log를 따로 봐야 합니다

원본 기록에서 가장 재사용 가치가 큰 root cause는 다음입니다.

원인401이 된 이유
RabbitMQ용 aud 누락broker가 token audience에 자신이 있다고 보지 못했습니다
azp에만 의존authorized party는 resource-server audience와 다릅니다
scope를 무리하게 사용Keycloak은 token 생성 후반에 최종 OAuth scope를 재구성합니다
wildcard TLS behaviorErlang TLS verification이 다른 client stack에서의 가정과 달랐습니다
broker config visibility 부족일부 설정은 Git뿐 아니라 live deployment에서 확인해야 했습니다

재현할 때는 token 자체를 증거로 보존합니다. Broker config를 바꾸기 전에 aud, azp, scope, custom claim을 decode합니다.