Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,4 @@ out/
/.nb-gradle/

### VS Code ###
.vscode/

### QueryDSL ###
src/main/generated/
.vscode/
23 changes: 3 additions & 20 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ dependencies {
// jpa
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

// redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'

// security
implementation 'org.springframework.boot:spring-boot-starter-security'

Expand Down Expand Up @@ -89,25 +92,6 @@ dependencies {
implementation 'io.sentry:sentry-spring-boot-starter-jakarta:8.5.0'
}

def generatedQueryDsl = 'src/main/generated'

sourceSets {
main.java.srcDirs += [generatedQueryDsl]
}

tasks.withType(JavaCompile).configureEach {
options.getGeneratedSourceOutputDirectory().set(file(generatedQueryDsl))
}

clean.doLast {
file(generatedQueryDsl).deleteDir()
}

tasks.named('test') {
useJUnitPlatform()
}


jib {
from {
image = 'openjdk:21'
Expand All @@ -120,4 +104,3 @@ jib {
creationTime = 'USE_CURRENT_TIMESTAMP'
}
}

122 changes: 122 additions & 0 deletions docs/infra/aws-elasticache-redis-local-setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Redis 로컬 개발 환경 접속 가이드 (with AWS ElastiCache)

> 본 문서는 **VPC 내 ElastiCache Redis**에 대해, 로컬 개발 환경에서도 운영 환경과 동일한 방식으로 접근할 수 있도록 포트 포워딩 기반 개발 흐름을 정리한 가이드입니다.
> Bastion Host를 별도로 구성하지 않고, **기존 EC2 인스턴스를 SSM 포워딩 노드로 활용**합니다.
---

## ✅ 개요

| 항목 | 내용 |
|-------------|-------------------------------------------------------|
| 대상 Redis | AWS ElastiCache for Redis (Private Subnet) |
| 접근 방식 | AWS Systems Manager - `PortForwardingSession` 사용 |
| 중계 노드 | 동일 VPC 내 EC2 인스턴스 (SSM Agent 연결 상태 필요) |

---

## 1. 요구 사항

### 1.1 사전 조건

- AWS CLI 설치 및 `configure` 완료
- EC2 인스턴스에 **SSM Agent 설치 + IAM Role 연결**되어 있어야 함
- Redis와 EC2는 동일 VPC/Subnet 내 존재
- Redis 보안 그룹에 EC2 인스턴스 허용 설정

---

## 2. 설정 단계

### 2.1 AWS CLI 인증 구성

```bash
aws configure --profile dev-redis
```

- Access Key, Secret, Region 입력
- 사용 목적에 맞게 별도 프로파일 구성 권장

---

### 2.2 EC2 인스턴스를 통한 포트 포워딩

1. EC2 인스턴스 ID 확인 (`i-xxxxxxxxxxxxxxxxx`)
2. SSM 포트 포워딩 세션 실행:

```bash
aws ssm start-session \
--target i-xxxxxxxxxxxxxxxxx \
--document-name AWS-StartPortForwardingSession \
--parameters '{"portNumber":["6379"],"localPortNumber":["6379"]}' \
--profile dev-redis
```

> 이 세션이 유지되는 동안 `localhost:6379`는 EC2 내부 Redis 포트에 직접 연결된 것과 동일하게 동작합니다.
---

### 2.3 연결 확인

```bash
valkey-cli --tls -h localhost -p 6379 ping
```

정상적으로 `PONG` 응답이 오면 연결 성공입니다.
Comment on lines +61 to +65
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

I pity the fool who uses the wrong Redis client! valkey-cli ain't standard!

Redis 연결 확인 명령어에 문제가 있습니다:

valkey-cli는 표준 Redis 클라이언트가 아닙니다. 다음과 같이 수정해야 합니다:

```bash
-valkey-cli --tls -h localhost -p 6379 ping
+redis-cli --tls -h localhost -p 6379 ping

또는 TLS 설정에 따라:

redis-cli -h localhost -p 6379 ping

대부분의 환경에서는 redis-cli가 표준 클라이언트입니다.

🤖 Prompt for AI Agents
In docs/infra/aws-elasticache-redis-local-setup.md lines 61 to 65, the command
for checking Redis connection uses a non-standard client 'valkey-cli'. Replace
'valkey-cli' with the standard 'redis-cli' to ensure compatibility. Also,
clarify that TLS options may vary; suggest using 'redis-cli --tls' if TLS is
enabled, or omit '--tls' if not. Update the code block to reflect these
corrections for accurate instructions.


---

### 2.4 Spring Boot 환경 구성 예시

```yaml
spring:
data:
redis:
host: localhost
port: 6379
ssl:
enabled: true
```
- 운영/로컬 환경 모두 동일 구성 사용
- 운영에서는 EC2 → Redis 직접 연결
- 로컬에서는 포트포워딩 세션을 통해 동일 흐름 유지
---
## 3. Redis 연결 트러블슈팅
### 3.1 systemd 기반 socat 포워딩 관리 (옵션)
```bash
sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable socat-redis
sudo systemctl start socat-redis
sudo systemctl status socat-redis
```

- 서비스 로그 확인:

```bash
journalctl -u socat-redis
```

---

## 4. 자주 발생하는 이슈

| 증상 | 원인 및 해결 방안 |
|----------------------------------|------------------------------------------------------------------------------------|
| `Timeout` 또는 연결 안됨 | - SSM 세션이 종료되었거나<br>- Redis 보안 그룹에서 EC2 인바운드 허용 누락 |
| 포워딩 명령어 실행 시 오류 발생 | - EC2에 SSM Agent 미설치<br>- IAM Role에 `ssm:StartSession` 권한 미설정<br>- AWS CLI 인증 오류 |
| 데이터가 깨져 보임 | - Redis 클러스터 모드 사용 중<br>- Lettuce 클라이언트 설정을 클러스터 대응으로 변경 필요 |

---

## 📎 참고 자료

- [AWS Blog - Port Forwarding with SSM to ElastiCache Redis](https://aws.amazon.com/blogs/mt/aws-systems-manager-session-manager-port-forwarding-to-amazon-elasticache-redis-inside-private-subnet/)
- [PR #139](https://github.com/juulabel/juulabel-back/pull/141): 인증 전략 개선 및 Redis 기반 세션 관리 적용 상세 내역
Comment on lines +119 to +120
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

I pity the fool who gives wrong PR references! Fix that link!

참조 링크에 오류가 있습니다:

-- [PR #139](https://github.com/juulabel/juulabel-back/pull/141): 인증 전략 개선 및 Redis 기반 세션 관리 적용 상세 내역
+- [PR #141](https://github.com/juulabel/juulabel-back/pull/141): 인증 전략 개선 및 Redis 기반 세션 관리 적용 상세 내역

PR 번호와 URL이 일치하지 않습니다. 현재 PR이 #141이므로 텍스트도 #141로 수정해야 합니다.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- [AWS Blog - Port Forwarding with SSM to ElastiCache Redis](https://aws.amazon.com/blogs/mt/aws-systems-manager-session-manager-port-forwarding-to-amazon-elasticache-redis-inside-private-subnet/)
- [PR #139](https://github.com/juulabel/juulabel-back/pull/141): 인증 전략 개선 및 Redis 기반 세션 관리 적용 상세 내역
- [AWS Blog - Port Forwarding with SSM to ElastiCache Redis](https://aws.amazon.com/blogs/mt/aws-systems-manager-session-manager-port-forwarding-to-amazon-elasticache-redis-inside-private-subnet/)
- [PR #141](https://github.com/juulabel/juulabel-back/pull/141): 인증 전략 개선 및 Redis 기반 세션 관리 적용 상세 내역
🤖 Prompt for AI Agents
In docs/infra/aws-elasticache-redis-local-setup.md around lines 119 to 120, the
PR reference link is incorrect as it points to PR #139 but the current PR is
#141. Update the link to match PR #141 to ensure the reference is accurate and
consistent.


---
96 changes: 96 additions & 0 deletions docs/pr/PR-139-refactor---auth-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Auth API 리팩터링 및 인증 전략 고도화 (PR [#139](https://github.com/juulabel/juulabel-back/pull/141))

## 📌 Summary

이 PR은 인증 모듈을 보안 중심의 구조로 리디자인하고, 유지보수성 및 확장성을 고려한 API 명세 리팩터링을 포함합니다. 주요 목표는 다음과 같습니다:

- 인증 API 도메인의 **명확한 경계 설정**
- **Refresh Token Rotation** 전략 기반의 인증 안정성 확보
- **서버 측 세션 관리**로 클라이언트 신뢰 수준 최소화
- **비정상 로그인 탐지 기반 확장**을 고려한 로깅 구조 설계

---

## 1. 구조 리팩터링: 인증 도메인 책임 분리

기존 API는 `/members` 하위에 인증과 사용자 관리 로직이 혼재되어 있어, 도메인 분리에 따른 유지보수 비용이 컸습니다. 다음과 같이 명확히 분리합니다:

| 기존 경로 | 신규 경로 | 목적 |
| ------------------------- | ---------------------- | ---------------------------- |
| `/v1/api/members/login` | `/v1/api/auth/login` | 인증 도메인 분리 |
| `/v1/api/members/sign-up` | `/v1/api/auth/sign-up` | |
| `/v1/api/members/me` | `/v1/api/auth/me` | |
| _(신규)_ | `/v1/api/auth/refresh` | Refresh Token 재발급 |
| _(신규)_ | `/v1/api/auth/logout` | 서버 측 로그아웃 (세션 종료) |

💡 **Outcome:** 인증 흐름과 사용자 정보 흐름의 경계가 명확해져 API 소비자 및 테스트 범위가 선명해집니다.

---

## 2. Refresh Token 기반 인증 및 Rotation 전략

### Why Rotation?

토큰 도난 시, 고정 Refresh Token 구조는 **세션 탈취 리스크**를 증가시킵니다. 이에 따라 Rotation 전략을 적용합니다.

### 동작 방식

- Access Token 만료 시 `/auth/refresh` 호출 → 새 Access + Refresh Token 응답
- 이전 Refresh Token은 **즉시 폐기** 및 Redis 블랙리스트 등록
- 동일 토큰 재사용 시 → 인증 실패 (401)

💡 **보안 장점:** 사용된 토큰은 재사용 불가 → 리플레이 공격 방지 강화

---

## 3. 비정상 로그인 탐지 기반 확장 고려

### 수집 항목

- `Device-Id` (필수 헤더)
- User-Agent, IP (서버 로그 자동 수집)

이 정보는 향후 다음 기능에 활용됩니다:

- 동일 계정 다중 위치/디바이스 로그인 탐지
- 의심 활동에 대한 보안 알림 트리거
- 로그인 히스토리 시각화

💡 **시사점:** 인증은 단일 절차가 아닌 보안 트래픽의 출발점이며, 메타데이터 수집이 이후 기능 확장의 기반이 됩니다.

---

## 4. 로그아웃: 서버 중심 세션 종료 방식으로 전환

기존 구조는 클라이언트 측에서 Access Token 제거만으로 로그아웃 처리하였습니다.
새로운 구조에서는 명시적 로그아웃 API 호출로 다음 동작 수행:

- Redis에 등록된 Refresh Token을 블랙리스트화
- 이후 해당 토큰 사용 시 인증 실패

💡 **효과:** 토큰 재사용 방지 → 클라이언트 신뢰도 최소화

---

## 5. Redis 기반 토큰 관리 및 인프라 구성

| 항목 | 내용 |
| ----------- | ---------------------------------------------------- |
| 저장소 구성 | AWS ElastiCache (Valkey) |
| 접근 방식 | VPC 내부 `socat + SSM 포트포워딩` 기반 접속 |
| 라이브러리 | `spring-data-redis (lettuce)` |
| 관리 전략 | TTL 기반 자동 만료 + Lua Script 기반 블랙리스트 삽입 |

💡 **운영 이점:** Redis는 고성능 키-밸류 스토어로써 세션 상태 관리에 적합하며, Lua Script로 atomic 블랙리스트 처리 가능

---

## 6. 적용 시 유의사항

| 항목 | 설명 |
| -------------------------------------------- | --------------------------------------------------------- |
| `Device-Id` 누락 시 400 반환 | 모든 인증 요청 시 필수 포함 필요 |
| `/auth/logout` 미호출 시 Refresh 무효화 누락 | 클라이언트에서만 로그아웃 처리 시 토큰은 유효 상태 유지됨 |
| `/members/*` 인증 경로 사용 중단 | 호출 시 404 응답 발생 가능성 있음. 즉시 경로 전환 필요 |

---

This file was deleted.

This file was deleted.

Loading
Loading