콘텐츠로 이동

보안

인프라 전반의 보안 정책과 구현 현황을 정리합니다.

네트워크 보안

방화벽 정책

인터페이스별 화이트리스트 방식으로 포트를 관리합니다.

인터페이스 용도 열린 포트
eth0 (퍼블릭) 외부 접근 80, 443, 10022 (eta만)
wg-admin (WireGuard) 내부 관리 서비스별 (5432, 8010, 5678, 5000 등)
tailscale0 (Headscale) 사용자 서비스 80, 443

기본 정책은 deny all이며, 각 서비스 모듈이 필요한 포트만 인터페이스별로 개방합니다.

Bastion 아키텍처

eta가 유일한 인터넷 노출 SSH 호스트입니다. 다른 호스트(psi, rho, tau)는 wg-admin 인터페이스에서만 SSH를 수신합니다.

flowchart LR
  inet["인터넷"] -- "포트 10022" --> eta["eta<br/>jump.sjanglab.org"]
  eta -- "wg-admin" --> psi["psi<br/>10.100.0.2"]
  eta -- "wg-admin" --> rho["rho<br/>10.100.0.3"]
  eta -- "wg-admin" --> tau["tau<br/>10.100.0.4"]

SSH 속도 제한

eta에 적용되는 방어 계층:

flowchart TD
  conn["SSH 연결 시도"] --> ipt{"iptables<br/>60초 내 NEW 5회 초과?"}
  ipt -- "초과" --> drop["즉시 DROP"]
  ipt -- "통과" --> sshd["sshd 인증"]
  sshd -- "성공" --> ok["접속 허용"]
  sshd -- "실패" --> log["sshd 로그 기록"]
  log --> f1["fail2ban sshd<br/>10분 내 3회 → 24시간 차단"]
  log --> f2["fail2ban aggressive<br/>24시간 내 공격 패턴 → 7일 차단"]

iptables(연결 빈도)와 fail2ban(인증 실패 로그)은 독립적인 병렬 계층입니다. iptables는 TCP 연결 시점에 즉시 판단하고, fail2ban은 sshd 로그를 감시하여 사후 차단합니다.

계층 조건 차단
iptables 60초 내 NEW 연결 5회 초과 즉시 DROP
fail2ban sshd 10분 내 인증 실패 3회 24시간
fail2ban sshd-aggressive 24시간 내 공격 패턴 1회 7일

화이트리스트: 10.0.0.0/8 (내부 네트워크), 다른 호스트의 공인 IP.

WireGuard VPN 분리

네트워크 대역 용도
wg-admin 10.100.0.0/24 인프라 관리 (SSH, DB, 내부 서비스)
Headscale 100.64.0.0/10 사용자 서비스 접근 (웹 서비스)

두 네트워크는 독립적이며, wg-admin은 관리자(wheel 그룹)만 접근합니다.

계정 및 권한 정책

사용자 계층

역할 NixOS 그룹 sudo Docker SSH 호스트 만료
관리자 wheel, docker, admin, input O O 전체
연구원 docker, researcher, input X O 지정 호스트 필수
학생 docker, student, input X O 지정 호스트 필수

Root 접근 정책

접근 경로 허용
SSH (인터넷) 차단 (PermitRootLogin no)
SSH (wg-admin, 10.100.0.0/24) 공개키만 (prohibit-password)
sudo (로컬) wheel 그룹만

root의 authorized_keys에는 관리자 키만 등록됩니다 (modules/users/admins.nix).

시스템 계정

서비스별로 전용 시스템 계정이 분리되어 있습니다.

계정 서비스 유형 특기 사항
buildbot Buildbot Master isSystemUser
buildbot-worker Buildbot Worker isSystemUser nix.settings.trusted-users
harmonia Nix 바이너리 캐시 isSystemUser nix.settings.allowed-users
borg Borgbackup SSH 키 전용, 특정 경로만 접근
acme-sync-* TLS 인증서 동기화 rsync 전용, 제한된 경로
postgres PostgreSQL isSystemUser DB 전용
nextcloud Nextcloud isSystemUser

Nix 권한

설정 대상 의미
trusted-users 관리자, buildbot-worker 캐시 서명, 임의 derivation 빌드 가능
allowed-users harmonia Nix store 읽기만 가능

SSH 보안

알고리즘 정책

항목 허용 알고리즘
Ciphers chacha20-poly1305, aes256-gcm, aes128-gcm
KexAlgorithms curve25519-sha256, diffie-hellman-group16-sha512, diffie-hellman-group18-sha512
MACs hmac-sha2-512-etm, hmac-sha2-256-etm

세션 정책

설정
인증 방식 공개키만 (비밀번호 비활성화)
키 알고리즘 Ed25519 권장
MaxAuthTries 3
LoginGraceTime 30초
ClientAliveInterval 1200초 (20분)
X11Forwarding 비활성화
Compression 비활성화

SSH CA 인증서

호스트 키는 CA로 서명되어 있어 known_hosts에 CA 공개키만 등록하면 모든 호스트를 신뢰할 수 있습니다.

@cert-authority *.sjanglab.org ssh-ed25519 AAAAC3...

설정 위치: modules/sshd/certs/

비밀 관리

sops-nix + age

모든 비밀은 age(Curve25519) 암호화로 보호됩니다. 호스트별 age 키와 관리자 키가 각 비밀 파일을 복호화할 수 있습니다.

비밀 파일 접근 가능 키 내용
hosts/<host>.yaml 해당 호스트 + admin root 비밀번호 해시, WireGuard 키
modules/acme/secrets.yaml eta, tau Cloudflare API 인증
modules/borgbackup/*/secrets.yaml 해당 호스트 Borg 암호화 키, SSH 키
modules/buildbot/secrets.yaml psi, rho GitHub App/OAuth 시크릿
modules/authentik/secrets.yaml eta OIDC 클라이언트 시크릿
modules/postgresql/secrets.yaml rho, tau DB 사용자 암호

비밀 편집

# 비밀 편집 (age 키 자동 사용)
sops hosts/psi.yaml

# 키 교체 후 재암호화
sops updatekeys hosts/psi.yaml

자세한 내용은 비밀 관리를 참조합니다.

TLS 인증서

모든 도메인은 eta에서 Let's Encrypt ACME + Cloudflare DNS 챌린지로 인증서를 발급합니다. 다른 호스트에서 사용하는 인증서는 acme-sync 서비스가 rsync로 동기화하고, 대상 호스트의 systemd path unit이 파일 변경을 감지하여 nginx를 자동 리로드합니다.

도메인 발급 호스트 사용 호스트
auth.sjanglab.org eta eta
vault.sjanglab.org eta eta
hs.sjanglab.org eta eta
cloud.sjanglab.org eta tau (동기화)
n8n.sjanglab.org eta tau (동기화)
ollama.sjanglab.org eta psi (동기화)
docling.sjanglab.org eta psi (동기화)
buildbot.sjanglab.org eta psi (동기화)

인증서 동기화: eta에서 발급 → acme-sync 서비스가 rsync로 대상 호스트에 전송 → systemd path unit이 변경 감지 → nginx 자동 리로드.

데이터 보안

PostgreSQL

설정
바인드 주소 wg-admin IP만
인증 방식 SCRAM-SHA-256 (원격), Peer (로컬)
복제 WAL 스트리밍 (rho → tau)
암호 관리 sops 암호화

Borgbackup

설정
암호화 repokey-blake2
보관 일 7개, 주 4개, 월 3~6개
전송 SSH (포트 10022, 전용 키)
저장소 tau (전용 borg 계정, 제한된 경로)

감사 및 모니터링

auditd

Linux 감사 데몬으로 다음을 추적합니다:

추적 대상 파일
PAM 세션 /var/log/wtmp, /var/log/btmp, /var/run/utmp
SSH 설정 변경 /etc/ssh/sshd_config

로그: /var/log/audit/audit.log (최대 8MB × 2)

로그 파이프라인

flowchart LR
  src["auditd / journald"] --> vec["Vector"]
  vec --> loki["Loki (rho)"]
  loki --> graf["Grafana"]
  graf --> ntfy["ntfy (알림)"]

시스템 안정성

자동 업그레이드

설정
소스 github:SBEE-lab/infra
업그레이드 system.autoUpgrade가 주기적으로 최신 설정 적용
재부팅 체크 매월 마지막 토요일 (auto-reboot 서비스)
재부팅 조건 커널 변경 시에만 24시간 후 자동 재부팅
지터 ±20분 (호스트별 분산)

서비스 복구

systemd가 서비스 실패 시 자동 재시작합니다. 모니터링은 Gatus(gatus.sjanglab.org)에서 헬스체크를 수행합니다.