14 KiB
title, source_type, status, confidence, tags, related_projects, last_reviewed
| title | source_type | status | confidence | tags | related_projects | last_reviewed | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ca-tmpl - Security Baseline 결정 (JWT + Actuator + Secrets) | project | verified | high |
|
|
2026-07-02 |
ca-tmpl - Security Baseline 결정 (JWT + Actuator + Secrets)
Layer:
wiki/projects/— ca-tmpl skeleton 내 보안 baseline 결정 사실 문서. 일반 개념/표준 정의는 wiki/concepts/security-baseline-jwt-actuator-secrets 참고.
프로젝트 컨텍스트
ca-tmpl은 Clean Architecture 기반 Spring Boot skeleton/template 저장소다. 이 문서가 다루는 범위는 운영 계약(raw/project-notes/ca-skeleton-operational-contract §18 Control Plane Contract, §29 Group G-B 외부 근거 인덱스) 중 보안 baseline 세 축의 설계 결정이다.
세 축:
- 데이터면 인증/인가: JWT Resource Server + AuthN/AuthZ matrix 12행 + JWKS 10분 refresh + clock skew tolerance 60s + key rotation overlap 24h + public path snapshot diff.
- 제어면 (Actuator): management port 9001 분리 + prod allowlist (
health/prometheus/info) +heapdump/threaddump/env/configprops/shutdownprod forbidden +loggersprod read-only + metrics network ACL default. - Secrets / Config: prod = secret manager OR mounted env, local만
.env허용.no-runtime-reloaddefault,@RefreshScope금지. JWT signing key 24h overlap / DB credential dual-bind 60s / API key restart-reload / HMAC salt 90d rotation.
진행 상태: C2 부분 구현 + 로컬 검증 완료. JWT Resource Server filter chain, lazy JWT decoder, security error classifier/envelope entry point, actuator management policy, secret source/reload guard는 코드화되어 있다. secret manager 연동과 실제 rotation automation은 아직 없다.
실제 구현 내용 (actually-implemented)
adapter-web의SecurityConfig가SecurityFilterChain과oauth2ResourceServer를 구성한다.JwtDecoderConfig가SupplierJwtDecoder로 JWKS discovery를 lazy 처리하고JwtTimestampValidator(Duration.ofSeconds(60)), issuer, audience validator를 명시한다.SecurityErrorClassifier와 envelope entry point/denied handler 테스트가 filter-layer 보안 실패를 API error envelope으로 분류한다.MethodSecurityConfig,RequiresPermission,AuthorizationPort,AuthorizationContractTest가 framework-free method authorization path를 구성한다.app-bootstrap의ManagementSecurityConfig, sample management config,SecretSource*,SecretReloadContractTest가 actuator/secret baseline 일부를 코드화한다.
로컬/dev 검증 (locally-verified)
./gradlew check통과(2026-07-02,BUILD SUCCESSFUL, 114 tasks).SecurityErrorClassifierTest,JwtDecoderConfigTest,EnvelopeAuthenticationEntryPointTest등 web security/error path 테스트가 통과한다.ManagementActuatorSecurityContractTest,ActuatorSecurityHttpTest가 management port/exposure/loggers read-only 정책을 검증한다.SecuritySettingsTest,SecretSourceTest,SecretSourceValidatorTest,SecretReloadContractTest가 설정/secret source/reload guard를 검증한다.
운영 검증 (prod-verified)
없음. ca-tmpl은 skeleton/template이며 운영 배포 대상이 아니다. prod 환경에서 JWT 검증 latency·JWKS rotation·secret rotation·actuator endpoint 노출을 측정한 적이 없다.
문서/계획만 존재 (documented-only / planned)
다음 항목은 구현된 baseline과 아직 documented-only / planned로 남은 영역을 분리한다. 면접/블로그에서 구현 범위와 혼동하면 안 된다.
D1. JWT Resource Server 채택 (actually-implemented / locally-verified)
- 결정: 데이터면 인증을 OAuth2 Resource Server + JWT (
spring-boot-starter-oauth2-resource-server) 로 표준화. - 검토한 대안:
- Session + Cookie — 분산 session store 비용, stateless 확장성 손실.
- OAuth2 Authorization Code (issuance flow) — 본 baseline은 검증 side이므로 직교. issuance 자체는 별도 IdP.
- mTLS (RFC 8705 sender-constrained token) — PKI 운영 비용 + public client(SPA/mobile) 운영 어려움.
- API key + HMAC (AWS SigV4 류) — webhook/외부 호출 인증에는 적합하나 일반 사용자 인증 모델이 아님.
- OPA (Open Policy Agent) — 외부 호출 latency + sidecar 운영. 인가 정책 2~3종에는 과한 인프라.
- 채택 이유: framework-neutral skeleton 가정과 정합 (Spring Security 6 표준 경로), revocation 한계는 short expiry + JWKS rotation overlap으로 완화.
- 설계만 동결한 파라미터: JWKS refresh 10분 + unknown
kid시 on-demand refresh, clock skew 60s, key rotation overlap 24h, AuthN/AuthZ matrix 12행, public path snapshot diff.
D2. Actuator management port 9001 분리 + prod allowlist (actually-implemented / locally-verified)
- 결정:
management.server.port=9001별도 포트 + prod allowlist=health,prometheus,info+ 그 외 prod forbidden. - 검토한 대안:
- Single port (8080) + path ACL — cloud ingress의 path 매칭 신뢰도, filter ordering / regex 우회 risk.
- mTLS for management — 강하지만 cert 운영 부담.
- Network ACL only (VPC SG / NetworkPolicy) — port가 같으면 비즈니스 트래픽과 분리 정책이 복잡.
- Istio sidecar AuthorizationPolicy — mesh 도입 전제, skeleton의 framework-neutral 가정 위배.
- 채택 이유: 외부 노출 차단을 네트워크 경계 단순화(다른 포트 = 다른 ingress 정책)로 풀어 single-port + path ACL의 우회 위험을 피함.
- 설계만 동결한 파라미터:
heapdump/threaddump/env/configprops/shutdownprod 차단,loggersprod read-only, metrics scrape는 internal network ACL default.
D3. Secrets: secret manager OR mounted env + restart-only rotation + HMAC salt 90d (partially-implemented)
- 결정: prod source = (secret manager) OR (mounted env),
.env는 local 전용.__LOCAL_DEV_sentinel로 prod 오탑재 차단.@RefreshScope금지 /no-runtime-reloaddefault. JWT signing key 24h overlap, DB credential dual-bind 60s, API key restart-reload, HMAC salt 90d rotation. - 검토한 대안:
- Vault dynamic secrets (short lease) —
@RefreshScope+ bean 재생성을 전제 → connection pool/캐시 lifecycle과 충돌, 본 계약(@RefreshScope금지)과 정면 충돌. - External Secrets Operator (ESO) — K8s native, 단 etcd 평문 저장은 cluster operator 책임 (이중 신뢰 경계).
- Doppler / 1Password SDK — dev 머신 보호에 강점이나 SaaS 외부 의존.
- Vault dynamic secrets (short lease) —
- 채택 이유: runtime reload를 거부하면 bean lifecycle / connection pool 충돌이 사라지고, rotation은 명시적 dual-bind window로만 처리. HMAC salt 90d 주기는 NIST SP 800-57 cryptoperiod 권고 범위 내에서 누적 노출/downstream re-hash 비용을 절충한 값.
Secret source abstraction과 local/prod guard는 구현되어 있으나, 외부 secret manager/Vault/KMS 통합 및 실제 rotation automation은 미구현이다.
D4. 한국 보안 사례 reference 추가 (2026-05-22) (documented-only)
- 추가된 reference (raw 출처만, 구현 변경 없음):
- raw/company-tech-blogs/security-woowahan-actuator-safe-usage — 우아한형제들 SOC팀 "Security Actuator 안전하게 사용하기" (별도 포트 + endpoint allowlist + shutdown/heapdump forbidden 권고). ca-tmpl D2 결정과 정합.
- raw/company-tech-blogs/security-toss-actuator-healthcheck — 토스 "Spring Boot Actuator의 헬스체크 살펴보기" (health detail 민감성 분류). ca-tmpl D2 + public path misconfiguration 정책과 정합.
- 영향: Group G-B Actuator 결정의 한국 도메인 사례 근거 보강. 현재 ca-tmpl의 actuator exposure/management security contract와 함께 보조 근거로만 사용한다.
- 여전히 미확보: 한국 기업의 JWT Resource Server 구현 사례, secret manager / Vault 운영 사례 직접 source는 미발견 — follow-up 후보로 유지.
면접에서 말할 수 있는 범위
자신 있게 답할 수 있는 질문
- JWT vs Session 선택 기준 — stateless 확장성, revocation trade-off, cookie 운영 비용, 클라이언트 타입에 따른 결정 근거.
- JWKS rotation 주기 설계 — 10분 refresh + unknown
kid시 on-demand refresh + 24h overlap window의 근거. - Management port 분리 이유 — single-port + path ACL의 filter ordering / regex 우회 risk 대비 별도 포트의 네트워크 경계 단순화.
- Secret rotation 방식 (dual-bind) — JWT key 24h overlap / DB credential dual-bind 60s / API key restart-reload가 왜 다른지.
- HMAC salt 90d rotation 근거 — NIST SP 800-57 cryptoperiod 권고 + 누적 노출량 한도 + downstream re-hash 비용 절충.
적당히 답할 수 있는 질문
- OPA vs in-process AUTHZ trade-off — 외부 호출 latency / sidecar 운영 / 정책 코드 분리 가치 / 정책 종수 임계.
- Vault dynamic secrets vs static lease —
@RefreshScope강제와 bean lifecycle 충돌, dynamic secret이 본 계약과 왜 충돌하는지. - clock skew tolerance 30s vs 60s — NTP drift 가정, 발급자/검증자 분산도, expired vs replay 창 trade-off.
답하면 안 되는 질문 (모른다고 해야 함)
- "JWT Resource Server baseline을 구현했다" — 가능. 단 IdP 운영/JWKS rotation 실측은 없음.
- "Secret rotation을 운영에서 돌려봤다" — prod 적용 사례 없음. dual-bind window는 설계 값.
- "Actuator endpoint 보안 침투 테스트 결과" — pentest 수행 안 함.
- "JWKS rotation 시 latency가 얼마였다" — 측정 안 함.
- "Vault/Secrets Manager를 ca-tmpl에 연결해서 돌려봤다" — 어떤 secret manager와도 통합하지 않음.
과장 금지 지점
- "JWT는 안전하다"는 단정 금지. token theft 시 stateless 검증은 즉시 revocation이 어렵다. JWKS rotation overlap + short expiry는 완화책일 뿐 근본 해결책이 아니다.
- "Vault가 secret 관리의 표준"이라는 표현 금지. dynamic secrets는
@RefreshScope흐름을 전제하며, ca-tmpl의@RefreshScope금지 계약과 정면 충돌. 채택 가능한 표준이 단일하지 않다. - 한국 보안 기술블로그 사례 참조 범위 한정. 2026-05-22 기준 ca-tmpl이 직접 참조하는 한국 사례는 Actuator 노출 정책 영역에 한정된다 (raw/company-tech-blogs/security-woowahan-actuator-safe-usage / raw/company-tech-blogs/security-toss-actuator-healthcheck). JWT Resource Server 운영, secret manager 통합, JWKS rotation 같은 영역의 한국 도메인 직접 사례는 부재 — 인용 시 영역을 actuator로 명시할 것.
- "Actuator를 닫아두면 안전하다"는 단정 금지. allowlist + 네트워크 경계 + 인증의 다층 방어가 필요하다.
info만 열어도 build/commit 메타데이터가 attack surface가 될 수 있다. - "AuthN/AuthZ matrix 12행 전체가 E2E로 검증됐다"고 말하면 안 됨. 주요 security/error path와 method authorization contract는 테스트되지만, 모든 matrix row의 외부 IdP 통합 검증은 없다.
Blog-topic ingest: secret-source-port-restart-only-rotation (2026-07-02)
raw/blog-topics/secret-source-port-restart-only-rotation-2026-07-02 는 secret source를 문자열 규칙이 아니라 SecretSource port, restart-only rotation, @RefreshScope 금지 계약으로 닫은 이유를 블로그로 풀기 위한 raw seed다.
- canonical 반영 범위: secrets/source/rotation 정책 글감을 security baseline canonical에 연결했다.
- blogify 전 조건: 충족. 이 문서는 2026-07-02 기준 코드와
./gradlew check로 검증됨. - 블로그 전 과장 방지: Vault/KMS dynamic secret 운영이나 secret manager 통합을 구현한 것처럼 쓰지 않고, restart-only contract 범위로 제한한다.
- raw/blog-topics/framework-free-method-authorization-clean-architecture-2026-06-08: Spring Security annotation을 application layer에 직접 붙이지 않고 plain annotation + authorization port + adapter method-security로 분리하는 글감. Spring Security 자체를 부정하지 않고 ca-tmpl layer boundary 선택으로 제한한다.
- raw/blog-topics/spring-security-filter-layer-error-envelope-2026-06-08: Spring Security 인증/인가 실패가 filter layer에서 entry point / denied handler로 처리되어 ControllerAdvice에 도달하지 않는다는 점을 envelope 통일과 연결하는 글감. heuristic 분류의 한계를 유지한다.
관련 개념
Sources
Canonical project SSOT
- raw/project-notes/ca-skeleton-operational-contract — §18 Control Plane Contract, §29 Group G-B 외부 근거 인덱스
Branch-notes (결정 동결 위치)
- 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-secrets-config-source-contract — secret source port + restart-only rotation +
@RefreshScope금지 결정 - raw/blog-topics/secret-source-port-restart-only-rotation-2026-07-02 — secret source/restart-only rotation 블로그 글감 raw seed
- raw/blog-topics/framework-free-method-authorization-clean-architecture-2026-06-08 — framework-free method authorization 블로그 글감 raw seed
- raw/blog-topics/spring-security-filter-layer-error-envelope-2026-06-08 — Spring Security filter-layer envelope 블로그 글감 raw seed
- 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 + HMAC salt 90d