agent: Add logic to validate env_template entries (#20569)
This commit is contained in:
parent
d12604eff2
commit
f3620b5b4f
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:improvement
|
||||||
|
agent: Add logic to validate env_template entries in configuration
|
||||||
|
```
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"github.com/hashicorp/hcl"
|
"github.com/hashicorp/hcl"
|
||||||
"github.com/hashicorp/hcl/hcl/ast"
|
"github.com/hashicorp/hcl/hcl/ast"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
|
"k8s.io/utils/strings/slices"
|
||||||
|
|
||||||
"github.com/hashicorp/vault/command/agentproxyshared"
|
"github.com/hashicorp/vault/command/agentproxyshared"
|
||||||
"github.com/hashicorp/vault/helper/namespace"
|
"github.com/hashicorp/vault/helper/namespace"
|
||||||
|
@ -342,7 +343,8 @@ func (c *Config) ValidateConfig() error {
|
||||||
if c.AutoAuth != nil {
|
if c.AutoAuth != nil {
|
||||||
if len(c.AutoAuth.Sinks) == 0 &&
|
if len(c.AutoAuth.Sinks) == 0 &&
|
||||||
(c.APIProxy == nil || !c.APIProxy.UseAutoAuthToken) &&
|
(c.APIProxy == nil || !c.APIProxy.UseAutoAuthToken) &&
|
||||||
len(c.Templates) == 0 {
|
len(c.Templates) == 0 &&
|
||||||
|
len(c.EnvTemplates) == 0 {
|
||||||
return fmt.Errorf("auto_auth requires at least one sink or at least one template or api_proxy.use_auto_auth_token=true")
|
return fmt.Errorf("auto_auth requires at least one sink or at least one template or api_proxy.use_auto_auth_token=true")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -351,6 +353,126 @@ func (c *Config) ValidateConfig() error {
|
||||||
return fmt.Errorf("no auto_auth, cache, or listener block found in config")
|
return fmt.Errorf("no auto_auth, cache, or listener block found in config")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return c.validateEnvTemplateConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) validateEnvTemplateConfig() error {
|
||||||
|
// if we are not in env-template mode, exit early
|
||||||
|
if c.Exec == nil && len(c.EnvTemplates) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Exec == nil {
|
||||||
|
return fmt.Errorf("a top-level 'exec' element must be specified with 'env_template' entries")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.EnvTemplates) == 0 {
|
||||||
|
return fmt.Errorf("must specify at least one 'env_template' element with a top-level 'exec' element")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.APIProxy != nil {
|
||||||
|
return fmt.Errorf("'api_proxy' cannot be specified with 'env_template' entries")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.Templates) > 0 {
|
||||||
|
return fmt.Errorf("'template' cannot be specified with 'env_template' entries")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.Exec.Command) == 0 {
|
||||||
|
return fmt.Errorf("'exec' requires a non-empty 'command' field")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !slices.Contains([]string{"always", "never"}, c.Exec.RestartOnSecretChanges) {
|
||||||
|
return fmt.Errorf("'exec.restart_on_secret_changes' unexpected value: %q", c.Exec.RestartOnSecretChanges)
|
||||||
|
}
|
||||||
|
|
||||||
|
uniqueKeys := make(map[string]struct{})
|
||||||
|
|
||||||
|
for _, template := range c.EnvTemplates {
|
||||||
|
// Required:
|
||||||
|
// - the key (environment variable name)
|
||||||
|
// - either "contents" or "source"
|
||||||
|
// Optional / permitted:
|
||||||
|
// - error_on_missing_key
|
||||||
|
// - error_fatal
|
||||||
|
// - left_delimiter
|
||||||
|
// - right_delimiter
|
||||||
|
// - ExtFuncMap
|
||||||
|
// - function_denylist / function_blacklist
|
||||||
|
|
||||||
|
if template.MapToEnvironmentVariable == nil {
|
||||||
|
return fmt.Errorf("env_template: an environment variable name is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
key := *template.MapToEnvironmentVariable
|
||||||
|
|
||||||
|
if _, exists := uniqueKeys[key]; exists {
|
||||||
|
return fmt.Errorf("env_template: duplicate environment variable name: %q", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
uniqueKeys[key] = struct{}{}
|
||||||
|
|
||||||
|
if template.Contents == nil && template.Source == nil {
|
||||||
|
return fmt.Errorf("env_template[%s]: either 'contents' or 'source' must be specified", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if template.Contents != nil && template.Source != nil {
|
||||||
|
return fmt.Errorf("env_template[%s]: 'contents' and 'source' cannot be specified together", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if template.Backup != nil {
|
||||||
|
return fmt.Errorf("env_template[%s]: 'backup' is not allowed", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if template.Command != nil {
|
||||||
|
return fmt.Errorf("env_template[%s]: 'command' is not allowed", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if template.CommandTimeout != nil {
|
||||||
|
return fmt.Errorf("env_template[%s]: 'command_timeout' is not allowed", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if template.CreateDestDirs != nil {
|
||||||
|
return fmt.Errorf("env_template[%s]: 'create_dest_dirs' is not allowed", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if template.Destination != nil {
|
||||||
|
return fmt.Errorf("env_template[%s]: 'destination' is not allowed", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if template.Exec != nil {
|
||||||
|
return fmt.Errorf("env_template[%s]: 'exec' is not allowed", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if template.Perms != nil {
|
||||||
|
return fmt.Errorf("env_template[%s]: 'perms' is not allowed", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if template.User != nil {
|
||||||
|
return fmt.Errorf("env_template[%s]: 'user' is not allowed", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if template.Uid != nil {
|
||||||
|
return fmt.Errorf("env_template[%s]: 'uid' is not allowed", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if template.Group != nil {
|
||||||
|
return fmt.Errorf("env_template[%s]: 'group' is not allowed", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if template.Gid != nil {
|
||||||
|
return fmt.Errorf("env_template[%s]: 'gid' is not allowed", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if template.Wait != nil {
|
||||||
|
return fmt.Errorf("env_template[%s]: 'wait' is not allowed", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if template.SandboxPath != nil {
|
||||||
|
return fmt.Errorf("env_template[%s]: 'sandbox_path' is not allowed", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2112,13 +2112,17 @@ func TestLoadConfigFile_Bad_Value_Disable_Keep_Alives(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestLoadConfigFile_EnvTemplates loads and validates an env_template config
|
// TestLoadConfigFile_EnvTemplates_Simple loads and validates an env_template config
|
||||||
func TestLoadConfigFile_EnvTemplates(t *testing.T) {
|
func TestLoadConfigFile_EnvTemplates_Simple(t *testing.T) {
|
||||||
cfg, err := LoadConfigFile("./test-fixtures/config-env-templates-simple.hcl")
|
cfg, err := LoadConfigFile("./test-fixtures/config-env-templates-simple.hcl")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error loading config file: %s", err)
|
t.Fatalf("error loading config file: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := cfg.ValidateConfig(); err != nil {
|
||||||
|
t.Fatalf("validation error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
expectedKey := "MY_DATABASE_USER"
|
expectedKey := "MY_DATABASE_USER"
|
||||||
found := false
|
found := false
|
||||||
for _, envTemplate := range cfg.EnvTemplates {
|
for _, envTemplate := range cfg.EnvTemplates {
|
||||||
|
@ -2131,16 +2135,20 @@ func TestLoadConfigFile_EnvTemplates(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestLoadConfigFile_EnvTemplateComplex loads and validates an env_template config
|
// TestLoadConfigFile_EnvTemplates_Complex loads and validates an env_template config
|
||||||
func TestLoadConfigFile_EnvTemplateComplex(t *testing.T) {
|
func TestLoadConfigFile_EnvTemplates_Complex(t *testing.T) {
|
||||||
cfg, err := LoadConfigFile("./test-fixtures/config-env-templates-complex.hcl")
|
cfg, err := LoadConfigFile("./test-fixtures/config-env-templates-complex.hcl")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error loading config file: %s", err)
|
t.Fatalf("error loading config file: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := cfg.ValidateConfig(); err != nil {
|
||||||
|
t.Fatalf("validation error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
expectedKeys := []string{
|
expectedKeys := []string{
|
||||||
"FOO_DATA_LOCK",
|
"FOO_PASSWORD",
|
||||||
"FOO_DATA_PASSWORD",
|
"FOO_USER",
|
||||||
"FOO_DATA_USER",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
envExists := func(key string) bool {
|
envExists := func(key string) bool {
|
||||||
|
@ -2159,31 +2167,44 @@ func TestLoadConfigFile_EnvTemplateComplex(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestLoadConfigFile_EnvTemplateNoName ensures that env_template with no name triggers an error
|
// TestLoadConfigFile_EnvTemplates_WithSource loads and validates an
|
||||||
func TestLoadConfigFile_EnvTemplateNoName(t *testing.T) {
|
// env_template config with "source" instead of "contents"
|
||||||
|
func TestLoadConfigFile_EnvTemplates_WithSource(t *testing.T) {
|
||||||
|
cfg, err := LoadConfigFile("./test-fixtures/config-env-templates-with-source.hcl")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error loading config file: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cfg.ValidateConfig(); err != nil {
|
||||||
|
t.Fatalf("validation error: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestLoadConfigFile_EnvTemplates_NoName ensures that env_template with no name triggers an error
|
||||||
|
func TestLoadConfigFile_EnvTemplates_NoName(t *testing.T) {
|
||||||
_, err := LoadConfigFile("./test-fixtures/bad-config-env-templates-no-name.hcl")
|
_, err := LoadConfigFile("./test-fixtures/bad-config-env-templates-no-name.hcl")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("expected error")
|
t.Fatalf("expected error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestLoadConfigFile_ExecInvalidSignal ensures that an invalid signal triggers an error
|
// TestLoadConfigFile_EnvTemplates_ExecInvalidSignal ensures that an invalid signal triggers an error
|
||||||
func TestLoadConfigFile_ExecInvalidSignal(t *testing.T) {
|
func TestLoadConfigFile_EnvTemplates_ExecInvalidSignal(t *testing.T) {
|
||||||
_, err := LoadConfigFile("./test-fixtures/bad-config-env-templates-invalid-signal.hcl")
|
_, err := LoadConfigFile("./test-fixtures/bad-config-env-templates-invalid-signal.hcl")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("expected error")
|
t.Fatalf("expected error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestLoadConfigFile_ExecSimple validates the exec section with default parameters
|
// TestLoadConfigFile_EnvTemplates_ExecSimple validates the exec section with default parameters
|
||||||
func TestLoadConfigFile_ExecSimple(t *testing.T) {
|
func TestLoadConfigFile_EnvTemplates_ExecSimple(t *testing.T) {
|
||||||
cfg, err := LoadConfigFile("./test-fixtures/config-env-templates-simple.hcl")
|
cfg, err := LoadConfigFile("./test-fixtures/config-env-templates-simple.hcl")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error loading config file: %s", err)
|
t.Fatalf("error loading config file: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Exec == nil {
|
if err := cfg.ValidateConfig(); err != nil {
|
||||||
t.Fatal("expected exec config to be parsed")
|
t.Fatalf("validation error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedCmd := []string{"/path/to/my/app", "arg1", "arg2"}
|
expectedCmd := []string{"/path/to/my/app", "arg1", "arg2"}
|
||||||
|
@ -2201,13 +2222,17 @@ func TestLoadConfigFile_ExecSimple(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestLoadConfigFile_ExecComplex validates the exec section with non-default parameters
|
// TestLoadConfigFile_EnvTemplates_ExecComplex validates the exec section with non-default parameters
|
||||||
func TestLoadConfigFile_ExecComplex(t *testing.T) {
|
func TestLoadConfigFile_EnvTemplates_ExecComplex(t *testing.T) {
|
||||||
cfg, err := LoadConfigFile("./test-fixtures/config-env-templates-complex.hcl")
|
cfg, err := LoadConfigFile("./test-fixtures/config-env-templates-complex.hcl")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error loading config file: %s", err)
|
t.Fatalf("error loading config file: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := cfg.ValidateConfig(); err != nil {
|
||||||
|
t.Fatalf("validation error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
if !slices.Equal(cfg.Exec.Command, []string{"env"}) {
|
if !slices.Equal(cfg.Exec.Command, []string{"env"}) {
|
||||||
t.Fatal("exec.command does not have expected value")
|
t.Fatal("exec.command does not have expected value")
|
||||||
}
|
}
|
||||||
|
@ -2220,3 +2245,55 @@ func TestLoadConfigFile_ExecComplex(t *testing.T) {
|
||||||
t.Fatalf("expected cfg.Exec.RestartStopSignal to be 'syscall.SIGINT', got %q", cfg.Exec.RestartStopSignal)
|
t.Fatalf("expected cfg.Exec.RestartStopSignal to be 'syscall.SIGINT', got %q", cfg.Exec.RestartStopSignal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestLoadConfigFile_Bad_EnvTemplates_MissingExec ensures that ValidateConfig
|
||||||
|
// errors when "env_template" stanza(s) are specified but "exec" is missing
|
||||||
|
func TestLoadConfigFile_Bad_EnvTemplates_MissingExec(t *testing.T) {
|
||||||
|
config, err := LoadConfigFile("./test-fixtures/bad-config-env-templates-missing-exec.hcl")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error loading config file: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := config.ValidateConfig(); err == nil {
|
||||||
|
t.Fatal("expected an error from ValidateConfig: exec section is missing")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestLoadConfigFile_Bad_EnvTemplates_WithProxy ensures that ValidateConfig
|
||||||
|
// errors when both env_template and api_proxy stanzas are present
|
||||||
|
func TestLoadConfigFile_Bad_EnvTemplates_WithProxy(t *testing.T) {
|
||||||
|
config, err := LoadConfigFile("./test-fixtures/bad-config-env-templates-with-proxy.hcl")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error loading config file: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := config.ValidateConfig(); err == nil {
|
||||||
|
t.Fatal("expected an error from ValidateConfig: listener / api_proxy are not compatible with env_template")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestLoadConfigFile_Bad_EnvTemplates_WithFileTemplates ensures that
|
||||||
|
// ValidateConfig errors when both env_template and template stanzas are present
|
||||||
|
func TestLoadConfigFile_Bad_EnvTemplates_WithFileTemplates(t *testing.T) {
|
||||||
|
config, err := LoadConfigFile("./test-fixtures/bad-config-env-templates-with-file-templates.hcl")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error loading config file: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := config.ValidateConfig(); err == nil {
|
||||||
|
t.Fatal("expected an error from ValidateConfig: file template stanza is not compatible with env_template")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestLoadConfigFile_Bad_EnvTemplates_DisalowedFields ensure that
|
||||||
|
// ValidateConfig errors for disalowed env_template fields
|
||||||
|
func TestLoadConfigFile_Bad_EnvTemplates_DisalowedFields(t *testing.T) {
|
||||||
|
config, err := LoadConfigFile("./test-fixtures/bad-config-env-templates-disalowed-fields.hcl")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error loading config file: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := config.ValidateConfig(); err == nil {
|
||||||
|
t.Fatal("expected an error from ValidateConfig: disallowed fields specified in env_template")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
auto_auth {
|
||||||
|
|
||||||
|
method {
|
||||||
|
type = "token_file"
|
||||||
|
|
||||||
|
config {
|
||||||
|
token_file_path = "/Users/avean/.vault-token"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template_config {
|
||||||
|
static_secret_render_interval = "5m"
|
||||||
|
exit_on_retry_failure = true
|
||||||
|
}
|
||||||
|
|
||||||
|
vault {
|
||||||
|
address = "http://localhost:8200"
|
||||||
|
}
|
||||||
|
|
||||||
|
env_template "FOO_PASSWORD" {
|
||||||
|
contents = "{{ with secret \"secret/data/foo\" }}{{ .Data.data.password }}{{ end }}"
|
||||||
|
|
||||||
|
# Error: destination and create_dest_dirs are not allowed in env_template
|
||||||
|
destination = "/path/on/disk/where/template/will/render.txt"
|
||||||
|
create_dest_dirs = true
|
||||||
|
}
|
||||||
|
|
||||||
|
exec {
|
||||||
|
command = ["./my-app", "arg1", "arg2"]
|
||||||
|
restart_on_secret_changes = "always"
|
||||||
|
restart_stop_signal = "SIGTERM"
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
auto_auth {
|
||||||
|
|
||||||
|
method {
|
||||||
|
type = "token_file"
|
||||||
|
|
||||||
|
config {
|
||||||
|
token_file_path = "/Users/avean/.vault-token"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template_config {
|
||||||
|
static_secret_render_interval = "5m"
|
||||||
|
exit_on_retry_failure = true
|
||||||
|
}
|
||||||
|
|
||||||
|
vault {
|
||||||
|
address = "http://localhost:8200"
|
||||||
|
}
|
||||||
|
|
||||||
|
env_template "FOO_PASSWORD" {
|
||||||
|
contents = "{{ with secret \"secret/data/foo\" }}{{ .Data.data.password }}{{ end }}"
|
||||||
|
error_on_missing_key = false
|
||||||
|
}
|
||||||
|
env_template "FOO_USER" {
|
||||||
|
contents = "{{ with secret \"secret/data/foo\" }}{{ .Data.data.user }}{{ end }}"
|
||||||
|
error_on_missing_key = false
|
||||||
|
}
|
||||||
|
|
||||||
|
# Error: missing a required "exec" section!
|
|
@ -0,0 +1,40 @@
|
||||||
|
auto_auth {
|
||||||
|
|
||||||
|
method {
|
||||||
|
type = "token_file"
|
||||||
|
|
||||||
|
config {
|
||||||
|
token_file_path = "/Users/avean/.vault-token"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template_config {
|
||||||
|
static_secret_render_interval = "5m"
|
||||||
|
exit_on_retry_failure = true
|
||||||
|
}
|
||||||
|
|
||||||
|
vault {
|
||||||
|
address = "http://localhost:8200"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Error: template is incompatible with env_template!
|
||||||
|
template {
|
||||||
|
source = "/path/on/disk/to/template.ctmpl"
|
||||||
|
destination = "/path/on/disk/where/template/will/render.txt"
|
||||||
|
}
|
||||||
|
|
||||||
|
env_template "FOO_PASSWORD" {
|
||||||
|
contents = "{{ with secret \"secret/data/foo\" }}{{ .Data.data.password }}{{ end }}"
|
||||||
|
error_on_missing_key = false
|
||||||
|
}
|
||||||
|
env_template "FOO_USER" {
|
||||||
|
contents = "{{ with secret \"secret/data/foo\" }}{{ .Data.data.user }}{{ end }}"
|
||||||
|
error_on_missing_key = false
|
||||||
|
}
|
||||||
|
|
||||||
|
exec {
|
||||||
|
command = ["./my-app", "arg1", "arg2"]
|
||||||
|
restart_on_secret_changes = "always"
|
||||||
|
restart_stop_signal = "SIGTERM"
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
auto_auth {
|
||||||
|
|
||||||
|
method {
|
||||||
|
type = "token_file"
|
||||||
|
|
||||||
|
config {
|
||||||
|
token_file_path = "/Users/avean/.vault-token"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template_config {
|
||||||
|
static_secret_render_interval = "5m"
|
||||||
|
exit_on_retry_failure = true
|
||||||
|
}
|
||||||
|
|
||||||
|
vault {
|
||||||
|
address = "http://localhost:8200"
|
||||||
|
}
|
||||||
|
|
||||||
|
env_template "FOO_PASSWORD" {
|
||||||
|
contents = "{{ with secret \"secret/data/foo\" }}{{ .Data.data.password }}{{ end }}"
|
||||||
|
error_on_missing_key = false
|
||||||
|
}
|
||||||
|
env_template "FOO_USER" {
|
||||||
|
contents = "{{ with secret \"secret/data/foo\" }}{{ .Data.data.user }}{{ end }}"
|
||||||
|
error_on_missing_key = false
|
||||||
|
}
|
||||||
|
|
||||||
|
exec {
|
||||||
|
command = ["./my-app", "arg1", "arg2"]
|
||||||
|
restart_on_secret_changes = "always"
|
||||||
|
restart_stop_signal = "SIGTERM"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Error: api_proxy is incompatible with env_template
|
||||||
|
api_proxy {
|
||||||
|
use_auto_auth_token = "force"
|
||||||
|
enforce_consistency = "always"
|
||||||
|
when_inconsistent = "forward"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Error: listener is incompatible with env_template
|
||||||
|
listener "tcp" {
|
||||||
|
address = "127.0.0.1:8300"
|
||||||
|
tls_disable = true
|
||||||
|
}
|
|
@ -9,19 +9,20 @@ auto_auth {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template_config {
|
||||||
|
static_secret_render_interval = "5m"
|
||||||
|
exit_on_retry_failure = true
|
||||||
|
}
|
||||||
|
|
||||||
vault {
|
vault {
|
||||||
address = "http://localhost:8200"
|
address = "http://localhost:8200"
|
||||||
}
|
}
|
||||||
|
|
||||||
env_template "FOO_DATA_LOCK" {
|
env_template "FOO_PASSWORD" {
|
||||||
contents = "{{ with secret \"secret/data/foo\" }}{{ .Data.data.lock }}{{ end }}"
|
|
||||||
error_on_missing_key = false
|
|
||||||
}
|
|
||||||
env_template "FOO_DATA_PASSWORD" {
|
|
||||||
contents = "{{ with secret \"secret/data/foo\" }}{{ .Data.data.password }}{{ end }}"
|
contents = "{{ with secret \"secret/data/foo\" }}{{ .Data.data.password }}{{ end }}"
|
||||||
error_on_missing_key = false
|
error_on_missing_key = false
|
||||||
}
|
}
|
||||||
env_template "FOO_DATA_USER" {
|
env_template "FOO_USER" {
|
||||||
contents = "{{ with secret \"secret/data/foo\" }}{{ .Data.data.user }}{{ end }}"
|
contents = "{{ with secret \"secret/data/foo\" }}{{ .Data.data.user }}{{ end }}"
|
||||||
error_on_missing_key = false
|
error_on_missing_key = false
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,14 @@
|
||||||
|
auto_auth {
|
||||||
|
|
||||||
|
method {
|
||||||
|
type = "token_file"
|
||||||
|
|
||||||
|
config {
|
||||||
|
token_file_path = "/Users/avean/.vault-token"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
env_template "MY_DATABASE_USER" {
|
env_template "MY_DATABASE_USER" {
|
||||||
contents = "{{ with secret \"secret/db-secret\" }}{{ .Data.data.user }}{{ end }}"
|
contents = "{{ with secret \"secret/db-secret\" }}{{ .Data.data.user }}{{ end }}"
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
auto_auth {
|
||||||
|
method {
|
||||||
|
type = "token_file"
|
||||||
|
config {
|
||||||
|
token_file_path = "/home/username/.vault-token"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
env_template "MY_PASSWORD" {
|
||||||
|
source = "/path/on/disk/to/template.ctmpl"
|
||||||
|
}
|
||||||
|
|
||||||
|
exec {
|
||||||
|
command = ["/path/to/my/app", "arg1", "arg2"]
|
||||||
|
}
|
Loading…
Reference in New Issue