잡 스펙의 `vault` 블록
잡 스펙의 vault 블록
vault 블록은 태스크가 HashiCorp Vault 서버에서 토큰을 요구한다고 명시할 수 있게 해요. Nomad는 태스크를 위한 Vault 토큰을 자동으로 가져오고 태스크의 토큰 갱신을 처리해요. group 레벨에서 지정하면 그 구성이 그룹 안의 모든 태스크에 적용돼요. job 레벨에서 지정하면 그 구성이 잡 안의 모든 태스크에 적용돼요. 여러 vault 블록이 지정되면 task 블록이 가장 높은 우선순위를 차지하고 그다음 group, 그다음 job으로 병합돼요.
출처: 문서
본문
| 배치 | job -> **vault** |
|---|---|
job -> group -> **vault** |
|
job -> group -> task -> **vault** |
job "docs" {
group "example" {
task "server" {
vault {
cluster = "default"
role = "prod"
change_mode = "signal"
change_signal = "SIGUSR1"
}
}
}
}
Nomad 클라이언트는 시크릿 디렉터리의 secrets/vault_token에 Vault 토큰을 쓰고 VAULT_TOKEN 환경 변수를 주입하여 태스크에 사용할 수 있게 해요. Nomad 클러스터가 Vault Namespaces를 사용하도록 구성되어 있으면, VAULT_TOKEN이 설정될 때마다 VAULT_NAMESPACE 환경 변수가 주입돼요. 이 동작은 env와 disable_file 매개변수로 변경할 수 있어요.
Nomad가 Vault 토큰을 갱신할 수 없으면(아마 Vault 중단 또는 네트워크 오류로), 클라이언트는 새 Vault 토큰을 가져오려고 시도해요. 성공하면 시크릿 파일의 내용이 디스크에서 업데이트되고 change_mode 매개변수에 설정된 값에 따라 조치가 취해져요.
vault 블록이 지정되면 template 블록도 Vault와 상호작용할 수 있어요.
매개변수 (Parameters)
allow_token_expiration(bool: false)- Nomad 클라이언트가 태스크의 Vault 토큰 갱신을 시도하지 않고 만료되도록 두는 것을 지정. 이것은 시크릿이 태스크 시작 시 한 번 요청되거나 수명이 짧은 prestart 태스크에서 요청되는 경우에만 사용해야 해요. 장수 태스크가template블록을 통해 Vault 시크릿을 얻는다면 절대allow_token_expiration=true를 설정해서는 안 돼요. Vault 토큰이 만료되고 템플릿 러너가vault_retry시도를 소진할 때까지 Vault에 실패하는 요청을 계속 보낸 다음 태스크가 실패하기 때문이에요.
Nomad가 Vault와 함께 Workload Identity를 사용하도록 구성되면, Nomad 클라이언트는 토큰을 갱신할 수 없을 때(예: Vault auth 메서드가 배치 토큰을 발급하도록 구성된 경우) 자동으로 감지해요. 이 경우 allow_token_expiration 옵션은 클라이언트에 의해 암시적으로 true로 설정돼요. 레거시 Vault 인증 워크플로우는 이를 자동으로 감지할 수 없어요.
-
change_mode(string: "restart")- Vault 토큰이 변경될 때 Nomad가 취해야 할 동작. 가능한 값: -
change_signal(string: "")-"SIGUSR1"또는"SIGINT"같은 문자열로 태스크에 보낼 신호.change_mode가signal이면 이 옵션은 필수예요. -
cluster(string: "default")
Enterprise
- 사용할 Vault 클러스터를 지정. Nomad 클라이언트는 에이전트 구성에서 같은 vault.name으로 구성된 클러스터에서 Vault 토큰을 가져와요. Nomad Community Edition에서는 이 필드가 무시돼요.
-
env(bool: true)- 태스크 시작 시VAULT_TOKEN과VAULT_NAMESPACE환경 변수를 설정해야 하는지 여부. -
disable_file(bool: false)- Vault 토큰을secrets/vault_token에 쓸지 여부.
경고
secrets 경로는 image 파일시스템 격리를 사용하는 태스크와 공유되지 않지만, chroot 또는 none 격리를 사용하는 태스크는 여전히 접근할 수 있어요.
namespace(string: "")
Enterprise
- 태스크에 사용할 Vault Namespace를 지정. Nomad 클라이언트는 이 특정 네임스페이스로 범위가 지정된 Vault 토큰을 가져와요.
role(string: "")- JWT와 워크로드 아이덴티티를 사용해 Vault에서 토큰을 가져올 때 사용하는 Vault 역할. 지정하지 않으면 클라이언트의create_from_role값이 사용돼요.
예시 (Examples)
다음 예시는 vault 블록만 보여줘요. vault 블록은 위에 나열된 배치에서만 유효하다는 점을 기억하세요.
토큰 가져오기 (Retrieve token)
이 예시는 Nomad 클라이언트에 Vault 토큰을 가져오라고 지시해요. 토큰은 표준 환경 변수 VAULT_TOKEN을 통해 태스크에 사용할 수 있고 secrets/vault_token에 디스크로 쓰여져요. 결과 토큰은 "prod" 역할의 Vault 정책을 갖게 돼요.
vault {
role = "prod"
}
태스크에 신호 보내기 (Signal task)
이 예시는 태스크를 재시작하는 대신 신호를 보내는 것을 보여줘요.
vault {
role = "prod"
change_mode = "signal"
change_signal = "SIGINT"
}
비공개 토큰과 변경 모드 (Private token and change modes)
이 예시는 Docker처럼 image 격리를 제공하는 드라이버를 사용할 때 태스크와 공유되지 않는 Vault 토큰을 가져와요.
이렇게 하면 Nomad가 태스크의 template 스탠자와 상호작용해 데이터베이스 시크릿, 다른 Vault 토큰 등 모든 종류의 시크릿을 발급하는 강력한 Vault 토큰을 사용하면서, 그 발급 권한을 태스크 자체와 공유하지 않을 수 있어요:
vault {
role = "prod"
change_mode = "noop"
env = false
disable_file = true
}
template {
data = <<-EOH
{{with secret "auth/token/create/nomad-job" "policies=examplepolicy"}}{{.Auth.ClientToken}}{{ end }}
EOH
destination = "${NOMAD_SECRETS_DIR}/examplepolicy.token"
change_mode = "noop"
perms = "600"
}
template {
data = <<-EOH
{{ with secret "pki_int/issue/nomad-task"
"common_name=example.service.consul" "ttl=72h"
"alt_names=localhost" "ip_sans=127.0.0.1"}}
{{ .Data.certificate }}
{{ .Data.private_key }}
{{ end }}
EOH
destination = "${NOMAD_SECRETS_DIR}/client.crt"
change_mode = "restart"
perms = "600"
}
위 예시는 examplepolicy.token의 template 스탠자에서 change_mode = "noop"를 사용해요. 이는 태스크의 워크로드가 해당 파일의 변경을 감지하고 처리할 책임이 있음을 의미해요. 반면 client.crt의 template 스탠자는 인증서가 재발급될 때마다 Nomad가 태스크를 재시작하도록 구성돼 있어요. change_mode = "restart"(change_mode의 기본값)로 표시돼요.
Vault 네임스페이스 (Vault namespace)
이 예시는 주어진 태스크에 특정 Vault 네임스페이스를 지정하는 것을 보여줘요.
Enterprise
이 기능은 Nomad Enterprise(새 탭에서 열림)가 필요해요.
vault {
role = "prod"
namespace = "engineering/frontend"
change_mode = "signal"
change_signal = "SIGINT"
}