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

Automatically renew the token used by the Vault CA provider #8560

Merged
merged 9 commits into from
Sep 16, 2020
77 changes: 75 additions & 2 deletions agent/connect/ca/provider_vault.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package ca
import (
"bytes"
"crypto/x509"
"encoding/json"
"encoding/pem"
"fmt"
"io/ioutil"
Expand All @@ -11,6 +12,8 @@ import (

"github.com/hashicorp/consul/agent/connect"
"github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/logging"
"github.com/hashicorp/go-hclog"
vaultapi "github.com/hashicorp/vault/api"
"github.com/mitchellh/mapstructure"
)
Expand All @@ -21,12 +24,15 @@ var ErrBackendNotMounted = fmt.Errorf("backend not mounted")
var ErrBackendNotInitialized = fmt.Errorf("backend not initialized")

type VaultProvider struct {
config *structs.VaultCAProviderConfig
client *vaultapi.Client
config *structs.VaultCAProviderConfig
client *vaultapi.Client
doneCh chan struct{}

isPrimary bool
clusterID string
spiffeID *connect.SpiffeIDSigning
setupIntermediatePKIPathDone bool
logger hclog.Logger
}

func vaultTLSConfig(config *structs.VaultCAProviderConfig) *vaultapi.TLSConfig {
Expand Down Expand Up @@ -65,10 +71,73 @@ func (v *VaultProvider) Configure(cfg ProviderConfig) error {
v.isPrimary = cfg.IsPrimary
v.clusterID = cfg.ClusterID
v.spiffeID = connect.SpiffeIDSigningForCluster(&structs.CAConfiguration{ClusterID: v.clusterID})
v.doneCh = make(chan struct{}, 0)

// Look up the token to see if we can auto-renew its lease.
secret, err := client.Auth().Token().Lookup(config.Token)
if err != nil {
return err
}
var renewable bool
if v, ok := secret.Data["renewable"]; ok {
renewable, _ = v.(bool)
}
var increment int64
if v, ok := secret.Data["ttl"]; ok {
if n, ok := v.(json.Number); ok {
increment, _ = n.Int64()
}
}
kyhavlov marked this conversation as resolved.
Show resolved Hide resolved

// Set up a renewer to renew the token automatically, if supported.
if renewable {
renewer, err := client.NewRenewer(&vaultapi.RenewerInput{
Secret: &vaultapi.Secret{
Auth: &vaultapi.SecretAuth{
ClientToken: config.Token,
Renewable: renewable,
},
},
Increment: int(increment),
})
if err != nil {
return fmt.Errorf("Error beginning Vault provider token renewal: %v", err)
}
go v.renewToken(renewer)
}

return nil
}

// renewToken uses a vaultapi.Renewer to repeatedly renew our token's lease.
func (v *VaultProvider) renewToken(renewer *vaultapi.Renewer) {
go renewer.Renew()

for {
select {
case <-v.doneCh:
renewer.Stop()
kyhavlov marked this conversation as resolved.
Show resolved Hide resolved
return

case err := <-renewer.DoneCh():
if err != nil {
v.logger.Error(fmt.Sprint("Error renewing token for Vault provider: %v", err))
}

case <-renewer.RenewCh():
v.logger.Error("Successfully renewed token for Vault provider")
}
}
}

// SetLogger implements the NeedsLogger interface so the provider can log important messages.
func (v *VaultProvider) SetLogger(logger hclog.Logger) {
v.logger = logger.
ResetNamed(logging.Connect).
Named(logging.CA).
Named(logging.Vault)
}

// State implements Provider. Vault provider needs no state other than the
// user-provided config currently.
func (v *VaultProvider) State() (map[string]string, error) {
Expand Down Expand Up @@ -431,6 +500,10 @@ func (c *VaultProvider) SupportsCrossSigning() (bool, error) {
// this down and recreate it on small config changes because the intermediate
// certs get bundled with the leaf certs, so there's no cost to the CA changing.
func (v *VaultProvider) Cleanup() error {
if v.doneCh != nil {
close(v.doneCh)
}

return v.client.Sys().Unmount(v.config.IntermediatePKIPath)
}

Expand Down
1 change: 1 addition & 0 deletions logging/names.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,5 @@ const (
Transaction string = "txn"
WAN string = "wan"
Watch string = "watch"
Vault string = "vault"
)