RUNBOOK   Sigil 배포 / 테스트

2-머신 테스트 + 배포 네트워크·포트 가이드

구성: Mac (agent + sender) ↔ Rocky/RHEL VM (bridged, sigil-server) · 같은 LAN 서브넷  ·  날짜: 2026-05-25  ·  예시 IP: VM = 192.168.0.50 (본인 값으로 치환)

목차   1. 토폴로지 · 2. 포트 / 방화벽 표 (실무) · 3. PKI 생성 · 4. VM(server) 설치·설정 · 5. Mac(agent+sender) · 6. 검증 · 7. 실무 배포 노트 · 8. 흔한 실패

1. 토폴로지 & 데이터 흐름

flowchart LR
  subgraph mac["Mac — agent 호스트 · inbound 포트 없음"]
    direction TB
    agent["sigil (agent)"]
    spool[("JSONL spool")]
    sender["sigil-sender"]
    agent -->|"watch·hash·JSONL"| spool
    spool -->|reads| sender
    sender -.->|"apply_policy (UDS·로컬)"| agent
  end
  subgraph vm["Rocky VM · bridged"]
    server["sigil-server :8443"]
    store[("events_out_dir · host_id별 JSONL")]
    server --> store
  end
  sender ==>|"mTLS 8443 · 이벤트 push"| server
  server -.->|"mTLS 8443 · 서명정책 pull (ETag)"| sender
  classDef comp fill:#d1fae5,stroke:#059669,color:#064e3b;
  class agent,spool,sender,server comp;

2. 포트 / 방화벽 표 (실무에서 열어야 할 것)

컴포넌트 (호스트)방향포트프로토콜용도상대
sigil-server (서버 VM)inbound8443/tcp
(bind 설정값)
TLS (mTLS) POST /v1/events 수신 · GET /v1/policy 서빙 · /v1/healthz · /v1/meta+read API — 전부 같은 포트agent 호스트들, (옵션) sigil-manager / 운영자
agent 호스트 (Mac/엔드포인트)outbound8443/tcpTLSsigil-sender → server (이벤트 push + 정책 pull)→ sigil-server
agent 호스트outbound443/tcp 또는 SIEM 포트
(예: Splunk HEC 8088)
TLSsigil-sender → SIEM 직접 경로 쓸 때만→ SIEM
agent ↔ sender로컬네트워크 포트 없음Unix socketapply_policy IPC (같은 호스트)n/a
(옵션) sigil-manageroutbound8443/tcpTLS+bearerserver read API(/v1/meta, fleet) 조회→ sigil-server
(옵션) sigil-managerinbound자체 웹 포트
(예: 8080)
TLSfleet 웹 콘솔운영자 브라우저

요점.서버만 inbound 1개(8443) 열면 끝. ② agent 호스트는 inbound 0개 — 리슨 포트 없음, outbound 만 (lockdown 된 엔드포인트 fleet 에 유리). ③ agent↔sender 는 로컬 UDS 라 방화벽 무관.

인증 계층 구분: data/control 경로(/v1/events, /v1/policy)는 mTLS 클라이언트 cert 로 인증. read API(/v1/meta, fleet)는 그 위에 bearer 토큰 게이트(Phase 3b.4) — 토큰 미설정이면 404. /v1/healthz 만 인증 없음(단 여전히 mTLS 핸드셰이크는 필요).

3. PKI 한 번 생성 (아무 박스, 예: Mac)

데모 demo/init.sh 의 openssl 묶음 그대로, server cert 의 SAN 만 조정.

# CA
openssl req -x509 -newkey rsa:2048 -nodes -days 3650 \
  -keyout ca.key -out ca.crt -subj "/CN=sigil-test-ca" \
  -addext "basicConstraints=critical,CA:TRUE" -addext "keyUsage=critical,keyCertSign,cRLSign"

# 서버 cert — SAN 에 hostname(권장) + IP. sender 가 접속할 주소가 SAN 에 있어야 함.
cat > server.ext <<'EOF'
basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = DNS:sigil-server, IP:192.168.0.50
EOF
openssl req -new -newkey rsa:2048 -nodes -keyout server.key -out server.csr -subj "/CN=sigil-server"
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 \
  -extfile server.ext -out server.crt

# 클라이언트(sender) cert
cat > client.ext <<'EOF'
basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature
extendedKeyUsage = clientAuth
EOF
openssl req -new -newkey rsa:2048 -nodes -keyout client.key -out client.csr -subj "/CN=mac-sender"
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 \
  -extfile client.ext -out client.crt

정책 서명 키 + keystore + signed bundle (control-plane 용; data-plane 만 볼 거면 생략 가능):

sigil-sign keygen --id test-key --out signing-key.json
PUB=$(jq -r .ed25519_pubkey_b64 signing-key.json)
cat > policy-signing-pubkeys.pem <<EOF
{ "pubkeys": [ { "id":"test-key","ed25519_pubkey_b64":"$PUB","valid_from":"2020-01-01T00:00:00Z","valid_until":"2099-01-01T00:00:00Z" } ] }
EOF
cp config/policy.example.yaml policy.yaml
sigil-sign sign --in policy.yaml --key signing-key.json \
  --policy-version 2 --valid-until 2099-01-01T00:00:00Z --out signed-policy.json

4. VM (Rocky aarch64, bridged) — sigil-server

ARM64 주의. Apple Silicon Mac 의 VM 은 aarch64. prebuilt/x86_64 rpm 은 안 됨(cross-arch 패키징 미구현 — open issue #12). VM 에서 소스 빌드가 정답.

# Rocky aarch64 — 소스 빌드
sudo dnf install -y gcc git
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh && source "$HOME/.cargo/env"
git clone https://github.com/Ju571nK/sigil && cd sigil
cargo build --release -p sigil-server         # → target/release/sigil-server (네이티브 aarch64)
sudo mkdir -p /etc/sigil-server /var/lib/sigil-server/events
# A에서 만든 것 전송: server.crt server.key ca.crt signed-policy.json
sudo cp server.crt server.key ca.crt signed-policy.json /etc/sigil-server/

/etc/sigil-server/server.yaml:

bind: "0.0.0.0:8443"
events_out_dir: "/var/lib/sigil-server/events"
policy_bundle_path: "/etc/sigil-server/signed-policy.json"
tls_cert_path: "/etc/sigil-server/server.crt"
tls_key_path: "/etc/sigil-server/server.key"
client_ca_path: "/etc/sigil-server/ca.crt"     # ← 3개 다 켜야 mTLS ON (안 켜면 PLAIN HTTP 경고)
# 방화벽 (Rocky/firewalld)
sudo firewall-cmd --add-port=8443/tcp --permanent && sudo firewall-cmd --reload
# SELinux enforcing 면: 8443 은 보통 http_port_t 에 포함. 커스텀 포트 쓰면:
#   sudo semanage port -a -t http_port_t -p tcp <port>
# 실행
./target/release/sigil-server serve --config /etc/sigil-server/server.yaml
ip addr | grep 192.168          # VM 의 LAN IP 확인 (bridged 면 LAN 대역)

5. Mac — agent + sender

echo "192.168.0.50  sigil-server" | sudo tee -a /etc/hosts   # hostname SAN 매핑
mkdir -p ~/sigil-test/{events,state,run}
# 소스 빌드 (Apple Silicon = aarch64-apple-darwin 네이티브)
cargo build --release -p sigil-agent -p sigil-sender
# A에서: ca.crt client.crt client.key policy-signing-pubkeys.pem policy.yaml 가져오기

~/sigil-test/sender.yaml:

server_base_url: "https://sigil-server:8443"
client_cert_path: "/Users/ju571nk3n/sigil-test/client.crt"
client_key_path:  "/Users/ju571nk3n/sigil-test/client.key"
server_ca_path:   "/Users/ju571nk3n/sigil-test/ca.crt"
events_dir:       "/Users/ju571nk3n/sigil-test/events"
offset_path:      "/Users/ju571nk3n/sigil-test/state/sender-offset.json"
agent_control:    "/Users/ju571nk3n/sigil-test/run/control.sock"
dead_letter_dir:  "/Users/ju571nk3n/sigil-test/events/dead-letter"
policy_poll_interval: 10
# 터미널 1 — agent (events-dir / control 경로를 sender.yaml 과 일치)
./target/release/sigil run --policy ~/sigil-test/policy.yaml \
  --events-dir ~/sigil-test/events --state-db ~/sigil-test/state/state.db
# 터미널 2 — sender
./target/release/sigil-sender --config ~/sigil-test/sender.yaml start

경로 정합이 핵심. sender 의 events_dir/agent_control 는 Mac agent 의 실제 events·control 경로와 같아야 함. agent 의 control socket override 플래그가 없으면 sigil show config 로 실제 경로를 확인하고 sender.yaml 을 맞추세요.

6. 검증

# Mac → VM mTLS 도달 (인증 없는 healthz, 단 클라이언트 cert 는 필요)
curl --cacert ca.crt --cert client.crt --key client.key https://sigil-server:8443/v1/healthz
# Mac 의 watch 대상 한번 건드리기 (예시)
touch ~/.claude/settings.json   # 또는 policy.yaml 의 targets 경로
# VM: host_id 별 JSONL 이 생기는지
ls -R /var/lib/sigil-server/events

/v1/meta·fleet 등 read API 는 bearer 토큰이 설정돼 있어야 200 (없으면 404). reachability 확인은 /v1/healthz 로.

7. 실무 배포 노트

8. 흔한 실패 3 + α

  1. VM 이 NAT (bridged 아님) → Mac 에서 curl timeout. bridged 로 VM 이 LAN IP 받게.
  2. server cert SAN 에 접속 주소 없음 → TLS handshake 실패. SAN 에 DNS:sigil-server(+/etc/hosts) 또는 IP:192.168.0.50.
  3. agent 실제 events/control 경로 ≠ sender.yaml → sender 가 spool 못 읽음/apply_policy 못 보냄. 양쪽 경로 명시·일치.
  4. 방화벽 8443 미개방 / 서버가 127.0.0.1 바인드 → 외부 도달 불가. 0.0.0.0:8443 + firewalld 허용.
  5. server.yaml 의 TLS 3필드 중 일부만 설정 → mTLS OFF(PLAIN HTTP 경고). 셋 다 켜야 mTLS.
  6. x86_64 rpm 을 aarch64 VM 에 설치 시도 → arch 불일치. 소스 빌드로.

이 문서는 테스트/배포 레퍼런스 (repo 미커밋, 본인 환경값 포함). 차트는 mermaid (CDN 렌더) — 오프라인이면 차트 소스가 텍스트로 보이고, GitHub/IDE preview 에서는 렌더됨. 일반화해서 정식 배포 doc 로 넣고 싶으면 IP/경로를 placeholder 로 바꿔 커밋하면 됩니다.