Vault Agent 템플릿 사용하기
Vault Agent 템플릿 사용하기
Vault Agent의 템플릿 기능을 사용하면 Consul Template 마크업을 사용해 Vault 시크릿을 파일 또는(프로세스 슈퍼바이저 모드를 통한) 환경 변수로 렌더링할 수 있습니다.
출처: 문서
본문
기능 (Functionality)
template_config 스탠자는 템플릿 엔진의 전반적인 기본 동작을 구성합니다. template_config는 한 번만 정의할 수 있으며 template 스탠자와 다릅니다. 특정 시크릿을 어디에 어떻게 렌더링하는지에 초점을 맞추는 template과 달리, template_config는 템플릿 엔진이 전체적으로 어떻게 동작하고 Agent의 나머지 부분과 어떻게 상호작용하는지에 영향을 주는 파라미터를 담습니다. 여기에는 프로그램 종료 동작이 포함되지만 이에 국한되지는 않습니다. 템플릿 엔진 전체에 적용되는 다른 파라미터도 시간이 지나면서 추가될 수 있습니다.
template 스탠자는 Consul Template 마크업 언어를 사용해 시크릿을 파일로 렌더링하도록 Vault Agent를 구성합니다. 여러 파일을 렌더링하기 위해 여러 template 스탠자를 정의할 수 있습니다.
Agent가 템플릿을 활성화한 채 시작되면 구성된 auto-auth 방법을 사용해 Vault 토큰을 얻으려 시도합니다. 실패하면 잠시(떼 몰림(thundering herd) 시나리오를 막기 위한 약간의 무작위성 포함) 백오프한 뒤 재시도합니다. 성공하면 템플릿에 정의된 시크릿이 Vault에서 검색되어 로컬로 렌더링됩니다.
템플릿 언어 (Templating language)
템플릿 출력 내용은 template 스탠자의 contents 옵션으로 직접 제공하거나, 별도의 .ctmpl 파일로 만들어 template 스탠자의 source 옵션에 지정할 수 있습니다.
Vault에서 시크릿을 가져오려면(정적 시크릿, 동적 자격 증명, 인증서 여부와 무관) Vault Agent 템플릿은 Consul Template의 secret 함수 또는 pkiCert 함수의 사용이 필요합니다.
secret 함수는 모든 유형의 시크릿에서 작동하며, 이 함수가 렌더링하는 시크릿 유형에 따라 템플릿은 갱신 섹션에 자세히 설명된 대로 다른 갱신 동작을 가집니다. pkiCert 함수는 PKI 시크릿 엔진이 발급한 인증서에 특히 작동하도록 설계되었습니다. secret와 pkiCert 사이의 인증서 갱신 동작 차이는 인증서 섹션을 참조하세요.
다음 링크는 Vault Agent 템플릿이 사용하는 템플릿 언어에 대한 추가 리소스를 담습니다.
템플릿 언어 예시
다음은 Vault의 KV 저장소에서 일반 시크릿을 검색하는 템플릿 예시입니다.
{{ with secret "secret/my-secret" }}
{{ .Data.data.foo }}
{{ end }}
다음은 Vault의 PKI 시크릿 엔진에서 PKI 인증서를 발급하는 템플릿 예시입니다. 이 함수를 통한 PKI 역할의 인증서·키 가져오기는 인증서 만료를 기준으로 합니다.
새 인증서를 생성하고 키, 인증서, CA가 있는 번들을 만들려면:
{{ with pkiCert "pki/issue/my-domain-dot-com" "common_name=foo.example.com" }}
{{ .Data.Key }}
{{ .Data.Cert }}
{{ .Data.CA }}
{{ end }}
이 마운트의 발급 CA만 가져오려면:
{{- with secret "pki/cert/ca" -}}
{{ .Data.certificate }}
{{- end -}}
또는 pki/cert/ca_chain을 사용해 전체 CA 체인을 가져올 수 있습니다.
전역 구성 (Global configurations)
최상위 template_config 블록에는 모든 템플릿에 영향을 주는 다음 구성 항목이 있습니다.
exit_on_retry_failure(bool: false)— 이 옵션은 실패로 인해 템플릿 재시도 횟수를 모두 소진한 후 Vault Agent가 종료하도록 구성합니다.static_secret_render_interval(string or integer: 5m)— 지정하면 KV v2 같은 임대되지 않은 시크릿을 Vault Agent Template이 얼마나 자주 렌더링할지 구성합니다. 이 설정은 Vault Agent Templating이 임대된 시크릿을 렌더링하는 빈도는 바꾸지 않습니다. 기간 형식 문자열을 사용합니다.max_connections_per_host(int: 10)— Vault Agent 템플릿 엔진이 특정 Vault 호스트에 사용할 수 있는 총 연결 수를 제한합니다. 이 제한에는 다이얼링, 활성, 유휴 상태의 연결이 모두 포함됩니다.lease_renewal_threshold(float: 0.9)— Vault Agent의 템플릿 엔진이 동적·비갱신 임대를 새로고침하기까지 기다려야 하는 시간으로, 임대 기간의 분율로 측정합니다. 임대가 없는pkiCert템플릿 함수로 렌더링된 인증서의 경우Not After속성이 임대 종료 시간으로 처리되며, 인증서는Not Before와Not After속성 사이 차이의 구성된 비율에서 회전합니다.
template_config 스탠자 예시
template_config {
exit_on_retry_failure = true
static_secret_render_interval = "10m"
max_connections_per_host = 20
}
또 다른 예로, template 스탠자의 error_on_missing_key 파라미터와 exit_on_retry_failure가 있는 template_config는 기본 재시도 동작 대신 키/값 문제가 있을 때 Agent가 종료하게 합니다.
template_config {
exit_on_retry_failure = true
static_secret_render_interval = "10m"
max_connections_per_host = 20
}
template {
source = "/tmp/agent/template.ctmpl"
destination = "/tmp/agent/render.txt"
error_on_missing_key = true
}
exit_on_retry_failure와 error_on_missing_key의 상호작용
error_on_missing_key 파라미터는 template 스탠자 안에 지정할 수 있으며, 시크릿에 키가 없을 때 템플릿이 오류를 낼지 결정합니다. error_on_missing_key가 지정되지 않았거나 false로 설정되고 렌더링할 키가 시크릿 응답에 없으면, 템플릿 엔진은 이를 무시하고("<no value>" 렌더링) 렌더링을 계속합니다.
키 누락 시 Agent가 실패·종료하기를 원한다면, template.error_on_missing_key와 template_config.exit_on_retry_failure를 모두 true로 설정해야 합니다. 그렇지 않으면 템플릿 엔진이 오류를 내고 대상에 렌더링하지만, Agent는 종료하지 않고 키가 존재하거나 프로세스가 종료될 때까지 재시도합니다.
시크릿 응답에서 키가 없는 것과 시크릿이 없거나 존재하지 않는 것은 다릅니다. 템플릿 엔진은 시크릿이 없으면 항상 오류를 내지만, 키가 없는 경우에만 error_on_missing_key가 설정된 경우에만 오류를 냅니다. 템플릿 엔진이 오류를 낼 때 Vault Agent가 종료할지는 exit_on_retry_failure 값에 달려 있습니다.
템플릿 구성 (Template configurations)
최상위 template 블록에는 여러 구성 항목이 있습니다. consul-template 문서 페이지의 템플릿 구성 섹션에 있는 파라미터를 여기서 사용할 수 있습니다.
팁
아래 Δ로 표시된 파라미터는 파일 템플릿에만 적용되며 프로세스 슈퍼바이저 모드의 env_template 엔트리에는 사용할 수 없습니다.
source(string: "")— 입력 템플릿으로 사용할 디스크 경로입니다.contents옵션을 사용하지 않으면 이 옵션이 필요합니다.destinationΔ(string: required)— 렌더링된 시크릿을 만들 디스크 경로입니다. 부모 디렉토리가 존재하지 않으면create_dest_dirs가 false가 아닌 한 Vault Agent가 만들려 시도합니다.create_dest_dirsΔ(bool: true)— 이 옵션은 대상 경로의 부모 디렉토리가 없을 때 Vault Agent가 만들게 합니다.contents(string: "")— 템플릿 파일의source경로를 제공하는 대신 템플릿의 내용을 구성 파일에 직접 포함할 수 있게 해 줍니다. 짧은 템플릿에 유용합니다. 이 옵션은source옵션과 상호 배타적입니다.commandΔ(string: "")— 템플릿이 렌더링될 때 실행할 선택적 명령입니다. 명령은 결과 템플릿이 변경된 경우에만 실행됩니다. 명령은 30초(구성 가능) 안에 반환되어야 하며 성공적인 종료 코드를 가져야 합니다. Vault Agent는 프로세스 모니터나 init 시스템의 대체물이 아닙니다.exec옵션을 위해 폐기(deprecated)되었습니다.command_timeoutΔ(duration: 30s)— 선택적 명령이 반환되기를 기다리는 최대 시간입니다.exec옵션을 위해 폐기되었습니다.error_on_missing_key(bool: false)— 존재하지 않는 구조체나 맵 필드/키에 접근할 때 오류와 함께 종료합니다. 기본 동작은 존재하지 않는 필드에 접근할 때<no value>를 출력하는 것입니다. 이 값을 "true"로 설정할 것을 적극 권장합니다. 전역 Vault Agent Template Config의exit_on_retry_failure도 참조하세요.execΔ(object: optional)— exec 블록은 템플릿이 렌더링되고 출력이 변경되었을 때 명령을 실행합니다. 블록 파라미터는command(string or array: required)와timeout(string: optional, 기본값 30s)입니다.command는"touch myfile"처럼 실행할 문자열이나["touch", "myfile"]처럼 문자열 배열로 줄 수 있습니다. 명령 인젝션을 막기 위해 문자열 배열 사용을 강력히 권하며, 우리도 먼저 그 방식으로 파싱하려 시도합니다. 문자열 방식에서 쉼표를 사용하면 배열로 해석되므로 바람직하지 않을 수 있음에 주의하세요.permsΔ(string: "")— 파일을 렌더링할 권한입니다. 이 옵션을 지정하지 않으면 Vault Agent는 대상 경로에 이미 존재하는 파일의 권한에 맞추려 시도합니다. 그 경로에 파일이 없으면 권한은 0644입니다.backupΔ(bool: true)— 이 옵션은 새 템플릿을 쓰기 전에 대상 경로의 이전에 렌더링된 템플릿을 백업합니다. 정확히 하나의 백업을 유지합니다. 이 옵션은 롤백 전략 없이 데이터에 우발적인 변경이 생기지 않도록 방지하는 데 유용합니다.left_delimiter(string: "{{")— 템플릿에서 사용할 구분자입니다. 기본값은 "{{"이지만, 일부 템플릿에서는 출력 파일 자체와 충돌하지 않는 다른 구분자를 사용하는 것이 더 쉬울 수 있습니다.right_delimiter(string: "}}")— 템플릿에서 사용할 구분자입니다. 기본값은 "}}"이지만, 일부 템플릿에서는 출력 파일 자체와 충돌하지 않는 다른 구분자를 사용하는 것이 더 쉬울 수 있습니다.sandbox_pathΔ(string: "")— 샌드박스 경로가 제공되면file함수에 제공된 모든 경로가 샌드박스 경로 안에 들어가는지 검사합니다. 샌드박스 경로 밖으로 벗어나려는 상대 경로는 오류와 함께 종료됩니다.waitΔ(object: required)— 새 템플릿을 디스크에 렌더링하고 명령을 트리거하기 전에 기다리는minimum(:maximum)으로, 콜론(:)으로 구분합니다.
template 스탠자 예시
template {
source = "/tmp/agent/template.ctmpl"
destination = "/tmp/agent/render.txt"
error_on_missing_key = true
}
Vault Agent를 하나 이상의 템플릿을 렌더링하는 데만 사용하고 획득한 자격 증명을 싱크할 필요가 없다면, Agent 구성의 auto_auth 스탠자에서 sink 스탠자를 생략할 수 있습니다.
갱신과 시크릿 갱신 (Renewals and updating secrets)
Vault Agent 템플릿은 시크릿/토큰을 자동으로 갱신하고 가져옵니다. Vault Agent 캐싱과 달리 Vault Agent 템플릿의 동작 방식은 시크릿 또는 토큰의 유형에 따라 다릅니다. 다음은 다양한 동작에 대한 높은 수준의 개요입니다.
갱신 가능한 시크릿
시크릿 또는 토큰이 갱신 가능하면, Vault Agent는 시크릿의 임대 기간의 2/3이 경과한 후 시크릿을 갱신합니다.
갱신 불가능한 시크릿
시크릿 또는 토큰이 갱신 가능하지 않거나 임대되지 않으면, Vault Agent는 5분마다 시크릿을 가져옵니다. 이는 template_config 스탠자 값 static_secret_render_interval로 구성할 수 있습니다(requires Vault 1.8+). 갱신 불가능한 시크릿은 KV 버전 2에 유효하지만 이에 국한되지는 않습니다.
갱신 불가능한 임대 시크릿
시크릿 또는 토큰이 갱신 불가능하지만 임대된 경우, Vault Agent는 시크릿의 TTL(time-to-live)의 90%에 도달했을 때, 즉 많은 클라이언트가 동시에 Vault를 때리지 않도록 약간의 지터(jitter)를 더·빼서 시크릿을 가져옵니다. 임대된 갱신 불가능한 시크릿에는 데이터베이스 자격 증명 같은 동적 시크릿이 포함되지만 이에 국한되지는 않습니다. 90% 값은 template_config 스탠자 값 lease_renewal_threshold로 구성할 수 있습니다. KVv1 시크릿은 임대되지 않지만, 이 값은 Agent가 lease_duration이 정의된 KV 버전 1 시크릿을 다시 가져오는 분율도 제어합니다.
정적 역할 (Static roles)
시크릿에 데이터베이스 정적 역할처럼 rotation_period가 있으면, Vault Agent 템플릿은 Vault에서 시크릿이 바뀔 때 새 시크릿을 가져옵니다. 이를 시크릿의 TTL을 검사해서 수행합니다.
인증서 (Certificates)
Vault 1.11부터 인증서는 pkiCert 또는 secret 템플릿 함수로 렌더링할 수 있습니다. 다만 Agent가 재시작하거나 재인증할 때마다 불필요하게 인증서를 생성하지 않도록 pkiCert를 사용할 것을 권장합니다.
pkiCert 템플릿 함수로 렌더링하기
인증서가 pkiCert 템플릿 함수로 렌더링되면 Vault Agent 템플릿은 인증서에 대해 다음 가져오기·다시 렌더링 동작을 가집니다.
- Agent 시작 시 이전에 렌더링된 것이 없거나 현재 렌더링된 것이 만료된 경우 새 인증서를 가져옵니다.
- 예를 들어 토큰 만료로 인한 Agent의 auto-auth 재인증 시, 현재 렌더링된 것이 만료되지 않았으면 가져오기를 건너뜁니다.
secret 템플릿 함수로 렌더링하기
인증서가 secret 템플릿 함수로 렌더링되면 Vault Agent 템플릿은 인증서에 대해 다음 가져오기·다시 렌더링 동작을 가집니다.
- 이전에 렌더링된 인증서가 여전히 유효해도 Agent 시작 시 새 인증서를 가져옵니다.
generate_lease가 설정되지 않았거나false로 설정되면 다시 가져오기 간격을 결정하기 위해 인증서의validTo필드를 사용합니다.generate_lease가true로 설정되면 갱신 불가능한 임대 시크릿 규칙을 적용합니다.- 예를 들어 토큰 만료로 인한 Agent의 auto-auth 재인증 시, 기존 인증서가 유효해도 새 인증서를 가져와 다시 렌더링합니다.
템플릿 구성 예시
다음은 Vault Agent 템플릿 구성 블록을 보여줍니다.
# Other Vault Agent configuration blocks
# ...
template_config {
static_secret_render_interval = "10m"
exit_on_retry_failure = true
max_connections_per_host = 20
}
template {
source = "/tmp/agent/template.ctmpl"
destination = "/tmp/agent/render.txt"
}
template {
contents = "{{ with secret \"secret/my-secret\" }}{{ .Data.data.foo }}{{ end }}"
destination = "/tmp/agent/render-content.txt"
}
다음은 프로세스 슈퍼바이저 모드에서 env_template을 사용할 때 템플릿이 어떻게 보이는지 보여줍니다.
# Other Vault Agent configuration blocks
# ...
template_config {
static_secret_render_interval = "10m"
exit_on_retry_failure = true
max_connections_per_host = 20
}
env_template "MY_ENV_VAR" {
contents = "{{ with secret \"secret/my-secret\" }}{{ .Data.data.foo }}{{ end }}"
}
env_template "ENV_VAR_FROM_FILE" {
source = "/tmp/agent/template.ctmpl"
}
PKI cert Agent 인젝터 예시
다음 예시는 consul-template의 pkiCert 함수와 writeToFile 함수를 사용해 하나의 템플릿에서 Vault의 PKI 시크릿 엔진이 생성한 인증서·CA용 파일(cert.pem)과 키용 파일(cert.key) 두 개를 만드는 방법을 보여줍니다.
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment
labels:
app: web
spec:
replicas: 1
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
annotations:
vault.hashicorp.com/agent-inject: 'true'
vault.hashicorp.com/role: 'web'
vault.hashicorp.com/agent-inject-secret-certs: 'pki/issue/cert'
vault.hashicorp.com/agent-inject-template-certs: |
{{- with pkiCert "pki/issue/cert" "common_name=test.example.com" "ttl=2h" -}}
{{ .Cert }}{{ .CA }}{{ .Key }}
{{ .Key | writeToFile "/vault/secrets/cert.key" "vault" "vault" "0644" }}
{{ .CA | writeToFile "/vault/secrets/cert.pem" "vault" "vault" "0644" }}
{{ .Cert | writeToFile "/vault/secrets/cert.pem" "vault" "vault" "0644" "append" }}
{{- end -}}
spec:
serviceAccountName: web
containers:
- name: web
image: nginx