Keycloak

총 15개의 글

Keycloak 인증이 실제로 동작하는 전체 흐름: 세션, 토큰, 쿠키 구조 완전 해부

Keycloak을 Kubernetes, ALB, oauth2-proxy, NGINX Ingress 같은 환경에 붙이다 보면 처음에는 단순히 “로그인 화면이 뜨는지”만 확인하게 됩니다. 하지만 실무에서 문제가 터지는 지점은 대부분 로그인 화면이 아니라 그 이후입니다.예를 들면 다음과 같은 문제가 자주 발생합니다.로그인은 성공했는데 다시 로그인 페이지로 돌아간다.Access Token은 살아 있는데 애플리케이션 세션은 끊겼다.Refresh Token이 만료되어 갑자기 401이 발생한다.브라우저 쿠키를 지웠더니 Keycloak 로그인 상태도 풀린다.로그아웃했는데 다른 서비스에서는 여전히 로그인된 것처럼 보인다.이 글에서는 Keycloak 인증이 실제로 어떻게 동작하는지 세션, 토큰, 쿠키 관점에서 끝까지 분해..

Keycloak Redirect URI 오류 해결 방법 (invalid_redirect_uri 완전 정리)

👉 Keycloak에서 invalid_redirect_uri 오류는 왜 발생할까?Keycloak을 OIDC, oauth2-proxy, ALB OIDC, Spring Security, Grafana와 연동할 때 가장 자주 만나는 오류가 있습니다.바로 invalid_redirect_uri 오류입니다.👉 이 오류는 대부분 “Keycloak에 등록된 Redirect URI”와 “실제 요청에 포함된 redirect_uri”가 다를 때 발생합니다.1. Redirect URI란 무엇인가Redirect URI는 로그인 성공 후 Keycloak이 사용자를 다시 돌려보낼 주소입니다.사용자 → App 접속App → Keycloak 로그인 페이지로 이동Keycloak 로그인 성공Keycloak → Redirect URI로..

Keycloak Audience Mapper 설정 방법 (invalid_token / audience mismatch 해결)

👉 Keycloak 로그인은 성공했는데 왜 invalid_token이 발생할까?Keycloak을 oauth2-proxy, ALB OIDC, API Gateway, 백엔드 API와 연동하다 보면 로그인은 성공했는데 실제 서비스 접근 단계에서 실패하는 경우가 있습니다.이때 자주 만나는 원인이 바로 Audience mismatch입니다.👉 인증은 성공했지만, 토큰의 대상(audience)이 맞지 않으면 서비스는 해당 토큰을 신뢰하지 않을 수 있습니다.1. Audience란 무엇인가Audience는 JWT 토큰의 aud claim에 들어가는 값입니다. 이 값은 “이 토큰이 누구를 위해 발급되었는가”를 의미합니다.User → Keycloak → Access Token 발급 ↓ aud ..

ALB OIDC만으로 Keycloak 붙이는 방법 (oauth2-proxy 없이)

👉 oauth2-proxy 없이 ALB만으로 Keycloak 인증을 붙일 수 있을까?가능합니다. AWS Application Load Balancer는 OIDC 인증 기능을 제공하므로, Keycloak이 OIDC Provider로 동작한다면 ALB에서 직접 인증을 처리할 수 있습니다.이 글에서는 oauth2-proxy 없이 ALB OIDC 기능만 사용해서 Keycloak 인증을 구성하는 방법을 정리합니다.👉 단순 로그인 보호가 목적이라면 oauth2-proxy 없이 ALB OIDC만으로도 구성할 수 있습니다.1. 전체 인증 구조Client → ALB → App ↳ ALB가 Keycloak OIDC 인증 처리이 구조에서는 oauth2-proxy가 없습니다. 사용자가 App에 접근하면 ALB..

ALB OIDC vs oauth2-proxy 차이점 (Keycloak 인증 구조 비교)

👉 ALB OIDC랑 oauth2-proxy, 둘 중 어떤 구조를 써야 할까?Keycloak 기반 인증을 Kubernetes에 붙일 때 가장 많이 고민하는 것이 바로 이 두 가지입니다.👉 ALB OIDC와 oauth2-proxy는 같은 기능이 아니라 “완전히 다른 아키텍처”다1. 전체 구조 비교ALB OIDC 방식Client → ALB → App ↳ ALB가 Keycloak OIDC 인증 처리oauth2-proxy 방식Client → ALB → oauth2-proxy → App ↓ Keycloak OIDC👉 ALB 방식은 “LB가 인증”, oauth2-proxy는 “애플리케이션 레벨 인증”2. 핵심 차이항목ALB OIDCoauth2-proxy인증 주체ALBoauth2-proxy구성 난이도낮음중간확장..

Keycloak + oauth2-proxy 설정 방법 (Kubernetes + ALB 완전 가이드)

👉 Kubernetes에서 Keycloak + oauth2-proxy + ALB 인증은 어떻게 구성해야 할까?이 글은 Keycloak과 oauth2-proxy를 Kubernetes 환경에서 실제로 연결하는 설정 가이드입니다.다만 먼저 구분해야 할 것이 있습니다. ALB는 Keycloak과 직접 OIDC 인증을 처리할 수도 있고, oauth2-proxy를 앞단 인증 프록시로 둘 수도 있습니다.👉 단순히 ALB에서 Keycloak OIDC 인증만 처리할 경우 oauth2-proxy는 필요 없습니다. 이 글은 ALB 직접 OIDC 방식이 아니라, oauth2-proxy를 인증 프록시로 사용하는 Kubernetes 구조를 설명합니다.1. 먼저 구분해야 하는 두 가지 인증 구조패턴 1: ALB가 Keycloa..

Keycloak 로그인 안될 때 해결 방법 (에러별 원인 정리)

👉 Keycloak 로그인은 되는데, 왜 계속 실패할까?Keycloak 인증 문제는 대부분 설정 오류에서 발생합니다. 특히 Redirect URI, Client 설정, Token 검증에서 문제가 자주 발생합니다.👉 Keycloak 장애의 90%는 설정 문제다1. 가장 먼저 확인해야 할 것Redirect URIClient SecretIssuer URLToken 구조👉 이 4개만 확인해도 대부분 해결된다2. invalid_redirect_uri 오류invalid_redirect_uri원인URI 불일치http / https 다름포트 누락trailing slash 문제해결 방법Keycloak Client 설정과 완전히 동일하게 맞춘다👉 한 글자라도 다르면 인증 실패3. invalid_client 오류in..

Keycloak OIDC 설정 방법 (로그인 안될 때 해결 포함)

👉 Keycloak 설정했는데 로그인 안 되는 이유는 무엇일까?Keycloak을 처음 설정할 때 대부분 OIDC(OpenID Connect) 구성에서 막힙니다. Client 설정, Redirect URI, Token 구조 중 하나라도 틀리면 인증은 실패합니다.👉 Keycloak 문제의 대부분은 “설정 + 흐름 이해 부족”1. OIDC 인증 흐름 (중요)1. Client → Keycloak (/authorize)2. 사용자 로그인3. Authorization Code 발급4. Client → Keycloak (/token)5. Access Token / ID Token 발급👉 Keycloak은 “Authorization Code Flow” 기반2. Keycloak Client 설정 핵심① 기본 설정..

Keycloak 사용자 관리 API 사용 방법 (조회/생성)

Keycloak이란 무엇인가Keycloak은 인증(Authentication)과 권한 부여(Authorization)를 담당하는 서버입니다. 왜 Keycloak을 사용하는가직접 인증을 구현하면:보안 취약점 발생 가능토큰 관리 복잡 Keycloak 사용자 관리 APIKeycloak에서 사용자 생성, 조회, 변경, 삭제는 Admin REST API를 사용합니다.일반 로그인 API가 아니라, 관리자 권한을 가진 토큰이 필요합니다. Keycloak 공식 Admin REST API는 사용자 생성 POST /{realm}/users, 사용자 조회 GET /{realm}/users, 사용자 수 조회 GET /{realm}/users/count 등을 제공합니다. 1. Admin Token 발급사용자 관리 API를 ..

[Kubernetes] Keycloak + oauth2-proxy + Ingress 인증 구성 방법 (OIDC 연동)

이 구조를 왜 쓰는가보통 서비스에 로그인 기능을 넣으려면:로그인 API 개발세션 관리토큰 검증이걸 서비스마다 반복해야 합니다.이 구조는 다르게 접근합니다.로그인은 Keycloak이 담당인증 체크는 oauth2-proxy가 담당서비스는 인증 여부만 전달받음즉, 애플리케이션은 인증 로직을 몰라도 됩니다.전체 흐름 사용자가 서비스 접속Ingress가 oauth2-proxy로 요청 전달인증 안 되어 있으면 Keycloak으로 리다이렉트로그인 성공 후 다시 돌아옴 (/oauth2/callback)oauth2-proxy가 쿠키 생성이후 요청은 인증된 상태로 서비스 전달브라우저 쿠키 기반 인증 유지 구성방법1. Keycloak 설정 Client 생성Client ID: my-clientClient Protocol: o..

Keycloak 인증이 실제로 동작하는 전체 흐름: 세션, 토큰, 쿠키 구조 완전 해부

Keycloak을 Kubernetes, ALB, oauth2-proxy, NGINX Ingress 같은 환경에 붙이다 보면 처음에는 단순히 “로그인 화면이 뜨는지”만 확인하게 됩니다. 하지만 실무에서 문제가 터지는 지점은 대부분 로그인 화면이 아니라 그 이후입니다.

예를 들면 다음과 같은 문제가 자주 발생합니다.

  • 로그인은 성공했는데 다시 로그인 페이지로 돌아간다.
  • Access Token은 살아 있는데 애플리케이션 세션은 끊겼다.
  • Refresh Token이 만료되어 갑자기 401이 발생한다.
  • 브라우저 쿠키를 지웠더니 Keycloak 로그인 상태도 풀린다.
  • 로그아웃했는데 다른 서비스에서는 여전히 로그인된 것처럼 보인다.

이 글에서는 Keycloak 인증이 실제로 어떻게 동작하는지 세션, 토큰, 쿠키 관점에서 끝까지 분해해봅니다. 단순 설정값 설명이 아니라 브라우저, 애플리케이션, Keycloak 사이에서 어떤 데이터가 오가는지 기준으로 설명합니다.


1. 먼저 구분해야 할 것: 인증과 인가

Keycloak을 이해하려면 먼저 인증(Authentication)과 인가(Authorization)를 분리해야 합니다.

구분 의미 예시
인증 사용자가 누구인지 확인 아이디/비밀번호, OTP, SSO 로그인
인가 사용자가 무엇을 할 수 있는지 판단 admin 역할만 관리자 API 접근 가능

Keycloak은 사용자를 인증하고, 인증 결과를 토큰으로 발급합니다. 애플리케이션은 이 토큰을 보고 “이 사용자가 누구인지”, “어떤 권한을 가지고 있는지”를 판단합니다.

즉 Keycloak은 일반적으로 다음 역할을 합니다.

  • 사용자 로그인 처리
  • SSO 세션 관리
  • ID Token, Access Token, Refresh Token 발급
  • 클라이언트별 세션 관리
  • 로그아웃 및 세션 종료 처리

2. Keycloak 인증 구조의 주요 구성요소

2.1 Browser

브라우저는 사용자가 접근하는 클라이언트입니다. 브라우저는 직접 토큰을 다루기도 하고, 경우에 따라 애플리케이션 서버나 oauth2-proxy가 토큰을 대신 보관하기도 합니다.

중요한 점은 브라우저가 항상 쿠키를 중심으로 상태를 유지한다는 것입니다. 브라우저는 요청할 때 도메인에 맞는 쿠키를 자동으로 전송합니다.

2.2 Application

애플리케이션은 실제 서비스를 제공하는 서버입니다. Spring Boot, Node.js, React + Backend API, Grafana, Argo CD 같은 서비스가 여기에 해당합니다.

애플리케이션은 직접 Keycloak과 OIDC 연동을 할 수도 있고, 앞단에 oauth2-proxy나 ALB OIDC를 두고 인증을 위임할 수도 있습니다.

2.3 Keycloak

Keycloak은 Identity Provider이자 OpenID Provider입니다. 사용자 인증을 수행하고, 인증 결과로 토큰을 발급합니다.

Keycloak은 단순히 로그인 화면만 제공하는 것이 아니라, 사용자 세션과 클라이언트 세션을 함께 관리합니다.

2.4 Client

Keycloak에서 말하는 Client는 애플리케이션을 의미합니다. 예를 들어 다음과 같은 단위가 모두 Client가 될 수 있습니다.

  • grafana-client
  • argocd-client
  • spring-api-client
  • oauth2-proxy-client
  • alb-oidc-client

Client에는 redirect URI, client secret, allowed scope, token lifespan 같은 설정이 연결됩니다. 실무에서는 이 Client 설정이 틀려서 인증 오류가 발생하는 경우가 매우 많습니다.


3. Keycloak 인증의 기본 흐름

가장 일반적인 웹 로그인 방식은 Authorization Code Flow입니다. 이 방식에서는 브라우저가 바로 토큰을 받지 않습니다. 먼저 authorization code를 받고, 애플리케이션 또는 프록시가 그 code를 Keycloak의 Token Endpoint로 교환합니다.

[1] 사용자 → 애플리케이션 접속
[2] 애플리케이션 → 인증 필요 판단
[3] 브라우저 → Keycloak 로그인 페이지로 리다이렉트
[4] 사용자 → Keycloak에서 로그인
[5] Keycloak → authorization code 발급
[6] 브라우저 → redirect_uri로 code 전달
[7] 애플리케이션 또는 프록시 → code를 token endpoint로 교환
[8] Keycloak → ID Token, Access Token, Refresh Token 발급
[9] 애플리케이션 또는 프록시 → 자체 세션 쿠키 생성
[10] 사용자 → 로그인된 상태로 서비스 이용

여기서 핵심은 브라우저가 처음부터 Access Token을 들고 다니는 구조가 아닐 수 있다는 점입니다. 서버사이드 웹 애플리케이션이나 oauth2-proxy 구조에서는 토큰을 서버 또는 프록시가 관리하고, 브라우저는 세션 쿠키만 들고 다니는 경우가 많습니다.


4. 토큰 3종류: ID Token, Access Token, Refresh Token

4.1 ID Token

ID Token은 사용자의 신원을 나타내는 토큰입니다. 즉 “이 사용자가 누구인가?”에 대한 정보를 담습니다.

보통 다음과 같은 claim이 들어갑니다.

  • sub: 사용자 고유 식별자
  • preferred_username: 사용자 이름
  • email: 이메일
  • name: 표시 이름
  • iss: 토큰 발급자
  • aud: 토큰 대상 클라이언트
  • exp: 만료 시간

ID Token은 주로 로그인 결과 확인과 사용자 프로필 확인에 사용합니다. API 권한 검사용으로 Access Token 대신 ID Token을 사용하는 것은 적절하지 않습니다.

4.2 Access Token

Access Token은 API 접근 권한을 나타내는 토큰입니다. 즉 “이 사용자가 어떤 리소스에 접근할 수 있는가?”에 더 가깝습니다.

API 서버는 Access Token을 검증해서 요청을 허용하거나 거부합니다. Keycloak Access Token에는 realm role, client role, scope 같은 권한 정보가 포함될 수 있습니다.

Authorization: Bearer eyJhbGciOiJSUzI1NiIs...

일반적으로 Access Token은 짧게 유지하는 것이 좋습니다. 탈취되었을 때 피해 시간을 줄이기 위해서입니다.

4.3 Refresh Token

Refresh Token은 Access Token을 재발급받기 위한 토큰입니다. Access Token이 만료될 때마다 사용자가 다시 로그인하면 사용성이 매우 나빠지기 때문에 Refresh Token을 사용합니다.

Access Token 만료
→ Refresh Token으로 Keycloak에 새 Access Token 요청
→ 새 Access Token 발급
→ 사용자는 재로그인 없이 계속 서비스 이용

단, Refresh Token은 Access Token보다 훨씬 민감합니다. Refresh Token이 탈취되면 공격자가 새 Access Token을 계속 발급받을 수 있기 때문입니다. 따라서 브라우저 로컬 스토리지에 Refresh Token을 직접 저장하는 구조는 신중해야 합니다.


5. 세션은 하나가 아니다

Keycloak 인증에서 가장 많이 헷갈리는 부분이 세션입니다. 세션은 하나가 아니라 여러 계층에 존재합니다.

세션 종류 관리 주체 역할
Keycloak SSO Session Keycloak 사용자가 Keycloak에 로그인되어 있는 상태
Client Session Keycloak 특정 Client에 로그인된 상태
Application Session 애플리케이션 서비스 내부 로그인 상태
Proxy Session oauth2-proxy 등 프록시가 인증 결과를 유지하는 상태
Browser Cookie 브라우저 요청마다 인증 상태를 전달하는 저장소

따라서 “로그아웃이 안 된다”는 말은 정확하지 않습니다. 어느 세션이 살아 있는지 확인해야 합니다.

  • Keycloak SSO 세션이 살아 있는가?
  • 애플리케이션 자체 세션이 살아 있는가?
  • oauth2-proxy 세션 쿠키가 살아 있는가?
  • 브라우저에 Keycloak 쿠키가 남아 있는가?
  • Refresh Token이 아직 유효한가?

6. Keycloak SSO Session

Keycloak SSO Session은 사용자가 Keycloak Realm에 로그인한 상태를 의미합니다. 한 번 Keycloak에 로그인하면 같은 Realm에 연결된 다른 Client에 접근할 때 다시 로그인하지 않아도 되는 이유가 바로 이 SSO Session 때문입니다.

사용자 → Grafana 로그인
→ Keycloak SSO Session 생성

사용자 → Argo CD 접속
→ 같은 Realm의 Keycloak SSO Session 확인
→ 비밀번호 재입력 없이 인증 완료

이것이 SSO의 핵심입니다. 각 애플리케이션이 독립적으로 로그인 정보를 저장하는 것이 아니라, Keycloak이 중앙에서 로그인 상태를 관리합니다.

SSO Session Idle

SSO Session Idle은 사용자가 아무 활동을 하지 않았을 때 세션이 만료되는 시간입니다. 예를 들어 30분으로 설정하면, 일정 시간 동안 갱신 활동이 없을 때 세션이 만료됩니다.

SSO Session Max

SSO Session Max는 사용자가 계속 활동하더라도 세션이 유지될 수 있는 최대 시간입니다. 예를 들어 10시간으로 설정하면 사용자가 계속 서비스를 사용하더라도 10시간 이후에는 다시 인증이 필요할 수 있습니다.

실무에서는 Idle과 Max를 함께 봐야 합니다. Idle만 길게 잡으면 보안 위험이 커지고, Max만 짧게 잡으면 사용자가 업무 중 자주 재로그인하게 됩니다.


7. Client Session

Client Session은 특정 Client에 대한 로그인 상태입니다. Keycloak SSO Session이 “사용자가 Realm에 로그인되어 있다”는 의미라면, Client Session은 “이 사용자가 특정 애플리케이션에도 로그인되어 있다”는 의미입니다.

Keycloak SSO Session
 ├── grafana-client session
 ├── argocd-client session
 └── spring-api-client session

이 구조 때문에 하나의 사용자가 여러 애플리케이션에 로그인할 수 있습니다. 또한 특정 Client만 세션을 종료하거나, 전체 SSO 세션을 종료하는 식의 처리가 가능해집니다.


8. 쿠키는 어디에 쓰이는가?

브라우저 기반 인증에서 쿠키는 매우 중요합니다. 토큰이 아무리 중요해도 브라우저가 매 요청마다 상태를 기억하려면 결국 쿠키가 개입하는 경우가 많습니다.

8.1 Keycloak 도메인의 쿠키

Keycloak은 로그인 과정에서 자신의 도메인에 쿠키를 설정합니다. 이 쿠키는 사용자가 Keycloak에 이미 로그인되어 있는지 확인하는 데 사용됩니다.

auth.example.com
 └── Keycloak 관련 쿠키

사용자가 다른 애플리케이션으로 이동해도 다시 Keycloak으로 리다이렉트되면, Keycloak은 자신의 쿠키를 보고 기존 SSO Session을 확인할 수 있습니다.

8.2 애플리케이션 도메인의 쿠키

애플리케이션도 자체 세션 쿠키를 만들 수 있습니다. 예를 들어 Spring Security를 사용하는 서버사이드 애플리케이션이라면 JSESSIONID 같은 쿠키를 사용할 수 있습니다.

app.example.com
 └── JSESSIONID 또는 application session cookie

이 쿠키는 Keycloak 쿠키와 다릅니다. Keycloak에서 로그아웃하지 않아도 애플리케이션 세션만 만료될 수 있고, 반대로 애플리케이션 쿠키를 지워도 Keycloak SSO Session은 살아 있을 수 있습니다.

8.3 oauth2-proxy 쿠키

oauth2-proxy를 사용하는 경우 브라우저에는 oauth2-proxy가 발급한 세션 쿠키가 저장됩니다. oauth2-proxy는 이 쿠키를 보고 사용자가 이미 인증되었는지 판단합니다.

service.example.com
 └── _oauth2_proxy 쿠키

oauth2-proxy 구조에서는 애플리케이션이 OIDC를 몰라도 됩니다. 대신 oauth2-proxy가 앞단에서 인증을 처리하고, 인증된 사용자 정보만 헤더로 넘겨줍니다.


9. 실제 요청 흐름: 로그인 전

사용자가 보호된 서비스에 처음 접근한다고 가정해보겠습니다.

사용자 브라우저
  ↓
https://app.example.com
  ↓
애플리케이션 또는 프록시
  ↓
"인증 쿠키 없음"
  ↓
Keycloak 로그인 페이지로 리다이렉트

이때 애플리케이션은 사용자를 바로 서비스 화면으로 보내지 않습니다. 인증되지 않았기 때문에 Keycloak의 authorization endpoint로 리다이렉트합니다.

리다이렉트 URL에는 보통 다음 정보가 포함됩니다.

  • client_id
  • redirect_uri
  • response_type=code
  • scope=openid
  • state
  • nonce

여기서 redirect_uri가 Keycloak Client 설정과 정확히 일치하지 않으면 Invalid redirect_uri 오류가 발생합니다.


10. 실제 요청 흐름: 로그인 성공 후

사용자가 Keycloak 로그인 화면에서 인증에 성공하면 Keycloak은 바로 Access Token을 브라우저에 던지는 것이 아니라, authorization code를 redirect_uri로 전달합니다.

Keycloak
  ↓
https://app.example.com/callback?code=abc123&state=xyz

그 다음 애플리케이션 또는 oauth2-proxy는 이 code를 가지고 Keycloak Token Endpoint에 요청합니다.

POST /realms/{realm}/protocol/openid-connect/token

grant_type=authorization_code
code=abc123
client_id=my-client
client_secret=...
redirect_uri=https://app.example.com/callback

Keycloak은 code가 유효하면 토큰을 반환합니다.

{
  "access_token": "...",
  "expires_in": 300,
  "refresh_token": "...",
  "refresh_expires_in": 1800,
  "id_token": "...",
  "token_type": "Bearer"
}

이 순간부터 애플리케이션 또는 프록시는 인증된 사용자를 알 수 있습니다. 그리고 브라우저에는 자체 세션 쿠키를 내려줍니다.


11. 로그인 이후 요청 흐름

로그인 이후 사용자가 다시 app.example.com에 접근하면 매번 Keycloak으로 가지 않습니다. 일반적으로 먼저 애플리케이션 또는 프록시 세션을 확인합니다.

사용자 요청
  ↓
브라우저가 세션 쿠키 전송
  ↓
애플리케이션 또는 oauth2-proxy가 쿠키 검증
  ↓
세션 유효
  ↓
서비스 접근 허용

즉 매 요청마다 Keycloak에 로그인 검사를 요청하는 구조가 아닙니다. 이 점을 오해하면 성능 구조와 장애 포인트를 잘못 판단하게 됩니다.

다만 Access Token이 만료되었고 Refresh Token이 유효한 경우에는 백그라운드에서 토큰 갱신이 발생할 수 있습니다.

Access Token 만료
  ↓
Refresh Token으로 token endpoint 호출
  ↓
새 Access Token 발급
  ↓
사용자 요청 계속 처리

12. Access Token 만료와 세션 만료는 다르다

실무에서 매우 중요한 포인트입니다. Access Token 만료와 로그인 세션 만료는 같은 개념이 아닙니다.

항목 의미 만료 시 결과
Access Token API 접근 권한 API 호출 실패 또는 토큰 갱신 필요
Refresh Token Access Token 재발급 권한 재로그인 필요
Keycloak SSO Session Keycloak 로그인 상태 SSO 재인증 필요
Application Session 애플리케이션 로그인 상태 앱 기준 로그아웃 또는 재인증

예를 들어 Access Token이 5분짜리여도 Refresh Token이 살아 있으면 사용자는 계속 로그인 상태를 유지할 수 있습니다. 반대로 Access Token이 아직 살아 있어도 애플리케이션 세션 쿠키가 사라지면 다시 인증 흐름을 탈 수 있습니다.


13. 로그아웃은 왜 복잡한가?

로그아웃이 복잡한 이유는 로그인 상태가 여러 곳에 나뉘어 있기 때문입니다.

  • 브라우저의 애플리케이션 쿠키
  • 브라우저의 Keycloak 쿠키
  • Keycloak SSO Session
  • Keycloak Client Session
  • 애플리케이션 서버 세션
  • oauth2-proxy 세션
  • Refresh Token

따라서 애플리케이션에서 로컬 쿠키만 삭제하면 Keycloak SSO Session은 살아 있을 수 있습니다. 이 상태에서 다시 로그인 버튼을 누르면 Keycloak 로그인 화면 없이 바로 로그인 완료될 수 있습니다. 사용자 입장에서는 “로그아웃이 안 됐다”고 느낍니다.

올바른 로그아웃 흐름

[1] 애플리케이션 세션 종료
[2] 애플리케이션 쿠키 삭제
[3] Keycloak logout endpoint로 리다이렉트
[4] Keycloak SSO Session 종료
[5] post_logout_redirect_uri로 복귀

SSO 환경에서는 “내 서비스에서만 로그아웃할 것인지”, “Keycloak 전체 SSO 세션까지 종료할 것인지”를 명확히 정해야 합니다.


14. ALB OIDC를 쓰는 경우

AWS ALB OIDC 인증을 사용하면 애플리케이션 앞단의 ALB가 OIDC Client 역할을 수행합니다. 이 경우 애플리케이션은 Keycloak과 직접 통신하지 않아도 됩니다.

Browser
  ↓
AWS ALB
  ↓ OIDC 인증 필요
Keycloak
  ↓ 인증 성공
AWS ALB 세션 쿠키 생성
  ↓
Target Application

이 구조에서는 ALB가 인증을 처리하고, 애플리케이션으로 사용자 정보를 헤더 형태로 전달할 수 있습니다.

장점은 애플리케이션 수정이 적다는 것입니다. 단점은 ALB가 제공하는 OIDC 처리 방식 안에서만 세부 제어가 가능하다는 점입니다. 세밀한 토큰 처리, 복잡한 권한 로직, 커스텀 세션 제어가 필요한 경우에는 제약이 생길 수 있습니다.


15. oauth2-proxy를 쓰는 경우

oauth2-proxy는 애플리케이션 앞단에서 인증을 처리하는 Reverse Proxy입니다. Keycloak과 OIDC 연동을 하고, 인증된 사용자만 내부 서비스로 전달합니다.

Browser
  ↓
oauth2-proxy
  ↓ 인증 필요
Keycloak
  ↓ 인증 성공
oauth2-proxy session 생성
  ↓
Upstream Application

oauth2-proxy를 사용하면 인증 기능이 없는 내부 서비스도 Keycloak으로 보호할 수 있습니다. 예를 들어 사내 대시보드, admin UI, legacy web app 등을 보호할 때 유용합니다.

하지만 oauth2-proxy의 세션 쿠키, Redis session store, cookie secret, refresh 설정을 제대로 이해하지 못하면 redirect loop나 세션 만료 문제가 발생할 수 있습니다.


16. SPA에서 주의할 점

React, Vue, Angular 같은 SPA는 브라우저에서 직접 OIDC 흐름을 처리할 수 있습니다. 하지만 이 경우 토큰 저장 위치가 매우 중요합니다.

저장 위치 장점 주의점
localStorage 구현이 단순함 XSS에 취약할 수 있음
sessionStorage 탭 세션 단위 관리 가능 XSS 위험은 여전히 존재
Memory 상대적으로 안전함 새로고침 시 토큰 유지 어려움
HttpOnly Cookie JS에서 직접 접근 불가 백엔드 세션 구조 필요

보안 관점에서는 브라우저 JavaScript가 Refresh Token을 장기간 직접 들고 있는 구조를 신중히 봐야 합니다. 가능하다면 BFF 또는 서버사이드 세션 구조를 고려하는 것이 안전합니다.


17. 실무에서 권장하는 토큰/세션 설계

모든 서비스에 정답은 없지만, 일반적인 내부 업무 시스템 기준으로는 다음 방향이 안정적입니다.

  • Access Token은 짧게 유지한다.
  • Refresh Token은 서버사이드 또는 프록시 계층에서 안전하게 관리한다.
  • 브라우저에는 가능하면 세션 쿠키 중심으로 상태를 유지한다.
  • SSO Session Idle과 Max를 업무 패턴에 맞게 조정한다.
  • 로그아웃은 애플리케이션 세션과 Keycloak SSO 세션을 분리해서 설계한다.
  • 운영 환경에서는 HTTPS, Secure Cookie, SameSite 정책을 반드시 확인한다.

예시 설정 방향

항목 권장 방향
Access Token Lifespan 짧게 설정. 예: 5~15분
SSO Session Idle 업무 시스템 기준 30분~2시간 범위 검토
SSO Session Max 업무일 단위 또는 보안 정책 기준으로 제한
Refresh Token 탈취 위험을 고려해 보관 위치와 재사용 정책 검토
Cookie Secure, HttpOnly, SameSite 정책 확인

단, 금융, 관리자 콘솔, 개인정보 처리 시스템은 더 짧은 세션 정책이 필요할 수 있습니다. 반대로 사내 대시보드처럼 민감도가 낮고 사용성이 중요한 시스템은 Idle 시간을 조금 길게 가져갈 수 있습니다.


18. 자주 발생하는 문제와 원인

18.1 Redirect Loop

증상은 로그인 후 다시 로그인 페이지로 돌아가는 것입니다.

주요 원인은 다음과 같습니다.

  • redirect_uri 불일치
  • 쿠키 도메인 불일치
  • SameSite 쿠키 정책 문제
  • HTTPS 설정 누락
  • 프록시 뒤에서 X-Forwarded-Proto 처리 오류
  • oauth2-proxy cookie secret 또는 session 설정 오류

18.2 401 Unauthorized

로그인은 된 것 같은데 API 호출이 401로 실패하는 경우입니다.

주요 원인은 다음과 같습니다.

  • Access Token 만료
  • audience 불일치
  • issuer 불일치
  • API 서버의 JWKS 검증 실패
  • role 또는 scope 매핑 누락

18.3 로그아웃 후 자동 재로그인

애플리케이션 쿠키만 삭제하고 Keycloak SSO Session은 종료하지 않았을 때 발생합니다. Keycloak 세션이 살아 있으면 다시 authorization endpoint로 이동했을 때 로그인 화면 없이 code가 발급될 수 있습니다.

18.4 새로고침 후 로그인 풀림

SPA에서 토큰을 메모리에만 저장한 경우 새로고침 시 토큰이 사라질 수 있습니다. 반대로 localStorage에 저장하면 유지성은 좋아지지만 XSS 위험이 커집니다.


19. 전체 구조 요약

Browser
 ├── 애플리케이션 쿠키
 ├── oauth2-proxy 쿠키
 └── Keycloak 도메인 쿠키

Application / Proxy
 ├── 세션 검증
 ├── Access Token 보관 또는 검증
 ├── Refresh Token으로 갱신
 └── 사용자 정보 헤더 또는 서버 세션 관리

Keycloak
 ├── 사용자 인증
 ├── SSO Session 관리
 ├── Client Session 관리
 ├── ID Token 발급
 ├── Access Token 발급
 └── Refresh Token 발급

결국 Keycloak 인증은 단순히 “로그인 화면을 띄우는 기능”이 아닙니다. 브라우저 쿠키, 애플리케이션 세션, Keycloak SSO Session, Client Session, Access Token, Refresh Token이 함께 동작하는 구조입니다.


20. 결론

Keycloak을 실무에서 안정적으로 운영하려면 토큰만 보면 안 됩니다. 반대로 쿠키만 봐도 안 됩니다. 반드시 세션, 토큰, 쿠키를 함께 봐야 합니다.

핵심은 다음과 같습니다.

  • ID Token은 사용자 신원 확인용이다.
  • Access Token은 API 접근 권한 검증용이다.
  • Refresh Token은 Access Token 재발급용이다.
  • Keycloak SSO Session과 애플리케이션 세션은 다르다.
  • 브라우저 쿠키는 인증 상태 전달의 핵심이다.
  • 로그아웃은 로컬 세션 종료와 Keycloak SSO 세션 종료를 분리해서 봐야 한다.
  • ALB OIDC, oauth2-proxy, 애플리케이션 직접 연동은 세션을 관리하는 위치가 다르다.

따라서 Keycloak 장애를 분석할 때는 항상 다음 순서로 확인하는 것이 좋습니다.

  1. 브라우저 쿠키가 정상적으로 저장되는가?
  2. redirect_uri가 정확히 일치하는가?
  3. authorization code가 정상 발급되는가?
  4. token endpoint에서 토큰 교환이 성공하는가?
  5. Access Token의 iss, aud, exp, role이 맞는가?
  6. Refresh Token으로 갱신이 가능한가?
  7. Keycloak SSO Session과 애플리케이션 세션 중 어느 쪽이 만료되었는가?

이 기준으로 보면 대부분의 Keycloak 인증 문제는 훨씬 빠르게 원인을 좁힐 수 있습니다.

Keycloak Redirect URI 오류 해결 방법 (invalid_redirect_uri 완전 정리)

👉 Keycloak에서 invalid_redirect_uri 오류는 왜 발생할까?

Keycloak을 OIDC, oauth2-proxy, ALB OIDC, Spring Security, Grafana와 연동할 때 가장 자주 만나는 오류가 있습니다.

바로 invalid_redirect_uri 오류입니다.

👉 이 오류는 대부분 “Keycloak에 등록된 Redirect URI”와 “실제 요청에 포함된 redirect_uri”가 다를 때 발생합니다.

1. Redirect URI란 무엇인가

Redirect URI는 로그인 성공 후 Keycloak이 사용자를 다시 돌려보낼 주소입니다.

사용자 → App 접속
App → Keycloak 로그인 페이지로 이동
Keycloak 로그인 성공
Keycloak → Redirect URI로 사용자 반환
핵심 개념
Redirect URI는 인증 완료 후 Keycloak이 Authorization Code 또는 Token 흐름을 이어가기 위해 호출하는 Callback URL이다

OIDC의 redirect 기반 흐름에서는 Client에 허용된 Redirect URI를 정확하게 설정해야 합니다. Keycloak 공식 문서에서도 redirect flow를 사용할 때 Valid Redirect URI를 가능한 구체적으로 설정하라고 안내합니다.

2. invalid_redirect_uri가 발생하는 구조

App 요청 redirect_uri = https://app.example.com/oauth2/callback
Keycloak Client 설정 = https://app.example.com/callback
결과 → invalid_redirect_uri

Keycloak은 요청에 포함된 redirect_uri가 Client의 Valid Redirect URIs 목록과 일치하는지 확인합니다.

👉 한 글자, 포트, 경로, 프로토콜이 달라도 오류가 발생할 수 있습니다.

3. 가장 많이 틀리는 Redirect URI 패턴

문제 예시
http / https 불일치 http://app.example.com vs https://app.example.com
도메인 불일치 app.example.com vs auth.example.com
포트 누락 localhost:8080 vs localhost
경로 불일치 /oauth2/callback vs /login/oauth2/code/keycloak
Trailing Slash 차이 /callback vs /callback/
프록시 뒤 URL 불일치 내부 http 주소가 redirect_uri로 생성됨
👉 Redirect URI 문제는 대부분 “내가 생각한 URL”과 “실제로 브라우저가 보낸 URL”이 다른 경우입니다.

4. oauth2-proxy에서 확인해야 할 값

oauth2-proxy를 사용하는 경우 callback URL은 기본적으로 /oauth2/callback 경로를 사용합니다. oauth2-proxy 공식 문서에서도 /oauth2/callback은 OAuth cycle 마지막에 사용되는 URL이며, OAuth app에 callback URL로 등록해야 한다고 설명합니다.

redirect_url = "https://app.example.com/oauth2/callback"

Keycloak Client의 Valid Redirect URIs에도 같은 값을 넣어야 합니다.

https://app.example.com/oauth2/callback
👉 oauth2-proxy 방식에서는 Keycloak Redirect URI와 oauth2-proxy redirect_url이 정확히 일치해야 합니다.

5. ALB OIDC에서 확인해야 할 값

ALB OIDC 방식은 oauth2-proxy와 callback 경로가 다릅니다.

https://app.example.com/oauth2/idpresponse

AWS ALB 인증 흐름에서는 IdP가 인증 완료 후 ALB의 /oauth2/idpresponse 경로로 사용자를 되돌려 보내야 합니다.

ALB OIDC Keycloak Client 설정
  • Client ID: alb-oidc
  • Access Type: confidential
  • Valid Redirect URI: https://app.example.com/oauth2/idpresponse
  • Web Origins: https://app.example.com
👉 ALB OIDC는 /oauth2/callback이 아니라 /oauth2/idpresponse를 사용합니다.

6. Spring Security에서 확인해야 할 값

Spring Security OAuth2 Client를 사용하는 경우 기본 redirect URI는 보통 아래 형식입니다.

https://app.example.com/login/oauth2/code/keycloak

따라서 Keycloak Client에도 동일한 Redirect URI를 등록해야 합니다.

https://app.example.com/login/oauth2/code/keycloak
👉 사용하는 클라이언트 종류에 따라 callback 경로가 다릅니다. oauth2-proxy, ALB, Spring Security는 서로 다른 callback 경로를 사용합니다.

7. Kubernetes / Ingress 환경에서 자주 발생하는 문제

Kubernetes 환경에서는 Ingress, ALB, Nginx, oauth2-proxy, App 사이에서 원래 요청의 host와 scheme이 제대로 전달되지 않아 redirect_uri가 잘못 생성되는 경우가 많습니다.

사용자는 https://app.example.com 접속
Pod 내부에서는 http://service.namespace.svc 로 인식
App이 redirect_uri를 http://service.namespace.svc/callback 으로 생성
Keycloak → invalid_redirect_uri

확인할 헤더

헤더 의미
X-Forwarded-Proto 원래 요청이 http인지 https인지 전달
X-Forwarded-Host 원래 요청 host 전달
X-Forwarded-Port 원래 요청 port 전달
👉 프록시 뒤에서 동작하는 App은 forwarded header 설정이 중요합니다.

8. Keycloak에서 Wildcard를 쓸 때 주의할 점

Keycloak은 Valid Redirect URIs에 wildcard 패턴을 사용할 수 있습니다. 하지만 무분별한 wildcard는 open redirect 위험을 만들 수 있습니다.

나쁜 예시

https://*

상대적으로 나은 예시

https://app.example.com/*
https://dev.example.com/*

Keycloak 문서에서도 redirect URI는 가능한 구체적으로 설정하는 것이 좋다고 안내합니다. 특히 public client나 브라우저 기반 앱에서는 더 엄격하게 설정하는 것이 안전합니다.

👉 운영 환경에서는 가능한 정확한 callback URL을 등록하고, wildcard는 제한적으로만 사용해야 합니다.

9. 실제 해결 순서

invalid_redirect_uri 해결 체크리스트
  • 브라우저 주소창 또는 로그에서 실제 redirect_uri 확인
  • Keycloak Client의 Valid Redirect URIs 확인
  • http / https 일치 여부 확인
  • host / port / path 일치 여부 확인
  • oauth2-proxy, ALB OIDC, Spring Security 중 어떤 방식을 쓰는지 확인
  • 프록시 뒤에서 X-Forwarded-* 헤더가 정상 전달되는지 확인
  • 설정 변경 후 브라우저 쿠키와 세션 삭제 후 재테스트
👉 먼저 실제 요청에 포함된 redirect_uri 값을 확인해야 합니다. 추측으로 고치면 계속 실패합니다.

10. 예시별 정답 Redirect URI

구성 Keycloak Valid Redirect URI
oauth2-proxy https://app.example.com/oauth2/callback
ALB OIDC https://app.example.com/oauth2/idpresponse
Spring Security https://app.example.com/login/oauth2/code/keycloak
Grafana https://grafana.example.com/login/generic_oauth
Local 개발 http://localhost:8080/login/oauth2/code/keycloak
👉 Redirect URI는 제품이나 프레임워크마다 다릅니다. 복사해서 쓰기 전에 실제 callback 경로를 확인해야 합니다.

11. 자주 하는 실수

oauth2-proxy인데 /oauth2/idpresponse를 등록
/oauth2/idpresponse는 ALB OIDC 방식에서 사용하는 callback 경로입니다. oauth2-proxy는 보통 /oauth2/callback을 사용합니다.
ALB OIDC인데 /oauth2/callback을 등록
ALB OIDC는 인증 후 /oauth2/idpresponse로 돌아와야 합니다.
localhost와 운영 도메인을 같이 혼동
개발 환경과 운영 환경은 Redirect URI를 따로 등록하는 것이 안전합니다.
프록시 설정 누락
Ingress나 ALB 뒤에서 App이 내부 주소를 기준으로 redirect_uri를 생성하면 오류가 발생합니다.

핵심 정리

항목 핵심 내용
invalid_redirect_uri 요청 redirect_uri와 Keycloak Valid Redirect URI 불일치
oauth2-proxy /oauth2/callback
ALB OIDC /oauth2/idpresponse
핵심 해결 실제 요청 redirect_uri를 확인하고 Keycloak에 정확히 등록
💡 Redirect URI 오류는 “설정값 문제”가 아니라 “실제 요청 URL과 등록 URL의 불일치 문제”다

마무리

Keycloak의 invalid_redirect_uri 오류는 복잡해 보이지만 원인은 단순합니다. Keycloak이 허용한 Redirect URI와 실제 요청에 포함된 redirect_uri가 다르기 때문입니다.

oauth2-proxy, ALB OIDC, Spring Security, Grafana처럼 사용하는 도구마다 callback 경로가 다르므로, 먼저 어떤 구조를 쓰는지 확인해야 합니다.

👉 해결 순서는 “실제 redirect_uri 확인 → Keycloak Valid Redirect URI 수정 → 세션 초기화 → 재로그인 테스트”입니다.

Keycloak Audience Mapper 설정 방법 (invalid_token / audience mismatch 해결)

👉 Keycloak 로그인은 성공했는데 왜 invalid_token이 발생할까?

Keycloak을 oauth2-proxy, ALB OIDC, API Gateway, 백엔드 API와 연동하다 보면 로그인은 성공했는데 실제 서비스 접근 단계에서 실패하는 경우가 있습니다.

이때 자주 만나는 원인이 바로 Audience mismatch입니다.

👉 인증은 성공했지만, 토큰의 대상(audience)이 맞지 않으면 서비스는 해당 토큰을 신뢰하지 않을 수 있습니다.

1. Audience란 무엇인가

Audience는 JWT 토큰의 aud claim에 들어가는 값입니다. 이 값은 “이 토큰이 누구를 위해 발급되었는가”를 의미합니다.

User → Keycloak → Access Token 발급
          ↓
      aud = 이 토큰을 사용할 대상
핵심 개념
audience는 토큰의 수신 대상이며, API나 프록시는 aud 값을 보고 토큰이 자신을 위한 것인지 판단한다

2. 왜 audience mismatch가 발생하는가

Keycloak에서 로그인은 성공했지만, access token에 기대하는 audience가 없으면 oauth2-proxy나 API 서버가 토큰을 거부할 수 있습니다.

oauth2-proxy client_id = oauth2-proxy
Access Token aud = account
결과 → audience mismatch
👉 oauth2-proxy는 토큰의 aud 값이 client-id 또는 oidc-extra-audience와 맞는지 확인할 수 있습니다.

3. 자주 보이는 오류

오류 의미
invalid_token 토큰 검증 실패
audience mismatch 토큰의 aud 값이 기대값과 다름
missing aud claim access token에 aud claim이 없음
401 Unauthorized 인증 토큰은 있지만 서비스가 신뢰하지 않음
👉 로그인 성공과 토큰 검증 성공은 다릅니다.

4. 현재 토큰의 aud 확인 방법

먼저 실제 발급된 access token을 확인해야 합니다. JWT는 점(.)으로 구분된 세 부분으로 구성됩니다.

header.payload.signature

payload를 디코딩하면 아래처럼 aud 값을 확인할 수 있습니다.

{
  "iss": "https://keycloak.example.com/realms/demo",
  "sub": "user-id",
  "aud": "account",
  "azp": "oauth2-proxy",
  "scope": "openid profile email"
}
문제 상황
oauth2-proxy는 oauth2-proxy audience를 기대하는데, 실제 aud가 account만 있으면 검증 단계에서 실패할 수 있습니다.

5. 해결 방법 1: Dedicated Client Mapper에 Audience 추가

가장 직관적인 방법은 oauth2-proxy Client에 Audience Mapper를 추가하는 것입니다.

Keycloak 설정 경로
  • Keycloak Admin Console 접속
  • Realm 선택
  • Clients 이동
  • oauth2-proxy Client 선택
  • Client scopes 또는 Dedicated scopes 이동
  • Add mapper 또는 Configure a new mapper 선택
  • Audience Mapper 추가

Audience Mapper 설정 예시

항목
Mapper Type Audience
Name oauth2-proxy-audience
Included Client Audience oauth2-proxy
Add to access token ON
Add to ID token 필요 시 ON
Add to token introspection 필요 시 ON
👉 API 인증이나 oauth2-proxy 검증에는 보통 access token의 aud 값이 중요합니다.

6. 해결 방법 2: Client Scope로 Audience 관리

여러 Client에서 같은 audience 설정을 재사용해야 한다면 Client Scope로 관리하는 방식이 좋습니다.

Client Scope 생성 → Audience Mapper 추가 → Client에 Scope 연결 → Token 재발급
Client Scope 방식이 적합한 경우
  • 여러 애플리케이션에서 같은 audience를 사용해야 할 때
  • Realm 단위로 공통 토큰 정책을 관리하고 싶을 때
  • Client별 mapper 중복 생성을 줄이고 싶을 때
👉 단일 Client만 수정하면 Dedicated Mapper, 여러 Client에 재사용하려면 Client Scope 방식이 적합합니다.

7. oauth2-proxy 설정에서 확인할 값

Keycloak에서 audience를 넣었더라도 oauth2-proxy 설정과 기대값이 맞지 않으면 실패할 수 있습니다.

provider = "keycloak-oidc"
oidc_issuer_url = "https://keycloak.example.com/realms/demo"
client_id = "oauth2-proxy"

기본적으로 client_id와 audience가 맞도록 구성하는 것이 가장 단순합니다.

추가 audience를 허용해야 하는 경우

--oidc-extra-audience=api-service

여러 API나 별도 audience를 허용해야 할 때는 extra audience 설정을 검토할 수 있습니다.

👉 Keycloak의 aud 값과 oauth2-proxy의 client-id 또는 extra-audience가 맞아야 합니다.

8. 설정 후 반드시 재로그인해야 하는 이유

Audience Mapper를 추가해도 기존 세션이나 기존 access token에는 바로 반영되지 않을 수 있습니다.

Mapper 추가 → 기존 토큰 유지 → 여전히 aud 없음 → 계속 실패
반드시 수행할 작업
  • 기존 브라우저 세션 로그아웃
  • oauth2-proxy 세션 쿠키 삭제
  • Keycloak 세션 종료
  • 새로 로그인해서 access token 재발급
  • JWT payload에서 aud 값 재확인
👉 Mapper 설정 변경 후에는 반드시 새 토큰을 발급받아야 합니다.

9. 정상 토큰 예시

Audience Mapper가 정상 적용되면 access token의 aud 값에 oauth2-proxy가 포함됩니다.

{
  "iss": "https://keycloak.example.com/realms/demo",
  "sub": "user-id",
  "aud": [
    "account",
    "oauth2-proxy"
  ],
  "azp": "oauth2-proxy",
  "scope": "openid profile email"
}
👉 aud에 oauth2-proxy가 포함되어 있으면 oauth2-proxy가 해당 토큰을 자신을 위한 토큰으로 인식할 수 있습니다.

10. 실무 체크리스트

체크 항목 확인 내용
Client ID oauth2-proxy 설정의 client_id와 Keycloak Client ID가 같은가
Audience Mapper Included Client Audience가 올바른가
Access Token Add to access token이 ON인가
토큰 재발급 설정 변경 후 새로 로그인했는가
JWT 확인 aud claim에 기대값이 들어갔는가
oauth2-proxy 설정 client-id 또는 oidc-extra-audience와 aud 값이 맞는가

11. 자주 하는 실수

ID Token에만 audience 추가
실제 API나 oauth2-proxy 검증은 access token을 기준으로 보는 경우가 많습니다. Add to access token을 확인해야 합니다.
Mapper 추가 후 기존 토큰으로 테스트
기존 토큰에는 새 mapper가 반영되지 않습니다. 반드시 재로그인 후 새 토큰으로 확인해야 합니다.
azp와 aud를 혼동
azp는 authorized party이고, aud는 token audience입니다. 두 값은 역할이 다릅니다.
audience parameter로 aud가 추가된다고 오해
Keycloak의 audience parameter는 audience를 추가하는 용도라기보다 이미 포함된 audience를 필터링하는 용도입니다. aud 추가는 mapper나 client scope로 처리해야 합니다.

핵심 정리

항목 핵심 내용
aud 토큰의 수신 대상
Audience Mapper 토큰에 aud claim을 추가하는 설정
invalid_token audience mismatch로 발생할 수 있음
핵심 체크 Add to access token, 새 토큰 발급, aud claim 확인
💡 Keycloak audience 문제는 “로그인 문제가 아니라 토큰 대상 검증 문제”다

마무리

Keycloak에서 Audience Mapper는 oauth2-proxy, API 서버, ALB OIDC, 마이크로서비스 인증 구조에서 중요한 역할을 합니다.

로그인은 성공했는데 invalid_token이나 audience mismatch가 발생한다면, 먼저 access token의 aud claim을 확인해야 합니다.

👉 해결 순서는 “토큰 확인 → Audience Mapper 설정 → 새 토큰 발급 → aud 재검증”입니다.

ALB OIDC만으로 Keycloak 붙이는 방법 (oauth2-proxy 없이)

👉 oauth2-proxy 없이 ALB만으로 Keycloak 인증을 붙일 수 있을까?

가능합니다. AWS Application Load Balancer는 OIDC 인증 기능을 제공하므로, Keycloak이 OIDC Provider로 동작한다면 ALB에서 직접 인증을 처리할 수 있습니다.

이 글에서는 oauth2-proxy 없이 ALB OIDC 기능만 사용해서 Keycloak 인증을 구성하는 방법을 정리합니다.

👉 단순 로그인 보호가 목적이라면 oauth2-proxy 없이 ALB OIDC만으로도 구성할 수 있습니다.

1. 전체 인증 구조

Client → ALB → App
        ↳ ALB가 Keycloak OIDC 인증 처리

이 구조에서는 oauth2-proxy가 없습니다. 사용자가 App에 접근하면 ALB가 먼저 인증 여부를 확인하고, 인증되지 않은 사용자는 Keycloak 로그인 화면으로 리다이렉트합니다.

핵심 개념
ALB OIDC 방식에서는 ALB가 인증 주체이고, Keycloak은 로그인과 토큰 발급을 담당한다

2. 이 방식이 적합한 경우

ALB OIDC 추천 상황
  • 단순히 로그인한 사용자만 서비스에 접근시키고 싶을 때
  • oauth2-proxy를 별도로 운영하고 싶지 않을 때
  • 인증 로직을 애플리케이션 밖으로 분리하고 싶을 때
  • ALB에서 인증을 끝내고 App은 비즈니스 로직만 처리하게 하고 싶을 때
👉 빠르고 단순한 인증 보호가 목적이면 ALB OIDC 방식이 가장 간단합니다.

3. 이 방식의 한계

⚠️
Role / Group 기반 세밀한 권한 제어는 제한적
ALB는 인증에는 적합하지만, 애플리케이션별 세밀한 인가 정책을 직접 처리하는 도구는 아닙니다.
⚠️
헤더 커스터마이징이 제한적
oauth2-proxy처럼 세밀하게 헤더를 가공하거나 사용자 정보를 원하는 형태로 넘기기는 어렵습니다.
⚠️
App이 ALB 뒤에만 있어야 함
App이 ALB를 우회해서 직접 접근 가능하면 인증을 우회할 수 있습니다.
👉 ALB OIDC는 인증에는 좋지만, 복잡한 인가 구조까지 해결해주지는 않습니다.

4. Keycloak Client 설정

Keycloak에는 ALB가 사용할 OIDC Client를 생성합니다. 이 Client는 oauth2-proxy용이 아니라 ALB용 Client입니다.

Keycloak Client 설정값
  • Client ID: alb-oidc
  • Client type: OpenID Connect
  • Access type: confidential
  • Standard Flow: Enabled
  • Client Authentication: Enabled
  • Valid Redirect URI: https://app.example.com/oauth2/idpresponse
  • Web Origins: https://app.example.com
👉 ALB OIDC의 callback 경로는 /oauth2/idpresponse 입니다. oauth2-proxy의 /oauth2/callback과 다릅니다.

5. Keycloak OIDC Endpoint 확인

ALB 설정에는 Keycloak의 OIDC endpoint가 필요합니다. Realm이 demo라면 보통 아래 형태입니다.

항목 예시
Issuer https://keycloak.example.com/realms/demo
Authorization Endpoint https://keycloak.example.com/realms/demo/protocol/openid-connect/auth
Token Endpoint https://keycloak.example.com/realms/demo/protocol/openid-connect/token
UserInfo Endpoint https://keycloak.example.com/realms/demo/protocol/openid-connect/userinfo
👉 ALB가 Keycloak의 token endpoint와 userinfo endpoint에 접근할 수 있어야 합니다.

6. Kubernetes Secret 생성

AWS Load Balancer Controller의 OIDC 설정에서는 Ingress와 같은 namespace에 clientID와 clientSecret을 담은 Secret이 필요합니다.

apiVersion: v1
kind: Secret
metadata:
  name: keycloak-alb-oidc-secret
  namespace: app
type: Opaque
stringData:
  clientID: alb-oidc
  clientSecret: "KEYCLOAK_CLIENT_SECRET"
👉 Secret key 이름은 clientID, clientSecret 형태로 맞춰야 합니다.

7. App Service 예시

ALB가 인증 후 전달할 App Service입니다.

apiVersion: v1
kind: Service
metadata:
  name: demo-app
  namespace: app
spec:
  type: ClusterIP
  selector:
    app: demo-app
  ports:
    - name: http
      port: 80
      targetPort: 8080
👉 ALB OIDC 방식에서는 backend가 oauth2-proxy가 아니라 App Service입니다.

8. ALB Ingress YAML

이제 Ingress에 ALB OIDC annotation을 설정합니다.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: demo-app-alb-oidc
  namespace: app
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80},{"HTTPS":443}]'
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-2:123456789012:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    alb.ingress.kubernetes.io/ssl-redirect: "443"

    alb.ingress.kubernetes.io/auth-type: oidc
    alb.ingress.kubernetes.io/auth-idp-oidc: >
      {"issuer":"https://keycloak.example.com/realms/demo",
       "authorizationEndpoint":"https://keycloak.example.com/realms/demo/protocol/openid-connect/auth",
       "tokenEndpoint":"https://keycloak.example.com/realms/demo/protocol/openid-connect/token",
       "userInfoEndpoint":"https://keycloak.example.com/realms/demo/protocol/openid-connect/userinfo",
       "secretName":"keycloak-alb-oidc-secret"}
    alb.ingress.kubernetes.io/auth-on-unauthenticated-request: authenticate
    alb.ingress.kubernetes.io/auth-scope: "openid profile email"
    alb.ingress.kubernetes.io/auth-session-cookie: "AWSELBAuthSessionCookie"
    alb.ingress.kubernetes.io/auth-session-timeout: "86400"

    alb.ingress.kubernetes.io/healthcheck-path: /
spec:
  ingressClassName: alb
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: demo-app
                port:
                  number: 80
👉 이 방식에서는 alb.ingress.kubernetes.io/auth-type: oidc 를 사용하고, oauth2-proxy 관련 설정은 넣지 않습니다.

9. 실제 인증 흐름

1. 사용자가 https://app.example.com 접속
2. ALB가 인증 세션 쿠키 확인
3. 미인증 상태면 Keycloak Authorization Endpoint로 리다이렉트
4. 사용자가 Keycloak에서 로그인
5. Keycloak이 https://app.example.com/oauth2/idpresponse 로 code 전달
6. ALB가 Token Endpoint와 UserInfo Endpoint를 호출
7. 인증 성공 후 App Service로 요청 전달
👉 인증 성공 후 App은 ALB가 넘겨주는 사용자 관련 헤더를 받을 수 있습니다.

10. App에서 받을 수 있는 헤더

ALB는 인증 성공 후 대상 애플리케이션에 OIDC 관련 헤더를 전달합니다.

헤더 의미
x-amzn-oidc-accesstoken Access Token
x-amzn-oidc-identity 사용자 식별자
x-amzn-oidc-data 사용자 claims 정보
👉 App에서 이 헤더를 사용할 경우, 반드시 ALB를 통해서만 App에 접근 가능하도록 네트워크를 제한해야 합니다.

11. 보안상 반드시 확인할 것

⚠️
App 직접 접근 차단
App이 ALB를 우회해서 접근 가능하면 인증 헤더를 위조하는 방식의 위험이 생길 수 있습니다. App은 ALB에서 오는 트래픽만 허용해야 합니다.
⚠️
HTTPS 리스너 필수
ALB 인증 기능은 HTTPS 리스너에서 동작합니다. ACM 인증서와 443 리스너 구성이 필요합니다.
⚠️
Keycloak Endpoint 접근성
ALB가 Keycloak의 token endpoint와 userinfo endpoint에 접근할 수 있어야 합니다.
⚠️
Redirect URI 정확성
Keycloak Client의 Valid Redirect URI는 https://app.example.com/oauth2/idpresponse 형식으로 설정해야 합니다.

12. 테스트 방법

1) Secret 확인

kubectl get secret keycloak-alb-oidc-secret -n app

2) Ingress 확인

kubectl get ingress demo-app-alb-oidc -n app

3) ALB 주소 확인

kubectl describe ingress demo-app-alb-oidc -n app

4) 브라우저 로그인 테스트

https://app.example.com

접속 시 Keycloak 로그인 화면으로 이동하고, 로그인 후 App 화면으로 돌아오면 기본 인증 흐름은 정상입니다.

👉 테스트는 브라우저 기준으로 해야 합니다. ALB OIDC는 리다이렉트와 쿠키 기반 흐름이 포함됩니다.

13. 자주 발생하는 오류

redirect_uri mismatch
Keycloak Valid Redirect URI가 /oauth2/idpresponse와 일치하지 않을 때 발생합니다.
561 Authentication Error
OIDC endpoint, client secret, token endpoint 접근성 문제가 있을 때 발생할 수 있습니다.
로그인 후 다시 로그인 페이지로 이동
쿠키, 도메인, HTTPS, session 설정을 확인해야 합니다.
App은 열리지만 사용자 정보가 없음
scope, userinfo endpoint, App의 헤더 처리 방식을 확인해야 합니다.

핵심 정리

항목 핵심 내용
구조 Client → ALB → App
인증 주체 ALB
IdP Keycloak OIDC
핵심 체크 /oauth2/idpresponse, client secret, HTTPS, endpoint 접근성
💡 ALB OIDC 방식은 oauth2-proxy 없이 Keycloak 인증을 붙이는 가장 단순한 구조다

마무리

ALB OIDC 방식은 Keycloak 인증을 빠르게 붙이기 좋은 구조입니다. oauth2-proxy를 운영하지 않아도 되고, 인증 로직을 ALB에 위임할 수 있습니다.

다만 세밀한 권한 제어, 헤더 커스터마이징, 복잡한 인증 정책이 필요하다면 oauth2-proxy 방식이 더 적합할 수 있습니다.

👉 단순 인증 보호는 ALB OIDC, 복잡한 인증/인가 처리는 oauth2-proxy 구조를 선택하는 것이 좋습니다.

ALB OIDC vs oauth2-proxy 차이점 (Keycloak 인증 구조 비교)

👉 ALB OIDC랑 oauth2-proxy, 둘 중 어떤 구조를 써야 할까?

Keycloak 기반 인증을 Kubernetes에 붙일 때 가장 많이 고민하는 것이 바로 이 두 가지입니다.

👉 ALB OIDC와 oauth2-proxy는 같은 기능이 아니라 “완전히 다른 아키텍처”다

1. 전체 구조 비교

ALB OIDC 방식

Client → ALB → App ↳ ALB가 Keycloak OIDC 인증 처리

oauth2-proxy 방식

Client → ALB → oauth2-proxy → App ↓ Keycloak OIDC
👉 ALB 방식은 “LB가 인증”, oauth2-proxy는 “애플리케이션 레벨 인증”

2. 핵심 차이

항목 ALB OIDC oauth2-proxy
인증 주체 ALB oauth2-proxy
구성 난이도 낮음 중간
확장성 제한적 높음
헤더 제어 제한적 가능
Role 처리 어려움 가능
운영 복잡도 낮음 높음

3. ALB OIDC 실무 YAML

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: alb-oidc
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/auth-type: oidc
    alb.ingress.kubernetes.io/auth-idp-oidc: >
      {"issuer":"https://keycloak.example.com/realms/demo",
       "authorizationEndpoint":"https://keycloak.example.com/realms/demo/protocol/openid-connect/auth",
       "tokenEndpoint":"https://keycloak.example.com/realms/demo/protocol/openid-connect/token",
       "userInfoEndpoint":"https://keycloak.example.com/realms/demo/protocol/openid-connect/userinfo",
       "secretName":"oidc-secret"}
spec:
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app
            port:
              number: 80
👉 ALB OIDC는 Secret에 clientId/clientSecret 저장 필요

4. oauth2-proxy 실무 YAML

apiVersion: apps/v1
kind: Deployment
metadata:
  name: oauth2-proxy
spec:
  replicas: 2
  template:
    spec:
      containers:
      - name: oauth2-proxy
        image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0
        args:
          - --provider=keycloak-oidc
          - --oidc-issuer-url=https://keycloak.example.com/realms/demo
          - --redirect-url=https://app.example.com/oauth2/callback
          - --upstream=http://app:80
          - --http-address=0.0.0.0:4180
👉 oauth2-proxy는 반드시 upstream 설정 필요

5. 언제 어떤걸 써야 하나

ALB OIDC 추천

  • 빠르게 인증 붙이고 싶을 때
  • 단순 로그인만 필요할 때

oauth2-proxy 추천

  • 권한(Role) 기반 접근 필요
  • 헤더 커스터마이징 필요
  • 내부 서비스 인증 구조 필요
👉 실무에서는 oauth2-proxy가 더 많이 쓰인다

핵심 정리

ALB OIDC vs oauth2-proxy
  • ALB OIDC = 간단 / 빠름
  • oauth2-proxy = 유연 / 확장성
💡 단순 인증이면 ALB, 실무 확장은 oauth2-proxy

마무리

두 방식은 경쟁 관계가 아니라 선택 구조입니다.

👉 먼저 “내가 원하는 인증 수준”을 정의하는 것이 가장 중요하다

Keycloak + oauth2-proxy 설정 방법 (Kubernetes + ALB 완전 가이드)

👉 Kubernetes에서 Keycloak + oauth2-proxy + ALB 인증은 어떻게 구성해야 할까?

이 글은 Keycloak과 oauth2-proxy를 Kubernetes 환경에서 실제로 연결하는 설정 가이드입니다.

다만 먼저 구분해야 할 것이 있습니다. ALB는 Keycloak과 직접 OIDC 인증을 처리할 수도 있고, oauth2-proxy를 앞단 인증 프록시로 둘 수도 있습니다.

👉 단순히 ALB에서 Keycloak OIDC 인증만 처리할 경우 oauth2-proxy는 필요 없습니다. 이 글은 ALB 직접 OIDC 방식이 아니라, oauth2-proxy를 인증 프록시로 사용하는 Kubernetes 구조를 설명합니다.

1. 먼저 구분해야 하는 두 가지 인증 구조

패턴 1: ALB가 Keycloak OIDC를 직접 처리하는 구조

Client → ALB → App
        ↳ ALB가 Keycloak OIDC 인증 처리

이 방식에서는 ALB가 인증 주체입니다. AWS Load Balancer Controller의 OIDC 인증 annotation을 사용하며, 이 경우 oauth2-proxy는 필요하지 않습니다.

이 방식을 쓰는 경우
  • 단순 로그인 보호만 필요할 때
  • ALB 레벨에서 인증을 끝내고 싶을 때
  • 별도 인증 프록시를 운영하고 싶지 않을 때
  • 헤더 변환, 세션 커스터마이징 요구가 크지 않을 때

패턴 2: ALB가 oauth2-proxy로 보내고, oauth2-proxy가 Keycloak 인증을 처리하는 구조

Client → ALB → oauth2-proxy → App
          ↓
       Keycloak OIDC

이 글에서 설명하는 구조는 두 번째 방식입니다. ALB는 외부 HTTPS 요청을 oauth2-proxy로 라우팅하고, oauth2-proxy가 Keycloak과 OIDC 인증을 수행한 뒤 인증된 요청만 내부 App Service로 프록시합니다.

핵심 개념
이 글의 구조에서 ALB는 라우팅 담당, oauth2-proxy는 인증 담당, Keycloak은 로그인과 토큰 발급 담당이다

2. ALB OIDC 방식과 oauth2-proxy 방식 비교

구분 ALB 직접 OIDC oauth2-proxy 방식
인증 처리 ALB oauth2-proxy
Keycloak 연동 ALB OIDC annotation oauth2-proxy provider 설정
oauth2-proxy 필요 여부 불필요 필요
구현 난이도 낮음 중간
헤더 제어 제한적 상대적으로 유연
Role / Group 기반 확장 구현 제약 있음 구성 방식에 따라 확장 가능
운영 포인트 ALB annotation / Secret oauth2-proxy 설정 / Secret / upstream
👉 단순 인증이면 ALB 직접 OIDC가 더 간단하고, 인증 이후 처리나 헤더 제어가 필요하면 oauth2-proxy 방식이 더 유연합니다.

3. 이 글에서 사용할 최종 구조

Client → ALB → oauth2-proxy → App
          ↓
       Keycloak OIDC

이 구조에서 App은 외부에 직접 노출되지 않습니다. 모든 요청은 ALB를 거쳐 oauth2-proxy로 전달되고, oauth2-proxy가 인증을 통과한 요청만 App으로 보냅니다.

👉 App을 ALB backend로 직접 연결하면 oauth2-proxy를 우회하므로 이 구조가 깨집니다.

4. 구성 요소 역할

구성 요소 역할
ALB 외부 HTTPS 요청 수신 및 oauth2-proxy로 라우팅
oauth2-proxy OIDC 인증 처리, 세션 관리, 인증 후 App으로 프록시
Keycloak 사용자 로그인, Authorization Code 발급, Token 발급
App 실제 보호 대상 애플리케이션

5. Keycloak Client 설정

먼저 Keycloak에 oauth2-proxy용 Client를 생성합니다. 이 Client는 ALB용 Client가 아니라 oauth2-proxy가 사용할 OIDC Client입니다.

Keycloak Client 설정값
  • Client ID: oauth2-proxy
  • Client type: OpenID Connect
  • Access type: confidential
  • Standard Flow: Enabled
  • Valid Redirect URI: https://app.example.com/oauth2/callback
  • Web Origins: https://app.example.com
👉 redirect URI는 oauth2-proxy의 redirect_url 값과 정확히 일치해야 합니다.

Audience Mapper 확인

oauth2-proxy는 토큰의 audience 값을 확인합니다. Keycloak에서 audience mapper가 빠져 있으면 토큰 검증 단계에서 실패할 수 있습니다.

Audience Mapper 예시
  • Mapper Type: Audience
  • Included Client Audience: oauth2-proxy
  • Add to ID token: ON
  • Add to access token: ON

6. Kubernetes Secret 생성

Client Secret과 Cookie Secret은 Kubernetes Secret으로 관리합니다.

apiVersion: v1
kind: Secret
metadata:
  name: oauth2-proxy-secret
  namespace: auth
type: Opaque
stringData:
  client-id: oauth2-proxy
  client-secret: "KEYCLOAK_CLIENT_SECRET"
  cookie-secret: "32_BYTE_RANDOM_SECRET"
👉 cookie-secret은 충분히 긴 랜덤 문자열을 사용해야 합니다. 운영 환경에서는 평문 관리하지 않는 것이 좋습니다.

7. oauth2-proxy ConfigMap

oauth2-proxy의 핵심 설정은 provider, issuer URL, redirect URL, upstream입니다.

apiVersion: v1
kind: ConfigMap
metadata:
  name: oauth2-proxy-config
  namespace: auth
data:
  oauth2-proxy.cfg: |
    provider = "keycloak-oidc"
    oidc_issuer_url = "https://keycloak.example.com/realms/demo"

    http_address = "0.0.0.0:4180"
    redirect_url = "https://app.example.com/oauth2/callback"

    upstreams = [
      "http://demo-app.demo.svc.cluster.local:80"
    ]

    reverse_proxy = true
    email_domains = [ "*" ]
    scope = "openid profile email"

    cookie_secure = true
    cookie_httponly = true
    cookie_samesite = "lax"

    pass_authorization_header = true
    pass_access_token = true
    pass_user_headers = true
    set_xauthrequest = true
설정 의미
provider Keycloak OIDC Provider 사용
oidc_issuer_url Keycloak Realm Issuer URL
redirect_url Keycloak 인증 후 돌아올 callback URL
upstreams 인증 후 요청을 전달할 App 주소
reverse_proxy ALB 같은 프록시 뒤에서 동작하도록 설정
👉 upstream은 App Service 주소를 바라봐야 합니다. ALB 주소를 넣는 것이 아닙니다.

8. oauth2-proxy Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: oauth2-proxy
  namespace: auth
spec:
  replicas: 2
  selector:
    matchLabels:
      app: oauth2-proxy
  template:
    metadata:
      labels:
        app: oauth2-proxy
    spec:
      containers:
        - name: oauth2-proxy
          image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0
          args:
            - --config=/etc/oauth2-proxy/oauth2-proxy.cfg
          ports:
            - containerPort: 4180
              name: http
          env:
            - name: OAUTH2_PROXY_CLIENT_ID
              valueFrom:
                secretKeyRef:
                  name: oauth2-proxy-secret
                  key: client-id
            - name: OAUTH2_PROXY_CLIENT_SECRET
              valueFrom:
                secretKeyRef:
                  name: oauth2-proxy-secret
                  key: client-secret
            - name: OAUTH2_PROXY_COOKIE_SECRET
              valueFrom:
                secretKeyRef:
                  name: oauth2-proxy-secret
                  key: cookie-secret
          volumeMounts:
            - name: config
              mountPath: /etc/oauth2-proxy
              readOnly: true
          readinessProbe:
            httpGet:
              path: /ping
              port: 4180
            initialDelaySeconds: 5
            periodSeconds: 10
          livenessProbe:
            httpGet:
              path: /ping
              port: 4180
            initialDelaySeconds: 10
            periodSeconds: 20
      volumes:
        - name: config
          configMap:
            name: oauth2-proxy-config
👉 이미지 태그는 예시입니다. 운영 환경에서는 사용 중인 oauth2-proxy 버전과 변경 내역을 확인한 뒤 고정해서 사용해야 합니다.

9. oauth2-proxy Service

ALB Ingress가 바라볼 Service는 App이 아니라 oauth2-proxy입니다.

apiVersion: v1
kind: Service
metadata:
  name: oauth2-proxy
  namespace: auth
spec:
  type: ClusterIP
  selector:
    app: oauth2-proxy
  ports:
    - name: http
      port: 80
      targetPort: 4180
👉 Service port는 80으로 열고, targetPort는 oauth2-proxy 컨테이너 포트인 4180으로 연결합니다.

10. ALB Ingress 설정

ALB Ingress는 oauth2-proxy Service를 backend로 바라봐야 합니다.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-alb
  namespace: auth
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80},{"HTTPS":443}]'
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-2:123456789012:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    alb.ingress.kubernetes.io/ssl-redirect: "443"
    alb.ingress.kubernetes.io/healthcheck-path: /ping
spec:
  ingressClassName: alb
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: oauth2-proxy
                port:
                  number: 80
주의
이 구조에서는 alb.ingress.kubernetes.io/auth-type: oidc annotation을 넣지 않습니다. 인증은 ALB가 아니라 oauth2-proxy가 담당합니다.

11. 실제 요청 흐름

1. 사용자가 https://app.example.com 접속
2. ALB가 oauth2-proxy로 요청 전달
3. oauth2-proxy가 인증 여부 확인
4. 미인증이면 Keycloak 로그인으로 리다이렉트
5. Keycloak 로그인 성공 후 /oauth2/callback으로 복귀
6. oauth2-proxy가 세션 쿠키 생성
7. 인증된 요청만 App upstream으로 프록시
👉 사용자는 App에 직접 접근하지 않고, 항상 oauth2-proxy를 통과합니다.

12. 테스트 방법

1) oauth2-proxy Pod 확인

kubectl get pod -n auth -l app=oauth2-proxy

2) Service 확인

kubectl get svc -n auth oauth2-proxy

3) Ingress 확인

kubectl get ingress -n auth app-alb

4) Health Check 확인

curl -k https://app.example.com/ping

5) Callback 확인

브라우저에서 실제 로그인 후 아래 경로로 정상 복귀하는지 확인합니다.

https://app.example.com/oauth2/callback
👉 테스트는 반드시 /oauth2/callback 실제 호출 흐름까지 확인해야 합니다.

13. 자주 하는 실수

ALB backend를 App으로 설정
이렇게 하면 oauth2-proxy를 우회하므로 인증이 적용되지 않습니다.
ALB 직접 OIDC 방식과 oauth2-proxy 방식을 혼동
ALB가 직접 OIDC 인증을 담당하는 구조라면 oauth2-proxy는 필요 없습니다. 반대로 oauth2-proxy 방식이라면 ALB OIDC auth annotation을 넣지 않습니다.
redirect_url 불일치
oauth2-proxy의 redirect_url과 Keycloak Valid Redirect URI가 다르면 invalid_redirect_uri가 발생합니다.
Audience Mapper 누락
토큰 검증 단계에서 invalid_token 또는 audience mismatch가 발생할 수 있습니다.

핵심 정리

항목 핵심 내용
ALB 직접 OIDC ALB가 인증 처리, oauth2-proxy 불필요
oauth2-proxy 방식 ALB는 라우팅, oauth2-proxy가 인증과 App 프록시 담당
Keycloak OIDC 로그인과 토큰 발급
핵심 체크 redirect_url, audience mapper, upstream, ALB backend
💡 ALB가 인증을 직접 처리하는 방식과 oauth2-proxy가 인증을 처리하는 방식은 서로 다른 구조다

마무리

Keycloak + oauth2-proxy + ALB 구조에서 가장 중요한 것은 역할 분리입니다.

ALB가 직접 OIDC 인증을 처리하는 구조라면 oauth2-proxy는 필요 없습니다. 반대로 oauth2-proxy를 사용하는 구조라면 ALB는 인증하지 않고 oauth2-proxy로 라우팅만 해야 합니다.

👉 인증 문제를 줄이려면 “ALB 직접 OIDC 방식인지, oauth2-proxy 방식인지”를 먼저 결정해야 합니다.

Keycloak 로그인 안될 때 해결 방법 (에러별 원인 정리)

👉 Keycloak 로그인은 되는데, 왜 계속 실패할까?

Keycloak 인증 문제는 대부분 설정 오류에서 발생합니다. 특히 Redirect URI, Client 설정, Token 검증에서 문제가 자주 발생합니다.

👉 Keycloak 장애의 90%는 설정 문제다

1. 가장 먼저 확인해야 할 것

  • Redirect URI
  • Client Secret
  • Issuer URL
  • Token 구조
👉 이 4개만 확인해도 대부분 해결된다

2. invalid_redirect_uri 오류

invalid_redirect_uri

원인

  • URI 불일치
  • http / https 다름
  • 포트 누락
  • trailing slash 문제

해결 방법

  • Keycloak Client 설정과 완전히 동일하게 맞춘다
👉 한 글자라도 다르면 인증 실패

3. invalid_client 오류

invalid_client

원인

  • Client Secret 오류
  • Client ID 불일치

해결

  • Secret 재확인
  • confidential / public 설정 확인

4. 401 Unauthorized

원인

  • Access Token 문제
  • 만료된 토큰

해결

  • 토큰 재발급
  • Refresh Token 확인
👉 대부분 토큰 만료 문제

5. invalid_token / audience 오류

invalid_token

원인

  • Audience mismatch

해결

  • Keycloak Client에 Audience Mapper 추가
👉 API 인증 실패의 핵심 원인

6. 로그인은 되는데 서비스 접근 안됨

원인

  • 쿠키 문제
  • 도메인 설정 오류
  • SameSite 설정

해결

  • 도메인 일치 확인
  • HTTPS 환경 구성

7. 실무 체크리스트

  • Redirect URI 정확한가
  • Client Secret 맞는가
  • Issuer URL 확인
  • Token decode 확인
  • Audience 설정 확인

👉 테스트는 반드시 /oauth2/callback 실제 호출로 확인해야 한다

핵심 정리

Keycloak 로그인 문제 해결 핵심
  • Redirect URI
  • Client 설정
  • Token 구조
  • Audience 설정
💡 Keycloak 문제는 대부분 설정에서 발생한다

마무리

Keycloak은 강력하지만 설정이 정확하지 않으면 동작하지 않습니다.

👉 에러 메시지를 보면 대부분 원인을 찾을 수 있다

Keycloak OIDC 설정 방법 (로그인 안될 때 해결 포함)

👉 Keycloak 설정했는데 로그인 안 되는 이유는 무엇일까?

Keycloak을 처음 설정할 때 대부분 OIDC(OpenID Connect) 구성에서 막힙니다. Client 설정, Redirect URI, Token 구조 중 하나라도 틀리면 인증은 실패합니다.

👉 Keycloak 문제의 대부분은 “설정 + 흐름 이해 부족”

1. OIDC 인증 흐름 (중요)

1. Client → Keycloak (/authorize)
2. 사용자 로그인
3. Authorization Code 발급
4. Client → Keycloak (/token)
5. Access Token / ID Token 발급
👉 Keycloak은 “Authorization Code Flow” 기반

2. Keycloak Client 설정 핵심

① 기본 설정

  • Client Protocol: openid-connect
  • Access Type: confidential / public

② 반드시 확인해야 하는 옵션

  • Standard Flow Enabled = ON
  • Valid Redirect URI 설정
  • Web Origins 설정
  • Direct Access Grants (필요 시)
👉 Standard Flow OFF면 로그인 자체가 안 된다

3. Redirect URI (가장 중요)

https://app.example.com/oauth2/callback

자주 하는 실수

  • http / https 불일치
  • 포트 누락
  • trailing slash 문제
  • wildcard(*) 잘못 사용
👉 redirect_uri 오류는 대부분 장애 원인

4. Token 구조 이해

토큰역할
ID Token사용자 인증
Access TokenAPI 권한
Refresh Token재발급
👉 ID Token = 인증 / Access Token = 권한

5. 실무에서 자주 발생하는 오류

에러원인
invalid_redirect_uriURI 불일치
invalid_clientClient Secret 오류
401 UnauthorizedToken 문제
invalid_tokenAudience mismatch
👉 에러 메시지가 원인을 알려준다

6. 실무 체크리스트

  • Redirect URI 정확한가
  • Client Secret 맞는가
  • Issuer URL 올바른가
  • Token decode 확인했는가

👉 테스트는 반드시 /oauth2/callback 실제 호출로 확인해야 한다

핵심 정리

Keycloak 인증 핵심
  • OIDC Flow 이해
  • Client 설정
  • Redirect URI
💡 인증 문제의 대부분은 설정에서 발생한다

마무리

Keycloak은 강력하지만 설정이 정확하지 않으면 동작하지 않습니다.

👉 구조를 이해하면 대부분 문제는 해결된다

Keycloak 사용자 관리 API 사용 방법 (조회/생성)

Keycloak이란 무엇인가

Keycloak은 인증(Authentication)과 권한 부여(Authorization)를 담당하는 서버입니다.

 

왜 Keycloak을 사용하는가

직접 인증을 구현하면:

  • 보안 취약점 발생 가능
  • 토큰 관리 복잡

 


 

Keycloak 사용자 관리 API

Keycloak에서 사용자 생성, 조회, 변경, 삭제는 Admin REST API를 사용합니다.
일반 로그인 API가 아니라, 관리자 권한을 가진 토큰이 필요합니다. Keycloak 공식 Admin REST API는 사용자 생성 POST /{realm}/users, 사용자 조회 GET /{realm}/users, 사용자 수 조회 GET /{realm}/users/count 등을 제공합니다.

 

 

1. Admin Token 발급

사용자 관리 API를 호출하려면 먼저 관리자용 Access Token을 받아야 합니다.

curl -X POST \
  https://keycloak.example.com/realms/master/protocol/openid-connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=admin-cli" \
  -d "client_secret=<CLIENT_SECRET>"

운영 환경에서는 관리자 계정의 아이디/비밀번호를 코드에 넣는 방식보다, 권한이 제한된 관리자용 client를 만들고 client_credentials 방식으로 호출하는 구성이 더 안전합니다.

 

2. 사용자 생성 API

POST /admin/realms/{realm}/users
curl -X POST \
  https://keycloak.example.com/admin/realms/lab/users \
  -H "Authorization: Bearer <ADMIN_ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "testuser",
    "email": "testuser@example.com",
    "firstName": "Test",
    "lastName": "User",
    "enabled": true,
    "emailVerified": false
  }'

생성 성공 시 보통 응답 본문은 비어 있고, 201 Created가 반환됩니다. 생성된 사용자의 ID는 응답 헤더의 Location 값에서 확인하거나, username으로 다시 조회해서 확인합니다.

 

3. 사용자 목록 조회 API

GET /admin/realms/{realm}/users
curl -X GET \
  "https://keycloak.example.com/admin/realms/lab/users?first=0&max=20" \
  -H "Authorization: Bearer <ADMIN_ACCESS_TOKEN>"
  
  
  curl -X GET \
  "https://keycloak.example.com/admin/realms/lab/users?username=testuser&exact=true" \
  -H "Authorization: Bearer <ADMIN_ACCESS_TOKEN>"

 

4. 사용자 상세 조회 API

사용자 상세 조회는 username이 아니라 user id 기준으로 호출합니다.

GET /admin/realms/{realm}/users/{user-id}
curl -X GET \
  https://keycloak.example.com/admin/realms/lab/users/<USER_ID> \
  -H "Authorization: Bearer <ADMIN_ACCESS_TOKEN>"

응답 예시:

{
  "id": "c9b1...",
  "username": "testuser",
  "email": "testuser@example.com",
  "enabled": true,
  "emailVerified": false
}

 

5. 사용자 정보 변경 API

PUT /admin/realms/{realm}/users/{user-id}
curl -X PUT \
  https://keycloak.example.com/admin/realms/lab/users/<USER_ID> \
  -H "Authorization: Bearer <ADMIN_ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "testuser",
    "email": "new-email@example.com",
    "firstName": "New",
    "lastName": "User",
    "enabled": true
  }'

주의할 점은 변경 API는 부분 업데이트처럼 생각하면 안 됩니다. 기존 값 유지가 필요한 필드는 함께 보내는 것이 안전합니다.

 

6. 사용자 비밀번호 변경 API

사용자 기본 정보 변경과 비밀번호 변경은 API가 다릅니다.

PUT /admin/realms/{realm}/users/{user-id}/reset-password
curl -X PUT \
  https://keycloak.example.com/admin/realms/lab/users/<USER_ID>/reset-password \
  -H "Authorization: Bearer <ADMIN_ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "password",
    "value": "NewPassword123!",
    "temporary": false
  }'

temporary: true로 설정하면 사용자는 다음 로그인 시 비밀번호 변경을 요구받습니다.

 

7. 사용자 비활성화

사용자를 삭제하지 않고 로그인을 막고 싶다면 enabled를 false로 변경합니다.

curl -X PUT \
  https://keycloak.example.com/admin/realms/lab/users/<USER_ID> \
  -H "Authorization: Bearer <ADMIN_ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": false
  }'

 

8. 사용자 삭제 API

DELETE /admin/realms/{realm}/users/{user-id}
curl -X DELETE \
  https://keycloak.example.com/admin/realms/lab/users/<USER_ID> \
  -H "Authorization: Bearer <ADMIN_ACCESS_TOKEN>"

 

 

[Kubernetes] Keycloak + oauth2-proxy + Ingress 인증 구성 방법 (OIDC 연동)

이 구조를 왜 쓰는가

보통 서비스에 로그인 기능을 넣으려면:

  • 로그인 API 개발
  • 세션 관리
  • 토큰 검증

이걸 서비스마다 반복해야 합니다.

이 구조는 다르게 접근합니다.

  • 로그인은 Keycloak이 담당
  • 인증 체크는 oauth2-proxy가 담당
  • 서비스는 인증 여부만 전달받음

즉, 애플리케이션은 인증 로직을 몰라도 됩니다.


전체 흐름 

  1. 사용자가 서비스 접속
  2. Ingress가 oauth2-proxy로 요청 전달
  3. 인증 안 되어 있으면 Keycloak으로 리다이렉트
  4. 로그인 성공 후 다시 돌아옴 (/oauth2/callback)
  5. oauth2-proxy가 쿠키 생성
  6. 이후 요청은 인증된 상태로 서비스 전달

브라우저 쿠키 기반 인증 유지

 


구성방법

1. Keycloak 설정 

Client 생성

  • Client ID: my-client
  • Client Protocol: openid-connect
  • Access Type: confidential

 

Redirect URI (가장 중요)

https://your-domain/oauth2/callback

 

2. oauth2-proxy 설정

args:
  - --provider=oidc
  - --oidc-issuer-url=https://keycloak.example.com/realms/<realm>
  - --client-id=my-client
  - --client-secret=<CLIENT_SECRET>
  - --redirect-url=https://your-domain/oauth2/callback
  - --cookie-secret=<BASE64_ENCODED_SECRET>
  - --cookie-secure=true
  - --cookie-samesite=lax
  - --email-domain=*
  - --upstream=http://your-service:80

issuer URL 수정

❌ 잘못된 예:

/auth/realms/<realm>

✅ 최신 Keycloak:

/realms/<realm>

cookie-secret

  • 반드시 base64 인코딩된 값
  • 32byte 이상 권장

upstream 설정

이 값이 없으면 인증 후 어디로 보낼지 모릅니다.

 

3. Ingress 설정 

Nginx Ingress 예시

annotations:
  nginx.ingress.kubernetes.io/auth-url: "http://oauth2-proxy.oauth2-proxy.svc.cluster.local/oauth2/auth"
  nginx.ingress.kubernetes.io/auth-signin: "https://your-domain/oauth2/start?rd=$request_uri"
  nginx.ingress.kubernetes.io/auth-response-headers: Authorization

auth-url은 내부 DNS 사용

oauth2-proxy.<namespace>.svc.cluster.local

 

/oauth2 path 반드시 열어야 함

Ingress에 아래 path 추가 필요:

- path: /oauth2
  pathType: Prefix
  backend:
    service:
      name: oauth2-proxy
      port:
        number: 80

 

 

4. 실제 동작 흐름 

브라우저 기준으로 보면:

  1. 서비스 접속 → 로그인 안됨
  2. Keycloak 로그인 페이지로 이동
  3. 로그인 성공
  4. 다시 서비스로 돌아옴
  5. 쿠키 생성됨
  6. 이후 로그인 없이 접근 가능

 


 

자주 발생하는 문제 

1. redirect_uri mismatch

  • Keycloak
  • oauth2-proxy

두 곳의 URL이 완전히 동일해야 합니다

 

2. 무한 리다이렉트

  • cookie-secret 문제
  • HTTPS 미사용

 

3. no such host

  • 내부 DNS 설정 오류
  • service 이름 틀림

 

4. 403 / 401 오류

  • auth-url 접근 실패
  • ingress annotation 오류

 

정리

Keycloak + oauth2-proxy 구조는
Kubernetes에서 인증을 표준화하는 강력한 방법입니다.

초기 설정은 복잡하지만,
구성 후에는 모든 서비스에 쉽게 인증을 붙일 수 있습니다.