Files
document-haness/docs/keycloak/tech-log-studio/oauth-oidc-auth-boundary/question/question-edge-authorization-scope.md
T
DongHyeonkaandClaude Opus 5 b2963105a8 docs(keycloak-session-store): import the session-storage lab as a new project
The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.

Follows the import procedure in README.md.

  source/     the originating repository verbatim — 78 documents, 28 SVGs,
              8 manifests, plus .source-revision recording the commit
  final/      the SSOT
    document.md   729 lines written from the 29 experiment documents, not
                  concatenated: what was predicted, what was measured, and
                  where the measurement itself was wrong
    evidence/raw    125 outputs, flattened to <experiment>__<file> because
                    the originals collided (01-baseline.txt appeared three
                    times) and the audit only globs the top level
    evidence/meta   one per raw file; command and exitCode are null and the
                    README says why rather than inventing them
    evidence/browser  22 captures
    assets/       three diagrams through techviz
    .techviz/     their VizSpecs

A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.

Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.

verify-pipeline.py passes. audit-records.py reports no issues.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 22:51:59 +09:00

8.6 KiB

id, kind, slug, title, topic, topicName, project, status, version, questionStatus, studio, public
id kind slug title topic topicName project status version questionStatus studio public
7ff40767-a00b-4db2-98f6-0cdfce8c8936 QUESTION edge-authorization-scope Forward-Auth 구조에서 Application Authorization을 어디까지 Edge에 둘 것인가 oauth-oidc-auth-boundary OAuth/OIDC 인증 경계 KeyCloak Patterns 게시 중 36 OPEN https://hyeonworks.com/studio/documents/7ff40767-a00b-4db2-98f6-0cdfce8c8936/edit https://hyeonworks.com/questions/edge-authorization-scope

Forward-Auth 구조에서 Application Authorization을 어디까지 Edge에 둘 것인가

현재 Edge는 인증된 사용자의 useremail만 Header로 전달하고 있으며, Upstream 애플리케이션에서는 Role을 이용한 인가 판단을 하지 않는다.

따라서 현재 구조만으로는 Role 기반 인가가 필요한 요구사항이 추가되었을 때 어떻게 처리할지 결정되어 있지 않다. Edge가 사용자의 Role까지 확인해 Header로 전달할지, 아니면 애플리케이션이 Role과 권한을 확인하고 인가를 직접 판단하도록 할지 별도로 결정해야 한다.

Role이나 권한처럼 애플리케이션의 기능과 밀접한 정보가 계속 늘어난다면, 이러한 정보를 Edge Header에 계속 추가하기보다 인가 책임을 애플리케이션에서 처리하는 구조가 더 적절한지도 함께 검토한다.

관계

  • Forward-Auth에서 Client가 보낸 Identity Header를 신뢰하면 안 되는 이유 edge가 user와 email만 전달한다는 사실의 출처다.
  • Forward-Auth에서 Identity Header를 신뢰하기 위한 조건 헤더 allowlist와 검증 조건이 이 기준에 있다.
  • BFF 인증 구조 설계 기준 되돌리는 선택지의 기준이 이 문서다.

사실

  • 지금 edge 응답은 user와 email만 전달한다. role과 groups, tenant, 인증 방식, token 만료는 전달하지 않는다.

  • upstream의 identity endpoint는 role을 확인하지 않는다. 누가 왔는지만 응답한다.

  • 현재 Internal Token 검증은 특정 Controller에서만 수행하고 있으며, Security 설정에서는 해당 경로를 permitAll로 허용하고 있다.

    이 구조에서는 같은 내부 경로 아래에 새로운 Endpoint를 추가하더라도 Internal Token 검증이 자동으로 적용되지 않는다. 그래서 Filter, Interceptor, 또는 Spring Security의 인증 처리 단계처럼 공통 경계에서 검증하도록 옮겨야 한다.

  • Nginx는 client가 보낸 동명 헤더를 merge하지 않고 덮어쓴다. 추가적으로 늘어나는 헤더도 같은 처리를 받아야 한다.

  • upstream은 JWT를 입력으로 받지 않아서 헤더로 넘어온 값을 검증할 방법이 없다.

가정

  • 헤더 종류가 늘어나면 정해야 할 계약도 늘어난다.
  • role이 바뀌는 시점과 요청이 오는 시점이 달라서 그 사이에 들어온 요청은 바뀌기 전의 값을 볼 수도 있다.

미지수

  • 다중 값 role을 어떤 구분자와 escaping으로 보낼지. 값 안에 그 구분자가 들어오면 어떻게 되는지.
  • 헤더 크기 상한을 넘으면 어떻게 되는지. proxy가 자르는지 요청 자체가 거부되는지.
  • role이 바뀌었을 때 proxy session과 downstream 인가가 언제 반영되는지. 권한 변경이 몇 분 뒤에 반영되는지.
  • upstream이 헤더 존재만 볼지 값과 service identity까지 볼지.

제약

  • 전달할 헤더는 allowlist로 해야 하고 client가 보낸 동명 헤더는 항상 덮어써야 한다.
  • internal token 검사가 controller 한 곳에만 있다. 헤더를 늘리기 전에 이 검사를 공통 경계로 옮겨야 된다.

선택지

1. 인증만 edge에 둔다

Edge가 전달하는 Header를 user와 email 정도로 제한하면 Edge와 Upstream 사이의 계약을 작게 유지할 수 있다. Role이나 Permission 정보를 Header에 계속 추가하지 않으므로 Header 크기가 커지는 문제도 줄일 수 있다.

이 경우 인가 판단은 각 Upstream 애플리케이션이 직접 수행한다. 애플리케이션은 전달받은 사용자 식별 정보를 기준으로 자신의 저장소에서 Role이나 Permission을 조회하고, 해당 요청을 허용할지 결정해야 한다.

이 구조에서는 서비스마다 권한 조회와 인가 로직을 별도로 구성해야 한다. 따라서 Edge의 책임은 단순하게 유지할 수 있지만, 서비스 수가 늘어나면 각 서비스에서 동일하거나 유사한 권한 조회 체계를 반복해서 구현하고 운영해야 할 수 있다.

2. role 전달까지 edge에 둔다

Edge가 공통 Role 정보를 확인해 Upstream에 전달하면 각 서비스가 별도로 사용자 권한을 조회해야 하는 작업을 줄일 수 있다.

대신 Role을 Header로 전달하기 위한 계약을 먼저 정해야 한다. 사용자가 여러 Role을 가질 때 어떤 형식으로 직렬화할지, Header에 허용할 최대 크기를 어디까지로 할지, 사용자의 Role이 변경되었을 때 언제부터 새로운 값이 요청에 반영되는지도 명확하게 정의해야 한다.

또한 Upstream은 전달받은 Role이 원래 인증 시스템의 값과 일치하는지 확인할 수 있어야 하고, 그러지 못하면 Edge가 전달한 값을 그대로 신뢰하게 된다. 따라서 Edge에서 Role을 잘못 계산하거나 오래된 값을 전달하면 Upstream의 인가 판단도 그대로 잘못될 수 있다.

이 구조를 선택하게 되면 Edge가 Role 정보를 만드는 과정과 Header를 전달하는 경로를 신뢰 경계의 일부로 보고, Role 갱신과 전달 오류를 어떻게 검증할지도 함께 설계해야 한다.

3. tenant와 인가 판단까지 edge에 둔다

Tenant 정보는 단순한 사용자 속성이 아니라 어떤 조직의 데이터에 접근할 수 있는지를 결정하는 값이다. 따라서 잘못된 Tenant 값 하나가 전달되면 다른 조직의 데이터에 접근하는 문제로 바로 이어질 수 있다.

이 때문에 Tenant를 Edge Header로 전달하려면 Upstream에서도 해당 사용자가 실제로 그 Tenant에 속하는지 다시 확인할 수 있는 방법이 필요하다. 현재 구성에는 이러한 재검증 수단이 없으므로 Tenant까지 Edge가 책임지는 구조로 확장하기에는 위험이 크다.

더 나아가 Tenant나 Role을 이용한 실제 인가 판단까지 Edge로 옮기면 Edge가 애플리케이션의 도메인 규칙을 알아야 한다. 어떤 사용자가 어떤 조직의 어떤 기능을 사용할 수 있는지 같은 정책이 바뀔 때마다 Edge의 로직도 함께 수정하고 배포해야 한다.

따라서 Edge는 인증된 사용자 정보를 전달하는 역할에 가깝게 유지하고, Tenant 소속 관계나 도메인에 종속된 인가 규칙은 Upstream 애플리케이션에서 검증하는 구조를 우선 검토한다.

4. 헤더 계약 대신 BFF가 인가와 API 호출을 맡는다

Role이나 Tenant 같은 정보를 Edge Header에 계속 추가하는 대신, BFF가 사용자에게 필요한 정보를 직접 조회하고 인가 판단과 API 호출을 처리하는 구조도 선택할 수 있다.

이 구조에서는 Edge가 애플리케이션의 Role, Tenant, 권한 정책까지 알 필요가 없다. BFF가 필요한 사용자와 권한 정보를 조회해 인가를 판단하고, 화면에 필요한 여러 Resource Server의 API를 호출해 결과를 조합할 수 있다. 따라서 애플리케이션 도메인에 가까운 책임을 Edge Header 계약에서 분리할 수 있다.

이 구조에서는 BFF를 도입하면서 서버가 다시 인증 상태를 관리해야 한다. 브라우저와 BFF 사이의 Application Session을 보호해야 하고, Cookie 기반 Session을 사용한다면 상태 변경 요청에 대한 CSRF 검증도 필요하다. 여러 BFF Replica에서 인증 상태를 유지해야 한다면 Session과 Authorized Client를 어떻게 공유할지 결정하고 Shared Store의 장애와 만료 처리도 운영해야 한다.

다음 검증

upstream이 실제로 요구하는 claim을 먼저 적는다.

  1. 전달하려는 claim이 계속 늘어나는가.
  2. role이나 tenant 변경이 즉시 반영돼야 하는가.
  3. 정책이 애플리케이션 도메인을 알아야 하는가.
  4. 헤더 값이 인가 판단의 근거가 되는가.
  5. 서비스별 정책 차이가 커지는가.

2번부터 5번 중 하나라도 그렇다면 헤더를 늘리는 대신 BFF 구조를 검토한다.

role을 헤더에 담는 구성을 먼저 만들고, 다중 값과 크기 상한을 넣어 무엇이 먼저 잘못되는지 확인한다. role을 바꾼 뒤 몇 번째 요청부터 반영되는지도 확인한다.