Add CA config to connect section of agent config

This commit is contained in:
Kyle Havlovitz 2018-04-25 11:34:08 -07:00 committed by Mitchell Hashimoto
parent 02fef5f9a2
commit 2167713226
No known key found for this signature in database
GPG key ID: 744E147AA52F5B0A
9 changed files with 86 additions and 8 deletions

View file

@ -894,6 +894,24 @@ func (a *Agent) consulConfig() (*consul.Config, error) {
base.TLSCipherSuites = a.config.TLSCipherSuites base.TLSCipherSuites = a.config.TLSCipherSuites
base.TLSPreferServerCipherSuites = a.config.TLSPreferServerCipherSuites base.TLSPreferServerCipherSuites = a.config.TLSPreferServerCipherSuites
// Copy the Connect CA bootstrap config
if a.config.ConnectEnabled {
base.ConnectEnabled = true
if a.config.ConnectCAProvider != "" {
base.CAConfig.Provider = a.config.ConnectCAProvider
// Merge with the default config if it's the consul provider.
if a.config.ConnectCAProvider == "consul" {
for k, v := range a.config.ConnectCAConfig {
base.CAConfig.Config[k] = v
}
} else {
base.CAConfig.Config = a.config.ConnectCAConfig
}
}
}
// Setup the user event callback // Setup the user event callback
base.UserEventHandler = func(e serf.UserEvent) { base.UserEventHandler = func(e serf.UserEvent) {
select { select {

View file

@ -522,6 +522,14 @@ func (b *Builder) Build() (rt RuntimeConfig, err error) {
// Connect proxy defaults. // Connect proxy defaults.
proxyBindMinPort, proxyBindMaxPort := b.connectProxyPortRange(c.Connect) proxyBindMinPort, proxyBindMaxPort := b.connectProxyPortRange(c.Connect)
var connectEnabled bool
var connectCAProvider string
var connectCAConfig map[string]interface{}
if c.Connect != nil {
connectEnabled = b.boolVal(c.Connect.Enabled)
connectCAProvider = b.stringVal(c.Connect.CAProvider)
connectCAConfig = c.Connect.CAConfig
}
// ---------------------------------------------------------------- // ----------------------------------------------------------------
// build runtime config // build runtime config
@ -641,8 +649,11 @@ func (b *Builder) Build() (rt RuntimeConfig, err error) {
CheckUpdateInterval: b.durationVal("check_update_interval", c.CheckUpdateInterval), CheckUpdateInterval: b.durationVal("check_update_interval", c.CheckUpdateInterval),
Checks: checks, Checks: checks,
ClientAddrs: clientAddrs, ClientAddrs: clientAddrs,
ConnectEnabled: connectEnabled,
ConnectProxyBindMinPort: proxyBindMinPort, ConnectProxyBindMinPort: proxyBindMinPort,
ConnectProxyBindMaxPort: proxyBindMaxPort, ConnectProxyBindMaxPort: proxyBindMaxPort,
ConnectCAProvider: connectCAProvider,
ConnectCAConfig: connectCAConfig,
DataDir: b.stringVal(c.DataDir), DataDir: b.stringVal(c.DataDir),
Datacenter: strings.ToLower(b.stringVal(c.Datacenter)), Datacenter: strings.ToLower(b.stringVal(c.Datacenter)),
DevMode: b.boolVal(b.Flags.DevMode), DevMode: b.boolVal(b.Flags.DevMode),

View file

@ -368,8 +368,10 @@ type ServiceConnectProxy struct {
type Connect struct { type Connect struct {
// Enabled opts the agent into connect. It should be set on all clients and // Enabled opts the agent into connect. It should be set on all clients and
// servers in a cluster for correct connect operation. TODO(banks) review that. // servers in a cluster for correct connect operation. TODO(banks) review that.
Enabled bool `json:"enabled,omitempty" hcl:"enabled" mapstructure:"enabled"` Enabled *bool `json:"enabled,omitempty" hcl:"enabled" mapstructure:"enabled"`
ProxyDefaults *ConnectProxyDefaults `json:"proxy_defaults,omitempty" hcl:"proxy_defaults" mapstructure:"proxy_defaults"` ProxyDefaults *ConnectProxyDefaults `json:"proxy_defaults,omitempty" hcl:"proxy_defaults" mapstructure:"proxy_defaults"`
CAProvider *string `json:"ca_provider,omitempty" hcl:"ca_provider" mapstructure:"ca_provider"`
CAConfig map[string]interface{} `json:"ca_config,omitempty" hcl:"ca_config" mapstructure:"ca_config"`
} }
// ConnectProxyDefaults is the agent-global connect proxy configuration. // ConnectProxyDefaults is the agent-global connect proxy configuration.

View file

@ -647,6 +647,12 @@ type RuntimeConfig struct {
// registration time to allow global control of defaults. // registration time to allow global control of defaults.
ConnectProxyDefaultConfig map[string]interface{} ConnectProxyDefaultConfig map[string]interface{}
// ConnectCAProvider is the type of CA provider to use with Connect.
ConnectCAProvider string
// ConnectCAConfig is the config to use for the CA provider.
ConnectCAConfig map[string]interface{}
// DNSAddrs contains the list of TCP and UDP addresses the DNS server will // DNSAddrs contains the list of TCP and UDP addresses the DNS server will
// bind to. If the DNS endpoint is disabled (ports.dns <= 0) the list is // bind to. If the DNS endpoint is disabled (ports.dns <= 0) the list is
// empty. // empty.

View file

@ -2354,6 +2354,11 @@ func TestFullConfig(t *testing.T) {
"check_update_interval": "16507s", "check_update_interval": "16507s",
"client_addr": "93.83.18.19", "client_addr": "93.83.18.19",
"connect": { "connect": {
"ca_provider": "b8j4ynx9",
"ca_config": {
"g4cvJyys": "IRLXE9Ds",
"hyMy9Oxn": "XeBp4Sis"
},
"enabled": true, "enabled": true,
"proxy_defaults": { "proxy_defaults": {
"bind_min_port": 2000, "bind_min_port": 2000,
@ -2811,6 +2816,11 @@ func TestFullConfig(t *testing.T) {
check_update_interval = "16507s" check_update_interval = "16507s"
client_addr = "93.83.18.19" client_addr = "93.83.18.19"
connect { connect {
ca_provider = "b8j4ynx9"
ca_config {
"g4cvJyys" = "IRLXE9Ds"
"hyMy9Oxn" = "XeBp4Sis"
}
enabled = true enabled = true
proxy_defaults { proxy_defaults {
bind_min_port = 2000 bind_min_port = 2000
@ -3403,10 +3413,15 @@ func TestFullConfig(t *testing.T) {
DeregisterCriticalServiceAfter: 13209 * time.Second, DeregisterCriticalServiceAfter: 13209 * time.Second,
}, },
}, },
CheckUpdateInterval: 16507 * time.Second, CheckUpdateInterval: 16507 * time.Second,
ClientAddrs: []*net.IPAddr{ipAddr("93.83.18.19")}, ClientAddrs: []*net.IPAddr{ipAddr("93.83.18.19")},
ConnectProxyBindMinPort: 2000, ConnectProxyBindMinPort: 2000,
ConnectProxyBindMaxPort: 3000, ConnectProxyBindMaxPort: 3000,
ConnectCAProvider: "b8j4ynx9",
ConnectCAConfig: map[string]interface{}{
"g4cvJyys": "IRLXE9Ds",
"hyMy9Oxn": "XeBp4Sis",
},
DNSAddrs: []net.Addr{tcpAddr("93.95.95.81:7001"), udpAddr("93.95.95.81:7001")}, DNSAddrs: []net.Addr{tcpAddr("93.95.95.81:7001"), udpAddr("93.95.95.81:7001")},
DNSARecordLimit: 29907, DNSARecordLimit: 29907,
DNSAllowStale: true, DNSAllowStale: true,

View file

@ -348,6 +348,9 @@ type Config struct {
// dead servers. // dead servers.
AutopilotInterval time.Duration AutopilotInterval time.Duration
// ConnectEnabled is whether to enable Connect features such as the CA.
ConnectEnabled bool
// CAConfig is used to apply the initial Connect CA configuration when // CAConfig is used to apply the initial Connect CA configuration when
// bootstrapping. // bootstrapping.
CAConfig *structs.CAConfiguration CAConfig *structs.CAConfiguration

View file

@ -1,6 +1,7 @@
package consul package consul
import ( import (
"errors"
"fmt" "fmt"
"reflect" "reflect"
@ -11,6 +12,8 @@ import (
"github.com/hashicorp/go-memdb" "github.com/hashicorp/go-memdb"
) )
var ErrConnectNotEnabled = errors.New("Connect must be enabled in order to use this endpoint")
// ConnectCA manages the Connect CA. // ConnectCA manages the Connect CA.
type ConnectCA struct { type ConnectCA struct {
// srv is a pointer back to the server. // srv is a pointer back to the server.
@ -21,6 +24,11 @@ type ConnectCA struct {
func (s *ConnectCA) ConfigurationGet( func (s *ConnectCA) ConfigurationGet(
args *structs.DCSpecificRequest, args *structs.DCSpecificRequest,
reply *structs.CAConfiguration) error { reply *structs.CAConfiguration) error {
// Exit early if Connect hasn't been enabled.
if !s.srv.config.ConnectEnabled {
return ErrConnectNotEnabled
}
if done, err := s.srv.forward("ConnectCA.ConfigurationGet", args, args, reply); done { if done, err := s.srv.forward("ConnectCA.ConfigurationGet", args, args, reply); done {
return err return err
} }
@ -48,6 +56,11 @@ func (s *ConnectCA) ConfigurationGet(
func (s *ConnectCA) ConfigurationSet( func (s *ConnectCA) ConfigurationSet(
args *structs.CARequest, args *structs.CARequest,
reply *interface{}) error { reply *interface{}) error {
// Exit early if Connect hasn't been enabled.
if !s.srv.config.ConnectEnabled {
return ErrConnectNotEnabled
}
if done, err := s.srv.forward("ConnectCA.ConfigurationSet", args, args, reply); done { if done, err := s.srv.forward("ConnectCA.ConfigurationSet", args, args, reply); done {
return err return err
} }
@ -244,6 +257,11 @@ func (s *ConnectCA) Roots(
func (s *ConnectCA) Sign( func (s *ConnectCA) Sign(
args *structs.CASignRequest, args *structs.CASignRequest,
reply *structs.IssuedCert) error { reply *structs.IssuedCert) error {
// Exit early if Connect hasn't been enabled.
if !s.srv.config.ConnectEnabled {
return ErrConnectNotEnabled
}
if done, err := s.srv.forward("ConnectCA.Sign", args, args, reply); done { if done, err := s.srv.forward("ConnectCA.Sign", args, args, reply); done {
return err return err
} }

View file

@ -291,7 +291,7 @@ func (c *ConsulCAProvider) CrossSignCA(cert *x509.Certificate) (string, error) {
privKey, err := connect.ParseSigner(providerState.PrivateKey) privKey, err := connect.ParseSigner(providerState.PrivateKey)
if err != nil { if err != nil {
return "", fmt.Errorf("error parsing private key %q: %v", providerState.PrivateKey, err) return "", fmt.Errorf("error parsing private key %q: %s", providerState.PrivateKey, err)
} }
rootCA, err := connect.ParseCert(providerState.RootCert) rootCA, err := connect.ParseCert(providerState.RootCert)
@ -363,7 +363,7 @@ func (c *ConsulCAProvider) generateCA(privateKey string, sn uint64) (string, err
privKey, err := connect.ParseSigner(privateKey) privKey, err := connect.ParseSigner(privateKey)
if err != nil { if err != nil {
return "", fmt.Errorf("error parsing private key %q: %v", privateKey, err) return "", fmt.Errorf("error parsing private key %q: %s", privateKey, err)
} }
name := fmt.Sprintf("Consul CA %d", sn) name := fmt.Sprintf("Consul CA %d", sn)

View file

@ -402,6 +402,11 @@ func (s *Server) initializeCAConfig() (*structs.CAConfiguration, error) {
// initializeCA sets up the CA provider when gaining leadership, bootstrapping // initializeCA sets up the CA provider when gaining leadership, bootstrapping
// the root in the state store if necessary. // the root in the state store if necessary.
func (s *Server) initializeCA() error { func (s *Server) initializeCA() error {
// Bail if connect isn't enabled.
if !s.config.ConnectEnabled {
return nil
}
conf, err := s.initializeCAConfig() conf, err := s.initializeCAConfig()
if err != nil { if err != nil {
return err return err