Skip to content

Latest commit

Β 

History

History
80 lines (53 loc) Β· 5.25 KB

File metadata and controls

80 lines (53 loc) Β· 5.25 KB

auth-api

Kotlin / Spring Boot 기반 인증 APIμž…λ‹ˆλ‹€. μ†Œμ…œ 둜그인(Google, Kakao, Naver), 이메일 인증, JWTΒ·μΏ ν‚€, GET /api/v1/auth/introspect 등을 μ œκ³΅ν•©λ‹ˆλ‹€.

λ¬Έμ„œ

μ‹€ν–‰

./gradlew bootRun

κΈ°λ³Έ 포트 9000, ν”„λ‘œν•„μ€ application.yml의 spring.profiles 그룹을 λ”°λ¦…λ‹ˆλ‹€.

ν™˜κ²½ λ³€μˆ˜

application.yml, application-jwt.yml, application-oauth.yml, ν”„λ‘œν•„λ³„ application-*.yml에 λ§€ν•‘λ©λ‹ˆλ‹€.
ν•„μš”ν•œ ν‚€λŠ” μœ„ API λͺ…세와 μ„€μ • νŒŒμΌμ„ μ°Έκ³ ν•˜μ„Έμš”.

JWT μ„œλͺ… ν‚€

ATΒ·RT λŠ” RS256 으둜 μ„œλͺ…ν•©λ‹ˆλ‹€. κ°œμΈν‚€λŠ” auth-api 만 κ°€μ§€κ³ , κ³΅κ°œν‚€λŠ” GET /.well-known/jwks.json 으둜 λ°°ν¬ν•©λ‹ˆλ‹€.

λ³€μˆ˜ ν•„μˆ˜ μ„€λͺ…
JWT_PRIVATE_KEY 예 PKCS#8 RSA κ°œμΈν‚€. PEM ν—€λ”Β·ν‘Έν„°Β·κ°œν–‰μ„ λΊ€ ν•œ 쀄 base64
JWT_SECRET μ•„λ‹ˆμ˜€ HS256 λ ˆκ±°μ‹œ 검증 μ „μš© μ‹œν¬λ¦Ώ. HS256 으둜 λ°œκΈ‰λœ 토큰이 μ‚΄μ•„ μžˆλŠ” μ „ν™˜ κΈ°κ°„(RT 만료 κΈ°κ°„)μ—λ§Œ 두고, μ§€λ‚˜λ©΄ μ§€μ›λ‹ˆλ‹€. λΉ„μ–΄ 있으면 HS256 토큰을 κ±°λΆ€ν•©λ‹ˆλ‹€
JWT_ACCESS_TOKEN_EXPIRATION 예 예: 30m
JWT_REFRESH_TOKEN_EXPIRATION 예 예: 7d

ν‚€ λ°œκΈ‰κ³Ό μ‹œν¬λ¦Ώ 등둝 (ν™˜κ²½λ§ˆλ‹€ 1회)

둜컬 ν„°λ―Έλ„μ—μ„œ μ‹€ν–‰ν•©λ‹ˆλ‹€. EC2 에 λ“€μ–΄κ°ˆ ν•„μš”κ°€ μ—†κ³ , μ„œλ²„μ—λŠ” ν‚€ νŒŒμΌμ„ 남기지 μ•ŠμŠ΅λ‹ˆλ‹€.

openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out jwt-private.pem
grep -v '^-----' jwt-private.pem | tr -d '\n' | pbcopy   # JWT_PRIVATE_KEY 값이 ν΄λ¦½λ³΄λ“œμ— λ³΅μ‚¬λœλ‹€
  • genpkey λŠ” PKCS#8(BEGIN PRIVATE KEY)둜 λ‚˜μ˜΅λ‹ˆλ‹€. openssl genrsa 둜 λ§Œλ“  PKCS#1(BEGIN RSA PRIVATE KEY)은 읽지 λͺ»ν•˜λ―€λ‘œ openssl pkcs8 -topk8 -nocrypt -in rsa.pem -out jwt-private.pem 으둜 λ³€ν™˜ν•©λ‹ˆλ‹€.
  • PEM 본문이 이미 base64 μ΄λ―€λ‘œ base64 λͺ…λ ΉμœΌλ‘œ ν•œ 번 더 감싸지 μ•ŠμŠ΅λ‹ˆλ‹€. 두 번 감싸면 "PKCS#8 RSA κ°œμΈν‚€κ°€ μ•„λ‹™λ‹ˆλ‹€" 둜 기동이 μ‹€νŒ¨ν•©λ‹ˆλ‹€.
  • ν•œ 쀄이어야 ν•©λ‹ˆλ‹€. .env λŠ” μ—¬λŸ¬ 쀄 값을 λ‹΄μ§€ λͺ»ν•©λ‹ˆλ‹€. κ°’ μ–‘ 끝에 λ”°μ˜΄ν‘œλ₯Ό 뢙이지 μ•ŠμŠ΅λ‹ˆλ‹€.
  • 2048λΉ„νŠΈ 미만 ν‚€λŠ” 기동 μ‹œ κ±°λΆ€λ©λ‹ˆλ‹€.

등둝: GitHub μ €μž₯μ†Œ Settings β†’ Environments β†’ (alpha | production) β†’ AUTH_BE_ENV_FILE 을 μ—΄μ–΄ μ•„λž˜ 쀄을 μΆ”κ°€ν•©λ‹ˆλ‹€. ν™˜κ²½λ§ˆλ‹€ ν‚€λ₯Ό λ”°λ‘œ λ§Œλ“­λ‹ˆλ‹€. 배포 μ›Œν¬ν”Œλ‘œκ°€ 이 μ‹œν¬λ¦Ώμ„ EC2 의 env/auth-api.env 둜 λ³΅μ‚¬ν•˜λ―€λ‘œ μ„œλ²„μ—μ„œ μ†λŒˆ 것은 μ—†μŠ΅λ‹ˆλ‹€.

JWT_PRIVATE_KEY=MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQD...   # ν•œ 쀄
  • 청첩μž₯(alphaΒ·prod): JWT_SECRET 쀄은 κ·ΈλŒ€λ‘œ 두고 이 μ€„λ§Œ μΆ”κ°€ν•©λ‹ˆλ‹€(μ•„λž˜ μ „ν™˜ 절차).
  • lnb: JWT_PRIVATE_KEY 만 λ„£κ³  JWT_SECRET 은 λ„£μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
  • 등둝이 λλ‚˜λ©΄ 둜컬의 jwt-private.pem 을 μ‚­μ œν•©λ‹ˆλ‹€. μ €μž₯μ†Œμ— μ»€λ°‹ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. ν…ŒμŠ€νŠΈ μ½”λ“œμ˜ TestJwtKeys ν‚€λŠ” ν…ŒμŠ€νŠΈ μ „μš©μ΄λΌ μš΄μ˜μ— μ“°λ©΄ μ•ˆ λ©λ‹ˆλ‹€.

배포 ν›„ 확인

ν‚€κ°€ 잘λͺ»λ˜λ©΄ μ»¨ν…Œμ΄λ„ˆκ°€ λœ¨μ§€ μ•Šκ³  docker logs 에 jwt.private-key κ°€ … 둜 μ‹œμž‘ν•˜λŠ” 원인이 λ‚¨μŠ΅λ‹ˆλ‹€. 정상 κΈ°λ™ν–ˆλ‹€λ©΄ JWKS 둜 ν™•μΈν•©λ‹ˆλ‹€.

JWKS λŠ” μ™ΈλΆ€μ—μ„œ 보이지 μ•ŠλŠ” 것이 μ •μƒμž…λ‹ˆλ‹€. 청첩μž₯ auth-api λŠ” API κ²Œμ΄νŠΈμ›¨μ΄ 뒀에 있고 κ²Œμ΄νŠΈμ›¨μ΄μ— 이 경둜 λΌμš°νŠΈκ°€ μ—†μœΌλ©°, 청첩μž₯ κ²½λ‘œμ—μ„œλŠ” JWKS λ₯Ό μ½λŠ” μͺ½μ΄ μ—†μŠ΅λ‹ˆλ‹€(검증은 auth-api κ°€ introspect μ•ˆμ—μ„œ ν•©λ‹ˆλ‹€). lnb-api λŠ” 같은 docker λ„€νŠΈμ›Œν¬μ—μ„œ http://auth-api:9000/.well-known/jwks.json 을 직접 μ½μŠ΅λ‹ˆλ‹€. κ·Έλž˜μ„œ 확인은 μ„œλ²„ μ•ˆμ—μ„œ ν•©λ‹ˆλ‹€.

# EC2 에 ssh 둜 λ“€μ–΄κ°„ λ’€
docker exec <auth-api μ»¨ν…Œμ΄λ„ˆλͺ…> wget -qO- http://localhost:9000/.well-known/jwks.json

keys[0].kid κ°€ λΉ„μ–΄ μžˆμ§€ μ•Šκ³  n 이 있으면 μ •μƒμž…λ‹ˆλ‹€. μ»¨ν…Œμ΄λ„ˆμ— wget 이 μ—†μœΌλ©΄ 같은 λ„€νŠΈμ›Œν¬μ˜ λ‹€λ₯Έ μ»¨ν…Œμ΄λ„ˆμ—μ„œ curl http://auth-api:9000/.well-known/jwks.json 으둜 λ΄…λ‹ˆλ‹€.

HS256 β†’ RS256 μ „ν™˜ 절차

JWT_PRIVATE_KEY λ₯Ό μΆ”κ°€ν•˜κ³  JWT_SECRET 은 μœ μ§€ν•œ 채 λ°°ν¬ν•œλ‹€(μ„Έμ…˜ μœ μ§€). JWT_REFRESH_TOKEN_EXPIRATION 이상 μ§€λ‚œ λ’€ JWT_SECRET 을 μ§€μš°κ³  μž¬λ°°ν¬ν•œλ‹€.

μ „ν™˜ μ‹œ 유의:

  • JWT_SECRET 을 λ„ˆλ¬΄ 일찍 μ§€μš°λ©΄: μ˜› HS256 AT λ₯Ό κ°€μ§„ λΈŒλΌμš°μ €λŠ” introspect μ—μ„œ μΏ ν‚€κ°€ μ§€μ›Œμ§€μ§€ μ•Šμ€ 채 401 을 λ°›κ³ , AT μΏ ν‚€ 만료(JWT_ACCESS_TOKEN_EXPIRATION) λ’€ silent refresh κ²½λ‘œμ—μ„œ μΏ ν‚€κ°€ μ§€μ›Œμ Έ μž¬λ‘œκ·ΈμΈν•˜κ²Œ λ©λ‹ˆλ‹€. JWT_REFRESH_TOKEN_EXPIRATION 이상 기닀리면 이 상황이 생기지 μ•ŠμŠ΅λ‹ˆλ‹€.
  • λ‘€λ°±: RS256 μ΄λ―Έμ§€μ—μ„œ HS256 μ΄λ―Έμ§€λ‘œ 되돌리면 κ·Έ 사이 λ°œκΈ‰λœ μ„Έμ…˜μ€ μ „λΆ€ κΉ¨μ§‘λ‹ˆλ‹€. λ‘€λ°± κ°€λŠ₯성을 남기렀면 μ „ν™˜ μ°½ λ™μ•ˆ JWT_SECRET 을 μœ μ§€ν•©λ‹ˆλ‹€.
  • ν‚€ ꡐ체(JWT_PRIVATE_KEY λ³€κ²½)λŠ” kid κ°€ λ°”λ€Œμ–΄ κΈ°μ‘΄ μ„Έμ…˜ 전원 λ‘œκ·Έμ•„μ›ƒμ΄λ©°, JWKS λ₯Ό μΊμ‹œν•˜λŠ” μ†ŒλΉ„μž(lnb-api)도 μž¬μ‹œμž‘ν•΄μ•Ό ν•©λ‹ˆλ‹€. νšŒμ „ 지원은 이번 λ²”μœ„ λ°–μž…λ‹ˆλ‹€.
  • 토큰 크기: RS256 μ„œλͺ…은 HS256 보닀 μ•½ 300 λ°”μ΄νŠΈ κΉλ‹ˆλ‹€(ATΒ·RT 각각). μΏ ν‚€Β·X-New-AT/X-New-RT 헀더 크기가 그만큼 λŠ˜μ–΄λ‚©λ‹ˆλ‹€.