# Security Hardening 운영 절차가 아닌 **정책 / 거버넌스** 영역. guide.md 가 *"오늘 oncall 이 따라할 절차"* 라면 이 문서는 *"이 클러스터를 책임진다면 알아야 할 보안 결정"* 이다. ## 목차 1. [etcd encryption at rest](#1-etcd-encryption-at-rest) 2. [Vault 운영자 토큰 관리](#2-vault-운영자-토큰-관리) 3. [bash history 에 비밀번호 남기지 않기](#3-bash-history-에-비밀번호-남기지-않기) --- ## 1. etcd encryption at rest VSO 가 만드는 K8s Secret 은 기본적으로 **etcd 에 base64 로만 저장된다 (평문과 동일)**. 운영 전 반드시 암호화를 켠다. ### K3s 방식 (권장 — 학습/소규모) 최초 설치 시: ```bash # /etc/rancher/k3s/config.yaml write-kubeconfig-mode: "0644" secrets-encryption: true # 또는 설치 커맨드 curl -sfL https://get.k3s.io | sh -s - server --secrets-encryption ``` K3s 가 AES-CBC 키를 자동 생성해서 `/var/lib/rancher/k3s/server/cred/encryption-config.json` 에 저장한다. 이미 돌고 있는 클러스터에서 켜는 경우: ```bash sudo vim /etc/rancher/k3s/config.yaml # secrets-encryption: true 추가 sudo systemctl restart k3s # 기존 Secret 을 즉시 재암호화 (없으면 새 Secret 부터 적용) sudo k3s secrets-encrypt prepare sudo systemctl restart k3s sudo k3s secrets-encrypt rotate sudo systemctl restart k3s sudo k3s secrets-encrypt reencrypt ``` 확인: ```bash sudo k3s secrets-encrypt status # Encryption Status: Enabled # Current Rotation Stage: start # Server Encryption Hashes: All hashes match ``` ### 표준 Kubernetes 방식 (kubeadm 등) 1. `/etc/kubernetes/encryption.yaml` 생성: ```yaml apiVersion: apiserver.config.k8s.io/v1 kind: EncryptionConfiguration resources: - resources: ["secrets"] providers: - aescbc: keys: - name: key-2026-04-21 secret:
- identity: {} ``` 2. kube-apiserver manifest 에 플래그 추가: ```yaml spec: containers: - command: - kube-apiserver - --encryption-provider-config=/etc/kubernetes/encryption.yaml volumeMounts: - name: encryption-config mountPath: /etc/kubernetes/encryption.yaml readOnly: true ``` 3. 기존 Secret 재암호화: ```bash kubectl get secrets --all-namespaces -o json \ | kubectl replace -f - ``` ### KMS provider (프로덕션 권장) `aescbc` 대신 KMS plugin (Vault transit / AWS KMS / GCP KMS) 사용. circular dependency (Vault 도 K8s Secret 에 의존) 회피를 위해 Vault transit 은 **별도 provider Vault** 를 띄워야 한다. 현 프로젝트는 단일 Vault 이므로 KMS 는 추후 작업. ### 검증 Secret 이 암호화됐는지 확인: ```bash # K3s sudo k3s kubectl -n mnt get secret auth-server-db -o yaml \ | grep -A1 "data:" # etcd 에 직접 접근해서 암호화 확인 (K3s) sudo ETCDCTL_API=3 etcdctl \ --endpoints=https://127.0.0.1:2379 \ --cacert=/var/lib/rancher/k3s/server/tls/etcd/server-ca.crt \ --cert=/var/lib/rancher/k3s/server/tls/etcd/client.crt \ --key=/var/lib/rancher/k3s/server/tls/etcd/client.key \ get /registry/secrets/mnt/auth-server-db # 출력이 'k8s:enc:aescbc:v1:...' 로 시작하면 암호화됨 ``` --- ## 2. Vault 운영자 토큰 관리 root token 은 **비상시 (rekey / generate-root / 전체 복구) 전용**으로만 사용한다. 평시 작업은 개인별 계정 + `vault-admin` policy 로 수행한다. ### 초기 설정 부트스트랩 완료 후 한 번만: ```bash REPO_ROOT="$(pwd)" \ VAULT_ADMIN_USERNAME='alice' \ VAULT_ADMIN_PASSWORD='<초기 비밀번호>' \ bash scripts/tasks/vault-setup-admin.sh ``` 이 스크립트가 수행: - `userpass` auth method 활성화 (idempotent) - `vault-admin` policy 작성 (`secret/*`, `auth/*`, `sys/mounts/*`, `sys/audit/*` 등 관리 권한) - `${VAULT_ADMIN_USERNAME}` 계정 생성 (token TTL 기본 8h / max 24h) ### 운영자 로그인 — root token 사용 중단 ```bash # port-forward 로 vault CLI 접근 kubectl -n mnt port-forward svc/vault 8200:8200 & export VAULT_ADDR=http://127.0.0.1:8200 # 로그인 (로그인 시 발급되는 토큰은 8h 후 자동 만료) vault login -method=userpass username=alice # Password (will be hidden): <입력> # Token is displayed and automatically cached in ~/.vault-token ``` 첫 로그인 후 비밀번호 변경: ```bash vault write auth/userpass/users/alice/password password='<새 비밀번호>' ``` ### root token 처리 `vault-init-keys.json` 에 있는 root token 은: 1. **즉시 오프라인 금고 (1Password Team / 하드웨어 보안 금고 / 봉인 봉투) 로 이동** 2. 원본 파일에서 `root_token` 필드 삭제 (unseal keys 는 재부팅 시 필요하므로 유지) 3. root token 이 필요하면: ```bash # 기존 root token 유효하면 재사용 vault login