Nomad poststop任务请求Vault token报错 密钥注入失败解决方法
报错Can't request Vault token for terminal allocation的触发逻辑很明确:Nomad 组级别配置的 Vault 令牌和分配(allocation)生命周期强绑定,当主任务退出、分配进入terminal终止状态后,关联的 Vault 令牌会被立即回收。poststop 生命周期钩子是在分配进入终止阶段后才启动,此时已经没有有效令牌可用于请求 Vault 密钥,自然渲染模板失败;主任务运行时分配处于活跃状态,所以可以正常拉取密钥。
优先用第一种方案,实现成本最低、兼容性最好:
方案1:主任务运行阶段提前渲染poststop所需密钥到共享目录
同任务组下的所有任务共享alloc/目录,你可以直接在主任务的template配置里,把poststop要用到的密钥提前渲染到alloc/路径下,poststop启动时直接读取本地文件即可,不需要再主动向Vault发起请求。
修改后的配置参考:
job "my-task" { group "my-task-group" { vault { policies = ["my-policy-name"] env = true } task "main-task" { service { name = "my-service" } driver = "docker" user = "root" config { image = "..." } template { data = <<EOF {% raw %}{{with secret "secrets/data/foo/bar/my-secret-this-works-fine"}}{{.Data.data.my_secret}}{{end}}{% endraw %} EOF destination = "local/works-fine.txt" } // 新增:提前渲染poststop需要的密钥到组共享目录 template { data = <<EOF {% raw %}{{with secret "secrets/data/foo/bar/my-secret-this-fails"}}{{.Data.data.my_secret_fails}}{{end}}{% endraw %} EOF destination = "alloc/poststop-secret.txt" perms = 600 // 严格控制密钥文件权限,仅所有者可读 } } task "task-that-fails" { lifecycle { hook = "poststop" sidecar = false } driver = "exec" // 删除原有的拉取Vault密钥的template块,直接在执行脚本中读取/alloc/poststop-secret.txt即可 config { command = "bash" args = ["..."] } } } }
说明:该方案拿到的是分配终止时刻的最新版本密钥,完全覆盖资源清理、状态上报等绝大多数poststop场景的需求。
方案2:poststop独立申请Vault访问凭证
如果poststop执行逻辑必须实时访问Vault获取最新数据,不要依赖Nomad自动注入的组级别令牌,可以提前给poststop准备独立的Vault认证凭证(比如AppRole凭证、固定TTL的短期令牌),存放到共享目录供poststop启动时自行认证获取有效令牌。这个方案需要自行维护凭证的签发和权限控制,复杂度更高,非必要不选。
注意:不要尝试给poststop任务单独配置vault块,分配进入terminal状态后Nomad不会为其签发新的Vault令牌,这种写法依然会报相同错误。
内容的提问来源于stack exchange,提问作者ThomasMX

