# 보안 설정 가이드

> **버전**: 1.0.0  
> **최종 수정**: 2026-05-25  
> **참고 기준**: NIST SP 800-53, 행안부 정보보안 관리체계

---

## 1. 개요

CI/CD 파이프라인에서 취급하는 민감 정보:

| 종류 | 예시 | 보관 방법 |
|------|------|----------|
| SSH 키 | 배포 서버 SSH 개인키 | Jenkins Credentials (SSH Key) |
| 서비스 계정 토큰 | ITSM API Token | Jenkins Credentials (Secret Text) |
| DB 접속 정보 | SonarQube DB Password | Jenkins Credentials (Username+Password) |
| 배포 서버 정보 | 서버 IP/포트 | Jenkins Credentials / Config File |

**절대 금지 사항**:
- Jenkinsfile 또는 스크립트에 민감 정보 하드코딩
- Git 저장소에 자격증명 커밋
- 빌드 로그에 비밀번호/토큰 출력

---

## 2. Jenkins Credentials 관리

### 2-1. Credentials 종류 및 용도

| Credential ID | 종류 | 용도 |
|--------------|------|------|
| `git-credentials` | Username+Password (또는 SSH Key) | Git 소스 체크아웃 |
| `ssh-{서버명}` | SSH Username+Private Key | 배포 서버 SSH 접속 |
| `itsm-api-token` | Secret Text | GUARDiA ITSM API 호출 |
| `sonar-token` | Secret Text | SonarQube 분석 |
| `deploy-key-prd` | SSH Username+Private Key | 운영 서버 배포 전용 |

### 2-2. SSH Credentials 등록

Jenkins 관리 → Credentials → System → Global credentials → Add Credentials:

```
Kind:         SSH Username with private key
Scope:        Global
ID:           ssh-app-server-01
Description:  APP-SERVER-01 배포 SSH Key
Username:     deploy
Private Key:  [Enter directly] → 개인키 내용 붙여넣기
Passphrase:   (있는 경우 입력)
```

### 2-3. Secret Text 등록 (API Token)

```
Kind:         Secret text
Scope:        Global
ID:           itsm-api-token
Description:  GUARDiA ITSM API Token
Secret:       <토큰값>
```

### 2-4. Jenkinsfile에서 Credentials 사용

```groovy
// SSH Key 사용
withCredentials([sshUserPrivateKey(
    credentialsId: 'ssh-app-server-01',
    keyFileVariable: 'SSH_KEY',
    usernameVariable: 'SSH_USER'
)]) {
    sh "ssh -i ${SSH_KEY} ${SSH_USER}@${TARGET_HOST} 'systemctl status tomcat'"
}

// Secret Text 사용
withCredentials([string(
    credentialsId: 'itsm-api-token',
    variable: 'ITSM_TOKEN'
)]) {
    sh "curl -H 'Authorization: Bearer ${ITSM_TOKEN}' ${ITSM_URL}/api/health"
}

// Username+Password 사용
withCredentials([usernamePassword(
    credentialsId: 'sonar-credentials',
    usernameVariable: 'SONAR_USER',
    passwordVariable: 'SONAR_PASS'
)]) {
    sh "mvn sonar:sonar -Dsonar.login=${SONAR_USER} -Dsonar.password=${SONAR_PASS}"
}
```

---

## 3. RBAC (역할 기반 접근 제어)

### 3-1. Role Strategy Plugin 설정

Jenkins 관리 → Security → Authorization → Role-Based Strategy

#### Global Roles

| Role | 권한 | 대상 |
|------|------|------|
| `admin` | 전체 | Jenkins 관리자 |
| `pm` | Job Read/Build, View | PM/프로젝트 관리자 |
| `developer` | Job Read/Build (dev 한정), View | 개발자 |
| `viewer` | Job Read, View | 감사/보안 담당 |

#### Project Roles (정규식 매핑)

| Role | 대상 Job 패턴 | 권한 |
|------|-------------|------|
| `dev-deployer` | `.*-dev$` | Build, Cancel, Read |
| `prd-deployer` | `.*-prd$` | Build, Cancel, Read |
| `rollback-only` | `.*-rollback$` | Build, Read |

### 3-2. 운영 배포 2인 승인 규칙

`main`, `hotfix/*` 브랜치 배포는 반드시 2명이 승인:

```groovy
stage('Production Approval') {
    steps {
        script {
            def approvers = []
            def required = 2

            timeout(time: 60, unit: 'MINUTES') {
                for (int i = 0; i < required; i++) {
                    def approval = input(
                        message: "운영 배포 ${i+1}/${required}차 승인",
                        ok: "승인",
                        submitterParameter: "APPROVER_${i+1}"
                    )
                    approvers << approval
                    echo "승인자 ${i+1}: ${approval}"
                }
            }
            env.APPROVERS = approvers.join(', ')
        }
    }
}
```

---

## 4. 네트워크 보안

### 4-1. Jenkins 접근 IP 제한

```nginx
# Nginx에서 허용 IP 제한
location / {
    allow 10.0.0.0/8;       # 내부망
    allow 192.168.0.0/16;   # 내부망
    deny all;
    proxy_pass http://jenkins;
}
```

```bash
# firewalld에서 특정 IP만 허용
sudo firewall-cmd --permanent --add-rich-rule='
    rule family="ipv4"
    source address="10.0.0.0/8"
    port protocol="tcp" port="8080"
    accept'
sudo firewall-cmd --reload
```

### 4-2. 배포 서버 SSH 보안

```bash
# 배포 서버 /etc/ssh/sshd_config 설정
# Jenkins 전용 deploy 계정만 허용
AllowUsers deploy jenkins-agent
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys

# deploy 계정 SSH sudo 제한 (특정 명령만)
# /etc/sudoers.d/jenkins-deploy
deploy ALL=(root) NOPASSWD: /bin/systemctl restart tomcat9, \
                             /bin/systemctl restart nginx, \
                             /opt/jeus/bin/stopServer, \
                             /opt/jeus/bin/startServer
```

---

## 5. 빌드 로그 보안

### 5-1. 민감 정보 마스킹

`Mask Passwords` 플러그인 사용:

```groovy
options {
    maskPasswords()
}
```

Jenkins 관리 → System → Mask Passwords:
- Global Passwords에 패턴 등록: `PASSWORD`, `TOKEN`, `SECRET`, `KEY`

### 5-2. 로그 보존 정책

```groovy
options {
    buildDiscarder(logRotator(
        numToKeepStr: '30',      // 30개 빌드 보관
        artifactNumToKeepStr: '10',  // 아티팩트 10개 보관
        daysToKeepStr: '90'      // 90일 이전 자동 삭제
    ))
}
```

---

## 6. 아티팩트 보안

### 6-1. 아티팩트 체크섬 검증

```bash
# 빌드 후 SHA256 체크섬 생성
sha256sum target/*.jar > target/checksums.sha256

# 배포 전 검증
sha256sum -c checksums.sha256
```

### 6-2. 아티팩트 접근 제한

```bash
# 아티팩트 디렉터리 권한 설정
sudo mkdir -p /opt/artifacts
sudo chown jenkins:jenkins /opt/artifacts
sudo chmod 750 /opt/artifacts
```

---

## 7. 감사 로그 (Audit Trail)

`Audit Trail Plugin` 설치 후:

Jenkins 관리 → System → Audit Trail:
- Log Location: `/var/log/jenkins/audit.log`
- Log File Size: 100 MB
- Log File Count: 30

기록 항목:
- 로그인/로그아웃
- 자격증명 접근
- 잡 빌드 시작/중단
- 설정 변경

---

## 8. Jenkins 보안 설정 체크리스트

| 항목 | 상태 | 비고 |
|------|------|------|
| CSRF Protection 활성화 | ✓ | 기본 활성화 |
| 익명 사용자 접근 차단 | ✓ | Authorization: Role-Based |
| 빌드 에이전트 인증 | ✓ | SSH or JNLP with secret |
| Credentials 암호화 | ✓ | Jenkins master key 사용 |
| 보안 업데이트 정기 적용 | 주 1회 | 매주 일요일 자동 업데이트 확인 |
| 사용하지 않는 플러그인 제거 | ✓ | 분기별 점검 |
| HTTPS 적용 | 내부망 선택 | 외부 연동 시 필수 |
| 빌드 로그 민감정보 마스킹 | ✓ | Mask Passwords Plugin |
| 운영 배포 2인 승인 | ✓ | input() step |
| 감사 로그 활성화 | ✓ | Audit Trail Plugin |
