Update consul-template
This commit is contained in:
parent
e0b48831b2
commit
8df67563c7
2
vendor/github.com/hashicorp/consul-template/config/config.go
generated
vendored
2
vendor/github.com/hashicorp/consul-template/config/config.go
generated
vendored
|
@ -230,7 +230,7 @@ func Parse(s string) (*Config, error) {
|
|||
})
|
||||
|
||||
// FlattenFlatten keys belonging to the templates. We cannot do this above
|
||||
// because it is an array of tmeplates.
|
||||
// because it is an array of templates.
|
||||
if templates, ok := parsed["template"].([]map[string]interface{}); ok {
|
||||
for _, template := range templates {
|
||||
flattenKeys(template, []string{
|
||||
|
|
2
vendor/github.com/hashicorp/consul-template/config/vault.go
generated
vendored
2
vendor/github.com/hashicorp/consul-template/config/vault.go
generated
vendored
|
@ -11,7 +11,7 @@ const (
|
|||
// DefaultVaultGrace is the default grace period before which to read a new
|
||||
// secret from Vault. If a lease is due to expire in 5 minutes, Consul
|
||||
// Template will read a new secret at that time minus this value.
|
||||
DefaultVaultGrace = 15 * time.Second
|
||||
DefaultVaultGrace = 5 * time.Minute
|
||||
|
||||
// DefaultVaultRenewToken is the default value for if the Vault token should
|
||||
// be renewed.
|
||||
|
|
2
vendor/github.com/hashicorp/consul-template/dependency/errors.go
generated
vendored
2
vendor/github.com/hashicorp/consul-template/dependency/errors.go
generated
vendored
|
@ -9,3 +9,5 @@ var ErrStopped = errors.New("dependency stopped")
|
|||
|
||||
// ErrContinue is a special error which says to continue (retry) on error.
|
||||
var ErrContinue = errors.New("dependency continue")
|
||||
|
||||
var ErrLeaseExpired = errors.New("lease expired or is not renewable")
|
||||
|
|
192
vendor/github.com/hashicorp/consul-template/dependency/vault_common.go
generated
vendored
192
vendor/github.com/hashicorp/consul-template/dependency/vault_common.go
generated
vendored
|
@ -1,15 +1,23 @@
|
|||
package dependency
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"log"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/vault/api"
|
||||
)
|
||||
|
||||
var (
|
||||
// VaultDefaultLeaseDuration is the default lease duration in seconds.
|
||||
VaultDefaultLeaseDuration = 5 * time.Minute
|
||||
)
|
||||
|
||||
// Secret is a vault secret.
|
||||
// Secret is the structure returned for every secret within Vault.
|
||||
type Secret struct {
|
||||
RequestID string
|
||||
// The request ID that generated this response
|
||||
RequestID string
|
||||
|
||||
LeaseID string
|
||||
LeaseDuration int
|
||||
Renewable bool
|
||||
|
@ -17,23 +25,171 @@ type Secret struct {
|
|||
// Data is the actual contents of the secret. The format of the data
|
||||
// is arbitrary and up to the secret backend.
|
||||
Data map[string]interface{}
|
||||
|
||||
// Warnings contains any warnings related to the operation. These
|
||||
// are not issues that caused the command to fail, but that the
|
||||
// client should be aware of.
|
||||
Warnings []string
|
||||
|
||||
// Auth, if non-nil, means that there was authentication information
|
||||
// attached to this response.
|
||||
Auth *SecretAuth
|
||||
|
||||
// WrapInfo, if non-nil, means that the initial response was wrapped in the
|
||||
// cubbyhole of the given token (which has a TTL of the given number of
|
||||
// seconds)
|
||||
WrapInfo *SecretWrapInfo
|
||||
}
|
||||
|
||||
// leaseDurationOrDefault returns a value or the default lease duration.
|
||||
func leaseDurationOrDefault(d int) int {
|
||||
if d == 0 {
|
||||
return int(VaultDefaultLeaseDuration.Nanoseconds() / 1000000000)
|
||||
}
|
||||
return d
|
||||
// SecretAuth is the structure containing auth information if we have it.
|
||||
type SecretAuth struct {
|
||||
ClientToken string
|
||||
Accessor string
|
||||
Policies []string
|
||||
Metadata map[string]string
|
||||
|
||||
LeaseDuration int
|
||||
Renewable bool
|
||||
}
|
||||
|
||||
// vaultRenewDuration accepts a given renew duration (lease duration) and
|
||||
// returns the cooresponding time.Duration. If the duration is 0 (not provided),
|
||||
// this falls back to the VaultDefaultLeaseDuration.
|
||||
func vaultRenewDuration(d int) time.Duration {
|
||||
dur := time.Duration(d/2.0) * time.Second
|
||||
if dur == 0 {
|
||||
dur = VaultDefaultLeaseDuration
|
||||
}
|
||||
return dur
|
||||
// SecretWrapInfo contains wrapping information if we have it. If what is
|
||||
// contained is an authentication token, the accessor for the token will be
|
||||
// available in WrappedAccessor.
|
||||
type SecretWrapInfo struct {
|
||||
Token string
|
||||
TTL int
|
||||
CreationTime time.Time
|
||||
WrappedAccessor string
|
||||
}
|
||||
|
||||
// vaultRenewDuration accepts a secret and returns the recommended amount of
|
||||
// time to sleep.
|
||||
func vaultRenewDuration(s *Secret) time.Duration {
|
||||
// Handle whether this is an auth or a regular secret.
|
||||
base := s.LeaseDuration
|
||||
if s.Auth != nil && s.Auth.LeaseDuration > 0 {
|
||||
base = s.Auth.LeaseDuration
|
||||
}
|
||||
|
||||
// Ensure we have a lease duration, since sometimes this can be zero.
|
||||
if base <= 0 {
|
||||
base = int(VaultDefaultLeaseDuration.Seconds())
|
||||
}
|
||||
|
||||
// Convert to float seconds.
|
||||
sleep := float64(time.Duration(base) * time.Second)
|
||||
|
||||
// Renew at 1/3 the remaining lease. This will give us an opportunity to retry
|
||||
// at least one more time should the first renewal fail.
|
||||
sleep = sleep / 3.0
|
||||
|
||||
// Use a randomness so many clients do not hit Vault simultaneously.
|
||||
sleep = sleep * (rand.Float64() + 1) / 2.0
|
||||
|
||||
return time.Duration(sleep)
|
||||
}
|
||||
|
||||
// printVaultWarnings prints warnings for a given dependency.
|
||||
func printVaultWarnings(d Dependency, warnings []string) {
|
||||
for _, w := range warnings {
|
||||
log.Printf("[WARN] %s: %s", d, w)
|
||||
}
|
||||
}
|
||||
|
||||
// vaultSecretRenewable determines if the given secret is renewable.
|
||||
func vaultSecretRenewable(s *Secret) bool {
|
||||
if s.Auth != nil {
|
||||
return s.Auth.Renewable
|
||||
}
|
||||
return s.Renewable
|
||||
}
|
||||
|
||||
// transformSecret transforms an api secret into our secret. This does not deep
|
||||
// copy underlying deep data structures, so it's not safe to modify the vault
|
||||
// secret as that may modify the data in the transformed secret.
|
||||
func transformSecret(theirs *api.Secret) *Secret {
|
||||
var ours Secret
|
||||
updateSecret(&ours, theirs)
|
||||
return &ours
|
||||
}
|
||||
|
||||
// updateSecret updates our secret with the new data from the api, careful to
|
||||
// not overwrite missing data. Renewals don't include the original secret, and
|
||||
// we don't want to delete that data accidentially.
|
||||
func updateSecret(ours *Secret, theirs *api.Secret) {
|
||||
if theirs.RequestID != "" {
|
||||
ours.RequestID = theirs.RequestID
|
||||
}
|
||||
|
||||
if theirs.LeaseID != "" {
|
||||
ours.LeaseID = theirs.LeaseID
|
||||
}
|
||||
|
||||
if theirs.LeaseDuration != 0 {
|
||||
ours.LeaseDuration = theirs.LeaseDuration
|
||||
}
|
||||
|
||||
if theirs.Renewable {
|
||||
ours.Renewable = theirs.Renewable
|
||||
}
|
||||
|
||||
if len(theirs.Data) != 0 {
|
||||
ours.Data = theirs.Data
|
||||
}
|
||||
|
||||
if len(theirs.Warnings) != 0 {
|
||||
ours.Warnings = theirs.Warnings
|
||||
}
|
||||
|
||||
if theirs.Auth != nil {
|
||||
if ours.Auth == nil {
|
||||
ours.Auth = &SecretAuth{}
|
||||
}
|
||||
|
||||
if theirs.Auth.ClientToken != "" {
|
||||
ours.Auth.ClientToken = theirs.Auth.ClientToken
|
||||
}
|
||||
|
||||
if theirs.Auth.Accessor != "" {
|
||||
ours.Auth.Accessor = theirs.Auth.Accessor
|
||||
}
|
||||
|
||||
if len(theirs.Auth.Policies) != 0 {
|
||||
ours.Auth.Policies = theirs.Auth.Policies
|
||||
}
|
||||
|
||||
if len(theirs.Auth.Metadata) != 0 {
|
||||
ours.Auth.Metadata = theirs.Auth.Metadata
|
||||
}
|
||||
|
||||
if theirs.Auth.LeaseDuration != 0 {
|
||||
ours.Auth.LeaseDuration = theirs.Auth.LeaseDuration
|
||||
}
|
||||
|
||||
if theirs.Auth.Renewable {
|
||||
ours.Auth.Renewable = theirs.Auth.Renewable
|
||||
}
|
||||
}
|
||||
|
||||
if theirs.WrapInfo != nil {
|
||||
if ours.WrapInfo == nil {
|
||||
ours.WrapInfo = &SecretWrapInfo{}
|
||||
}
|
||||
|
||||
if theirs.WrapInfo.Token != "" {
|
||||
ours.WrapInfo.Token = theirs.WrapInfo.Token
|
||||
}
|
||||
|
||||
if theirs.WrapInfo.TTL != 0 {
|
||||
ours.WrapInfo.TTL = theirs.WrapInfo.TTL
|
||||
}
|
||||
|
||||
if !theirs.WrapInfo.CreationTime.IsZero() {
|
||||
ours.WrapInfo.CreationTime = theirs.WrapInfo.CreationTime
|
||||
}
|
||||
|
||||
if theirs.WrapInfo.WrappedAccessor != "" {
|
||||
ours.WrapInfo.WrappedAccessor = theirs.WrapInfo.WrappedAccessor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
146
vendor/github.com/hashicorp/consul-template/dependency/vault_read.go
generated
vendored
146
vendor/github.com/hashicorp/consul-template/dependency/vault_read.go
generated
vendored
|
@ -7,6 +7,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/vault/api"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -21,6 +22,9 @@ type VaultReadQuery struct {
|
|||
|
||||
path string
|
||||
secret *Secret
|
||||
|
||||
// vaultSecret is the actual Vault secret which we are renewing
|
||||
vaultSecret *api.Secret
|
||||
}
|
||||
|
||||
// NewVaultReadQuery creates a new datacenter dependency.
|
||||
|
@ -47,71 +51,68 @@ func (d *VaultReadQuery) Fetch(clients *ClientSet, opts *QueryOptions) (interfac
|
|||
|
||||
opts = opts.Merge(&QueryOptions{})
|
||||
|
||||
// If this is not the first query and we have a lease duration, sleep until we
|
||||
// try to renew.
|
||||
if opts.WaitIndex != 0 && d.secret != nil && d.secret.LeaseDuration != 0 {
|
||||
dur := vaultRenewDuration(d.secret.LeaseDuration)
|
||||
if d.secret != nil {
|
||||
if vaultSecretRenewable(d.secret) {
|
||||
log.Printf("[TRACE] %s: starting renewer", d)
|
||||
|
||||
log.Printf("[TRACE] %s: long polling for %s", d, dur)
|
||||
renewer, err := clients.Vault().NewRenewer(&api.RenewerInput{
|
||||
Grace: opts.VaultGrace,
|
||||
Secret: d.vaultSecret,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, d.String())
|
||||
}
|
||||
go renewer.Renew()
|
||||
defer renewer.Stop()
|
||||
|
||||
select {
|
||||
case <-d.stopCh:
|
||||
return nil, nil, ErrStopped
|
||||
case <-time.After(dur):
|
||||
RENEW:
|
||||
for {
|
||||
select {
|
||||
case err := <-renewer.DoneCh():
|
||||
if err != nil {
|
||||
log.Printf("[WARN] %s: failed to renew: %s", d, err)
|
||||
}
|
||||
log.Printf("[WARN] %s: renewer returned (maybe the lease expired)", d)
|
||||
break RENEW
|
||||
case renewal := <-renewer.RenewCh():
|
||||
log.Printf("[TRACE] %s: successfully renewed", d)
|
||||
printVaultWarnings(d, renewal.Secret.Warnings)
|
||||
updateSecret(d.secret, renewal.Secret)
|
||||
case <-d.stopCh:
|
||||
return nil, nil, ErrStopped
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The secret isn't renewable, probably the generic secret backend.
|
||||
dur := vaultRenewDuration(d.secret)
|
||||
if dur < opts.VaultGrace {
|
||||
log.Printf("[TRACE] %s: remaining lease %s is less than grace, skipping sleep", d, dur)
|
||||
} else {
|
||||
log.Printf("[TRACE] %s: secret is not renewable, sleeping for %s", d, dur)
|
||||
select {
|
||||
case <-time.After(dur):
|
||||
// The lease is almost expired, it's time to request a new one.
|
||||
case <-d.stopCh:
|
||||
return nil, nil, ErrStopped
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to renew the secret. If we do not have a secret or if that secret
|
||||
// is not renewable, we will attempt a (re-)read later.
|
||||
if d.secret != nil && d.secret.LeaseID != "" && d.secret.Renewable {
|
||||
log.Printf("[TRACE] %s: PUT %s", d, &url.URL{
|
||||
Path: "/v1/sys/renew/" + d.secret.LeaseID,
|
||||
RawQuery: opts.String(),
|
||||
})
|
||||
|
||||
renewal, err := clients.Vault().Sys().Renew(d.secret.LeaseID, 0)
|
||||
if err == nil {
|
||||
log.Printf("[TRACE] %s: successfully renewed %s", d, d.secret.LeaseID)
|
||||
|
||||
// Print any warnings
|
||||
d.printWarnings(renewal.Warnings)
|
||||
|
||||
secret := &Secret{
|
||||
RequestID: renewal.RequestID,
|
||||
LeaseID: renewal.LeaseID,
|
||||
LeaseDuration: d.secret.LeaseDuration,
|
||||
Renewable: renewal.Renewable,
|
||||
Data: d.secret.Data,
|
||||
}
|
||||
// For some older versions of Vault, the renewal did not include the
|
||||
// remaining lease duration, so just use the original lease duration,
|
||||
// because it's the best we can do.
|
||||
if renewal.LeaseDuration != 0 {
|
||||
secret.LeaseDuration = renewal.LeaseDuration
|
||||
}
|
||||
d.secret = secret
|
||||
|
||||
// If the remaining time on the lease is less than or equal to our
|
||||
// configured grace period, generate a new credential now. This will help
|
||||
// minimize downtime, since Vault will revoke credentials immediately
|
||||
// when their maximum TTL expires.
|
||||
remaining := time.Duration(d.secret.LeaseDuration) * time.Second
|
||||
if remaining <= opts.VaultGrace {
|
||||
log.Printf("[DEBUG] %s: remaining lease (%s) < grace (%s), acquiring new",
|
||||
d, remaining, opts.VaultGrace)
|
||||
return d.readSecret(clients, opts)
|
||||
}
|
||||
|
||||
return respWithMetadata(secret)
|
||||
}
|
||||
|
||||
// The renewal failed for some reason.
|
||||
log.Printf("[WARN] %s: failed to renew %s: %s", d, d.secret.LeaseID, err)
|
||||
// We don't have a secret, or the prior renewal failed
|
||||
vaultSecret, err := d.readSecret(clients, opts)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, d.String())
|
||||
}
|
||||
|
||||
// If we got this far, we either didn't have a secret to renew, the secret was
|
||||
// not renewable, or the renewal failed, so attempt a fresh read.
|
||||
return d.readSecret(clients, opts)
|
||||
// Print any warnings
|
||||
printVaultWarnings(d, vaultSecret.Warnings)
|
||||
|
||||
// Create the cloned secret which will be exposed to the template.
|
||||
d.vaultSecret = vaultSecret
|
||||
d.secret = transformSecret(vaultSecret)
|
||||
|
||||
return respWithMetadata(d.secret)
|
||||
}
|
||||
|
||||
// CanShare returns if this dependency is shareable.
|
||||
|
@ -134,38 +135,17 @@ func (d *VaultReadQuery) Type() Type {
|
|||
return TypeVault
|
||||
}
|
||||
|
||||
func (d *VaultReadQuery) printWarnings(warnings []string) {
|
||||
for _, w := range warnings {
|
||||
log.Printf("[WARN] %s: %s", d, w)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *VaultReadQuery) readSecret(clients *ClientSet, opts *QueryOptions) (interface{}, *ResponseMetadata, error) {
|
||||
func (d *VaultReadQuery) readSecret(clients *ClientSet, opts *QueryOptions) (*api.Secret, error) {
|
||||
log.Printf("[TRACE] %s: GET %s", d, &url.URL{
|
||||
Path: "/v1/" + d.path,
|
||||
RawQuery: opts.String(),
|
||||
})
|
||||
vaultSecret, err := clients.Vault().Logical().Read(d.path)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, d.String())
|
||||
return nil, errors.Wrap(err, d.String())
|
||||
}
|
||||
|
||||
// The secret could be nil if it does not exist.
|
||||
if vaultSecret == nil {
|
||||
return nil, nil, fmt.Errorf("%s: no secret exists at %s", d, d.path)
|
||||
return nil, fmt.Errorf("no secret exists at %s", d.path)
|
||||
}
|
||||
|
||||
// Print any warnings.
|
||||
d.printWarnings(vaultSecret.Warnings)
|
||||
|
||||
// Create our cloned secret.
|
||||
secret := &Secret{
|
||||
LeaseID: vaultSecret.LeaseID,
|
||||
LeaseDuration: leaseDurationOrDefault(vaultSecret.LeaseDuration),
|
||||
Renewable: vaultSecret.Renewable,
|
||||
Data: vaultSecret.Data,
|
||||
}
|
||||
d.secret = secret
|
||||
|
||||
return respWithMetadata(secret)
|
||||
return vaultSecret, nil
|
||||
}
|
||||
|
|
93
vendor/github.com/hashicorp/consul-template/dependency/vault_token.go
generated
vendored
93
vendor/github.com/hashicorp/consul-template/dependency/vault_token.go
generated
vendored
|
@ -2,9 +2,9 @@ package dependency
|
|||
|
||||
import (
|
||||
"log"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/vault/api"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -15,16 +15,24 @@ var (
|
|||
|
||||
// VaultTokenQuery is the dependency to Vault for a secret
|
||||
type VaultTokenQuery struct {
|
||||
stopCh chan struct{}
|
||||
|
||||
leaseID string
|
||||
leaseDuration int
|
||||
stopCh chan struct{}
|
||||
secret *Secret
|
||||
vaultSecret *api.Secret
|
||||
}
|
||||
|
||||
// NewVaultTokenQuery creates a new dependency.
|
||||
func NewVaultTokenQuery() (*VaultTokenQuery, error) {
|
||||
func NewVaultTokenQuery(token string) (*VaultTokenQuery, error) {
|
||||
vaultSecret := &api.Secret{
|
||||
Auth: &api.SecretAuth{
|
||||
ClientToken: token,
|
||||
Renewable: true,
|
||||
LeaseDuration: 1,
|
||||
},
|
||||
}
|
||||
return &VaultTokenQuery{
|
||||
stopCh: make(chan struct{}, 1),
|
||||
stopCh: make(chan struct{}, 1),
|
||||
vaultSecret: vaultSecret,
|
||||
secret: transformSecret(vaultSecret),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -38,44 +46,53 @@ func (d *VaultTokenQuery) Fetch(clients *ClientSet, opts *QueryOptions) (interfa
|
|||
|
||||
opts = opts.Merge(&QueryOptions{})
|
||||
|
||||
log.Printf("[TRACE] %s: GET %s", d, &url.URL{
|
||||
Path: "/v1/auth/token/renew-self",
|
||||
RawQuery: opts.String(),
|
||||
})
|
||||
if vaultSecretRenewable(d.secret) {
|
||||
log.Printf("[TRACE] %s: starting renewer", d)
|
||||
|
||||
// If this is not the first query and we have a lease duration, sleep until we
|
||||
// try to renew.
|
||||
if opts.WaitIndex != 0 && d.leaseDuration != 0 {
|
||||
dur := vaultRenewDuration(d.leaseDuration)
|
||||
renewer, err := clients.Vault().NewRenewer(&api.RenewerInput{
|
||||
Grace: opts.VaultGrace,
|
||||
Secret: d.vaultSecret,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, d.String())
|
||||
}
|
||||
go renewer.Renew()
|
||||
defer renewer.Stop()
|
||||
|
||||
log.Printf("[TRACE] %s: long polling for %s", d, dur)
|
||||
|
||||
select {
|
||||
case <-d.stopCh:
|
||||
return nil, nil, ErrStopped
|
||||
case <-time.After(dur):
|
||||
RENEW:
|
||||
for {
|
||||
select {
|
||||
case err := <-renewer.DoneCh():
|
||||
if err != nil {
|
||||
log.Printf("[WARN] %s: failed to renew: %s", d, err)
|
||||
}
|
||||
log.Printf("[WARN] %s: renewer returned (maybe the lease expired)", d)
|
||||
break RENEW
|
||||
case renewal := <-renewer.RenewCh():
|
||||
log.Printf("[TRACE] %s: successfully renewed", d)
|
||||
printVaultWarnings(d, renewal.Secret.Warnings)
|
||||
updateSecret(d.secret, renewal.Secret)
|
||||
case <-d.stopCh:
|
||||
return nil, nil, ErrStopped
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
token, err := clients.Vault().Auth().Token().RenewSelf(0)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, d.String())
|
||||
// The secret isn't renewable, probably the generic secret backend.
|
||||
dur := vaultRenewDuration(d.secret)
|
||||
if dur < opts.VaultGrace {
|
||||
log.Printf("[TRACE] %s: remaining lease %s is less than grace, skipping sleep", d, dur)
|
||||
} else {
|
||||
log.Printf("[TRACE] %s: token is not renewable, sleeping for %s", d, dur)
|
||||
select {
|
||||
case <-time.After(dur):
|
||||
// The lease is almost expired, it's time to request a new one.
|
||||
case <-d.stopCh:
|
||||
return nil, nil, ErrStopped
|
||||
}
|
||||
}
|
||||
|
||||
// Create our cloned secret
|
||||
secret := &Secret{
|
||||
LeaseID: token.LeaseID,
|
||||
LeaseDuration: token.Auth.LeaseDuration,
|
||||
Renewable: token.Auth.Renewable,
|
||||
Data: token.Data,
|
||||
}
|
||||
|
||||
d.leaseID = secret.LeaseID
|
||||
d.leaseDuration = secret.LeaseDuration
|
||||
|
||||
log.Printf("[DEBUG] %s: renewed token", d)
|
||||
|
||||
return respWithMetadata(secret)
|
||||
return nil, nil, ErrLeaseExpired
|
||||
}
|
||||
|
||||
// CanShare returns if this dependency is shareable.
|
||||
|
|
140
vendor/github.com/hashicorp/consul-template/dependency/vault_write.go
generated
vendored
140
vendor/github.com/hashicorp/consul-template/dependency/vault_write.go
generated
vendored
|
@ -10,6 +10,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/vault/api"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -26,6 +27,9 @@ type VaultWriteQuery struct {
|
|||
data map[string]interface{}
|
||||
dataHash string
|
||||
secret *Secret
|
||||
|
||||
// vaultSecret is the actual Vault secret which we are renewing
|
||||
vaultSecret *api.Secret
|
||||
}
|
||||
|
||||
// NewVaultWriteQuery creates a new datacenter dependency.
|
||||
|
@ -54,70 +58,68 @@ func (d *VaultWriteQuery) Fetch(clients *ClientSet, opts *QueryOptions) (interfa
|
|||
|
||||
opts = opts.Merge(&QueryOptions{})
|
||||
|
||||
// If this is not the first query and we have a lease duration, sleep until we
|
||||
// try to renew.
|
||||
if opts.WaitIndex != 0 && d.secret != nil && d.secret.LeaseDuration != 0 {
|
||||
dur := vaultRenewDuration(d.secret.LeaseDuration)
|
||||
if d.secret != nil {
|
||||
if vaultSecretRenewable(d.secret) {
|
||||
log.Printf("[TRACE] %s: starting renewer", d)
|
||||
|
||||
log.Printf("[TRACE] %s: long polling for %s", d, dur)
|
||||
renewer, err := clients.Vault().NewRenewer(&api.RenewerInput{
|
||||
Grace: opts.VaultGrace,
|
||||
Secret: d.vaultSecret,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, d.String())
|
||||
}
|
||||
go renewer.Renew()
|
||||
defer renewer.Stop()
|
||||
|
||||
select {
|
||||
case <-d.stopCh:
|
||||
return nil, nil, ErrStopped
|
||||
case <-time.After(dur):
|
||||
RENEW:
|
||||
for {
|
||||
select {
|
||||
case err := <-renewer.DoneCh():
|
||||
if err != nil {
|
||||
log.Printf("[WARN] %s: failed to renew: %s", d, err)
|
||||
}
|
||||
log.Printf("[WARN] %s: renewer returned (maybe the lease expired)", d)
|
||||
break RENEW
|
||||
case renewal := <-renewer.RenewCh():
|
||||
log.Printf("[TRACE] %s: successfully renewed", d)
|
||||
printVaultWarnings(d, renewal.Secret.Warnings)
|
||||
updateSecret(d.secret, renewal.Secret)
|
||||
case <-d.stopCh:
|
||||
return nil, nil, ErrStopped
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The secret isn't renewable, probably the generic secret backend.
|
||||
dur := vaultRenewDuration(d.secret)
|
||||
if dur < opts.VaultGrace {
|
||||
log.Printf("[TRACE] %s: remaining lease %s is less than grace, skipping sleep", d, dur)
|
||||
} else {
|
||||
log.Printf("[TRACE] %s: secret is not renewable, sleeping for %s", d, dur)
|
||||
select {
|
||||
case <-time.After(dur):
|
||||
// The lease is almost expired, it's time to request a new one.
|
||||
case <-d.stopCh:
|
||||
return nil, nil, ErrStopped
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to renew the secret. If we do not have a secret or if that secret
|
||||
// is not renewable, we will attempt a (re-)write later.
|
||||
if d.secret != nil && d.secret.LeaseID != "" && d.secret.Renewable {
|
||||
log.Printf("[TRACE] %s: PUT %s", d, &url.URL{
|
||||
Path: "/v1/sys/renew/" + d.secret.LeaseID,
|
||||
RawQuery: opts.String(),
|
||||
})
|
||||
|
||||
renewal, err := clients.Vault().Sys().Renew(d.secret.LeaseID, 0)
|
||||
if err == nil {
|
||||
log.Printf("[TRACE] %s: successfully renewed %s", d, d.secret.LeaseID)
|
||||
|
||||
// Print any warnings
|
||||
d.printWarnings(renewal.Warnings)
|
||||
|
||||
secret := &Secret{
|
||||
RequestID: renewal.RequestID,
|
||||
LeaseID: renewal.LeaseID,
|
||||
Renewable: renewal.Renewable,
|
||||
Data: d.secret.Data,
|
||||
}
|
||||
// For some older versions of Vault, the renewal did not include the
|
||||
// remaining lease duration, so just use the original lease duration,
|
||||
// because it's the best we can do.
|
||||
if renewal.LeaseDuration != 0 {
|
||||
secret.LeaseDuration = renewal.LeaseDuration
|
||||
}
|
||||
d.secret = secret
|
||||
|
||||
// If the remaining time on the lease is less than or equal to our
|
||||
// configured grace period, generate a new credential now. This will help
|
||||
// minimize downtime, since Vault will revoke credentials immediately
|
||||
// when their maximum TTL expires.
|
||||
remaining := time.Duration(d.secret.LeaseDuration) * time.Second
|
||||
if remaining <= opts.VaultGrace {
|
||||
log.Printf("[DEBUG] %s: remaining lease (%s) < grace (%s), acquiring new",
|
||||
d, remaining, opts.VaultGrace)
|
||||
return d.writeSecret(clients, opts)
|
||||
}
|
||||
|
||||
return respWithMetadata(secret)
|
||||
}
|
||||
|
||||
// The renewal failed for some reason.
|
||||
log.Printf("[WARN] %s: failed to renew %s: %s", d, d.secret.LeaseID, err)
|
||||
// We don't have a secret, or the prior renewal failed
|
||||
vaultSecret, err := d.writeSecret(clients, opts)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, d.String())
|
||||
}
|
||||
|
||||
// If we got this far, we either didn't have a secret to renew, the secret was
|
||||
// not renewable, or the renewal failed, so attempt a fresh write.
|
||||
return d.writeSecret(clients, opts)
|
||||
// Print any warnings
|
||||
printVaultWarnings(d, vaultSecret.Warnings)
|
||||
|
||||
// Create the cloned secret which will be exposed to the template.
|
||||
d.vaultSecret = vaultSecret
|
||||
d.secret = transformSecret(vaultSecret)
|
||||
|
||||
return respWithMetadata(d.secret)
|
||||
}
|
||||
|
||||
// CanShare returns if this dependency is shareable.
|
||||
|
@ -164,7 +166,7 @@ func (d *VaultWriteQuery) printWarnings(warnings []string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (d *VaultWriteQuery) writeSecret(clients *ClientSet, opts *QueryOptions) (interface{}, *ResponseMetadata, error) {
|
||||
func (d *VaultWriteQuery) writeSecret(clients *ClientSet, opts *QueryOptions) (*api.Secret, error) {
|
||||
log.Printf("[TRACE] %s: PUT %s", d, &url.URL{
|
||||
Path: "/v1/" + d.path,
|
||||
RawQuery: opts.String(),
|
||||
|
@ -172,27 +174,11 @@ func (d *VaultWriteQuery) writeSecret(clients *ClientSet, opts *QueryOptions) (i
|
|||
|
||||
vaultSecret, err := clients.Vault().Logical().Write(d.path, d.data)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, d.String())
|
||||
return nil, errors.Wrap(err, d.String())
|
||||
}
|
||||
|
||||
// The secret could be nil if it does not exist.
|
||||
if vaultSecret == nil {
|
||||
return nil, nil, fmt.Errorf("%s: no secret exists at %s", d, d.path)
|
||||
return nil, fmt.Errorf("no secret exists at %s", d.path)
|
||||
}
|
||||
|
||||
// Print any warnings.
|
||||
for _, w := range vaultSecret.Warnings {
|
||||
log.Printf("[WARN] %s: %s", d, w)
|
||||
}
|
||||
|
||||
// Create our cloned secret.
|
||||
secret := &Secret{
|
||||
LeaseID: vaultSecret.LeaseID,
|
||||
LeaseDuration: leaseDurationOrDefault(vaultSecret.LeaseDuration),
|
||||
Renewable: vaultSecret.Renewable,
|
||||
Data: vaultSecret.Data,
|
||||
}
|
||||
d.secret = secret
|
||||
|
||||
return respWithMetadata(secret)
|
||||
return vaultSecret, nil
|
||||
}
|
||||
|
|
18
vendor/github.com/hashicorp/consul-template/manager/renderer.go
generated
vendored
18
vendor/github.com/hashicorp/consul-template/manager/renderer.go
generated
vendored
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// RenderInput is used as input to the render function.
|
||||
type RenderInput struct {
|
||||
Backup bool
|
||||
Contents []byte
|
||||
|
@ -20,9 +21,22 @@ type RenderInput struct {
|
|||
Perms os.FileMode
|
||||
}
|
||||
|
||||
// RenderResult is returned and stored. It contains the status of the render
|
||||
// operationg.
|
||||
type RenderResult struct {
|
||||
DidRender bool
|
||||
// DidRender indicates if the template rendered to disk. This will be false in
|
||||
// the event of an error, but it will also be false in dry mode or when the
|
||||
// template on disk matches the new result.
|
||||
DidRender bool
|
||||
|
||||
// WouldRender indicates if the template would have rendered to disk. This
|
||||
// will return false in the event of an error, but will return true in dry
|
||||
// mode or when the template on disk matches the new result.
|
||||
WouldRender bool
|
||||
|
||||
// Contents are the actual contents of the resulting template from the render
|
||||
// operation.
|
||||
Contents []byte
|
||||
}
|
||||
|
||||
// Render atomically renders a file contents to disk, returning a result of
|
||||
|
@ -37,6 +51,7 @@ func Render(i *RenderInput) (*RenderResult, error) {
|
|||
return &RenderResult{
|
||||
DidRender: false,
|
||||
WouldRender: true,
|
||||
Contents: existing,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -51,6 +66,7 @@ func Render(i *RenderInput) (*RenderResult, error) {
|
|||
return &RenderResult{
|
||||
DidRender: true,
|
||||
WouldRender: true,
|
||||
Contents: existing,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
10
vendor/github.com/hashicorp/consul-template/manager/runner.go
generated
vendored
10
vendor/github.com/hashicorp/consul-template/manager/runner.go
generated
vendored
|
@ -42,8 +42,7 @@ type Runner struct {
|
|||
dry, once bool
|
||||
|
||||
// outStream and errStream are the io.Writer streams where the runner will
|
||||
// write information. These streams can be set using the SetOutStream()
|
||||
// and SetErrStream() functions.
|
||||
// write information.
|
||||
|
||||
// inStream is the ioReader where the runner will read information.
|
||||
outStream, errStream io.Writer
|
||||
|
@ -118,6 +117,9 @@ type RenderEvent struct {
|
|||
// Template is the template attempting to be rendered.
|
||||
Template *template.Template
|
||||
|
||||
// Contents is the raw, rendered contents from the template.
|
||||
Contents []byte
|
||||
|
||||
// TemplateConfigs is the list of template configs that correspond to this
|
||||
// template.
|
||||
TemplateConfigs []*config.TemplateConfig
|
||||
|
@ -643,6 +645,9 @@ func (r *Runner) Run() error {
|
|||
event.DidRender = true
|
||||
event.LastDidRender = renderTime
|
||||
|
||||
// Update the contents
|
||||
event.Contents = result.Contents
|
||||
|
||||
// Record that at least one template was rendered.
|
||||
renderedAny = true
|
||||
|
||||
|
@ -1175,6 +1180,7 @@ func newWatcher(c *config.Config, clients *dep.ClientSet, once bool) (*watch.Wat
|
|||
RetryFuncDefault: nil,
|
||||
RetryFuncVault: watch.RetryFunc(c.Vault.Retry.RetryFunc()),
|
||||
VaultGrace: config.TimeDurationVal(c.Vault.Grace),
|
||||
VaultToken: config.StringVal(c.Vault.Token),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "runner")
|
||||
|
|
2
vendor/github.com/hashicorp/consul-template/watch/view.go
generated
vendored
2
vendor/github.com/hashicorp/consul-template/watch/view.go
generated
vendored
|
@ -150,7 +150,7 @@ func (v *View) poll(viewCh chan<- *View, errCh chan<- error) {
|
|||
// example, Consul make have an outage, but when it returns, the view
|
||||
// is unchanged. We have to reset the counter retries, but not update the
|
||||
// actual template.
|
||||
log.Printf("[TRACE] view %s successful contact, resetting retries", v.dependency)
|
||||
log.Printf("[TRACE] (view) %s successful contact, resetting retries", v.dependency)
|
||||
retries = 0
|
||||
goto WAIT
|
||||
case err := <-fetchErrCh:
|
||||
|
|
5
vendor/github.com/hashicorp/consul-template/watch/watcher.go
generated
vendored
5
vendor/github.com/hashicorp/consul-template/watch/watcher.go
generated
vendored
|
@ -62,6 +62,9 @@ type NewWatcherInput struct {
|
|||
// RenewVault indicates if this watcher should renew Vault tokens.
|
||||
RenewVault bool
|
||||
|
||||
// VaultToken is the vault token to renew.
|
||||
VaultToken string
|
||||
|
||||
// RetryFuncs specify the different ways to retry based on the upstream.
|
||||
RetryFuncConsul RetryFunc
|
||||
RetryFuncDefault RetryFunc
|
||||
|
@ -90,7 +93,7 @@ func NewWatcher(i *NewWatcherInput) (*Watcher, error) {
|
|||
|
||||
// Start a watcher for the Vault renew if that config was specified
|
||||
if i.RenewVault {
|
||||
vt, err := dep.NewVaultTokenQuery()
|
||||
vt, err := dep.NewVaultTokenQuery(i.VaultToken)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "watcher")
|
||||
}
|
||||
|
|
36
vendor/vendor.json
vendored
36
vendor/vendor.json
vendored
|
@ -611,44 +611,44 @@
|
|||
{
|
||||
"checksumSHA1": "Nu2j1GusM7ZH0uYrGzqr1K7yH7I=",
|
||||
"path": "github.com/hashicorp/consul-template/child",
|
||||
"revision": "ecbc27c1922fed2f562e7fb63e1ad24e818fa60e",
|
||||
"revisionTime": "2017-07-05T14:04:00Z"
|
||||
"revision": "7b3f45039cf3ad1a758683fd3eebb1cc72affa06",
|
||||
"revisionTime": "2017-08-01T00:58:49Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "QWcGW3wELSp/YsOVzCW02oEYR7c=",
|
||||
"checksumSHA1": "lemUzh6uQDMxuvTT/BREYdGcS0U=",
|
||||
"path": "github.com/hashicorp/consul-template/config",
|
||||
"revision": "ecbc27c1922fed2f562e7fb63e1ad24e818fa60e",
|
||||
"revisionTime": "2017-07-05T14:04:00Z"
|
||||
"revision": "7b3f45039cf3ad1a758683fd3eebb1cc72affa06",
|
||||
"revisionTime": "2017-08-01T00:58:49Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "mV7yjHpIfO4yRAdQaBlAqdGDKO8=",
|
||||
"checksumSHA1": "WVZ+pqn/HLLXjj+Tj5ZZvD7w6r0=",
|
||||
"path": "github.com/hashicorp/consul-template/dependency",
|
||||
"revision": "ecbc27c1922fed2f562e7fb63e1ad24e818fa60e",
|
||||
"revisionTime": "2017-07-05T14:04:00Z"
|
||||
"revision": "7b3f45039cf3ad1a758683fd3eebb1cc72affa06",
|
||||
"revisionTime": "2017-08-01T00:58:49Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "ZTlPhrxNzME75A4ydXM88TFt3Qs=",
|
||||
"checksumSHA1": "Cu8hIII8Z6FAuunFI/jXPLl0nQA=",
|
||||
"path": "github.com/hashicorp/consul-template/manager",
|
||||
"revision": "ecbc27c1922fed2f562e7fb63e1ad24e818fa60e",
|
||||
"revisionTime": "2017-07-05T14:04:00Z"
|
||||
"revision": "7b3f45039cf3ad1a758683fd3eebb1cc72affa06",
|
||||
"revisionTime": "2017-08-01T00:58:49Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "oskgb0WteBKOItG8NNDduM7E/D0=",
|
||||
"path": "github.com/hashicorp/consul-template/signals",
|
||||
"revision": "ecbc27c1922fed2f562e7fb63e1ad24e818fa60e",
|
||||
"revisionTime": "2017-07-05T14:04:00Z"
|
||||
"revision": "7b3f45039cf3ad1a758683fd3eebb1cc72affa06",
|
||||
"revisionTime": "2017-08-01T00:58:49Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "zSvJlNfZS3fCRlFaZ7r9Q+N17T8=",
|
||||
"path": "github.com/hashicorp/consul-template/template",
|
||||
"revision": "ecbc27c1922fed2f562e7fb63e1ad24e818fa60e",
|
||||
"revisionTime": "2017-07-05T14:04:00Z"
|
||||
"revision": "7b3f45039cf3ad1a758683fd3eebb1cc72affa06",
|
||||
"revisionTime": "2017-08-01T00:58:49Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "85W96Fo50FmrMaba7Dk12aDfwWs=",
|
||||
"checksumSHA1": "b4+Y+02pY2Y5620F9ALzKg8Zmdw=",
|
||||
"path": "github.com/hashicorp/consul-template/watch",
|
||||
"revision": "ecbc27c1922fed2f562e7fb63e1ad24e818fa60e",
|
||||
"revisionTime": "2017-07-05T14:04:00Z"
|
||||
"revision": "7b3f45039cf3ad1a758683fd3eebb1cc72affa06",
|
||||
"revisionTime": "2017-08-01T00:58:49Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "jfELEMRhiTcppZmRH+ZwtkVS5Uw=",
|
||||
|
|
Loading…
Reference in a new issue