Vault Secrets Operator refreshAfter — HMAC 기반 변경 감지
시크릿을 Git 에 평문으로 둘 수는 없으니 값은 Vault 에 두고, Vault Secrets Operator 가 그걸 읽어다 쿠버네티스 Secret 으로 만들어 줍니다. Git 에는 어느 경로에서 읽을지만 남습니다.
이렇게 두면 값이 바뀌었을 때 Git 을 안 고쳐도 됩니다. Vault 에서 값만 바꾸면 오퍼레이터가 다음
주기에 그걸 읽어다 Secret 을 갱신해 주는데, 그 주기를 정하는 게 refreshAfter 입니다.
여기에 refreshAfter: 30s 를 걸어 뒀는데, 30초마다 Vault 를 다시 읽는다는 뜻이라 처음 볼 때는
이래도 되나 싶은 숫자였습니다.
kind: VaultStaticSecret
spec:
mount: vso-secrets
path: <namespace>/<app>/.env
type: kv-v2
refreshAfter: 30s # 30초마다 Vault 폴링
hmacSecretData: true # 값이 같으면 K8s Secret 을 안 건드림
destination:
create: true
name: <secret-name>
overwrite: true
refreshAfter 가 Vault 를 얼마나 자주 읽을지를 정하고, hmacSecretData 는 읽은 값이 같을 때
K8s Secret 을 건드릴지를 정하는 것이라, 이름이 나란히 붙어 있어도 하는 일이 다릅니다.
Vault 폴링 자체는 비용 아님
refreshAfter: 30s, VaultStaticSecret 10개 기준으로 계산하면 이렇습니다.
분당 10개 × 2회 = 20 호출
하루 28,800 호출
초당으로 치면 0.3 회라, 부하라고 부를 수준이 아닙니다.
진짜 비용은 Kubernetes Secret 쓰기
Secret 을 쓸 때마다 etcd 에 쓰기가 일어나고 그 Secret 을 보고 있는 watch 로 전부 전파되니, Vault
를 한 번 더 읽는 것과는 비용이 다릅니다. hmacSecretData: true 가 하는 일이 여기서 나옵니다 —
30초마다 Vault 를 읽지만 값이 안 바뀌었으면 Kubernetes Secret 을 갱신하지 않습니다.
1. 30초마다 Vault kv-v2에서 현재 값 읽기
2. 읽어온 값의 HMAC 계산
3. 이전에 저장한 HMAC과 비교
4. 같으면: 아무것도 안 함 (K8s API 호출 없음)
5. 다르면: K8s Secret 업데이트
비교에 쓰는 해시는 리소스 상태에 남아 있어서 직접 꺼내 볼 수 있습니다.
kubectl get vaultstaticsecret <vss-name> -n <namespace> \
-o jsonpath='{.status.secretMAC}'
hmacSecretData 가 없으면 값이 같아도 매번 Secret 을 덮어쓰니 불필요한 Kubernetes API write 가
생기고, rolloutRestartTargets 를 걸어 뒀다면 그때마다 파드가 다시 뜹니다. 30초마다 시크릿을
다시 읽는 구성이 아니라 30초마다 파드가 재시작하는 구성이 되는 겁니다.
30초가 항상 맞는 값은 아님
시크릿을 바꿨을 때 빠르게 반영돼야 하는 워크로드라 30초로 잡았습니다. 반영이 몇 분 늦어도 되는 서비스면 주기를 늘려도 되지만, 늘려서 얻는 건 크지 않습니다.
폴링 주기를 줄일지 정하는 기준은 Vault 부하가 아니라 얼마나 빨리 반영돼야 하는가 쪽입니다.
부하 쪽은 이미 hmacSecretData 가 막고 있습니다.
댓글 0