From 4f923f14b9e554dbc79ba964adba5dfb23802b5b Mon Sep 17 00:00:00 2001 From: Alex Dadgar Date: Wed, 23 Mar 2016 11:45:03 -0700 Subject: [PATCH 1/2] Pass environment variables from host to exec based tasks --- client/config/config.go | 12 ++++++++++++ client/driver/env/env.go | 24 ++++++++++++++++++++++++ client/driver/env/env_test.go | 21 +++++++++++++++++++++ client/driver/exec.go | 8 +++++++- client/driver/java.go | 5 +++++ client/driver/raw_exec.go | 5 +++++ website/source/docs/agent/config.html.md | 11 +++++++++++ 7 files changed, 85 insertions(+), 1 deletion(-) diff --git a/client/config/config.go b/client/config/config.go index ac0968eff1f..702d9a5e28d 100644 --- a/client/config/config.go +++ b/client/config/config.go @@ -10,6 +10,18 @@ import ( "github.com/hashicorp/nomad/nomad/structs" ) +var ( + // DefaultEnvBlacklist is the default set of environment variables that are + // filtered when passing the environment variables of the host to a task. + DefaultEnvBlacklist = strings.Join([]string{ + "CONSUL_TOKEN", + "VAULT_TOKEN", + "ATLAS_TOKEN", + "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN", + "GOOGLE_APPLICATION_CREDENTIALS", + }, ",") +) + // RPCHandler can be provided to the Client if there is a local server // to avoid going over the network. If not provided, the Client will // maintain a connection pool to the servers diff --git a/client/driver/env/env.go b/client/driver/env/env.go index 447836ec19c..ece460043ee 100644 --- a/client/driver/env/env.go +++ b/client/driver/env/env.go @@ -2,6 +2,7 @@ package env import ( "fmt" + "os" "strconv" "strings" @@ -305,6 +306,29 @@ func (t *TaskEnvironment) AppendEnvvars(m map[string]string) *TaskEnvironment { return t } +func (t *TaskEnvironment) AppendHostEnvvars(filter []string) *TaskEnvironment { + hostEnv := os.Environ() + if t.Env == nil { + t.Env = make(map[string]string, len(hostEnv)) + } + + // Index the filtered environment variables. + index := make(map[string]struct{}, len(filter)) + for _, f := range filter { + index[f] = struct{}{} + } + + for _, e := range hostEnv { + parts := strings.Split(e, "=") + key, value := parts[0], parts[1] + if _, filtered := index[key]; !filtered { + t.Env[key] = value + } + } + + return t +} + func (t *TaskEnvironment) ClearEnvvars() *TaskEnvironment { t.Env = nil return t diff --git a/client/driver/env/env_test.go b/client/driver/env/env_test.go index de2d6805d89..f2dcbccfa54 100644 --- a/client/driver/env/env_test.go +++ b/client/driver/env/env_test.go @@ -2,8 +2,10 @@ package env import ( "fmt" + "os" "reflect" "sort" + "strings" "testing" "github.com/hashicorp/nomad/nomad/mock" @@ -204,3 +206,22 @@ func TestEnvironment_Interprolate(t *testing.T) { t.Fatalf("env.List() returned %v; want %v", act, exp) } } + +func TestEnvironment_AppendHostEnvVars(t *testing.T) { + host := os.Environ() + if len(host) < 2 { + t.Skip("No host environment variables. Can't test") + } + skip := strings.Split(host[0], "=")[0] + env := testTaskEnvironment(). + AppendHostEnvvars([]string{skip}). + Build() + + act := env.EnvMap() + if len(act) < 1 { + t.Fatalf("Host environment variables not properly set") + } + if _, ok := act[skip]; ok { + t.Fatalf("Didn't filter environment variable %q", skip) + } +} diff --git a/client/driver/exec.go b/client/driver/exec.go index 672f0e96cb0..2e898b8f195 100644 --- a/client/driver/exec.go +++ b/client/driver/exec.go @@ -6,6 +6,7 @@ import ( "log" "os/exec" "path/filepath" + "strings" "syscall" "time" @@ -74,13 +75,18 @@ func (d *ExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, if err := mapstructure.WeakDecode(task.Config, &driverConfig); err != nil { return nil, err } + // Get the command to be ran command := driverConfig.Command if err := validateCommand(command, "args"); err != nil { return nil, err } - // Create a location to download the artifact. + // Set the host environment variables. + filter := strings.Split(d.config.ReadDefault("env.blacklist", config.DefaultEnvBlacklist), ",") + d.taskEnv.AppendHostEnvvars(filter) + + // Get the task directory for storing the executor logs. taskDir, ok := ctx.AllocDir.TaskDirs[d.DriverContext.taskName] if !ok { return nil, fmt.Errorf("Could not find task directory for task: %v", d.DriverContext.taskName) diff --git a/client/driver/java.go b/client/driver/java.go index d4863df57c9..eaa2a01d5bd 100644 --- a/client/driver/java.go +++ b/client/driver/java.go @@ -117,6 +117,11 @@ func (d *JavaDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, if err := mapstructure.WeakDecode(task.Config, &driverConfig); err != nil { return nil, err } + + // Set the host environment variables. + filter := strings.Split(d.config.ReadDefault("env.blacklist", config.DefaultEnvBlacklist), ",") + d.taskEnv.AppendHostEnvvars(filter) + taskDir, ok := ctx.AllocDir.TaskDirs[d.DriverContext.taskName] if !ok { return nil, fmt.Errorf("Could not find task directory for task: %v", d.DriverContext.taskName) diff --git a/client/driver/raw_exec.go b/client/driver/raw_exec.go index 2dc0aceebbd..4143cb4dfc7 100644 --- a/client/driver/raw_exec.go +++ b/client/driver/raw_exec.go @@ -6,6 +6,7 @@ import ( "log" "os/exec" "path/filepath" + "strings" "time" "github.com/hashicorp/go-plugin" @@ -82,6 +83,10 @@ func (d *RawExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandl return nil, err } + // Set the host environment variables. + filter := strings.Split(d.config.ReadDefault("env.blacklist", config.DefaultEnvBlacklist), ",") + d.taskEnv.AppendHostEnvvars(filter) + bin, err := discover.NomadExecutable() if err != nil { return nil, fmt.Errorf("unable to find the nomad binary: %v", err) diff --git a/website/source/docs/agent/config.html.md b/website/source/docs/agent/config.html.md index 2590defe0fe..9ceed03fe95 100644 --- a/website/source/docs/agent/config.html.md +++ b/website/source/docs/agent/config.html.md @@ -370,6 +370,17 @@ documentation [here](/docs/drivers/index.html) If the whitelist is empty, all drivers are fingerprinted and enabled where applicable. +* `env.blacklist`: Nomad passes the host environment variables to `exec`, + `raw_exec` and `java` tasks. `env.blacklist` is a comma seperated list of + environment variable keys not to pass to these tasks. If specified, the + defaults are overriden. The following are the default: + + * `CONSUL_TOKEN` + * `VAULT_TOKEN` + * `ATLAS_TOKEN` + * `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN` + * `GOOGLE_APPLICATION_CREDENTIALS` + * `fingerprint.whitelist`: A comma separated list of whitelisted fingerprinters. If specified, fingerprinters not in the whitelist will be disabled. If the whitelist is empty, all fingerprinters are used. From 5352bab6dcc1c833fdc6f0ec334cd589104036c0 Mon Sep 17 00:00:00 2001 From: Alex Dadgar Date: Wed, 23 Mar 2016 14:07:12 -0700 Subject: [PATCH 2/2] Comment and don't override --- client/driver/env/env.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/client/driver/env/env.go b/client/driver/env/env.go index ece460043ee..c59cb2f87bd 100644 --- a/client/driver/env/env.go +++ b/client/driver/env/env.go @@ -306,6 +306,9 @@ func (t *TaskEnvironment) AppendEnvvars(m map[string]string) *TaskEnvironment { return t } +// AppendHostEnvvars adds the host environment variables to the tasks. The +// filter parameter can be use to filter host environment from entering the +// tasks. func (t *TaskEnvironment) AppendHostEnvvars(filter []string) *TaskEnvironment { hostEnv := os.Environ() if t.Env == nil { @@ -321,7 +324,14 @@ func (t *TaskEnvironment) AppendHostEnvvars(filter []string) *TaskEnvironment { for _, e := range hostEnv { parts := strings.Split(e, "=") key, value := parts[0], parts[1] - if _, filtered := index[key]; !filtered { + + // Skip filtered environment variables + if _, filtered := index[key]; filtered { + continue + } + + // Don't override the tasks environment variables. + if _, existing := t.Env[key]; !existing { t.Env[key] = value } }