145 lines
17 KiB
Markdown
145 lines
17 KiB
Markdown
---
|
|
title: OAuth2 Proxy — Nginx Integration (Official Docs)
|
|
source_type: official-doc
|
|
url: https://oauth2-proxy.github.io/oauth2-proxy/configuration/integrations/nginx/
|
|
archive_url:
|
|
status: raw
|
|
confidence: high
|
|
tags: [keycloak-patterns, p1a-edge-forward-auth, oauth2-proxy, nginx, auth_request, official-doc]
|
|
related_projects: [keycloak-patterns]
|
|
related_branches: [feature-keycloak-patterns, feature-keycloak-edge-forwardauth-no-google, feature-keycloak-nginx-auth-request-integration, feature-keycloak-oauth2-proxy-oidc-flow]
|
|
created: 2026-05-25
|
|
last_reviewed: 2026-07-17
|
|
---
|
|
|
|
# OAuth2 Proxy — Nginx Integration (Official Docs)
|
|
|
|
> Layer: `raw/official-docs/` — oauth2-proxy 공식 문서 중 nginx `auth_request` 결합 가이드. P1A 패턴 토큰 sequence 2단계(`/oauth2/auth` 엔드포인트)와 7단계(헤더 주입)의 1차 근거.
|
|
|
|
## Parent / 활용 branch (필수)
|
|
|
|
| Branch | 이 자료가 정당화하는 결정 |
|
|
|---|---|
|
|
| [[raw/branch-notes/feature-keycloak-patterns]] | keycloak-patterns root — edge 패턴에서 nginx `auth_request` + oauth2-proxy 결합이 정식 통합 방식이라는 사실 |
|
|
| [[raw/branch-notes/feature-keycloak-edge-forwardauth-no-google]] | P1A — `/oauth2/auth` 가 요청을 프록시하지 않고 202/401 만 반환하는 subrequest 패턴 채택 근거 |
|
|
| [[raw/branch-notes/feature-keycloak-nginx-auth-request-integration]] | nginx `auth_request_set` + `X-Auth-Request-User/Email/Access-Token` 변수 매핑 + `error_page 401 = @oauth2_signin;` 패턴의 공식 근거 |
|
|
| [[raw/branch-notes/feature-keycloak-oauth2-proxy-oidc-flow]] | OIDC code flow 의 edge subrequest 단계 + access token forwarding (`--pass-access-token`) 결정 근거 |
|
|
|
|
## 컨텍스트 / 왜 저장했는지
|
|
|
|
P1A의 핵심 메커니즘인 "ingress에서 ForwardAuth subrequest → 202 또는 401 응답 → 사용자 헤더를 backend에 forward" 의 공식 패턴이 어떻게 표현되는지 raw로 보존.
|
|
|
|
## 출처 / Source
|
|
|
|
- 원본 URL: https://oauth2-proxy.github.io/oauth2-proxy/configuration/integrations/nginx/
|
|
- 아카이브 URL: (미수집)
|
|
- 저자 / 조직: oauth2-proxy maintainers
|
|
- 발행일: rolling docs
|
|
- 마지막 확인일: 2026-07-17
|
|
|
|
## 핵심 인용 / Key quotes (verbatim)
|
|
|
|
> [§Nginx auth_request directive] "The [Nginx `auth_request` directive](http://nginx.org/en/docs/http/ngx_http_auth_request_module.html) allows Nginx to authenticate requests via the oauth2-proxy's `/auth` endpoint"
|
|
|
|
> [§Endpoint behavior] "only returns a 202 Accepted response or a 401 Unauthorized response without proxying the request through" — endpoint expects: "**2xx**: Request is authenticated, allow access" and "**401 or 403**: Request is not authenticated, deny access"
|
|
|
|
> [§Headers] "pass information via X-User and X-Email headers to backend, requires running with --set-xauthrequest flag" — example: "auth_request_set $user $upstream_http_x_auth_request_user; auth_request_set $email $upstream_http_x_auth_request_email"
|
|
|
|
> [§Access token] "if you enabled --pass-access-token, this will pass the token to the backend: auth_request_set $token $upstream_http_x_auth_request_access_token"
|
|
|
|
> [§Sign-in redirect] "When a 401 is returned, nginx triggers the `error_page` directive...returns a proper **302 redirect**" — named location returns `302 /oauth2/sign_in?rd=$scheme://$host$request_uri`
|
|
|
|
> [§Large cookies] "some provider's cookies can exceed the 4kb limit and so the OAuth2 Proxy splits these into multiple parts. Nginx normally only copies the first `Set-Cookie` header from the auth_request to the response"
|
|
|
|
> [§Configuring for use with the Nginx `auth_request` directive — 전체 nginx.conf 예제, `location /oauth2/` 와 `location = /oauth2/auth` 두 block 분리] (2026-07-17 추가, 출처: `docs/versioned_docs/version-7.15.x/configuration/integrations/nginx.md` raw markdown, master branch)
|
|
>
|
|
> ```nginx
|
|
> location /oauth2/ {
|
|
> proxy_pass http://127.0.0.1:4180;
|
|
> proxy_set_header Host $host;
|
|
> proxy_set_header X-Real-IP $remote_addr;
|
|
> proxy_set_header X-Auth-Request-Redirect $request_uri;
|
|
> # or, if you are handling multiple domains:
|
|
> # proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri;
|
|
> }
|
|
> location = /oauth2/auth {
|
|
> proxy_pass http://127.0.0.1:4180;
|
|
> proxy_set_header Host $host;
|
|
> proxy_set_header X-Real-IP $remote_addr;
|
|
> proxy_set_header X-Forwarded-Uri $request_uri;
|
|
> # nginx auth_request includes headers but not body
|
|
> proxy_set_header Content-Length "";
|
|
> proxy_pass_request_body off;
|
|
> }
|
|
> ```
|
|
>
|
|
> (verbatim, elide 미적용 — controller 지정에 따라 코드 블록 완전성 보존을 위해 200자 elide 규칙의 예외로 전체 보존함)
|
|
|
|
> [§Browser vs API Routes] (2026-07-17 추가) "Redirecting authentication failures (302 to `/oauth2/sign_in`) should **only be used for browser-facing routes**. API or machine clients should receive a plain 401/403 response without redirect."
|
|
|
|
> [§API / Machine routes (no redirect)] (2026-07-17 추가, verbatim code block)
|
|
>
|
|
> ```nginx
|
|
> location /api/ {
|
|
> auth_request /oauth2/auth;
|
|
> error_page 401 =401; # Pass through the 401 status
|
|
> proxy_pass http://backend/;
|
|
> }
|
|
> ```
|
|
|
|
## Claims Extracted / 추출된 주장
|
|
|
|
| Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove |
|
|
|---|---|---|---|---|---|
|
|
| O2PN-C1 | nginx 의 `auth_request` 디렉티브를 통해 oauth2-proxy 의 `/auth` 엔드포인트로 인증을 위임할 수 있다 | [§Nginx auth_request directive] "The [Nginx `auth_request` directive](http://nginx.org/en/docs/http/ngx_http_auth_request_module.html) allows Nginx to authenticate requests via the oauth2-proxy's `/auth` endpoint" | `official-vendor-doc` | nginx + oauth2-proxy 통합 | 모든 nginx 빌드에 `auth_request` 가 컴파일되어 있다는 뜻은 아님 (별도 module — `nginx-auth-request-module-official.md` 참조) |
|
|
| O2PN-C2 | `/oauth2/auth` 엔드포인트는 요청을 upstream 으로 프록시하지 않고 오직 2xx (인증됨) 또는 401/403 (거부) 만 반환 | [§Endpoint behavior] "only returns a 202 Accepted response or a 401 Unauthorized response without proxying the request through" — "**2xx**: Request is authenticated, allow access" / "**401 or 403**: Request is not authenticated, deny access" | `official-vendor-doc` | oauth2-proxy subrequest mode | 정상 reverse-proxy mode (`/oauth2/start`, `/oauth2/callback`) 의 동작에 적용된다는 뜻 아님 — subrequest 전용 |
|
|
| O2PN-C3 | backend 로 `X-User`/`X-Email` 헤더 전달은 oauth2-proxy 가 `--set-xauthrequest` 플래그로 실행되어 응답 헤더 `X-Auth-Request-User`/`X-Auth-Request-Email` 을 내보낼 때 가능 | [§Headers] "pass information via X-User and X-Email headers to backend, requires running with --set-xauthrequest flag" — "auth_request_set $user $upstream_http_x_auth_request_user; auth_request_set $email $upstream_http_x_auth_request_email" | `official-vendor-doc` | nginx → backend 사용자 신원 전달 | nginx 가 backend 가 X-User 헤더를 신뢰해도 안전하다는 뜻 아님 — 헤더 spoofing 방지는 별도 (header-stripping 결정 필요) |
|
|
| O2PN-C4 | `--pass-access-token` 활성화 시 access token 은 `X-Auth-Request-Access-Token` 응답 헤더로 노출되며 nginx `auth_request_set` 으로 backend 로 전달 가능 | [§Access token] "if you enabled --pass-access-token, this will pass the token to the backend: auth_request_set $token $upstream_http_x_auth_request_access_token" | `official-vendor-doc` | edge 에서 backend 로 access token forwarding | access token forwarding 이 RS audience validation 을 대체한다는 뜻은 아님 (별도 RS 측 검증) |
|
|
| O2PN-C5 | 401 응답 시 nginx 가 `error_page` 디렉티브로 named location 트리거 → 브라우저에 302 redirect (`/oauth2/sign_in?rd=...`) 반환 | [§Sign-in redirect] "When a 401 is returned, nginx triggers the `error_page` directive...returns a proper **302 redirect**" — `return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri` | `official-vendor-doc` | 미인증 브라우저 요청 처리 | XHR/API 요청에 302 redirect 반환이 적절하다는 뜻 아님 — API client 별도 처리 권장 |
|
|
| O2PN-C6 | 일부 provider 의 cookie 는 4KB 한도를 초과해 oauth2-proxy 가 여러 part 로 분리하며, nginx 는 기본적으로 auth_request 응답에서 첫 번째 `Set-Cookie` 헤더만 복사한다 | [§Large cookies] "some provider's cookies can exceed the 4kb limit and so the OAuth2 Proxy splits these into multiple parts. Nginx normally only copies the first `Set-Cookie` header from the auth_request to the response" | `official-vendor-doc` | 큰 토큰 (Keycloak refresh token 포함 세션 등) 처리 | multi-part cookie 처리 nginx 코드의 정확한 lua/scripting 방식은 본 인용 범위 밖 |
|
|
| O2PN-C7 | 공식 nginx.conf 예제는 oauth2-proxy 자체 endpoint(`/oauth2/callback`, `/oauth2/start`, `/oauth2/sign_out` 등)를 위한 **prefix location block** (`location /oauth2/ { ... }`, `X-Auth-Request-Redirect` 헤더 포함)과 auth_request 대상인 `/oauth2/auth` 를 위한 **exact-match location block** (`location = /oauth2/auth { ... }`)을 **별도의 두 block으로 분리**해서 정의한다 | [§전체 nginx.conf 예제] 위 "핵심 인용" §Configuring for use with the Nginx `auth_request` directive 의 verbatim 코드 블록 (`location /oauth2/ { ... }` + `location = /oauth2/auth { ... }` 두 block, line 26-42 of fetched raw markdown) | `official-vendor-doc` | D7 — oauth2-proxy 자체 endpoint 라우팅을 `location /oauth2/` prefix block 으로, auth_request 대상을 `location = /oauth2/auth` exact block 으로 분리하는 결정 | **Negative finding**: 공식 예제는 `location = /oauth2/auth` block 에 `internal;` directive 를 붙이지 **않는다** (fetched 원문 전체에 `internal` 문자열 자체가 존재하지 않음 — grep 으로 확인). 즉 공식 예제만으로는 "이 location 을 외부에서 직접 호출 불가하게 격리해야 한다"는 하드닝을 증명하지 않는다 — 이는 사용자가 예제를 넘어 추가하는 보안 결정. 또한 이 예제는 standalone nginx 설정이며, ingress-nginx annotation 방식(K8s)에 그대로 적용된다는 뜻은 아니다 |
|
|
| O2PN-C8 | 공식 nginx.conf 예제의 `location = /oauth2/auth` block 은 `# nginx auth_request includes headers but not body` 라는 인라인 주석과 함께 `proxy_set_header Content-Length "";` 및 `proxy_pass_request_body off;` 두 directive 를 포함한다 | [§전체 nginx.conf 예제] "# nginx auth_request includes headers but not body" / "proxy_set_header Content-Length \"\";" / "proxy_pass_request_body off;" (line 39-41 of fetched raw markdown) | `official-vendor-doc` | D6 — `proxy_pass_request_body off` + `Content-Length ""` 로 auth_request subrequest 의 body 전달을 차단하는 결정 | 원문은 "nginx 의 `auth_request` 메커니즘 자체가 subrequest 에 헤더는 포함하되 body 는 포함하지 않는다"는 **사실**만 명시한다. **원문은 "body 를 전달하면 POST endpoint 가 의도치 않게 오발동하거나 oauth2-proxy 의 CPU 사용량이 증가한다"는 인과관계를 말하지 않는다** — 이는 branch-note D6 의 Open Risk 컬럼에 있는 사용자 추론이며 이 quote 로 증명되지 않는다. 이 두 directive 를 생략해도 nginx auth_request 자체 동작(2xx/401 판정)에 문제가 생긴다고 원문이 말하는 것도 아니다 — 원문은 단지 공식 예제가 이 설정을 포함한다는 사실만 보여준다 |
|
|
| O2PN-C9 | 공식 문서는 인증 실패 시 302 redirect (`/oauth2/sign_in`)를 **browser-facing route 에만** 사용해야 하며, API/machine client 는 redirect 없는 plain 401/403 응답을 받아야 한다고 명시한다. 이를 위한 별도 예시로 `location /api/ { auth_request /oauth2/auth; error_page 401 =401; proxy_pass http://backend/; }` 패턴(302 redirect 없이 401 status 를 그대로 pass-through)을 제공한다 | [§Browser vs API Routes] "Redirecting authentication failures (302 to `/oauth2/sign_in`) should **only be used for browser-facing routes**. API or machine clients should receive a plain 401/403 response without redirect." + [§API / Machine routes (no redirect)] verbatim 코드 블록 (`error_page 401 =401; # Pass through the 401 status`) | `official-vendor-doc` | **D9 — 인증 실패 응답의 route 별 분기(1차 근거)** / D7 부가 참고. (2026-07-17: 본 claim 을 근거로 `feature-keycloak-nginx-auth-request-integration` 에 D9 가 신설됨 — 최초 작성 시점엔 D9 가 없어 "D7 부가" 로만 라벨돼 있었다) | 이 섹션은 **backend API route (예: `/api/`) 의 인증 실패 응답 정책**을 다루는 것이지, **oauth2-proxy 자체 endpoint 라우팅**(`location /oauth2/` prefix block 을 쓸지, callback/start/sign_out 을 internal 로 격리할지)의 근거는 아니다 — D7 의 핵심 근거는 O2PN-C7 이며, O2PN-C9 는 부가 참고 자료로만 D7 에 연결된다. 또한 이 자료 하나만으로 "모든 API 는 반드시 401 을 그대로 반환해야 한다"는 강제 규범이 존재한다는 뜻도 아니다 — 공식 문서는 권고(should)로 표현했을 뿐 |
|
|
|
|
## Usage Boundaries / 적용 경계
|
|
|
|
- **이 자료가 직접 증명하는 것**:
|
|
- `O2PN-C1` ~ `C6`: nginx `auth_request` + oauth2-proxy `/oauth2/auth` 의 공식 통합 패턴, 응답 코드 의미, 헤더 매핑 변수명, 401 redirect 패턴, large cookie 한계
|
|
- `O2PN-C7`: 공식 예제가 oauth2-proxy 자체 endpoint(`/oauth2/` prefix)와 auth_request 대상(`/oauth2/auth` exact)을 별도 location block 으로 분리한다는 사실 — D7 의 라우팅 분리 결정의 1차 근거
|
|
- `O2PN-C8`: 공식 예제가 `location = /oauth2/auth` block 에 `proxy_set_header Content-Length ""` + `proxy_pass_request_body off` 를 포함한다는 사실 (인과관계·이유는 증명 안 함) — D6 의 1차 근거
|
|
- `O2PN-C9`: 공식 문서가 302 redirect 를 browser-facing route 에만 권고하고 API/machine client 는 plain 401/403 을 받아야 한다고 명시하는 사실 — D7 부가 참고
|
|
- **이 자료가 증명하지 않는 것**:
|
|
- nginx `auth_request` 모듈이 모든 distribution 의 nginx 패키지에 컴파일되어 있는지 (별도 `nginx-auth-request-module-official.md`)
|
|
- backend 가 `X-User` 헤더를 신뢰해도 안전한 보안 전제 (header-spoofing 방어는 별도 P1A 결정)
|
|
- `--pass-access-token` 가 활성화된 환경에서 access token 의 audience 가 backend RS 와 일치할 것임 (audience validator 별도 RS 책임)
|
|
- `location = /oauth2/auth` 를 `internal;` 로 격리해야 한다는 것 (공식 예제에 `internal` 자체가 없음 — `O2PN-C7` negative finding)
|
|
- `proxy_pass_request_body off` 를 생략하면 POST 오발동이나 CPU 증가가 발생한다는 인과관계 (`O2PN-C8` does-not-prove — 원문은 설정 사실만 보여줌)
|
|
- "모든 API 는 반드시 401 을 그대로 반환해야 한다"는 강제 규범 (`O2PN-C9` 는 권고(should) 표현일 뿐)
|
|
- **내 프로젝트에 적용하려면 추가 확인이 필요한 것**:
|
|
- 사용하는 nginx 빌드에 `auth_request` 모듈 포함 여부 (`nginx -V 2>&1 | grep auth_request`)
|
|
- P1A 의 Keycloak realm 에서 access token 크기가 4KB 를 넘는지 (refresh token 포함 cookie split 필요 여부)
|
|
- edge 에서 forward 되는 `X-User`/`X-Email` 의 spoofing 방지를 위해 backend 가 edge 외부 traffic 을 차단하는지
|
|
- `location = /oauth2/auth` 를 외부에서 직접 호출 불가하게 만들려면 `internal;` 등 별도 하드닝을 사용자가 직접 추가해야 함 (공식 예제 범위 밖)
|
|
|
|
## 메모 / Notes (내 프로젝트 해석)
|
|
|
|
> 본 섹션은 자료 직접 인용 아님. P1A 결정 컨텍스트 해석.
|
|
|
|
- `/oauth2/auth` 가 **요청을 프록시하지 않음** 이 핵심. 일반 reverse-proxy 모드(`/oauth2/start`, `/oauth2/callback`)와 구분.
|
|
- 401 처리는 `error_page 401 = @oauth2_signin;` named location 패턴 사용 → 사용자 브라우저에 302 redirect 응답.
|
|
- `auth_request_set` 의 `$upstream_http_x_auth_request_user` 변수명은 oauth2-proxy 응답 헤더 `X-Auth-Request-User` 의 nginx 변수 표현.
|
|
- (2026-07-17) `O2PN-C7`~`C9` 추가 시 렌더링된 HTML 페이지(curl)와 GitHub raw markdown(`docs/versioned_docs/version-7.15.x/configuration/integrations/nginx.md`, master branch, edit-URL 로 경로 확인) 두 fetch 를 대조. 둘 다 "Browser vs API Routes" 섹션을 포함 — 선행 조사에서 제기된 "렌더링된 HTML 에는 없음" 불일치는 이번 재확인(2026-07-17 시점)에서는 재현되지 않음. raw markdown 을 self-grep 의 canonical 텍스트로 채택(기존 C1~C6 인용의 backtick·markdown-link 표기 스타일과 일치하기 때문).
|
|
- `O2PN-C7`/`C8` 의 nginx.conf 코드 블록은 200자 elide 규칙의 예외로 전체 verbatim 보존 — controller 지정 사항이며, 코드 config 블록을 elide 하면 기술적 완전성이 깨지기 때문.
|
|
|
|
## Related / 관련
|
|
|
|
- 같은 주제 다른 official-doc:
|
|
- [[raw/official-docs/oauth2-proxy-keycloak-oidc-provider-official]]
|
|
- [[raw/official-docs/oauth2-proxy-overview-config-official]]
|
|
- [[raw/official-docs/nginx-auth-request-module-official]]
|
|
- [[raw/official-docs/traefik-forwardauth-middleware-official]] (대안 ingress)
|
|
- 인용하는 branch:
|
|
- [[raw/branch-notes/feature-keycloak-edge-forwardauth-no-google]] (P1A)
|
|
- [[raw/branch-notes/feature-keycloak-nginx-auth-request-integration]]
|
|
- 인용하는 wiki: (미작성)
|