Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for providing Consul ACL Token via a file #1516

Merged
merged 3 commits into from
Jan 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ this functionality might prove useful.
- [Plugins](docs/plugins.md)
- [Caveats](#caveats)
- [Docker Image Use](#docker-image-use)
- [Dots in Service Names](#dots-in-service-names)
- [Dots in Service Names](#dots-in-service-names)
- [Termination on Error](#termination-on-error)
- [Commands](#commands)
- [Environment](#environment)
Expand Down Expand Up @@ -222,6 +222,7 @@ The current processes environment is used when executing commands with the follo

- `CONSUL_HTTP_ADDR`
- `CONSUL_HTTP_TOKEN`
- `CONSUL_HTTP_TOKEN_FILE`
- `CONSUL_HTTP_AUTH`
- `CONSUL_HTTP_SSL`
- `CONSUL_HTTP_SSL_VERIFY`
Expand All @@ -235,7 +236,7 @@ users the ability to further customize their command script.
#### Multiple Commands

The command configured for running on template rendering must take one of two
forms.
forms.

The first is as a single command without spaces in its name and no arguments.
This form of command will be called directly by consul-template and is good for
Expand Down
8 changes: 8 additions & 0 deletions cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,11 @@ func (cli *CLI) ParseFlags(args []string) (
return nil
}), "consul-token", "")

flags.Var((funcVar)(func(s string) error {
c.Consul.TokenFile = config.String(s)
return nil
}), "consul-token-file", "")

flags.Var((funcDurationVar)(func(d time.Duration) error {
c.Consul.Transport.DialKeepAlive = config.TimeDuration(d)
return nil
Expand Down Expand Up @@ -676,6 +681,9 @@ Options:
-consul-token=<token>
Sets the Consul API token

-consul-token-file=<path>
Sets the path to a file containing the Consul API token

-consul-transport-dial-keep-alive=<duration>
Sets the amount of time to use for keep-alives

Expand Down
10 changes: 10 additions & 0 deletions cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,16 @@ func TestCLI_ParseFlags(t *testing.T) {
},
false,
},
{
"consul-token-file",
[]string{"-consul-token-file", "/a/very/secret/path"},
&config.Config{
Consul: &config.ConsulConfig{
TokenFile: config.String("/a/very/secret/path"),
},
},
false,
},
{
"consul-transport-dial-keep-alive",
[]string{"-consul-transport-dial-keep-alive", "30s"},
Expand Down
17 changes: 17 additions & 0 deletions config/consul.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ type ConsulConfig struct {
// Token is the token to communicate with Consul securely.
Token *string

// TokenFile is the path to a token to communicate with Consul securely.
TokenFile *string `mapstructure:"token_file"`

// Transport configures the low-level network connection details.
Transport *TransportConfig `mapstructure:"transport"`
}
Expand Down Expand Up @@ -65,6 +68,7 @@ func (c *ConsulConfig) Copy() *ConsulConfig {
}

o.Token = c.Token
o.TokenFile = c.TokenFile

if c.Transport != nil {
o.Transport = c.Transport.Copy()
Expand Down Expand Up @@ -115,6 +119,10 @@ func (c *ConsulConfig) Merge(o *ConsulConfig) *ConsulConfig {
r.Token = o.Token
}

if o.TokenFile != nil {
r.TokenFile = o.TokenFile
}

if o.Transport != nil {
r.Transport = r.Transport.Merge(o.Transport)
}
Expand Down Expand Up @@ -156,6 +164,13 @@ func (c *ConsulConfig) Finalize() {
}, "")
}

if c.TokenFile == nil {
c.TokenFile = stringFromEnv([]string{
"CONSUL_TOKEN_FILE",
"CONSUL_HTTP_TOKEN_FILE",
}, "")
}

if c.Transport == nil {
c.Transport = DefaultTransportConfig()
}
Expand All @@ -175,6 +190,7 @@ func (c *ConsulConfig) GoString() string {
"Retry:%#v, "+
"SSL:%#v, "+
"Token:%t, "+
"TokenFile:%s, "+
"Transport:%#v"+
"}",
StringGoString(c.Address),
Expand All @@ -183,6 +199,7 @@ func (c *ConsulConfig) GoString() string {
c.Retry,
c.SSL,
StringPresent(c.Token),
StringGoString(c.TokenFile),
c.Transport,
)
}
28 changes: 27 additions & 1 deletion config/consul_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func TestConsulConfig_Copy(t *testing.T) {
Retry: &RetryConfig{Enabled: Bool(true)},
SSL: &SSLConfig{Enabled: Bool(true)},
Token: String("abcd1234"),
TokenFile: String("/a/very/secret/path"),
Transport: &TransportConfig{
DialKeepAlive: TimeDuration(20 * time.Second),
},
Expand Down Expand Up @@ -223,6 +224,30 @@ func TestConsulConfig_Merge(t *testing.T) {
&ConsulConfig{Token: String("same")},
&ConsulConfig{Token: String("same")},
},
{
"token_file_overrides",
&ConsulConfig{TokenFile: String("same")},
&ConsulConfig{TokenFile: String("different")},
&ConsulConfig{TokenFile: String("different")},
},
{
"token_file_empty_one",
&ConsulConfig{TokenFile: String("same")},
&ConsulConfig{},
&ConsulConfig{TokenFile: String("same")},
},
{
"token_file_empty_two",
&ConsulConfig{},
&ConsulConfig{TokenFile: String("same")},
&ConsulConfig{TokenFile: String("same")},
},
{
"token_file_same",
&ConsulConfig{TokenFile: String("same")},
&ConsulConfig{TokenFile: String("same")},
&ConsulConfig{TokenFile: String("same")},
},
{
"transport_overrides",
&ConsulConfig{Transport: &TransportConfig{DialKeepAlive: TimeDuration(10 * time.Second)}},
Expand Down Expand Up @@ -292,7 +317,8 @@ func TestConsulConfig_Finalize(t *testing.T) {
ServerName: String(""),
Verify: Bool(true),
},
Token: String(""),
Token: String(""),
TokenFile: String(""),
Transport: &TransportConfig{
DialKeepAlive: TimeDuration(DefaultDialKeepAlive),
DialTimeout: TimeDuration(DefaultDialTimeout),
Expand Down
5 changes: 5 additions & 0 deletions dependency/client_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type CreateConsulClientInput struct {
Address string
Namespace string
Token string
TokenFile string
AuthEnabled bool
AuthUsername string
AuthPassword string
Expand Down Expand Up @@ -104,6 +105,10 @@ func (c *ClientSet) CreateConsulClient(i *CreateConsulClientInput) error {
consulConfig.Token = i.Token
}

if i.TokenFile != "" {
consulConfig.TokenFile = i.TokenFile
}

if i.AuthEnabled {
consulConfig.HttpAuth = &consulapi.HttpBasicAuth{
Username: i.AuthUsername,
Expand Down
11 changes: 9 additions & 2 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,18 @@ consul {
# This is the ACL token to use when connecting to Consul. If you did not
# enable ACLs on your Consul cluster, you do not need to set this option.
#
# This option is also available via the environment variable CONSUL_TOKEN.
# This option is also available via the environment variable CONSUL_TOKEN or
# CONSUL_HTTP_TOKEN
# It is highly recommended that you do not put your token in plain-text in a
# configuration file.
token = ""

# Alternatively, you can specify a path to a file containing the token with
# this option.
# This option is also available via the environment variable CONSUL_TOKEN_FILE or
# CONSUL_HTTP_TOKEN_FILE
token_file = ""

# This controls the retry behavior when an error is returned from Consul.
# Consul Template is highly fault tolerant, meaning it does not exit in the
# face of failure. Instead, it uses exponential back-off and retry functions
Expand Down Expand Up @@ -347,7 +354,7 @@ vault {
# documentation for more information.
unwrap_token = true

# The default lease duration Consul Template will use on a Vault secret that
# The default lease duration Consul Template will use on a Vault secret that
# does not have a lease duration. This is used to calculate the sleep duration
# for rechecking a Vault secret value. This field is optional and will default to
# 5 minutes.
Expand Down
9 changes: 9 additions & 0 deletions manager/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,14 @@ func (r *Runner) childEnv() []string {
m["CONSUL_HTTP_AUTH"] = r.config.Consul.Auth.String()
}

if config.StringPresent(r.config.Consul.Token) {
m["CONSUL_HTTP_TOKEN"] = config.StringVal(r.config.Consul.Token)
}

if config.StringPresent(r.config.Consul.TokenFile) {
m["CONSUL_HTTP_TOKEN_FILE"] = config.StringVal(r.config.Consul.TokenFile)
}

m["CONSUL_HTTP_SSL"] = strconv.FormatBool(config.BoolVal(r.config.Consul.SSL.Enabled))
m["CONSUL_HTTP_SSL_VERIFY"] = strconv.FormatBool(config.BoolVal(r.config.Consul.SSL.Verify))

Expand Down Expand Up @@ -1251,6 +1259,7 @@ func newClientSet(c *config.Config) (*dep.ClientSet, error) {
Address: config.StringVal(c.Consul.Address),
Namespace: config.StringVal(c.Consul.Namespace),
Token: config.StringVal(c.Consul.Token),
TokenFile: config.StringVal(c.Consul.TokenFile),
AuthEnabled: config.BoolVal(c.Consul.Auth.Enabled),
AuthUsername: config.StringVal(c.Consul.Auth.Username),
AuthPassword: config.StringVal(c.Consul.Auth.Password),
Expand Down