1package config 2 3import ( 4 "fmt" 5 "time" 6 7 "github.com/hashicorp/vault/api" 8) 9 10const ( 11 // XXX Change use to api.EnvVaultSkipVerify once we've updated vendored 12 // vault to version 1.1.0 or newer. 13 EnvVaultSkipVerify = "VAULT_SKIP_VERIFY" 14 15 // DefaultVaultGrace is the default grace period before which to read a new 16 // secret from Vault. If a lease is due to expire in 15 seconds, Consul 17 // Template will read a new secret at that time minus this value. 18 DefaultVaultGrace = 15 * time.Second 19 20 // DefaultVaultRenewToken is the default value for if the Vault token should 21 // be renewed. 22 DefaultVaultRenewToken = true 23 24 // DefaultVaultUnwrapToken is the default value for if the Vault token should 25 // be unwrapped. 26 DefaultVaultUnwrapToken = false 27 28 // DefaultVaultRetryBase is the default value for the base time to use for 29 // exponential backoff. 30 DefaultVaultRetryBase = 250 * time.Millisecond 31 32 // DefaultVaultRetryMaxAttempts is the default maximum number of attempts to 33 // retry before quitting. 34 DefaultVaultRetryMaxAttempts = 5 35) 36 37// VaultConfig is the configuration for connecting to a vault server. 38type VaultConfig struct { 39 // Address is the URI to the Vault server. 40 Address *string `mapstructure:"address"` 41 42 // Enabled controls whether the Vault integration is active. 43 Enabled *bool `mapstructure:"enabled"` 44 45 // Grace is the amount of time before a lease is about to expire to force a 46 // new secret to be read. 47 Grace *time.Duration `mapstructure:"grace"` 48 49 // Namespace is the Vault namespace to use for reading/writing secrets. This can 50 // also be set via the VAULT_NAMESPACE environment variable. 51 Namespace *string `mapstructure:"namespace"` 52 53 // RenewToken renews the Vault token. 54 RenewToken *bool `mapstructure:"renew_token"` 55 56 // Retry is the configuration for specifying how to behave on failure. 57 Retry *RetryConfig `mapstructure:"retry"` 58 59 // SSL indicates we should use a secure connection while talking to Vault. 60 SSL *SSLConfig `mapstructure:"ssl"` 61 62 // Token is the Vault token to communicate with for requests. It may be 63 // a wrapped token or a real token. This can also be set via the VAULT_TOKEN 64 // environment variable, or via the VaultAgentTokenFile. 65 Token *string `mapstructure:"token" json:"-"` 66 67 // VaultAgentTokenFile is the path of file that contains a Vault Agent token. 68 // If vault_agent_token_file is specified: 69 // - Consul Template will not try to renew the Vault token. 70 // - Consul Template will periodically stat the file and update the token if it has 71 // changed. 72 VaultAgentTokenFile *string `mapstructure:"vault_agent_token_file" json:"-"` 73 74 // Transport configures the low-level network connection details. 75 Transport *TransportConfig `mapstructure:"transport"` 76 77 // UnwrapToken unwraps the provided Vault token as a wrapped token. 78 UnwrapToken *bool `mapstructure:"unwrap_token"` 79} 80 81// DefaultVaultConfig returns a configuration that is populated with the 82// default values. 83func DefaultVaultConfig() *VaultConfig { 84 v := &VaultConfig{ 85 Retry: DefaultRetryConfig(), 86 SSL: DefaultSSLConfig(), 87 Transport: DefaultTransportConfig(), 88 } 89 90 // Force SSL when communicating with Vault. 91 v.SSL.Enabled = Bool(true) 92 93 return v 94} 95 96// Copy returns a deep copy of this configuration. 97func (c *VaultConfig) Copy() *VaultConfig { 98 if c == nil { 99 return nil 100 } 101 102 var o VaultConfig 103 o.Address = c.Address 104 105 o.Enabled = c.Enabled 106 107 o.Grace = c.Grace 108 109 o.Namespace = c.Namespace 110 111 o.RenewToken = c.RenewToken 112 113 if c.Retry != nil { 114 o.Retry = c.Retry.Copy() 115 } 116 117 if c.SSL != nil { 118 o.SSL = c.SSL.Copy() 119 } 120 121 o.Token = c.Token 122 123 o.VaultAgentTokenFile = c.VaultAgentTokenFile 124 125 if c.Transport != nil { 126 o.Transport = c.Transport.Copy() 127 } 128 129 o.UnwrapToken = c.UnwrapToken 130 131 return &o 132} 133 134// Merge combines all values in this configuration with the values in the other 135// configuration, with values in the other configuration taking precedence. 136// Maps and slices are merged, most other values are overwritten. Complex 137// structs define their own merge functionality. 138func (c *VaultConfig) Merge(o *VaultConfig) *VaultConfig { 139 if c == nil { 140 if o == nil { 141 return nil 142 } 143 return o.Copy() 144 } 145 146 if o == nil { 147 return c.Copy() 148 } 149 150 r := c.Copy() 151 152 if o.Address != nil { 153 r.Address = o.Address 154 } 155 156 if o.Enabled != nil { 157 r.Enabled = o.Enabled 158 } 159 160 if o.Grace != nil { 161 r.Grace = o.Grace 162 } 163 164 if o.Namespace != nil { 165 r.Namespace = o.Namespace 166 } 167 168 if o.RenewToken != nil { 169 r.RenewToken = o.RenewToken 170 } 171 172 if o.Retry != nil { 173 r.Retry = r.Retry.Merge(o.Retry) 174 } 175 176 if o.SSL != nil { 177 r.SSL = r.SSL.Merge(o.SSL) 178 } 179 180 if o.Token != nil { 181 r.Token = o.Token 182 } 183 184 if o.VaultAgentTokenFile != nil { 185 r.VaultAgentTokenFile = o.VaultAgentTokenFile 186 } 187 188 if o.Transport != nil { 189 r.Transport = r.Transport.Merge(o.Transport) 190 } 191 192 if o.UnwrapToken != nil { 193 r.UnwrapToken = o.UnwrapToken 194 } 195 196 return r 197} 198 199// Finalize ensures there no nil pointers. 200func (c *VaultConfig) Finalize() { 201 if c.Address == nil { 202 c.Address = stringFromEnv([]string{ 203 api.EnvVaultAddress, 204 }, "") 205 } 206 207 if c.Grace == nil { 208 c.Grace = TimeDuration(DefaultVaultGrace) 209 } 210 211 if c.Namespace == nil { 212 c.Namespace = stringFromEnv([]string{"VAULT_NAMESPACE"}, "") 213 } 214 215 if c.RenewToken == nil { 216 default_renew := DefaultVaultRenewToken 217 if c.VaultAgentTokenFile != nil { 218 default_renew = false 219 } 220 c.RenewToken = boolFromEnv([]string{ 221 "VAULT_RENEW_TOKEN", 222 }, default_renew) 223 } 224 225 if c.Retry == nil { 226 c.Retry = DefaultRetryConfig() 227 } 228 c.Retry.Finalize() 229 230 // Vault has custom SSL settings 231 if c.SSL == nil { 232 c.SSL = DefaultSSLConfig() 233 } 234 if c.SSL.Enabled == nil { 235 c.SSL.Enabled = Bool(true) 236 } 237 if c.SSL.CaCert == nil { 238 c.SSL.CaCert = stringFromEnv([]string{api.EnvVaultCACert}, "") 239 } 240 if c.SSL.CaPath == nil { 241 c.SSL.CaPath = stringFromEnv([]string{api.EnvVaultCAPath}, "") 242 } 243 if c.SSL.Cert == nil { 244 c.SSL.Cert = stringFromEnv([]string{api.EnvVaultClientCert}, "") 245 } 246 if c.SSL.Key == nil { 247 c.SSL.Key = stringFromEnv([]string{api.EnvVaultClientKey}, "") 248 } 249 if c.SSL.ServerName == nil { 250 c.SSL.ServerName = stringFromEnv([]string{api.EnvVaultTLSServerName}, "") 251 } 252 if c.SSL.Verify == nil { 253 c.SSL.Verify = antiboolFromEnv([]string{ 254 EnvVaultSkipVerify, api.EnvVaultInsecure}, true) 255 } 256 c.SSL.Finalize() 257 258 // Order of precedence 259 // 1. `vault_agent_token_file` configuration value 260 // 2. `token` configuration value` 261 // 3. `VAULT_TOKEN` environment variable 262 if c.Token == nil { 263 c.Token = stringFromEnv([]string{ 264 "VAULT_TOKEN", 265 }, "") 266 } 267 268 if c.VaultAgentTokenFile == nil { 269 if StringVal(c.Token) == "" { 270 if homePath != "" { 271 c.Token = stringFromFile([]string{ 272 homePath + "/.vault-token", 273 }, "") 274 } 275 } 276 } else { 277 c.Token = stringFromFile([]string{*c.VaultAgentTokenFile}, "") 278 } 279 280 if c.Transport == nil { 281 c.Transport = DefaultTransportConfig() 282 } 283 c.Transport.Finalize() 284 285 if c.UnwrapToken == nil { 286 c.UnwrapToken = boolFromEnv([]string{ 287 "VAULT_UNWRAP_TOKEN", 288 }, DefaultVaultUnwrapToken) 289 } 290 291 if c.Enabled == nil { 292 c.Enabled = Bool(StringPresent(c.Address)) 293 } 294} 295 296// GoString defines the printable version of this struct. 297func (c *VaultConfig) GoString() string { 298 if c == nil { 299 return "(*VaultConfig)(nil)" 300 } 301 302 return fmt.Sprintf("&VaultConfig{"+ 303 "Address:%s, "+ 304 "Enabled:%s, "+ 305 "Grace:%s, "+ 306 "Namespace:%s,"+ 307 "RenewToken:%s, "+ 308 "Retry:%#v, "+ 309 "SSL:%#v, "+ 310 "Token:%t, "+ 311 "VaultAgentTokenFile:%t, "+ 312 "Transport:%#v, "+ 313 "UnwrapToken:%s"+ 314 "}", 315 StringGoString(c.Address), 316 BoolGoString(c.Enabled), 317 TimeDurationGoString(c.Grace), 318 StringGoString(c.Namespace), 319 BoolGoString(c.RenewToken), 320 c.Retry, 321 c.SSL, 322 StringPresent(c.Token), 323 StringPresent(c.VaultAgentTokenFile), 324 c.Transport, 325 BoolGoString(c.UnwrapToken), 326 ) 327} 328