2023-03-28 18:39:22 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
2023-08-11 13:12:13 +00:00
|
|
|
// SPDX-License-Identifier: BUSL-1.1
|
2023-03-28 18:39:22 +00:00
|
|
|
|
2020-02-07 21:50:24 +00:00
|
|
|
package ca
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2022-02-14 17:45:45 +00:00
|
|
|
"github.com/hashicorp/consul-net-rpc/go-msgpack/codec"
|
2020-02-07 21:50:24 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2021-07-05 23:10:23 +00:00
|
|
|
|
|
|
|
"github.com/hashicorp/consul/agent/structs"
|
2020-02-07 21:50:24 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestStructs_CAConfiguration_MsgpackEncodeDecode(t *testing.T) {
|
|
|
|
type testcase struct {
|
|
|
|
in *structs.CAConfiguration
|
|
|
|
expectConfig interface{} // provider specific
|
|
|
|
parseFunc func(*testing.T, map[string]interface{}) interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
commonBaseMap := map[string]interface{}{
|
|
|
|
"LeafCertTTL": "30h",
|
|
|
|
"SkipValidate": true,
|
|
|
|
"CSRMaxPerSecond": 5.25,
|
|
|
|
"CSRMaxConcurrent": int64(55),
|
|
|
|
"PrivateKeyType": "rsa",
|
|
|
|
"PrivateKeyBits": int64(4096),
|
|
|
|
}
|
|
|
|
expectCommonBase := &structs.CommonCAProviderConfig{
|
2020-09-10 06:04:56 +00:00
|
|
|
LeafCertTTL: 30 * time.Hour,
|
|
|
|
IntermediateCertTTL: 90 * time.Hour,
|
|
|
|
SkipValidate: true,
|
|
|
|
CSRMaxPerSecond: 5.25,
|
|
|
|
CSRMaxConcurrent: 55,
|
|
|
|
PrivateKeyType: "rsa",
|
|
|
|
PrivateKeyBits: 4096,
|
2021-11-02 18:02:10 +00:00
|
|
|
RootCertTTL: 10 * 24 * 365 * time.Hour,
|
2020-02-07 21:50:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cases := map[string]testcase{
|
|
|
|
structs.ConsulCAProvider: {
|
|
|
|
in: &structs.CAConfiguration{
|
|
|
|
ClusterID: "abc",
|
|
|
|
Provider: structs.ConsulCAProvider,
|
|
|
|
State: map[string]string{
|
|
|
|
"foo": "bar",
|
|
|
|
},
|
|
|
|
ForceWithoutCrossSigning: true,
|
|
|
|
RaftIndex: structs.RaftIndex{
|
|
|
|
CreateIndex: 5,
|
|
|
|
ModifyIndex: 99,
|
|
|
|
},
|
|
|
|
Config: map[string]interface{}{
|
|
|
|
"PrivateKey": "key",
|
|
|
|
"RootCert": "cert",
|
2021-07-05 23:10:23 +00:00
|
|
|
"RotationPeriod": "5m", // old unused field
|
2020-02-10 23:05:49 +00:00
|
|
|
"IntermediateCertTTL": "90h",
|
2020-02-07 21:50:24 +00:00
|
|
|
"DisableCrossSigning": true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expectConfig: &structs.ConsulCAProviderConfig{
|
|
|
|
CommonCAProviderConfig: *expectCommonBase,
|
|
|
|
PrivateKey: "key",
|
|
|
|
RootCert: "cert",
|
|
|
|
DisableCrossSigning: true,
|
|
|
|
},
|
|
|
|
parseFunc: func(t *testing.T, raw map[string]interface{}) interface{} {
|
|
|
|
config, err := ParseConsulCAConfig(raw)
|
|
|
|
require.NoError(t, err)
|
|
|
|
return config
|
|
|
|
},
|
|
|
|
},
|
|
|
|
structs.VaultCAProvider: {
|
|
|
|
in: &structs.CAConfiguration{
|
|
|
|
ClusterID: "abc",
|
|
|
|
Provider: structs.VaultCAProvider,
|
|
|
|
State: map[string]string{
|
|
|
|
"foo": "bar",
|
|
|
|
},
|
|
|
|
ForceWithoutCrossSigning: true,
|
|
|
|
RaftIndex: structs.RaftIndex{
|
|
|
|
CreateIndex: 5,
|
|
|
|
ModifyIndex: 99,
|
|
|
|
},
|
|
|
|
Config: map[string]interface{}{
|
|
|
|
"Address": "addr",
|
|
|
|
"Token": "token",
|
|
|
|
"RootPKIPath": "root-pki/",
|
|
|
|
"IntermediatePKIPath": "im-pki/",
|
2020-09-10 06:04:56 +00:00
|
|
|
"IntermediateCertTTL": "90h",
|
2020-02-07 21:50:24 +00:00
|
|
|
"CAFile": "ca-file",
|
|
|
|
"CAPath": "ca-path",
|
|
|
|
"CertFile": "cert-file",
|
|
|
|
"KeyFile": "key-file",
|
|
|
|
"TLSServerName": "server-name",
|
|
|
|
"TLSSkipVerify": true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expectConfig: &structs.VaultCAProviderConfig{
|
|
|
|
CommonCAProviderConfig: *expectCommonBase,
|
|
|
|
Address: "addr",
|
|
|
|
Token: "token",
|
|
|
|
RootPKIPath: "root-pki/",
|
|
|
|
IntermediatePKIPath: "im-pki/",
|
|
|
|
CAFile: "ca-file",
|
|
|
|
CAPath: "ca-path",
|
|
|
|
CertFile: "cert-file",
|
|
|
|
KeyFile: "key-file",
|
|
|
|
TLSServerName: "server-name",
|
|
|
|
TLSSkipVerify: true,
|
|
|
|
},
|
|
|
|
parseFunc: func(t *testing.T, raw map[string]interface{}) interface{} {
|
2023-06-21 19:34:42 +00:00
|
|
|
config, err := ParseVaultCAConfig(raw, true)
|
2020-02-07 21:50:24 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
return config
|
|
|
|
},
|
|
|
|
},
|
|
|
|
structs.AWSCAProvider: {
|
|
|
|
in: &structs.CAConfiguration{
|
|
|
|
ClusterID: "abc",
|
|
|
|
Provider: structs.AWSCAProvider,
|
|
|
|
State: map[string]string{
|
|
|
|
"foo": "bar",
|
|
|
|
},
|
|
|
|
ForceWithoutCrossSigning: true,
|
|
|
|
RaftIndex: structs.RaftIndex{
|
|
|
|
CreateIndex: 5,
|
|
|
|
ModifyIndex: 99,
|
|
|
|
},
|
|
|
|
Config: map[string]interface{}{
|
2020-09-10 06:04:56 +00:00
|
|
|
"ExistingARN": "arn://foo",
|
|
|
|
"DeleteOnExit": true,
|
|
|
|
"IntermediateCertTTL": "90h",
|
2020-02-07 21:50:24 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
expectConfig: &structs.AWSCAProviderConfig{
|
|
|
|
CommonCAProviderConfig: *expectCommonBase,
|
|
|
|
ExistingARN: "arn://foo",
|
|
|
|
DeleteOnExit: true,
|
|
|
|
},
|
|
|
|
parseFunc: func(t *testing.T, raw map[string]interface{}) interface{} {
|
|
|
|
config, err := ParseAWSCAConfig(raw)
|
|
|
|
require.NoError(t, err)
|
|
|
|
return config
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
// underlay common ca config stuff
|
|
|
|
for _, tc := range cases {
|
|
|
|
for k, v := range commonBaseMap {
|
|
|
|
if _, ok := tc.in.Config[k]; !ok {
|
|
|
|
tc.in.Config[k] = v
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
// This is the common configuration pre-1.7.0
|
|
|
|
handle1 = structs.TestingOldPre1dot7MsgpackHandle
|
|
|
|
// This is the common configuration post-1.7.0
|
|
|
|
handle2 = structs.MsgpackHandle
|
|
|
|
)
|
|
|
|
|
|
|
|
decoderCase := func(t *testing.T, tc testcase, encHandle, decHandle *codec.MsgpackHandle) {
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
enc := codec.NewEncoder(&buf, encHandle)
|
|
|
|
require.NoError(t, enc.Encode(tc.in))
|
|
|
|
|
|
|
|
out := &structs.CAConfiguration{}
|
|
|
|
dec := codec.NewDecoder(&buf, decHandle)
|
|
|
|
require.NoError(t, dec.Decode(out))
|
|
|
|
|
|
|
|
config := tc.parseFunc(t, out.Config)
|
|
|
|
|
|
|
|
out.Config = tc.in.Config // no longer care about how this field decoded
|
|
|
|
require.Equal(t, tc.in, out)
|
|
|
|
require.Equal(t, tc.expectConfig, config)
|
|
|
|
// TODO: verify json?
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range cases {
|
|
|
|
tc := tc
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
t.Run("old encoder and old decoder", func(t *testing.T) {
|
|
|
|
decoderCase(t, tc, handle1, handle1)
|
|
|
|
})
|
|
|
|
t.Run("old encoder and new decoder", func(t *testing.T) {
|
|
|
|
decoderCase(t, tc, handle1, handle2)
|
|
|
|
})
|
|
|
|
t.Run("new encoder and old decoder", func(t *testing.T) {
|
|
|
|
decoderCase(t, tc, handle2, handle1)
|
|
|
|
})
|
|
|
|
t.Run("new encoder and new decoder", func(t *testing.T) {
|
|
|
|
decoderCase(t, tc, handle2, handle2)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|