Files

119 lines
5.7 KiB
Markdown

# k3s Secret 암호화 수동 운영 절차
> **현재 경계(2026-08-09):** bootstrap의
> `--recovery-policy local-separate-disk-luks`, 물리 디스크 lineage validator,
> `LOCAL_RISK_ACCEPTED`, pre/post 동적 용량 gate는 구현·fixture 검증을 마쳤다.
> 수동 LUKS header 복구 proof, recovery close·잔류 없음 검사와 closed validator를
> 통과한 뒤 live 전환도 완료했다. 현재 Secret encryption은
> `Enabled/reencrypt_finished`이며 hash·integrity·API·node 검사와 post bundle 기록,
> 최신 bundle marker 검증이 모두 통과했다. lifecycle 자동화, 격리 restore drill,
> off-host 복제와 암호화 escrow 검증은 별도 미완료 gate이므로 관측성 Phase 4를 열지 않는다.
이 문서는 단일 k3s server에서 Kubernetes Secret 저장 암호화를 fail-stop 방식으로
전환하는 수동 절차다. 아래 상태 순서의 **live 전 역사적 기준선**은
`v1.36.2+k3s1`, 단일 Ready 노드 `donghyeon-system-product-name`, SQLite, Secret
encryption Disabled, API `readyz` pass였다. 현재 live 상태는 위 banner의
`Enabled/reencrypt_finished`다. 모든 단계는 운영자가 명시적으로 실행하고 확인한다.
자동화는 상태가 불명확하거나 검증이 실패하면 다음 단계로 진행하지 않는다.
## 상태 순서
다음 순서와 각 화살표 사이의 검증을 바꾸지 않는다.
```text
disabled_no_config
-> k3s secrets-encrypt enable
-> drop-in install + restart
-> transition_start + hashes_match
-> k3s secrets-encrypt rotate-keys
-> bounded wait for reencrypt_finished
-> final restart
-> Enabled/reencrypt_finished + server_hashes_match + local_integrity_match
```
각 상태 전환 전후에는 Task 2 validator를 해당 기대 상태로 실행해 version, 단일
Ready server, datastore, API `readyz`, status와 hash/integrity를 확인한다. validator
출력이나 운영 로그에 server token, 비밀번호, encryption config 본문을 기록하지
않는다.
## 사전 판정과 소유 위치
이미 `enabled_stable`로 분류되면 Task 1 effective-source resolver를 사용하여
`ExecStart`, `Environment`/`EnvironmentFile`, systemd drop-in, default 또는
alternate config 및 그 config drop-in을 순서대로 판정한다. 여기서
`secrets-encryption`과 provider의 **유효 소유 위치만** 확인한다.
계획한 `40-secrets-encryption.yaml`이 아닌 기존 위치가 owner이면 그 위치를 그대로
보존하고 config rewrite를 하지 않는다. 서로 충돌하는 두 owner, provider 판정 불가,
또는 기존 provider가 `aescbc`가 아닌 경우에는 자동 변경하지 않는다. 이 경우에는
별도 ADR을 먼저 승인해야 한다.
`enabled_stable`의 stage가 `reencrypt_finished`이면 rotation을 건너뛴다. stage가
`start`이면 Phase 4 전에 `--rotate-existing`을 사용한 명시 승인 재암호화만 수행한다.
## Bootstrap 진입 명령
인자 없는 명령은 상태만 읽고 변경하지 않는다.
```sh
cd /home/donghyeon/workspace/platform
bash scripts/bootstrap/apply-k3s-secret-encryption.sh
```
실제 전환 명령은 recovery volume이 열린 상태에서 backup root를 직접 지정하고 로컬
정책을 명시한다. 다음 명령은 maintenance 승인 전에는 실행하지 않는다.
```sh
cd /home/donghyeon/workspace/platform
bash scripts/bootstrap/apply-k3s-secret-encryption.sh \
--execute \
--backup-root /srv/recovery/k3s \
--recovery-policy local-separate-disk-luks
```
실행 확인 순서는 `APPLY <context>` → 자동 root·lineage·용량 검증 →
`RECOVERY <context>``ENCRYPTED <context>`
`LOCAL_RISK_ACCEPTED <context>`다. 어느 검사나 확인이 실패해도 다음 mutation으로
진행하지 않는다. 비밀번호나 복구 키를 이 명령의 인자·환경변수로 전달하지 않는다.
## 실행 단계
1. `disabled_no_config`을 validator로 확인한 뒤에만 `k3s secrets-encrypt enable`
실행한다.
2. repository의 host artifact를 root 소유, mode `0644`로 설치한다.
```sh
install -o root -g root -m 0644 \
infrastructure/security/k3s/40-secrets-encryption.yaml \
/etc/rancher/k3s/config.yaml.d/40-secrets-encryption.yaml
```
3. k3s를 재시작하고, `transition_start + hashes_match`가 validator로 확인될 때까지
중단한다.
4. 확인 뒤에만 `k3s secrets-encrypt rotate-keys`를 한 번 실행한다.
5. 제한된 시간 동안 `reencrypt_finished`를 기다린다. 시간 초과, API 실패, hash
mismatch 또는 local integrity mismatch이면 중단하고 조사한다.
6. 완료 상태를 확인한 후 final restart를 하고,
`Enabled/reencrypt_finished + server_hashes_match + local_integrity_match`를
다시 확인한다.
> **금지 및 중단 조건**
>
> - `transition_start` 확인 전에는 `rotate-keys`를 실행하지 않는다.
> - 중간 stage에서는 다른 rotation 명령을 실행하지 않는다.
> - drop-in을 자동 삭제하지 않는다.
> - live datastore 자동 restore 금지: 복구 판단과 수행은 별도 승인 절차다.
> - server token 또는 encryption key material을 명령 인자, 로그, ticket, Git에
> 남기지 않는다.
post bundle의 격리 복구, 결과 반출·파기와 evidence 등록은
[k3s Secret 암호화 복구 drill](k3s-secret-encryption-restore-drill.md)을 따른다.
## 재시도와 복구 경계
상태가 `disabled_no_config`, `transition_start`, `enabled_stable` 중 하나로 명확히
판정되지 않으면 재시도나 설정 변경을 하지 않는다. 특히 hash mismatch, provider
불명확, owner 충돌, API `readyz` 실패는 자동 보정 대상이 아니다. 라이브 datastore를
되돌리거나 Secret을 변경하는 동작도 이 절차의 권한 밖이며, 별도 ADR과 명시 승인을
필요로 한다.