docs(DOC): Jenkins 보안 강화 — Java 21 업그레이드, CSP 활성화, 분산 빌드 설정

- Java 17 → 21 업그레이드 (17은 2026-03-31 지원 종료)
- CSP(Content Security Policy) JVM 옵션 추가
- Built-in Node executor 0으로 변경, local-agent 분산 빌드 구성
- 운영 매뉴얼 3개 파일 업데이트 (01, 04, 11)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-24 17:15:25 +09:00
parent 5a6859ce23
commit 801c9ddfd5
3 changed files with 114 additions and 15 deletions

View File

@@ -156,7 +156,7 @@
| Prometheus | 2.51.0 | 9090 | - (localhost only) |
| Grafana | - | 3100 | monitor.sam.it.kr |
| node_exporter | 1.8.2 | 9100 | - |
| Java | OpenJDK 17.0.18 | - | Jenkins 런타임 |
| Java | OpenJDK 21.0.10 | - | Jenkins 런타임 |
| Certbot | - | - | SSL 자동 갱신 |
| fail2ban | - | - | SSH 보호 |
@@ -180,6 +180,8 @@
| Nginx 사이트 | /etc/nginx/sites-available/{ci,git,monitor}.sam.it.kr |
| Jenkins 홈 | /var/lib/jenkins/ |
| Jenkins JVM 설정 | /etc/systemd/system/jenkins.service.d/override.conf |
| Jenkins Agent | /var/lib/jenkins-agent/ (workspace, agent.jar) |
| Jenkins Agent 서비스 | /etc/systemd/system/jenkins-agent.service |
| Jenkins 환경파일 | /var/lib/jenkins/env-files/react/.env.{develop,stage,main} |
| Gitea 설정 | /etc/gitea/app.ini |
| Gitea 저장소 | /var/lib/gitea/data/repositories/ |

View File

@@ -20,14 +20,17 @@ sudo systemctl status jenkins
| 파일 | 용도 |
|------|------|
| /var/lib/jenkins/ | Jenkins 홈 (jobs, plugins, credentials) |
| /etc/systemd/system/jenkins.service.d/override.conf | JVM 메모리 설정 |
| /etc/systemd/system/jenkins.service.d/override.conf | JVM 옵션 (메모리, CSP) |
| /var/lib/jenkins/env-files/ | 배포 환경변수 (.env 파일) |
| /var/lib/jenkins-agent/ | Agent 워크스페이스 (빌드 실행 격리) |
| /etc/systemd/system/jenkins-agent.service | Agent systemd 서비스 |
**JVM 메모리 설정:**
**JVM 설정:**
```bash
# /etc/systemd/system/jenkins.service.d/override.conf
# Environment="JAVA_OPTS=-Xmx2048m -Xms512m -Djava.awt.headless=true"
# - 메모리: -Xmx2048m -Xms512m
# - CSP: DirectoryBrowserSupport.CSP (workspace 브라우저 보안)
# 변경 후 적용
sudo systemctl daemon-reload
@@ -75,16 +78,46 @@ sudo journalctl -u jenkins --since "2 hours ago" --no-pager
플러그인 업데이트 후 Jenkins 재시작이 필요한 경우: `sudo systemctl restart jenkins`
### Build Agent (분산 빌드)
Built-in Node의 executor는 0으로 설정되어 있으며, 빌드는 로컬 Agent(`local-agent`)에서 실행된다.
| 항목 | 값 |
|------|-----|
| Agent 이름 | local-agent |
| Workspace | /var/lib/jenkins-agent/ |
| Executor 수 | 2 |
| 라벨 | build |
| 연결 방식 | WebSocket (Inbound) |
**서비스 제어:**
```bash
sudo systemctl start jenkins-agent
sudo systemctl stop jenkins-agent
sudo systemctl restart jenkins-agent
sudo systemctl status jenkins-agent
# Agent 로그
sudo journalctl -u jenkins-agent -f
```
> **참고**: Jenkins 마스터 재시작 시 Agent가 자동 재연결된다. Agent가 연결 실패하면 `sudo systemctl restart jenkins-agent`로 수동 재시작.
### Workspace 정리
```bash
# 용량 확인
sudo du -sh /var/lib/jenkins/workspace/*
# Agent workspace 용량 확인
sudo du -sh /var/lib/jenkins-agent/workspace/*
# 특정 workspace 삭제
sudo rm -rf /var/lib/jenkins/workspace/<JOB_NAME>
sudo rm -rf /var/lib/jenkins-agent/workspace/<JOB_NAME>
# 전체 workspace 정리 (빌드 중이 아닌지 확인 후)
sudo rm -rf /var/lib/jenkins-agent/workspace/*
# 레거시 Built-in workspace (이전 빌드 잔존 시)
sudo du -sh /var/lib/jenkins/workspace/*
sudo rm -rf /var/lib/jenkins/workspace/*
# 임시 파일 정리

View File

@@ -580,7 +580,7 @@ stage-api.sam.it.kr은 api.sam.it.kr과 동일 구조 (소켓: php8.4-fpm-api-st
|------|------|--------|
| ① | OS 기본 셋팅 (UFW, 스왑, 타임존) | - |
| ② | MySQL 8.4 | ① |
| ③ | Java 17 (Jenkins 런타임) | ① |
| ③ | Java 21 (Jenkins 런타임) | ① |
| ④ | Gitea | ② |
| ⑤ | 개발서버 post-receive hook 설정 | ④ |
| ⑥ | Jenkins | ③ |
@@ -626,13 +626,19 @@ GRANT ALL PRIVILEGES ON *.* TO 'hskwon'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
```
### ③ Java 17
### ③ Java 21
```bash
sudo apt install -y openjdk-17-jre-headless
sudo apt install -y openjdk-21-jre-headless
java -version
# openjdk version "21.0.x" 확인
# 여러 버전 설치 시 기본 Java 전환
sudo update-alternatives --set java /usr/lib/jvm/java-21-openjdk-amd64/bin/java
```
> **참고**: Java 17은 2026-03-31 Jenkins 지원 종료. Java 21 사용 필수.
### ④ Gitea
```bash
@@ -746,11 +752,11 @@ done
| 저장소 | hook 대상 브랜치 | 동작 |
|--------|-----------------|------|
| sam-react-prod | stage, develop | CI/CD Gitea에 push |
| sam-api | stage | CI/CD Gitea에 push |
| sam-react-prod | main, develop | CI/CD Gitea에 push |
| sam-api | main | CI/CD Gitea에 push |
| sam-manage | main | CI/CD Gitea에 push (2026-02-24 추가) |
| sam-sales | main | CI/CD Gitea에 push |
| sam-landing | main | CI/CD Gitea에 push |
| sam-manage | ❌ 없음 | main만 사용, 배포관리자 수동 push |
### ⑥ Jenkins
@@ -765,11 +771,11 @@ echo "deb [signed-by=/usr/share/keyrings/jenkins-keyring.gpg]" \
sudo apt update
sudo apt install -y jenkins
# JVM 메모리 제한
# JVM 옵션 (메모리 + CSP)
sudo mkdir -p /etc/systemd/system/jenkins.service.d
sudo tee /etc/systemd/system/jenkins.service.d/override.conf > /dev/null << 'EOF'
[Service]
Environment="JAVA_OPTS=-Xmx2048m -Xms512m -Djava.awt.headless=true"
Environment="JAVA_OPTS=-Xmx2048m -Xms512m -Djava.awt.headless=true -Dhudson.model.DirectoryBrowserSupport.CSP=\"default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:;\""
EOF
sudo systemctl daemon-reload
@@ -810,6 +816,64 @@ sudo -u jenkins ssh-keyscan -H 114.203.209.83 >> /var/lib/jenkins/.ssh/known_hos
- `deploy-ssh-key`: SSH 키 (hskwon@운영/개발 서버 공용)
- `gitea-api-token`: Gitea API 토큰
**분산 빌드 설정 (Built-in Node 보안 격리):**
```bash
# 1. Built-in Node executor를 0으로 변경 (Jenkins 정지 상태에서)
sudo systemctl stop jenkins
sudo sed -i 's|<numExecutors>2</numExecutors>|<numExecutors>0</numExecutors>|' /var/lib/jenkins/config.xml
# Agent 포트 활성화 (0 = 랜덤 포트)
sudo sed -i 's|<slaveAgentPort>-1</slaveAgentPort>|<slaveAgentPort>0</slaveAgentPort>|' /var/lib/jenkins/config.xml
# 2. Agent workspace 디렉토리
sudo mkdir -p /var/lib/jenkins-agent/workspace
sudo chown -R jenkins:jenkins /var/lib/jenkins-agent
# 3. Agent 노드 설정
sudo mkdir -p /var/lib/jenkins/nodes/local-agent
# config.xml 생성 (JNLP WebSocket, executor 2, label: build)
sudo chown -R jenkins:jenkins /var/lib/jenkins/nodes/local-agent
# 4. Jenkins 시작 → Agent secret 확인 (UI 또는 Groovy 스크립트)
sudo systemctl start jenkins
# 5. Agent jar 다운로드
sudo curl -sL http://localhost:8080/jnlpJars/agent.jar -o /var/lib/jenkins-agent/agent.jar
sudo chown jenkins:jenkins /var/lib/jenkins-agent/agent.jar
# 6. Agent systemd 서비스
sudo tee /etc/systemd/system/jenkins-agent.service > /dev/null << 'AGENTEOF'
[Unit]
Description=Jenkins Build Agent
After=network.target jenkins.service
Wants=jenkins.service
[Service]
Type=simple
User=jenkins
Group=jenkins
WorkingDirectory=/var/lib/jenkins-agent
ExecStart=/usr/bin/java -jar /var/lib/jenkins-agent/agent.jar \
-url http://localhost:8080/ \
-secret <AGENT_SECRET> \
-name local-agent \
-workDir /var/lib/jenkins-agent \
-webSocket
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
AGENTEOF
sudo systemctl daemon-reload
sudo systemctl enable jenkins-agent
sudo systemctl start jenkins-agent
```
> **참고**: Agent secret은 Jenkins UI > Manage Jenkins > Nodes > local-agent에서 확인하거나,
> init.groovy.d 스크립트로 추출 가능.
### ⑦ Nginx + SSL (CI/CD)
**리버스 프록시 설정:**