Keycloak 클라이언트 하나만 Google 로그인 전용으로
Sentry 로그인 화면에는 Google 버튼과 아이디·비밀번호 폼이 같이 떴다. 목표는 폼을 없애고 Google 로그인만 남기는 것. 폼만 지우면 될 줄 알았는데 로그인이 깨졌고, 대신 넣은 redirector는 아무 일도 하지 않고 지나갔다. 네 번 만에 붙였다.
CSRF 6단계 편에서 Sentry에 Keycloak SSO를 붙였고, 권한 편에서 Sentry 쪽 권한을 좁혔다. 이번엔 Keycloak 쪽에서 로그인 흐름 자체를 좁힌 이야기다.
(사내 인프라 특성상 realm·도메인은 일반화했다.)
무엇을 바꾸려 했나
Sentry는 사내 Keycloak realm에 OIDC 클라이언트로 붙어 있다. 로그인 화면에 들어가면 위쪽에 “Sign in with Google” 버튼이, 아래쪽에 아이디·비밀번호 폼이 같이 나왔다.
바라는 모습은 단순했다. 폼은 없애고, 로그인 화면에 들어오는 순간 곧바로 Google 로그인으로 넘어가게.
Keycloak의 로그인 흐름(flow) 짧게
Keycloak에서 로그인 과정은 여러 단계(authenticator)를 이어 붙인 flow로 정의된다. 브라우저 로그인에 쓰는 기본 browser flow는 대략 이렇게 생겼다.
Cookie ← 이미 로그인한 세션이 있으면 통과
Identity Provider Redirector ← Google 같은 외부 IdP로 보내는 단계
Forms
├ Username Password Form ← 아이디·비밀번호 폼
└ OTP Form
각 단계에는 REQUIRED / ALTERNATIVE / DISABLED / CONDITIONAL 중 하나의 요구 조건이 붙는다. ALTERNATIVE는 “여럿 중 하나만 성공하면 된다”는 뜻이라, SSO 버튼과 폼이 나란히 뜨는 기본 화면이 여기서 나온다.
할 일은 이 flow에서 폼을 걷어내고 redirector만 남기는 것이었다. 다만 realm의 기본 flow를 직접 고치면 같은 realm에 붙은 다른 클라이언트까지 함께 바뀐다. 이 판단은 마지막에 다시 나온다.
네 번 만에
[1차] 폼을 지웠더니 로그인이 깨졌다
flow 편집 화면에서 Username Password Form을 Delete했다. 로그인 화면에 이런 에러가 떴다.
We are sorry... Invalid username or password.
아이디도 비밀번호도 넣지 않았는데 나온 에러다. 폼이 사라진 자리를 대신해 Google로 보내 줄 경로가 동작하지 않으니, 갈 곳 없이 실패로 끝난 것이다. 단계를 지운다고 그 자리가 다른 경로로 저절로 채워지지는 않는다.
[2차] redirector에 Alias만 채웠더니 그냥 지나갔다
Identity Provider Redirector 설정(Config)을 열어 Alias에 google을 넣었다. 기대한 건 로그인 화면에 들어오자마자 Google로 넘어가는 것이었다.
실제로는 redirector가 아무 일도 하지 않고 다음 단계로 지나갔다. 화면은 여전히 폼이거나, 폼을 지운 상태라면 1차와 같은 실패였다.
[3차] Default Identity Provider는 별개 칸이었다
설정 화면을 다시 열어 칸을 하나씩 짚었다. Alias 바로 아래에 Default Identity Provider라는 칸이 따로 있었다. 이름도 비슷하고 붙어 있어서 같은 값을 다르게 부르는 줄 알았다.
Alias— 이 설정 묶음의 이름Default Identity Provider— 실제로 어느 IdP로 보낼지
Alias만 채운 redirector는 “내 이름은 google”일 뿐 어디로 보낼지는 모르는 상태다. 그래서 아무것도 하지 않고 지나갔다. Default Identity Provider에도 google을 넣자, 로그인 화면에 들어오는 순간 Google 로그인으로 넘어갔다.
[4차] realm 전체가 아니라 Sentry에만
flow는 완성됐다. 그런데 이걸 realm의 기본 browser flow로 지정하면, 같은 realm에 붙은 다른 클라이언트도 전부 Google 전용이 된다. 관리 화면 로그인까지 Google로만 되면, Google 쪽에 문제가 생겼을 때 들어가서 고칠 길이 막힐 수 있다.
그래서 원본은 그대로 두고 복제본을 만들어, 그 복제본을 Sentry 클라이언트에만 붙였다. 폼은 Disable이 아니라 Delete로 걷어냈다. Disable만 해 두면 redirector가 실패했을 때 그 폼으로 다시 넘어가기 때문이다.
Authentication → browser flow → Duplicate → 복제본 이름 "Browser Google Only"
복제본 편집
- Cookie (ALTERNATIVE)
- Identity Provider Redirector (ALTERNATIVE)
Config: Alias = google
Default Identity Provider = google ← 둘 다 채운다
- Forms 아래 단계 전부 Delete
(Username Password Form, Registration, Reset Password 등 — Disable 아님)
Clients → sentry → Authentication Flow Overrides → Browser Flow = "Browser Google Only"
다른 클라이언트는 원본 browser flow를 그대로 쓴다. 실수가 번질 수 있는 범위가 Sentry 클라이언트 하나로 줄었다.
마치며
폼 하나를 지우는 일이라고 생각했는데, 실제로 고친 건 칸 하나와 적용 범위였다.
진짜로 배운 것
- 나란히 붙은 칸이 한 세트라는 보장은 없다.
Alias와Default Identity Provider는 이름도 위치도 붙어 있지만 하는 일이 다르다. CSRF 편에서 왼쪽 위 realm 드롭다운을 못 보고 엉뚱한 realm을 고쳤던 것과 같은 결이다. Keycloak 관리 화면은 칸과 화면 사이의 관계를 잘 드러내지 않으니, 칸마다 역할을 따로 확인한다. - 끄기(Disable)와 지우기(Delete)는 다르다. flow에서는 꺼 둔 단계가 다른 길이 막혔을 때 다시 나타날 수 있다. 완전히 없애야 할 단계는 지운다.
- 바꾸는 범위는 가장 작은 단위로. realm 전체 대신 복제본을 만들어 클라이언트 하나에만 붙였다. 권한 편의 “권한은 최소 범위로 준다”와 같은 방향이다.
참고 — Keycloak 공식 문서: Authentication flows · Default Identity Provider