diff --git a/agent/connect/ca/ca_provider.go b/agent/connect/ca/provider.go similarity index 100% rename from agent/connect/ca/ca_provider.go rename to agent/connect/ca/provider.go diff --git a/agent/connect/ca/ca_provider_consul.go b/agent/connect/ca/provider_consul.go similarity index 85% rename from agent/connect/ca/ca_provider_consul.go rename to agent/connect/ca/provider_consul.go index 922472eb76..8fa1fb3d30 100644 --- a/agent/connect/ca/ca_provider_consul.go +++ b/agent/connect/ca/provider_consul.go @@ -2,8 +2,6 @@ package connect import ( "bytes" - "crypto/ecdsa" - "crypto/elliptic" "crypto/rand" "crypto/x509" "crypto/x509/pkix" @@ -20,26 +18,26 @@ import ( "github.com/mitchellh/mapstructure" ) -type ConsulCAProvider struct { +type ConsulProvider struct { config *structs.ConsulCAProviderConfig id string - delegate ConsulCAStateDelegate + delegate ConsulProviderStateDelegate sync.RWMutex } -type ConsulCAStateDelegate interface { +type ConsulProviderStateDelegate interface { State() *state.Store ApplyCARequest(*structs.CARequest) error } -// NewConsulCAProvider returns a new instance of the Consul CA provider, +// NewConsulProvider returns a new instance of the Consul CA provider, // bootstrapping its state in the state store necessary -func NewConsulCAProvider(rawConfig map[string]interface{}, delegate ConsulCAStateDelegate) (*ConsulCAProvider, error) { +func NewConsulProvider(rawConfig map[string]interface{}, delegate ConsulProviderStateDelegate) (*ConsulProvider, error) { conf, err := ParseConsulCAConfig(rawConfig) if err != nil { return nil, err } - provider := &ConsulCAProvider{ + provider := &ConsulProvider{ config: conf, delegate: delegate, id: fmt.Sprintf("%s,%s", conf.PrivateKey, conf.RootCert), @@ -81,7 +79,7 @@ func NewConsulCAProvider(rawConfig map[string]interface{}, delegate ConsulCAStat // Generate a private key if needed if conf.PrivateKey == "" { - pk, err := GeneratePrivateKey() + pk, err := connect.GeneratePrivateKey() if err != nil { return nil, err } @@ -127,7 +125,7 @@ func ParseConsulCAConfig(raw map[string]interface{}) (*structs.ConsulCAProviderC } // Return the active root CA and generate a new one if needed -func (c *ConsulCAProvider) ActiveRoot() (string, error) { +func (c *ConsulProvider) ActiveRoot() (string, error) { state := c.delegate.State() _, providerState, err := state.CAProviderState(c.id) if err != nil { @@ -139,13 +137,13 @@ func (c *ConsulCAProvider) ActiveRoot() (string, error) { // We aren't maintaining separate root/intermediate CAs for the builtin // provider, so just return the root. -func (c *ConsulCAProvider) ActiveIntermediate() (string, error) { +func (c *ConsulProvider) ActiveIntermediate() (string, error) { return c.ActiveRoot() } // We aren't maintaining separate root/intermediate CAs for the builtin // provider, so just generate a CSR for the active root. -func (c *ConsulCAProvider) GenerateIntermediate() (string, error) { +func (c *ConsulProvider) GenerateIntermediate() (string, error) { ca, err := c.ActiveIntermediate() if err != nil { return "", err @@ -157,7 +155,7 @@ func (c *ConsulCAProvider) GenerateIntermediate() (string, error) { } // Remove the state store entry for this provider instance. -func (c *ConsulCAProvider) Cleanup() error { +func (c *ConsulProvider) Cleanup() error { args := &structs.CARequest{ Op: structs.CAOpDeleteProviderState, ProviderState: &structs.CAConsulProviderState{ID: c.id}, @@ -171,7 +169,7 @@ func (c *ConsulCAProvider) Cleanup() error { // Sign returns a new certificate valid for the given SpiffeIDService // using the current CA. -func (c *ConsulCAProvider) Sign(csr *x509.CertificateRequest) (string, error) { +func (c *ConsulProvider) Sign(csr *x509.CertificateRequest) (string, error) { // Lock during the signing so we don't use the same index twice // for different cert serial numbers. c.Lock() @@ -262,7 +260,7 @@ func (c *ConsulCAProvider) Sign(csr *x509.CertificateRequest) (string, error) { } // CrossSignCA returns the given intermediate CA cert signed by the current active root. -func (c *ConsulCAProvider) CrossSignCA(cert *x509.Certificate) (string, error) { +func (c *ConsulProvider) CrossSignCA(cert *x509.Certificate) (string, error) { c.Lock() defer c.Unlock() @@ -319,7 +317,7 @@ func (c *ConsulCAProvider) CrossSignCA(cert *x509.Certificate) (string, error) { // incrementProviderIndex does a write to increment the provider state store table index // used for serial numbers when generating certificates. -func (c *ConsulCAProvider) incrementProviderIndex(providerState *structs.CAConsulProviderState) error { +func (c *ConsulProvider) incrementProviderIndex(providerState *structs.CAConsulProviderState) error { newState := *providerState args := &structs.CARequest{ Op: structs.CAOpSetProviderState, @@ -332,31 +330,8 @@ func (c *ConsulCAProvider) incrementProviderIndex(providerState *structs.CAConsu return nil } -// GeneratePrivateKey returns a new private key -func GeneratePrivateKey() (string, error) { - var pk *ecdsa.PrivateKey - - pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - return "", fmt.Errorf("error generating private key: %s", err) - } - - bs, err := x509.MarshalECPrivateKey(pk) - if err != nil { - return "", fmt.Errorf("error generating private key: %s", err) - } - - var buf bytes.Buffer - err = pem.Encode(&buf, &pem.Block{Type: "EC PRIVATE KEY", Bytes: bs}) - if err != nil { - return "", fmt.Errorf("error encoding private key: %s", err) - } - - return buf.String(), nil -} - // generateCA makes a new root CA using the current private key -func (c *ConsulCAProvider) generateCA(privateKey string, sn uint64) (string, error) { +func (c *ConsulProvider) generateCA(privateKey string, sn uint64) (string, error) { state := c.delegate.State() _, config, err := state.CAConfig() if err != nil { diff --git a/agent/connect/ca/ca_provider_consul_test.go b/agent/connect/ca/provider_consul_test.go similarity index 94% rename from agent/connect/ca/ca_provider_consul_test.go rename to agent/connect/ca/provider_consul_test.go index fd1c8ec295..9f8cc04b4a 100644 --- a/agent/connect/ca/ca_provider_consul_test.go +++ b/agent/connect/ca/provider_consul_test.go @@ -74,7 +74,7 @@ func TestCAProvider_Bootstrap(t *testing.T) { conf := testConsulCAConfig() delegate := newMockDelegate(t, conf) - provider, err := NewConsulCAProvider(conf.Config, delegate) + provider, err := NewConsulProvider(conf.Config, delegate) assert.NoError(err) root, err := provider.ActiveRoot() @@ -104,7 +104,7 @@ func TestCAProvider_Bootstrap_WithCert(t *testing.T) { } delegate := newMockDelegate(t, conf) - provider, err := NewConsulCAProvider(conf.Config, delegate) + provider, err := NewConsulProvider(conf.Config, delegate) assert.NoError(err) root, err := provider.ActiveRoot() @@ -119,7 +119,7 @@ func TestCAProvider_SignLeaf(t *testing.T) { conf := testConsulCAConfig() delegate := newMockDelegate(t, conf) - provider, err := NewConsulCAProvider(conf.Config, delegate) + provider, err := NewConsulProvider(conf.Config, delegate) assert.NoError(err) spiffeService := &connect.SpiffeIDService{ @@ -143,7 +143,7 @@ func TestCAProvider_SignLeaf(t *testing.T) { assert.NoError(err) assert.Equal(parsed.URIs[0], spiffeService.URI()) assert.Equal(parsed.Subject.CommonName, "foo") - assert.Equal(parsed.SerialNumber.Uint64(), uint64(1)) + assert.Equal(uint64(2), parsed.SerialNumber.Uint64()) // Ensure the cert is valid now and expires within the correct limit. assert.True(parsed.NotAfter.Sub(time.Now()) < 3*24*time.Hour) @@ -180,7 +180,7 @@ func TestCAProvider_CrossSignCA(t *testing.T) { assert := assert.New(t) conf := testConsulCAConfig() delegate := newMockDelegate(t, conf) - provider, err := NewConsulCAProvider(conf.Config, delegate) + provider, err := NewConsulProvider(conf.Config, delegate) assert.NoError(err) // Make a new CA cert to get cross-signed. diff --git a/agent/connect/generate.go b/agent/connect/generate.go new file mode 100644 index 0000000000..1226323f08 --- /dev/null +++ b/agent/connect/generate.go @@ -0,0 +1,34 @@ +package connect + +import ( + "bytes" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "encoding/pem" + "fmt" +) + +// GeneratePrivateKey returns a new private key +func GeneratePrivateKey() (string, error) { + var pk *ecdsa.PrivateKey + + pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return "", fmt.Errorf("error generating private key: %s", err) + } + + bs, err := x509.MarshalECPrivateKey(pk) + if err != nil { + return "", fmt.Errorf("error generating private key: %s", err) + } + + var buf bytes.Buffer + err = pem.Encode(&buf, &pem.Block{Type: "EC PRIVATE KEY", Bytes: bs}) + if err != nil { + return "", fmt.Errorf("error encoding private key: %s", err) + } + + return buf.String(), nil +} diff --git a/agent/connect_ca_endpoint_test.go b/agent/connect_ca_endpoint_test.go index 04abcfa9ac..afaa5f049b 100644 --- a/agent/connect_ca_endpoint_test.go +++ b/agent/connect_ca_endpoint_test.go @@ -8,7 +8,7 @@ import ( "time" "github.com/hashicorp/consul/agent/connect" - connect_ca "github.com/hashicorp/consul/agent/connect/ca" + ca "github.com/hashicorp/consul/agent/connect/ca" "github.com/hashicorp/consul/agent/structs" "github.com/stretchr/testify/assert" ) @@ -77,7 +77,7 @@ func TestConnectCAConfig(t *testing.T) { assert.NoError(err) value := obj.(structs.CAConfiguration) - parsed, err := connect_ca.ParseConsulCAConfig(value.Config) + parsed, err := ca.ParseConsulCAConfig(value.Config) assert.NoError(err) assert.Equal("consul", value.Provider) assert.Equal(expected, parsed) @@ -107,8 +107,7 @@ func TestConnectCAConfig(t *testing.T) { assert.NoError(err) value := obj.(structs.CAConfiguration) - //t.Fatalf("%#v", value) - parsed, err := connect_ca.ParseConsulCAConfig(value.Config) + parsed, err := ca.ParseConsulCAConfig(value.Config) assert.NoError(err) assert.Equal("consul", value.Provider) assert.Equal(expected, parsed) diff --git a/agent/consul/connect_ca_endpoint_test.go b/agent/consul/connect_ca_endpoint_test.go index 49baddfb9a..4609934ada 100644 --- a/agent/consul/connect_ca_endpoint_test.go +++ b/agent/consul/connect_ca_endpoint_test.go @@ -7,7 +7,7 @@ import ( "time" "github.com/hashicorp/consul/agent/connect" - connect_ca "github.com/hashicorp/consul/agent/connect/ca" + ca "github.com/hashicorp/consul/agent/connect/ca" "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/testrpc" "github.com/hashicorp/net-rpc-msgpackrpc" @@ -83,9 +83,9 @@ func TestConnectCAConfig_GetSet(t *testing.T) { var reply structs.CAConfiguration assert.NoError(msgpackrpc.CallWithCodec(codec, "ConnectCA.ConfigurationGet", args, &reply)) - actual, err := connect_ca.ParseConsulCAConfig(reply.Config) + actual, err := ca.ParseConsulCAConfig(reply.Config) assert.NoError(err) - expected, err := connect_ca.ParseConsulCAConfig(s1.config.CAConfig.Config) + expected, err := ca.ParseConsulCAConfig(s1.config.CAConfig.Config) assert.NoError(err) assert.Equal(reply.Provider, s1.config.CAConfig.Provider) assert.Equal(actual, expected) @@ -118,9 +118,9 @@ func TestConnectCAConfig_GetSet(t *testing.T) { var reply structs.CAConfiguration assert.NoError(msgpackrpc.CallWithCodec(codec, "ConnectCA.ConfigurationGet", args, &reply)) - actual, err := connect_ca.ParseConsulCAConfig(reply.Config) + actual, err := ca.ParseConsulCAConfig(reply.Config) assert.NoError(err) - expected, err := connect_ca.ParseConsulCAConfig(newConfig.Config) + expected, err := ca.ParseConsulCAConfig(newConfig.Config) assert.NoError(err) assert.Equal(reply.Provider, newConfig.Provider) assert.Equal(actual, expected) @@ -150,7 +150,7 @@ func TestConnectCAConfig_TriggerRotation(t *testing.T) { // Update the provider config to use a new private key, which should // cause a rotation. - newKey, err := connect_ca.GeneratePrivateKey() + newKey, err := connect.GeneratePrivateKey() assert.NoError(err) newConfig := &structs.CAConfiguration{ Provider: "consul", @@ -220,9 +220,9 @@ func TestConnectCAConfig_TriggerRotation(t *testing.T) { var reply structs.CAConfiguration assert.NoError(msgpackrpc.CallWithCodec(codec, "ConnectCA.ConfigurationGet", args, &reply)) - actual, err := connect_ca.ParseConsulCAConfig(reply.Config) + actual, err := ca.ParseConsulCAConfig(reply.Config) assert.NoError(err) - expected, err := connect_ca.ParseConsulCAConfig(newConfig.Config) + expected, err := ca.ParseConsulCAConfig(newConfig.Config) assert.NoError(err) assert.Equal(reply.Provider, newConfig.Provider) assert.Equal(actual, expected) diff --git a/agent/consul/leader.go b/agent/consul/leader.go index a06871888e..579ff4b1dc 100644 --- a/agent/consul/leader.go +++ b/agent/consul/leader.go @@ -11,7 +11,7 @@ import ( "github.com/armon/go-metrics" "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/connect" - connect_ca "github.com/hashicorp/consul/agent/connect/ca" + ca "github.com/hashicorp/consul/agent/connect/ca" "github.com/hashicorp/consul/agent/consul/autopilot" "github.com/hashicorp/consul/agent/metadata" "github.com/hashicorp/consul/agent/structs" @@ -496,18 +496,18 @@ func parseCARoot(pemValue, provider string) (*structs.CARoot, error) { } // createProvider returns a connect CA provider from the given config. -func (s *Server) createCAProvider(conf *structs.CAConfiguration) (connect_ca.Provider, error) { +func (s *Server) createCAProvider(conf *structs.CAConfiguration) (ca.Provider, error) { switch conf.Provider { case structs.ConsulCAProvider: - return connect_ca.NewConsulCAProvider(conf.Config, &consulCADelegate{s}) + return ca.NewConsulProvider(conf.Config, &consulCADelegate{s}) default: return nil, fmt.Errorf("unknown CA provider %q", conf.Provider) } } -func (s *Server) getCAProvider() connect.CAProvider { +func (s *Server) getCAProvider() ca.Provider { retries := 0 - var result connect.CAProvider + var result ca.Provider for result == nil { s.caProviderLock.RLock() result = s.caProvider @@ -528,7 +528,7 @@ func (s *Server) getCAProvider() connect.CAProvider { return result } -func (s *Server) setCAProvider(newProvider connect_ca.Provider) { +func (s *Server) setCAProvider(newProvider ca.Provider) { s.caProviderLock.Lock() defer s.caProviderLock.Unlock() s.caProvider = newProvider diff --git a/agent/consul/server.go b/agent/consul/server.go index 871115c359..7b589d753b 100644 --- a/agent/consul/server.go +++ b/agent/consul/server.go @@ -18,7 +18,7 @@ import ( "time" "github.com/hashicorp/consul/acl" - connect_ca "github.com/hashicorp/consul/agent/connect/ca" + ca "github.com/hashicorp/consul/agent/connect/ca" "github.com/hashicorp/consul/agent/consul/autopilot" "github.com/hashicorp/consul/agent/consul/fsm" "github.com/hashicorp/consul/agent/consul/state" @@ -99,7 +99,7 @@ type Server struct { // caProvider is the current CA provider in use for Connect. This is // only non-nil when we are the leader. - caProvider connect_ca.Provider + caProvider ca.Provider caProviderLock sync.RWMutex // Consul configuration