Files
llm-wiki/wiki/concepts/security-baseline-jwt-actuator-secrets.md
T

139 lines
12 KiB
Markdown

---
title: Security Baseline (JWT Resource Server + Actuator + Secrets)
source_type: llm-generated
status: draft
confidence: medium
tags: [security, jwt, oauth2, actuator, secrets]
related_projects: [ca-skeleton]
last_reviewed: 2026-05-22
---
# Security Baseline (JWT Resource Server + Actuator + Secrets)
> Layer: `wiki/concepts/` — JWT Resource Server 기반 인증/인가, Actuator 관리면 보안, secret 소스/rotation 세 가지를 한 묶음으로 다루는 백엔드 보안 baseline 개념 문서. 실무 적용은 `wiki/projects/` 문서로 분리.
## Summary
운영 가능한 백엔드 보안 baseline은 **세 축**으로 구성된다. ① 데이터면 인증/인가는 **JWT Resource Server**(RFC 7519/8725, OAuth2 Resource Server) 기준으로 표준화하고, 토큰 실패를 `missing / malformed / expired / invalid signature / issuer / audience / unknown kid / claim mapping` 등으로 분류한다. JWKS는 주기 refresh(예: 10분 + unknown kid 시 on-demand)로 키 회전을 흡수하고, JWT 시간 검증은 **clock skew tolerance 60s** 정도를 둔다. ② 제어면(Actuator)은 **management port 분리**(예: 9001) + prod allowlist(health / prometheus / info) + heapdump/threaddump/env/configprops/shutdown forbidden을 default로 한다. ③ Secret은 **prod = secret manager 또는 mounted secret**, local만 `.env` 허용, runtime reload 금지, rotation은 restart 또는 명시적 dual-bind/overlap window로만 한다.
## Standard (공식 정의)
### JWT / OAuth2 / 인가
- **RFC 7519 (JSON Web Token)**: JWT 구조와 `iss`, `aud`, `exp`, `nbf`, `iat`, `jti`, `sub` 등 표준 claim, 서명/검증 의무를 규정. `exp`/`nbf` 검증 시 "a few minutes leeway"가 일반적이며 구현은 명시된 허용치를 설정해야 한다.
- **RFC 8725 (JWT Best Current Practices)**: algorithm confusion 회피(`alg: none` 금지, `HS256``RS256` 혼용 금지), `kid` 사용, audience/issuer 명시 검증, `typ: JWT` 검증 등 운영상 함정 정리.
- **RFC 6749/6750 + OAuth2 Resource Server**: bearer token으로 보호된 리소스에서 token validation 책임을 resource server에 두는 모델. Spring Security 6의 `spring-boot-starter-oauth2-resource-server`가 표준 구현 경로.
- **RFC 8252 (OAuth 2.0 for Native Apps) + PKCE**: public client(SPA, mobile)의 authorization code flow에서 code interception 방어. **issuance flow** 영역으로 resource server JWT 검증과는 보완재.
- **RFC 8705 (Mutual-TLS Client Authentication and Certificate-Bound Access Tokens)**: mTLS 또는 sender-constrained token. JWT보다 강한 보장이나 PKI 운영 비용이 큼.
- **OWASP Authorization Cheatsheet**: deny-by-default, least privilege, server-side enforcement, ABAC/RBAC 혼합, audit logging 등 인가 설계 원칙.
### Actuator / 관리면
- **Spring Boot Actuator 공식 문서**: 기본적으로 `health`, `info`만 web exposure, 그 외(`env`, `configprops`, `heapdump`, `threaddump`, `loggers`, `shutdown`)는 default disabled. `management.endpoints.web.exposure.include`로 명시 허용 + `SecurityFilterChain`으로 별도 보호 권고.
- **`management.server.port`**: app port(8080)와 별도의 management port(예: 9001)로 분리 가능. 네트워크 ACL/Ingress에서 외부 노출 차단을 단순화하는 것이 분리 권고의 핵심.
- **Istio sidecar / service mesh**: mTLS, AuthorizationPolicy로 management endpoint 보호 가능. mesh 가정이 강하므로 framework-neutral skeleton에서는 대안.
### Secrets / Config
- **12-factor App §III. Config**: 환경 사이에서 변하는 값은 **환경변수**로 외부화, 코드와 분리. config dump 금지의 이론 근거.
- **AWS Secrets Manager (auto-rotation)**: Lambda 기반 rotation function 표준. dual-binding window 동안 old/new credential을 둘 다 유효하게 두어 connection pool/검증자 캐시가 흡수하도록 설계.
- **HashiCorp Vault (dynamic secrets)**: lease 기반 짧은 수명 credential 발급. lease renewal 책임을 클라이언트가 짊.
- **K8s Secret + External Secrets Operator (ESO)**: 외부 secret manager → K8s Secret → 컨테이너 mount/env 경로. etcd 암호화 미설정 시 평문 저장 한계.
- **NIST SP 800-57 (Recommendation for Key Management)**: cryptoperiod, key rotation, key destruction의 표준. HMAC salt/JWT signing key rotation 주기 결정의 reference.
## 한계 / 주의점
### JWT Resource Server
- **Revocation 한계**: 표준 JWT는 stateless 검증이므로 발급 후 강제 무효화가 어렵다. 회수 수단은 ① short expiry + refresh token, ② JWKS rotation + 작은 key overlap, ③ deny-list cache(상태 부활), ④ token introspection(stateless 포기) 중 trade-off. "JWT라 안전하다"는 단정 금지.
- **algorithm confusion**: RFC 8725가 명시적으로 경고. 구현 단에서 server-side로 허용 알고리즘을 fix해야 함(`alg: none`/HS↔RS 혼용 금지).
- **clock skew**: 너무 작게 잡으면 서버 시계 drift로 false negative, 너무 크면 expired token 수용 창 확대. 일반적으로 30~60s 권고.
- **JWKS endpoint outage**: cache miss + IdP 장애 시 모든 인증이 막힘. 캐시 TTL + on-demand refresh + 명시적 outage status 분류가 필요.
### Session + Cookie
- stateless 확장성 손실(서버 측 session store 필요).
- CSRF 방어, SameSite/HttpOnly/Secure cookie 운영 복잡도.
- revocation은 session 삭제로 즉시 가능 — 보안상 강점이지만 비용은 분산 session store.
### mTLS
- sender-constrained로 token theft 위협에 강함.
- 단점: PKI(발급/갱신/폐기) 운영 비용, public client(브라우저 SPA, 모바일 일반 사용자) 사용 어려움.
### OPA (Open Policy Engine)
- 정책-코드 분리, 외부에서 정책 변경/감사 가능.
- 단점: 외부 호출 latency, sidecar/agent 운영, in-process 인가 2~3종에는 과한 인프라.
### Actuator
- **single-port + path ACL**: cloud ingress가 path 기반 차단을 강하게 보장할 때만 안전. 잘못된 filter ordering, regex 매칭 우회 risk.
- **mTLS for management**: 강하지만 cert 운영 부담.
- **mesh sidecar (Istio)**: mesh 도입을 전제 → skeleton/framework-neutral 가정과 충돌.
- **info endpoint**: build info 외에 commit hash/branch만 노출해도 attack surface가 될 수 있음 — 무엇이 들어가는지 명시 필요.
- **한국 사례 (토스/우아한형제들 등) 일부 참조 가능 (G-B 후속 보강 결과).** Actuator 노출 보안에 대한 한국 도메인 사례가 존재하며, JWT/secret 관리 직접 사례는 follow-up 후보로 남음.
### Secrets
- **Vault dynamic secrets**: 짧은 lease가 보안 우위이나, **Spring `@RefreshScope` + bean 재생성** 흐름을 강제 → connection pool/캐시 lifecycle과 충돌. ca-tmpl처럼 `@RefreshScope` 금지 환경에서는 정면 충돌.
- **AWS Secrets Manager auto-rotation**: dual-binding window 60s 패턴과 정합하지만, rotation Lambda 자체가 운영/감사 대상.
- **ESO**: K8s native이지만 etcd 평문 저장은 cluster operator의 별도 책임.
- **Doppler / 1Password SDK**: dev 머신까지 reference 보호 강점이지만 SaaS 외부 의존.
- **plain env**: prod에서 ps/dump/log 노출 가능성 — 단독 baseline으로는 거부 대상.
## Project Application
- [[wiki/projects/ca-tmpl/security-baseline-jwt-actuator-secrets]] — ca-tmpl 의사결정 기록 (현재 `documented-only`, Phase C2 미진입). 실제 구현 여부는 project 문서 참조.
이 baseline은 ca-skeleton 운영 계약과 세 개의 branch-note 결정에 적용된다(검증 등급은 각 branch/project 문서가 판정한다 — 이 concept 문서는 등급을 매기지 않는다).
- [[raw/project-notes/ca-skeleton-operational-contract]] — §18 Control Plane Contract (Secrets / Config Source, Management / Actuator Security)
- [[raw/branch-notes/feature-security-operational-baseline]] — JWT Resource Server + AuthN/AuthZ Matrix 12행 + JWKS 10min refresh + clock skew 60s + rotation overlap 24h + public path snapshot diff
- [[raw/branch-notes/feature-management-actuator-security-contract]] — management port 9001 + prod allowlist + heapdump/threaddump prod forbidden + loggers prod read-only + metrics network ACL default
- [[raw/branch-notes/feature-secrets-config-source-contract]] — prod = secret manager OR mounted env + `no-runtime-reload` default + `__LOCAL_DEV_` sentinel + JWT key 24h overlap / DB credential dual-bind 60s / API key restart-reload
## Interview Questions
- JWT vs Session 기반 인증을 어떤 기준으로 선택하는가? (stateless 확장성 / revocation 용이성 / cookie 운영 비용 / 클라이언트 타입)
- JWKS rotation 주기와 unknown `kid` 처리 정책을 어떻게 설계하는가? (refresh 주기, on-demand refresh, overlap window)
- Spring Boot Actuator를 운영에서 노출할 때 management port를 분리하는 이유는? (network 경계 단순화, ingress 정책, single-port + path ACL 위험)
- secret rotation을 zero-downtime으로 만들 때 어떤 패턴을 쓰는가? (dual-bind window, JWT key overlap, restart-only vs runtime reload)
- HMAC salt rotation을 90일 등으로 두는 근거는? (NIST cryptoperiod 권고, 누적 노출량 한도, downstream re-hash 비용)
- JWT 검증의 `clock skew tolerance`를 어떻게 정하는가? (NTP drift 가정, 발급자/검증자 분산도, expired vs replay trade-off)
## Do Not Overclaim
- **"JWT는 안전하다"는 단정 금지.** 토큰 탈취 시 revocation이 어렵다는 한계가 있다. JWT의 보안성은 발급/저장/전송/회수 전 과정 설계에 좌우된다.
- **"HashiCorp Vault가 secret 관리의 표준"이라는 단정 금지.** dynamic secrets는 강력하지만 `@RefreshScope`/bean refresh 패턴을 전제로 하며, 이를 금지하는 운영 계약(예: ca-skeleton)과는 충돌한다. AWS Secrets Manager, K8s + ESO, 1Password 등은 각자 다른 운영 상충점을 갖는다.
- **"actuator를 켜두는 것은 항상 안전하다"는 단정 금지.** default exposure가 `health`/`info`로 좁아도 `env`, `configprops`, `heapdump`, `threaddump`, `shutdown`이 잘못 열리면 그대로 공격 표면이 된다. allowlist + 네트워크 경계 + 인증의 다층 방어가 필요하다.
- **"company tech blog가 JWT/secret를 이렇게 쓴다 = 공식 best practice"** 로 격상 금지. 사례는 참고일 뿐 RFC/OWASP/공식 문서 기준과 구분해야 한다.
## Sources
### Canonical project SSOT
- [[raw/project-notes/ca-skeleton-operational-contract]] — §18 Control Plane Contract, §29 Group G-B 외부 근거 인덱스
### JWT / OAuth2 / 인가 (raw)
- [[raw/official-docs/security-jwt-rfc-7519-validation]] — RFC 7519 JWT claim 검증 표준
- [[raw/official-docs/security-oauth2-pkce-rfc-8252]] — OAuth2 PKCE (RFC 8252) issuance flow 표준
- [[raw/official-docs/security-mtls-rfc-8705]] — mTLS sender-constrained token (RFC 8705)
- [[raw/official-docs/security-aws-sigv4-hmac-signing]] — AWS SigV4 HMAC signing (webhook/외부 호출 인증 영역)
- [[raw/official-docs/security-authorization-cheatsheet-owasp]] — OWASP Authorization Cheatsheet (deny-by-default)
### Actuator / 관리면 (raw)
- [[raw/official-docs/actuator-endpoint-exposure-spring-official]] — Spring 공식 actuator default exposure 정책
- [[raw/official-docs/actuator-management-port-spring-official]] — Spring 공식 separate management port 권고
- [[raw/official-docs/actuator-istio-sidecar-management-alt]] — Istio sidecar 기반 management 보호 (대안)
- [[raw/company-tech-blogs/security-woowahan-actuator-safe-usage]] — 우아한형제들 SOC팀 Actuator 안전 사용 사례 (한국 도메인)
- [[raw/company-tech-blogs/security-toss-actuator-healthcheck]] — 토스 Spring Boot Actuator 헬스체크 (health detail 민감성, 한국 도메인)
### Secrets / Config (raw)
- [[raw/official-docs/secrets-aws-secrets-manager-rotation]] — AWS Secrets Manager + auto-rotation (dual-bind 패턴 정합)
- [[raw/official-docs/secrets-vault-dynamic-secrets-hashicorp]] — HashiCorp Vault dynamic secrets (short lease)
- [[raw/official-docs/secrets-k8s-secret-external-secrets-operator]] — K8s Secret + External Secrets Operator
- [[raw/company-tech-blogs/secrets-1password-developer-secret-references]] — 1Password developer secret references (dev 머신 보호 사례)