zioinfo-mail/itsm/scripts/sm/ssl/ssl_auto_renew.sh
DESKTOP-TKLFCPR\ython e228faabf5 feat(itsm): G-1~G-12 확장 기능 + 하네스/봇/설치스크립트 구현
G-1: 메신저 Webhook Relay + _send_to_room 실제 httpx 호출 구현
G-2: POST /api/tasks/bulk SR 대량작업 엔드포인트 (최대 100건)
G-3: 라이선스 만료 알림 스케줄러 (매일 09:00 KST)
G-4: 체험판 upgrade_banner 필드 + license.py 배너 로직
G-5: core/auto_rca.py + incidents/problem auto-rca 엔드포인트
G-6: core/deploy_impact.py + vibe impact-analysis 엔드포인트
G-7: core/ticket_classifier.py + SR 생성 시 AI 분류 + ai-suggestion API
G-8: VulnPatchRecord 모델 + vuln_scan 패치추적 4개 엔드포인트
G-9: core/jira_sync.py + gateway Jira/Confluence 연동 엔드포인트
G-10: core/push_notify.py + routers/push.py + PushSubscription 모델
G-11: approvals 다중승인 (위임/서명/기한초과/마감연장)
G-12: alembic.ini + migrations/ + cicd/migrate_to_postgres.sh

하네스: guardia-orchestrator 확장기능 Phase 반영
봇명령어: /sr /status /license /bulk 슬래시 명령어 추가
설치스크립트: setup/ (Ubuntu, CentOS, RHEL, Windows) --test 옵션 포함

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:18:52 +09:00

203 lines
7.9 KiB
Bash

#!/bin/bash
# ==============================================================================
# GUARDiA ITSM — SSL 인증서 자동 갱신 스크립트 (certbot)
# 경로: /opt/guardia/scripts/ssl/ssl_auto_renew.sh
#
# 기능:
# 1. certbot renew --dry-run 으로 사전 검증
# 2. certbot renew 실행 (갱신 대상 인증서만)
# 3. nginx/apache 서비스 재시작 (갱신 성공 시)
# 4. GUARDiA ITSM API 콜백 — 갱신 결과 전달 (SR 자동 생성)
#
# 환경변수 (실행 전 .env 또는 시스템에 설정):
# GUARDIA_ITSM_URL — ITSM 서버 URL (기본: http://localhost:8000)
# GUARDIA_ITSM_TOKEN — ITSM API Bearer 토큰
# SSL_WEB_SERVER — nginx 또는 apache2 (기본: nginx)
# SSL_CERT_EMAIL — certbot 알림 이메일
# SSL_DOMAINS — 갱신할 도메인 (쉼표 구분, 미설정 시 certbot 전체 갱신)
# SSL_RENEW_DAYS — 만료 N일 이내 갱신 시도 (기본: 30)
# SSL_DRY_RUN_ONLY — true 이면 dry-run 만 수행 (테스트용, 기본: false)
# SSL_RELOAD_CMD — 서비스 재시작 명령어 오버라이드
#
# 반환 코드:
# 0 — 성공 (갱신 없음 포함)
# 1 — 갱신 실패
# 2 — 사전 점검 실패 (dry-run 오류)
# 3 — 설치 환경 오류 (certbot 미설치 등)
# ==============================================================================
set -euo pipefail
IFS=$'\n\t'
# ── 설정 ──────────────────────────────────────────────────────────────────────
ITSM_URL="${GUARDIA_ITSM_URL:-http://localhost:8000}"
ITSM_TOKEN="${GUARDIA_ITSM_TOKEN:-}"
WEB_SERVER="${SSL_WEB_SERVER:-nginx}"
CERT_EMAIL="${SSL_CERT_EMAIL:-}"
DOMAINS="${SSL_DOMAINS:-}"
RENEW_DAYS="${SSL_RENEW_DAYS:-30}"
DRY_RUN_ONLY="${SSL_DRY_RUN_ONLY:-false}"
LOG_DIR="/var/log/guardia/ssl"
LOG_FILE="${LOG_DIR}/renew_$(date +%Y%m%d_%H%M%S).log"
SCRIPT_NAME="$(basename "$0")"
# certbot 재시작 후크 우선순위: 환경변수 > 자동 감지
if [ -n "${SSL_RELOAD_CMD:-}" ]; then
RELOAD_CMD="${SSL_RELOAD_CMD}"
elif command -v systemctl &>/dev/null; then
RELOAD_CMD="systemctl reload ${WEB_SERVER}"
else
RELOAD_CMD="service ${WEB_SERVER} reload"
fi
# ── 로그 함수 ─────────────────────────────────────────────────────────────────
mkdir -p "${LOG_DIR}"
exec > >(tee -a "${LOG_FILE}") 2>&1
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] $*"; }
warn() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [WARN] $*"; }
err() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $*" >&2; }
log "=== ${SCRIPT_NAME} 시작 ==="
log "ITSM URL : ${ITSM_URL}"
log "WEB SERVER : ${WEB_SERVER}"
log "RENEW DAYS : ${RENEW_DAYS}"
log "DRY RUN ONLY : ${DRY_RUN_ONLY}"
log "LOG FILE : ${LOG_FILE}"
# ── certbot 설치 확인 ─────────────────────────────────────────────────────────
if ! command -v certbot &>/dev/null; then
err "certbot 명령어를 찾을 수 없습니다."
err "설치: apt install certbot 또는 yum install certbot"
_itsm_callback "ERROR" "certbot 미설치" "" 3
exit 3
fi
CERTBOT_VERSION="$(certbot --version 2>&1 | head -1)"
log "certbot 버전: ${CERTBOT_VERSION}"
# ── ITSM API 콜백 함수 ────────────────────────────────────────────────────────
# 보안: ITSM 서버 주소만 포함 — IP·계정·비밀번호 전송 금지
_itsm_callback() {
local status="$1" # SUCCESS | FAILURE | DRY_RUN_OK | DRY_RUN_FAIL
local message="$2"
local renewed_domains="${3:-}"
local exit_code="${4:-0}"
if [ -z "${ITSM_TOKEN}" ]; then
warn "GUARDIA_ITSM_TOKEN 미설정 — ITSM 콜백 건너뜀"
return 0
fi
local payload
payload="$(cat <<EOF
{
"event": "ssl_renew",
"status": "${status}",
"message": "${message}",
"renewed_domains": "${renewed_domains}",
"web_server": "${WEB_SERVER}",
"renew_days": ${RENEW_DAYS},
"exit_code": ${exit_code},
"log_file": "${LOG_FILE}",
"timestamp": "$(date -u '+%Y-%m-%dT%H:%M:%SZ')"
}
EOF
)"
# curl: 연결 실패 시 오류 무시 (ITSM가 다운돼도 갱신 스크립트는 계속 진행)
if curl -sf \
-X POST \
-H "Authorization: Bearer ${ITSM_TOKEN}" \
-H "Content-Type: application/json; charset=utf-8" \
--data "${payload}" \
--max-time 10 \
"${ITSM_URL}/api/ssl/renew-callback" \
> /dev/null 2>&1; then
log "ITSM 콜백 전송 성공: status=${status}"
else
warn "ITSM 콜백 전송 실패 (서버 응답 없음 — 무시하고 계속 진행)"
fi
}
# ── 사전 점검: dry-run ────────────────────────────────────────────────────────
log "--- 사전 점검 (dry-run) 시작 ---"
CERTBOT_ARGS=(
renew
--non-interactive
--agree-tos
"--deploy-hook" "${RELOAD_CMD}"
"--days" "${RENEW_DAYS}"
)
if [ -n "${CERT_EMAIL}" ]; then
CERTBOT_ARGS+=("--email" "${CERT_EMAIL}")
fi
if [ -n "${DOMAINS}" ]; then
# 도메인 개별 지정 시 각 도메인을 --domain 으로 전달
IFS=',' read -ra DOMAIN_LIST <<< "${DOMAINS}"
for domain in "${DOMAIN_LIST[@]}"; do
domain="$(echo "${domain}" | tr -d ' ')"
[ -n "${domain}" ] && CERTBOT_ARGS+=("--domain" "${domain}")
done
fi
if ! certbot "${CERTBOT_ARGS[@]}" --dry-run >> "${LOG_FILE}" 2>&1; then
err "dry-run 실패 — 실제 갱신을 중단합니다."
_itsm_callback "DRY_RUN_FAIL" "certbot dry-run 실패. 로그: ${LOG_FILE}" "" 2
exit 2
fi
log "dry-run 성공."
if [ "${DRY_RUN_ONLY}" = "true" ]; then
log "DRY_RUN_ONLY=true — 실제 갱신 건너뜀."
_itsm_callback "DRY_RUN_OK" "dry-run 전용 실행 완료." "" 0
exit 0
fi
# ── 실제 갱신 ─────────────────────────────────────────────────────────────────
log "--- 실제 갱신 시작 ---"
RENEW_OUTPUT="$(certbot "${CERTBOT_ARGS[@]}" 2>&1)" || {
err "certbot renew 실패."
err "${RENEW_OUTPUT}"
_itsm_callback "FAILURE" "certbot renew 실패. 상세: ${LOG_FILE}" "" 1
exit 1
}
log "${RENEW_OUTPUT}"
# 갱신된 인증서 도메인 추출
RENEWED=""
if echo "${RENEW_OUTPUT}" | grep -q "Successfully renewed"; then
RENEWED="$(echo "${RENEW_OUTPUT}" \
| grep -oP '(?<=Successfully renewed certificate for )[^\s]+' \
| paste -sd ',' -)"
log "갱신 완료 도메인: ${RENEWED:-없음}"
else
log "갱신 대상 없음 (모든 인증서가 유효 기간 내)."
fi
# ── 웹서버 재시작 (갱신 발생 시) ──────────────────────────────────────────────
if [ -n "${RENEWED}" ]; then
log "웹서버 재시작 중: ${RELOAD_CMD}"
if eval "${RELOAD_CMD}" >> "${LOG_FILE}" 2>&1; then
log "웹서버 재시작 성공."
else
warn "웹서버 재시작 실패 — 수동 확인 필요: ${RELOAD_CMD}"
fi
fi
# ── ITSM 콜백 ─────────────────────────────────────────────────────────────────
if [ -n "${RENEWED}" ]; then
_itsm_callback "SUCCESS" "인증서 갱신 완료." "${RENEWED}" 0
else
_itsm_callback "SUCCESS" "갱신 대상 없음 (모두 유효)." "" 0
fi
log "=== ${SCRIPT_NAME} 완료 ==="
exit 0