Secret key 관리 방법
Secret 관리
- DB 비밀번호, AWS 키, 토큰과 AES 암호화 시크릿 키 등 공개되어선 안되는 비밀 값들을 관리할 수 있는 방법을 고민한다.
- 지금은 환경 변수를 세팅하는 쉘 스크립트와 k8s secret 값을 만들어두고 git ignore으로 숨기고 있는데 값 관리가 어렵고 실행이 번거롭다.
- 비밀 키 값, 환경 변수를 관리하는 저장소를 구성하고, 비밀 키 값이 포함된 쉘 스크립트나 파일들을 제거한다.
Private repository
- public 으로 올리지 않는 파일만 private repository 에 따로 관리하여 숨긴다.
- 암호화된 파일을 아예 분리된 경로에 위치시켜야해서 파일이 분산되고 디렉토리 관리가 편하지 않았다.
- 다른 도구가 불필요해 설정이 쉽다.
Submodule + Private repository
- 키 값, 환경 변수 값 저장의 버전 문제를 풀이할 때 사용한 경험이 있다.
- 예를 들어 A,B 프로젝트에서 공통 저장소로 Private repository 를 사용하는 도중, A가 업데이트 되면서 키 값이 서로 달라질 수 있다.
- Submodule은 특정 commit 을 끌어와 사용하기에 위 상황에서 A와 B는 공통된 저장소를 사용하나 서로에게 유효한 값을 가진 Commit 을 바라볼 수 있게된다.
- 개인적으로는 사용이 불편했다. 팀에서 모두 submodule 을 신경써야하고 (사용 방법, 사용 여부, Commit 버전 등), 충돌이나 꼬이면 푸는게 귀찮았다.
- 다른 도구 없이 Git 으로 해결할 수 있어 편하면서도 Private repo 로도 풀 수 있으면 굳이 싶다.
Vault
- 키 관리 저장소를 따로 둔다.
- 인증부와 키 자체를 분리하여 사용자와 권한 범위를 관리하기 좋다. (퇴사자 문제)
- Dynamic secret이나 TTL 으로 권한의 유효 기간을 두거나 권한 자체를 임시로 생성 - 제거할 수 있어 안전하다.
- AWS Dynamic secret 으로 CI/CD에 필요한 AWS 권한만을 갖는, 작업 기간 동안만 유효한 임시 키를 사용한 경험이 있다.
- 다양한 인증 방법과 저장 공간(Storage engine), 관리 가능한 키를 제공하고, 참고할 수 있는 자료가 많다는 것도 큰 강점이었다.
배포 시점에 Vault secret key 환경 변수 주입
Vault kubernetes injector
- Pod 가 생성될 때 Init container에서 Service account(token)로 Vault k8s auth 에 로그인을 요청한다.
- Vault agent container는 발급 받은 로그인 토큰과 함께 필요한 Secret 값을 요청한다.
- Vault에선 로그인 토큰의 유효함, 사용자의 권한을 확인한다.
- 요청한 Secret 값을 전달하고, Vault agent 는 이를 임시 저장 공간에 저장한다.
- Application container에서 저장된 Secret 값을 참조하여 환경 변수를 구성한다.
적용 결과
- 관리되지 못하던 Secret 파일과 설정을 모두 제거할 수 있었다.
- Vault 서버에 접근만 가능하다면 여러 프로젝트나 모듈에서 값을 가져올 수 있어 공동 변수 관리에도 유리했다.
- 예를 들어 기존에는 Redis port 가 바뀌면 Redis port를 사용하고 있는 파일들을 다 추적해야 했었는데,
- 이제는 Vault에서 바뀐 값 하나만 변경하면 된다.
- 개발자는 설정 값, Secret 값을 개발에서 고려하지 않아도 되어 관리 포인트가 줄고, 값을 알 수 도 없어서 퇴사자 문제에서 자유롭다.

설정 방법
- Helm values.yaml 준비
- KUBERNETES_IP : 쿠버네티스 host ip
- PORT : 쿠버네티스 port
global:
externalVaultAddr: "${KUBERNETES_IP:PORT}
injector:
enabled: "true"
port: ${PORT}
- Vault-agent-injector 설치
helm repo add hashicorp https://helm.releases.hashicorp.com
helm install vault -f values.yaml hashicorp/vault
- Vault kubernetes 인증에 사용할 Secret 생성
- SECRET_NAME : 생성할 secret 이름
apiVersion: v1
kind: Secret
metadata:
name: $SECRET_NAME
annotations:
kubernetes.io/service-account.name: vault
type: kubernetes.io/service-account-token
- Vault kubernetes 인증 생성
- TOKEN_REVIEWER_JWT : 앞서 생성한 secret의 token 값
TOKEN_REVIEWER_JWT=$(kubectl get secret $SECRET_NAME --output='go-template={{ .data.token }}' | base64 --decode)
KUBE_CA_CERT=$(kubectl config view --raw --minify --flatten --output 'jsonpath={.clusters[].cluster.certificate-authority-data}' | base64 --decode)
KUBE_HOST=$(kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.server}')
vault auth enable kubernetes
vault write auth/kubernetes/config \
token_reviewer_jwt="$TOKEN_REVIEW_JWT} \
kubernetes_ca_cert="$KUBE_CA_CERT" \
kubernetes_host="$KUBE_HOST"
- Vault Secret 생성, 값 추가
ex,
vault secrets enable -path=picup kv
vault kv put picup/common version=1 created=20240516
- Vault Policy 정의 (Secret 사용 범위 지정)
ex,
path "picup/*" {
capabilities = ["read", "list"]
}
vault policy write {POLICY_NAME} {POLICY_FILE_PATH}
- Vault Auth role 정의
- ROLE_NAME : 생성할 Role 이름
- SERVICE_ACCOUNT_NAME_OF_POD : Vault agent 가 생성될 Pod 의 Service account 이름
- POD_NAME_SPACE : Vault agent 가 생성될 Pod 의 namespace
- POLICY_NAME : 미리 정의한 Vault policy 이름
- TTL : 로그인 유효 기간 (ex, 24h)
vault write auth/kubernetes/role/$ROLE_NAME \
bound_service_account_names=$SERVICE_ACCOUNT_NAME_OF_POD \
bound_service_account_namespaces=$POD_NAME_SPACE \
policies=$POLICY_NAME \
ttl=$TTL
- Deployment 에 Vault agent 설정 추가
- vault.hashicorp.com/role: 사용할 Vault auth role 이름을 정의한다.
- vault.hashicorp.com/agent-inject-secret-$PREFIX : 저장될 파일 경로 prefix를 표시한다.
- 예를 들어 'agent-inject-secret-picup' 을 key로 하면 읽어온 데이터는 '/vault/secret/picup'에 저장된다.
- vault.hashicorp.com/agent-inject-secret 의 값은 읽을 vault secret path를 의미한다.
- vault.hashicorp.com/agent-inject-template-$PREFIX : 파일에 저장되는 형태를 결정한다.
- .Data 의 형태를 확인하고 저장할 포맷을 정의한다.
- 예시의 .Data는 map[created:20240516 version:1] 꼴이었고, k=v 로 저장하는 Template 코드를 정의했다.
- source 로 secret 값이 저장된 파일을 환경 변수로 올린다.
ex)
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: vault-injector-test
name: vault-injector-test
namespace: picup
spec:
replicas: 1
selector:
matchLabels:
app: vault-injector-test
template:
metadata:
annotations:
vault.hashicorp.com/role: internal-app
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/agent-inject-secret-picup: picup/common
vault.hashicorp.com/agent-inject-template-picup: |
{{- with secret "picup/common" -}}
{{- range $k, $v := .Data }}
{{- $k }}={{ $v }}
{{end}}{{end}}
labels:
app: vault-injector-test
spec:
containers:
- image: alpine
args:
- "sh"
- "-c"
- "source /vault/secrets/picup && sleep 10000"
imagePullPolicy: IfNotPresent
name: vault-injector-test
resources: {}
terminationGracePeriodSeconds: 30
Ref
Secret key 관리 방법
Secret 관리
Private repository
Submodule + Private repository
Vault
배포 시점에 Vault secret key 환경 변수 주입
Vault kubernetes injector
적용 결과
설정 방법
Ref