Support giving the duration as a string in CA config

This commit is contained in:
Kyle Havlovitz 2018-05-23 14:43:40 -07:00 committed by Mitchell Hashimoto
parent 118aa0f00a
commit 4d46bba2c4
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
5 changed files with 103 additions and 17 deletions

View File

@ -1,4 +1,4 @@
package connect
package ca
import (
"crypto/x509"

View File

@ -1,4 +1,4 @@
package connect
package ca
import (
"bytes"
@ -15,7 +15,6 @@ import (
"github.com/hashicorp/consul/agent/connect"
"github.com/hashicorp/consul/agent/consul/state"
"github.com/hashicorp/consul/agent/structs"
"github.com/mitchellh/mapstructure"
)
type ConsulProvider struct {
@ -111,19 +110,6 @@ func NewConsulProvider(rawConfig map[string]interface{}, delegate ConsulProvider
return provider, nil
}
func ParseConsulCAConfig(raw map[string]interface{}) (*structs.ConsulCAProviderConfig, error) {
var config structs.ConsulCAProviderConfig
if err := mapstructure.WeakDecode(raw, &config); err != nil {
return nil, fmt.Errorf("error decoding config: %s", err)
}
if config.PrivateKey == "" && config.RootCert != "" {
return nil, fmt.Errorf("must provide a private key when providing a root cert")
}
return &config, nil
}
// Return the active root CA and generate a new one if needed
func (c *ConsulProvider) ActiveRoot() (string, error) {
state := c.delegate.State()

View File

@ -0,0 +1,77 @@
package ca
import (
"fmt"
"reflect"
"time"
"github.com/hashicorp/consul/agent/structs"
"github.com/mitchellh/mapstructure"
)
func ParseConsulCAConfig(raw map[string]interface{}) (*structs.ConsulCAProviderConfig, error) {
var config structs.ConsulCAProviderConfig
decodeConf := &mapstructure.DecoderConfig{
DecodeHook: ParseDurationFunc(),
ErrorUnused: true,
Result: &config,
WeaklyTypedInput: true,
}
decoder, err := mapstructure.NewDecoder(decodeConf)
if err != nil {
return nil, err
}
if err := decoder.Decode(raw); err != nil {
return nil, fmt.Errorf("error decoding config: %s", err)
}
if config.PrivateKey == "" && config.RootCert != "" {
return nil, fmt.Errorf("must provide a private key when providing a root cert")
}
return &config, nil
}
// ParseDurationFunc is a mapstructure hook for decoding a string or
// []uint8 into a time.Duration value.
func ParseDurationFunc() mapstructure.DecodeHookFunc {
uint8ToString := func(bs []uint8) string {
b := make([]byte, len(bs))
for i, v := range bs {
b[i] = byte(v)
}
return string(b)
}
return func(
f reflect.Type,
t reflect.Type,
data interface{}) (interface{}, error) {
var v time.Duration
if t != reflect.TypeOf(v) {
return data, nil
}
switch {
case f.Kind() == reflect.String:
if dur, err := time.ParseDuration(data.(string)); err != nil {
return nil, err
} else {
v = dur
}
return v, nil
case f == reflect.SliceOf(reflect.TypeOf(uint8(0))):
s := uint8ToString(data.([]uint8))
if dur, err := time.ParseDuration(s); err != nil {
return nil, err
} else {
v = dur
}
return v, nil
default:
return data, nil
}
}
}

View File

@ -1,4 +1,4 @@
package connect
package ca
import (
"fmt"

View File

@ -47,6 +47,7 @@ func (s *HTTPServer) ConnectCAConfigurationGet(resp http.ResponseWriter, req *ht
var reply structs.CAConfiguration
err := s.agent.RPC("ConnectCA.ConfigurationGet", &args, &reply)
fixupConfig(&reply)
return reply, err
}
@ -67,3 +68,25 @@ func (s *HTTPServer) ConnectCAConfigurationSet(resp http.ResponseWriter, req *ht
err := s.agent.RPC("ConnectCA.ConfigurationSet", &args, &reply)
return nil, err
}
// A hack to fix up the config types inside of the map[string]interface{}
// so that they get formatted correctly during json.Marshal. Without this,
// duration values given as text like "24h" end up getting output back
// to the user in base64-encoded form.
func fixupConfig(conf *structs.CAConfiguration) {
if conf.Provider == structs.ConsulCAProvider {
if v, ok := conf.Config["RotationPeriod"]; ok {
if raw, ok := v.([]uint8); ok {
conf.Config["RotationPeriod"] = uint8ToString(raw)
}
}
}
}
func uint8ToString(bs []uint8) string {
b := make([]byte, len(bs))
for i, v := range bs {
b[i] = byte(v)
}
return string(b)
}