# SSL 사설 인증서 설정 가이드 (RedHat 9.6)

## 개요

이 문서는 RedHat 9.6 환경에서 `https://api.train-kamco.com` 및 `https://train-kamco.com` 도메인을 위한 100년 유효한 사설 SSL 인증서 설정 방법을 설명합니다.

## 디렉토리 구조

```
nginx/
├── nginx.conf              # Nginx 설정 파일
├── ssl/
│   ├── openssl.cnf         # OpenSSL 설정 파일 (SAN 포함)
│   ├── train-kamco.com.crt # 사설 SSL 인증서 (멀티 도메인)
│   └── train-kamco.com.key # 개인 키 (비공개)
└── SSL_SETUP.md            # 이 문서
```

## 인증서 정보

- **도메인**: api.train-kamco.com, train-kamco.com (멀티 도메인)
- **유효 기간**: 100년 (36500일)
- **알고리즘**: RSA 4096-bit
- **CN (Common Name)**: api.train-kamco.com
- **SAN (Subject Alternative Names)**: api.train-kamco.com, train-kamco.com

## 사설 SSL 인증서 생성 (이미 생성됨)

인증서가 이미 생성되어 있습니다. 재생성이 필요한 경우 아래 단계를 따르세요.

### 1. OpenSSL 설정 파일 생성

```bash
cd /path/to/kamco-train-api

cat > nginx/ssl/openssl.cnf << 'EOF'
[req]
default_bits = 4096
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = v3_req

[dn]
C=KR
ST=Seoul
L=Seoul
O=KAMCO
OU=Training
CN=api.train-kamco.com

[v3_req]
subjectAltName = @alt_names

[alt_names]
DNS.1 = api.train-kamco.com
DNS.2 = train-kamco.com
EOF
```

### 2. SSL 인증서 및 개인 키 생성

```bash
# nginx/ssl 디렉토리 생성 (없는 경우)
mkdir -p nginx/ssl
chmod 700 nginx/ssl

# 인증서 및 개인 키 생성 (100년 유효)
openssl req -new -x509 -newkey rsa:4096 -sha256 -nodes \
  -keyout nginx/ssl/train-kamco.com.key \
  -out nginx/ssl/train-kamco.com.crt \
  -days 36500 \
  -config nginx/ssl/openssl.cnf \
  -extensions v3_req

# 파일 권한 설정
chmod 600 nginx/ssl/train-kamco.com.key
chmod 644 nginx/ssl/train-kamco.com.crt
```

### 3. 인증서 검증

```bash
# 인증서 정보 확인
openssl x509 -in nginx/ssl/train-kamco.com.crt -text -noout

# 유효 기간 확인
openssl x509 -in nginx/ssl/train-kamco.com.crt -text -noout | grep -A2 "Validity"

# SAN (멀티 도메인) 확인
openssl x509 -in nginx/ssl/train-kamco.com.crt -text -noout | grep -A1 "Subject Alternative Name"

# CN 확인
openssl x509 -in nginx/ssl/train-kamco.com.crt -noout -subject

# 개인 키 확인
openssl rsa -in nginx/ssl/train-kamco.com.key -check
```

**예상 결과**:
```
X509v3 Subject Alternative Name:
    DNS:api.train-kamco.com, DNS:train-kamco.com

Validity
    Not Before: Mar  2 23:39:XX 2026 GMT
    Not After : Feb  6 23:39:XX 2126 GMT
```

## /etc/hosts 설정 (RedHat 9.6)

### 1. hosts 파일에 도메인 추가

```bash
# root 권한으로 실행
echo "127.0.0.1   api.train-kamco.com train-kamco.com" | sudo tee -a /etc/hosts

# 확인
cat /etc/hosts | grep train-kamco
```

**예상 결과**:
```
127.0.0.1   api.train-kamco.com train-kamco.com
```

### 2. 도메인 확인

```bash
# ping 테스트
ping -c 2 api.train-kamco.com
ping -c 2 train-kamco.com
```

## Docker Compose 배포

### 1. 기존 컨테이너 중지 (실행 중인 경우)

```bash
cd /path/to/kamco-train-api
docker-compose -f docker-compose-prod.yml down
```

### 2. Production 환경 실행

```bash
# IMAGE_TAG 환경 변수 설정 (선택사항)
export IMAGE_TAG=latest

# Docker Compose 실행
docker-compose -f docker-compose-prod.yml up -d

# 컨테이너 상태 확인
docker-compose -f docker-compose-prod.yml ps
```

### 3. 로그 확인

```bash
# Nginx 로그
docker logs kamco-cd-nginx

# API 로그
docker logs kamco-cd-training-api

# 실시간 로그 확인
docker-compose -f docker-compose-prod.yml logs -f
```

## HTTPS 접속 테스트

### 1. HTTP → HTTPS 리다이렉트 테스트

```bash
# api.train-kamco.com
curl -I http://api.train-kamco.com

# train-kamco.com
curl -I http://train-kamco.com

# 예상 결과: 301 Moved Permanently
# Location: https://api.train-kamco.com/ 또는 https://train-kamco.com/
```

### 2. HTTPS 헬스체크 (-k: 사설 인증서 경고 무시)

```bash
# api.train-kamco.com
curl -k https://api.train-kamco.com/monitor/health

# train-kamco.com
curl -k https://train-kamco.com/monitor/health

# 예상 결과: {"status":"UP","components":{...}}
```

### 3. SSL 인증서 확인

```bash
# api.train-kamco.com
openssl s_client -connect api.train-kamco.com:443 -showcerts

# train-kamco.com
openssl s_client -connect train-kamco.com:443 -showcerts

# CN 및 SAN 확인
```

### 4. 브라우저 테스트

브라우저에서 다음 URL에 접속:

- `https://api.train-kamco.com/monitor/health`
- `https://train-kamco.com/monitor/health`

**주의**: 사설 인증서이므로 "안전하지 않음" 경고가 표시됩니다.
- **Chrome/Edge**: "고급" → "계속 진행" 클릭
- **Firefox**: "위험 감수 및 계속" 클릭

## 브라우저에서 사설 인증서 신뢰 설정 (선택사항)

사설 인증서를 브라우저에 등록하면 경고 없이 접속 가능합니다.

### Chrome/Edge (RedHat Desktop)

1. `chrome://settings/certificates` 접속
2. **Authorities** 탭 선택
3. **Import** 클릭
4. `nginx/ssl/train-kamco.com.crt` 선택
5. **Trust this certificate for identifying websites** 체크
6. **OK** 클릭

### Firefox

1. `about:preferences#privacy` 접속
2. **Certificates** → **View Certificates** 클릭
3. **Authorities** 탭 선택
4. **Import** 클릭
5. `nginx/ssl/train-kamco.com.crt` 선택
6. **Trust this CA to identify websites** 체크
7. **OK** 클릭

## 방화벽 설정 (RedHat 9.6)

### 1. 방화벽 상태 확인

```bash
sudo firewall-cmd --state
```

### 2. HTTP (80) 및 HTTPS (443) 포트 개방

```bash
# HTTP 포트 개방
sudo firewall-cmd --permanent --add-port=80/tcp

# HTTPS 포트 개방
sudo firewall-cmd --permanent --add-port=443/tcp

# 방화벽 재로드
sudo firewall-cmd --reload

# 확인
sudo firewall-cmd --list-ports
```

**예상 결과**:
```
80/tcp 443/tcp
```

## 보안 체크리스트

- [x] `train-kamco.com.key` 파일 권한이 600으로 설정됨
- [x] ssl 디렉토리가 버전 관리에서 제외됨 (.gitignore 확인)
- [x] 두 도메인(api.train-kamco.com, train-kamco.com) 모두 SAN에 포함됨
- [ ] 방화벽에서 80, 443 포트 개방 확인
- [x] HSTS 헤더 활성화 확인
- [x] TLS 1.2 이상만 허용 확인
- [ ] /etc/hosts에 도메인 매핑 확인

## 트러블슈팅

### 인증서 관련 오류

**"certificate verify failed"**
```bash
# 해결: -k 플래그 사용 (사설 인증서 경고 무시)
curl -k https://api.train-kamco.com/monitor/health
```

**"NET::ERR_CERT_AUTHORITY_INVALID" (브라우저)**
- 정상 동작: 사설 인증서이므로 브라우저 경고는 예상된 동작입니다
- 해결: 브라우저에 인증서 등록 (위 "브라우저에서 사설 인증서 신뢰 설정" 참조)

### 연결 오류

**"Connection refused"**
```bash
# 컨테이너 상태 확인
docker ps | grep kamco-cd

# 포트 바인딩 확인
docker port kamco-cd-nginx

# 예상 결과:
# 80/tcp -> 0.0.0.0:80
# 443/tcp -> 0.0.0.0:443
```

**"502 Bad Gateway"**
```bash
# API 컨테이너 상태 확인
docker logs kamco-cd-training-api

# nginx → API 연결 확인
docker exec kamco-cd-nginx wget -qO- http://kamco-changedetection-api:8080/monitor/health
```

**"Name or service not known" (도메인 해석 실패)**
```bash
# /etc/hosts 확인
cat /etc/hosts | grep train-kamco

# 없으면 추가
echo "127.0.0.1   api.train-kamco.com train-kamco.com" | sudo tee -a /etc/hosts
```

### 방화벽 관련 오류

**외부에서 접속 안 됨**
```bash
# 방화벽 확인
sudo firewall-cmd --list-ports

# 포트 개방
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --reload
```

## 인증서 만료 및 갱신

### 만료 확인

```bash
# 인증서 만료일 확인
openssl x509 -in nginx/ssl/train-kamco.com.crt -noout -enddate

# 예상 결과: notAfter=Feb  6 23:39:XX 2126 GMT (100년 후)
```

### 갱신 방법 (필요시)

100년 유효한 인증서이므로 갱신이 필요하지 않지만, 재생성이 필요한 경우:

```bash
# 기존 인증서 백업
cp nginx/ssl/train-kamco.com.crt nginx/ssl/train-kamco.com.crt.bak
cp nginx/ssl/train-kamco.com.key nginx/ssl/train-kamco.com.key.bak

# 위의 "사설 SSL 인증서 생성" 단계 재실행

# nginx 재시작
docker-compose -f docker-compose-prod.yml restart nginx
```

## 주의사항

1. **사설 인증서 경고**: 브라우저에서 "안전하지 않음" 경고가 표시됩니다. 프로덕션 환경에서는 **공인 인증서(Let's Encrypt, GlobalSign 등) 사용을 권장**합니다.

2. **포트 80/443**: Docker가 자동으로 처리하지만, 이미 사용 중인 프로세스가 있으면 충돌할 수 있습니다.
   ```bash
   # 포트 사용 확인
   sudo lsof -i :80
   sudo lsof -i :443
   ```

3. **대용량 파일 업로드**: `client_max_body_size`를 10GB로 설정했으므로, 서버 메모리 및 디스크 용량을 충분히 확보하세요.

4. **인증서 백업**: `train-kamco.com.key` 파일은 매우 중요합니다. 안전한 곳에 백업하세요.

5. **SELinux**: RedHat 9.6에서 SELinux가 활성화된 경우, Docker 볼륨 마운트 권한 문제가 발생할 수 있습니다.
   ```bash
   # SELinux 상태 확인
   getenforce

   # 필요시 permissive 모드로 변경
   sudo setenforce 0
   ```


### 2단계: 시스템 신뢰 폴더로 복사
터미널을 열고 관리자 권한(sudo)을 사용해 인증서를 시스템 폴더로 복사합니다.

```
sudo cp mycert.crt /etc/pki/ca-trust/source/anchors/
```

### 3단계: 시스템 신뢰 목록 업데이트
아래 명령어를 입력해 추가한 인증서를 시스템에 갱신시킵니다.

```
sudo update-ca-trust
```



## 참고 자료

- [OpenSSL Documentation](https://www.openssl.org/docs/)
- [Nginx SSL Configuration](https://nginx.org/en/docs/http/configuring_https_servers.html)
- [Docker Compose Documentation](https://docs.docker.com/compose/)
- [Let's Encrypt (공인 인증서)](https://letsencrypt.org/)
