mirror of https://github.com/status-im/consul.git
Move generation of the CA Configuration from the agent code into a method on the RuntimeConfig (#8363)
This allows this to be reused elsewhere.
This commit is contained in:
parent
bd8d3afc6a
commit
2ee9fe0a4d
|
@ -1460,38 +1460,12 @@ func (a *Agent) consulConfig() (*consul.Config, error) {
|
||||||
base.ConnectEnabled = true
|
base.ConnectEnabled = true
|
||||||
base.ConnectMeshGatewayWANFederationEnabled = a.config.ConnectMeshGatewayWANFederationEnabled
|
base.ConnectMeshGatewayWANFederationEnabled = a.config.ConnectMeshGatewayWANFederationEnabled
|
||||||
|
|
||||||
// Allow config to specify cluster_id provided it's a valid UUID. This is
|
ca, err := a.config.ConnectCAConfiguration()
|
||||||
// meant only for tests where a deterministic ID makes fixtures much simpler
|
if err != nil {
|
||||||
// to work with but since it's only read on initial cluster bootstrap it's not
|
return nil, err
|
||||||
// that much of a liability in production. The worst a user could do is
|
|
||||||
// configure logically separate clusters with same ID by mistake but we can
|
|
||||||
// avoid documenting this is even an option.
|
|
||||||
if clusterID, ok := a.config.ConnectCAConfig["cluster_id"]; ok {
|
|
||||||
if cIDStr, ok := clusterID.(string); ok {
|
|
||||||
if _, err := uuid.ParseUUID(cIDStr); err == nil {
|
|
||||||
// Valid UUID configured, use that
|
|
||||||
base.CAConfig.ClusterID = cIDStr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if base.CAConfig.ClusterID == "" {
|
|
||||||
// If the tried to specify an ID but typoed it don't ignore as they will
|
|
||||||
// then bootstrap with a new ID and have to throw away the whole cluster
|
|
||||||
// and start again.
|
|
||||||
a.logger.Error("connect CA config cluster_id specified but " +
|
|
||||||
"is not a valid UUID, aborting startup")
|
|
||||||
return nil, fmt.Errorf("cluster_id was supplied but was not a valid UUID")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.config.ConnectCAProvider != "" {
|
base.CAConfig = ca
|
||||||
base.CAConfig.Provider = a.config.ConnectCAProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge connect CA Config regardless of provider (since there are some
|
|
||||||
// common config options valid to all like leaf TTL).
|
|
||||||
for k, v := range a.config.ConnectCAConfig {
|
|
||||||
base.CAConfig.Config[k] = v
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy over auto config settings
|
// copy over auto config settings
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/hashicorp/consul/lib"
|
"github.com/hashicorp/consul/lib"
|
||||||
"github.com/hashicorp/consul/tlsutil"
|
"github.com/hashicorp/consul/tlsutil"
|
||||||
"github.com/hashicorp/consul/types"
|
"github.com/hashicorp/consul/types"
|
||||||
|
"github.com/hashicorp/go-uuid"
|
||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1686,6 +1687,60 @@ func (c *RuntimeConfig) ClientAddress() (unixAddr, httpAddr, httpsAddr string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *RuntimeConfig) ConnectCAConfiguration() (*structs.CAConfiguration, error) {
|
||||||
|
if !c.ConnectEnabled {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ca := &structs.CAConfiguration{
|
||||||
|
Provider: "consul",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"RotationPeriod": structs.DefaultCARotationPeriod,
|
||||||
|
"LeafCertTTL": structs.DefaultLeafCertTTL,
|
||||||
|
"IntermediateCertTTL": structs.DefaultIntermediateCertTTL,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow config to specify cluster_id provided it's a valid UUID. This is
|
||||||
|
// meant only for tests where a deterministic ID makes fixtures much simpler
|
||||||
|
// to work with but since it's only read on initial cluster bootstrap it's not
|
||||||
|
// that much of a liability in production. The worst a user could do is
|
||||||
|
// configure logically separate clusters with same ID by mistake but we can
|
||||||
|
// avoid documenting this is even an option.
|
||||||
|
if clusterID, ok := c.ConnectCAConfig["cluster_id"]; ok {
|
||||||
|
// If they tried to specify an ID but typoed it then don't ignore as they
|
||||||
|
// will then bootstrap with a new ID and have to throw away the whole cluster
|
||||||
|
// and start again.
|
||||||
|
|
||||||
|
// ensure the cluster_id value in the opaque config is a string
|
||||||
|
cIDStr, ok := clusterID.(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("cluster_id was supplied but was not a string")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure that the cluster_id string is a valid UUID
|
||||||
|
_, err := uuid.ParseUUID(cIDStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cluster_id was supplied but was not a valid UUID")
|
||||||
|
}
|
||||||
|
|
||||||
|
// now that we know the cluster_id is okay we can set it in the CAConfiguration
|
||||||
|
ca.ClusterID = cIDStr
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.ConnectCAProvider != "" {
|
||||||
|
ca.Provider = c.ConnectCAProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge connect CA Config regardless of provider (since there are some
|
||||||
|
// common config options valid to all like leaf TTL).
|
||||||
|
for k, v := range c.ConnectCAConfig {
|
||||||
|
ca.Config[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return ca, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *RuntimeConfig) APIConfig(includeClientCerts bool) (*api.Config, error) {
|
func (c *RuntimeConfig) APIConfig(includeClientCerts bool) (*api.Config, error) {
|
||||||
cfg := &api.Config{
|
cfg := &api.Config{
|
||||||
Datacenter: c.Datacenter,
|
Datacenter: c.Datacenter,
|
||||||
|
|
|
@ -7440,3 +7440,103 @@ func metaPairs(n int, format string) string {
|
||||||
panic("invalid format: " + format)
|
panic("invalid format: " + format)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConnectCAConfiguration(t *testing.T) {
|
||||||
|
type testCase struct {
|
||||||
|
config RuntimeConfig
|
||||||
|
expected *structs.CAConfiguration
|
||||||
|
err string
|
||||||
|
}
|
||||||
|
|
||||||
|
cases := map[string]testCase{
|
||||||
|
"connect-disabled": {
|
||||||
|
config: RuntimeConfig{
|
||||||
|
ConnectEnabled: false,
|
||||||
|
},
|
||||||
|
expected: nil,
|
||||||
|
},
|
||||||
|
"defaults": {
|
||||||
|
config: RuntimeConfig{
|
||||||
|
ConnectEnabled: true,
|
||||||
|
},
|
||||||
|
expected: &structs.CAConfiguration{
|
||||||
|
Provider: "consul",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"RotationPeriod": "2160h",
|
||||||
|
"LeafCertTTL": "72h",
|
||||||
|
"IntermediateCertTTL": "8760h", // 365 * 24h
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"cluster-id-override": {
|
||||||
|
config: RuntimeConfig{
|
||||||
|
ConnectEnabled: true,
|
||||||
|
ConnectCAConfig: map[string]interface{}{
|
||||||
|
"cluster_id": "adfe7697-09b4-413a-ac0a-fa81ed3a3001",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: &structs.CAConfiguration{
|
||||||
|
Provider: "consul",
|
||||||
|
ClusterID: "adfe7697-09b4-413a-ac0a-fa81ed3a3001",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"RotationPeriod": "2160h",
|
||||||
|
"LeafCertTTL": "72h",
|
||||||
|
"IntermediateCertTTL": "8760h", // 365 * 24h
|
||||||
|
"cluster_id": "adfe7697-09b4-413a-ac0a-fa81ed3a3001",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"cluster-id-non-uuid": {
|
||||||
|
config: RuntimeConfig{
|
||||||
|
ConnectEnabled: true,
|
||||||
|
ConnectCAConfig: map[string]interface{}{
|
||||||
|
"cluster_id": "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err: "cluster_id was supplied but was not a valid UUID",
|
||||||
|
},
|
||||||
|
"provider-override": {
|
||||||
|
config: RuntimeConfig{
|
||||||
|
ConnectEnabled: true,
|
||||||
|
ConnectCAProvider: "vault",
|
||||||
|
},
|
||||||
|
expected: &structs.CAConfiguration{
|
||||||
|
Provider: "vault",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"RotationPeriod": "2160h",
|
||||||
|
"LeafCertTTL": "72h",
|
||||||
|
"IntermediateCertTTL": "8760h", // 365 * 24h
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"other-config": {
|
||||||
|
config: RuntimeConfig{
|
||||||
|
ConnectEnabled: true,
|
||||||
|
ConnectCAConfig: map[string]interface{}{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: &structs.CAConfiguration{
|
||||||
|
Provider: "consul",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"RotationPeriod": "2160h",
|
||||||
|
"LeafCertTTL": "72h",
|
||||||
|
"IntermediateCertTTL": "8760h", // 365 * 24h
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tcase := range cases {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
actual, err := tcase.config.ConnectCAConfiguration()
|
||||||
|
if tcase.err != "" {
|
||||||
|
testutil.RequireErrorContains(t, err, tcase.err)
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, tcase.expected, actual)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -594,9 +594,9 @@ func DefaultConfig() *Config {
|
||||||
CAConfig: &structs.CAConfiguration{
|
CAConfig: &structs.CAConfiguration{
|
||||||
Provider: "consul",
|
Provider: "consul",
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"RotationPeriod": "2160h",
|
"RotationPeriod": structs.DefaultCARotationPeriod,
|
||||||
"LeafCertTTL": "72h",
|
"LeafCertTTL": structs.DefaultLeafCertTTL,
|
||||||
"IntermediateCertTTL": "8760h", // 365 * 24h
|
"IntermediateCertTTL": structs.DefaultIntermediateCertTTL,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,12 @@ import (
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultCARotationPeriod = "2160h"
|
||||||
|
DefaultLeafCertTTL = "72h"
|
||||||
|
DefaultIntermediateCertTTL = "8760h" // 365 * 24h
|
||||||
|
)
|
||||||
|
|
||||||
// IndexedCARoots is the list of currently trusted CA Roots.
|
// IndexedCARoots is the list of currently trusted CA Roots.
|
||||||
type IndexedCARoots struct {
|
type IndexedCARoots struct {
|
||||||
// ActiveRootID is the ID of a root in Roots that is the active CA root.
|
// ActiveRootID is the ID of a root in Roots that is the active CA root.
|
||||||
|
|
Loading…
Reference in New Issue