Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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