2020-06-10 20:47:35 +00:00
|
|
|
package autoconf
|
|
|
|
|
|
|
|
import (
|
2020-07-28 19:31:48 +00:00
|
|
|
"fmt"
|
|
|
|
|
2020-08-10 17:03:33 +00:00
|
|
|
"github.com/hashicorp/consul/agent/config"
|
2020-07-28 19:31:48 +00:00
|
|
|
"github.com/hashicorp/consul/agent/structs"
|
|
|
|
"github.com/hashicorp/consul/proto"
|
|
|
|
"github.com/hashicorp/consul/proto/pbautoconf"
|
2020-07-23 15:24:20 +00:00
|
|
|
"github.com/hashicorp/consul/proto/pbconfig"
|
2020-07-28 19:31:48 +00:00
|
|
|
"github.com/hashicorp/consul/proto/pbconnect"
|
|
|
|
"github.com/mitchellh/mapstructure"
|
2020-06-10 20:47:35 +00:00
|
|
|
)
|
|
|
|
|
2020-07-23 15:24:20 +00:00
|
|
|
// translateAgentConfig is meant to take in a proto/pbconfig.Config type
|
2020-06-10 20:47:35 +00:00
|
|
|
// and craft the corresponding agent/config.Config type. The need for this function
|
|
|
|
// should eventually be removed with the protobuf and normal version converging.
|
|
|
|
// In the meantime, its not desirable to have the flatter Config struct in protobufs
|
|
|
|
// as in the long term we want a configuration with more nested groupings.
|
|
|
|
//
|
2020-07-23 15:24:20 +00:00
|
|
|
// Why is this function not in the proto/pbconfig package? The answer, that
|
2020-06-10 20:47:35 +00:00
|
|
|
// package cannot import the agent/config package without running into import cycles.
|
2020-08-10 17:03:33 +00:00
|
|
|
func translateConfig(c *pbconfig.Config) config.Config {
|
|
|
|
result := config.Config{
|
2020-08-31 17:12:17 +00:00
|
|
|
Datacenter: stringPtrOrNil(c.Datacenter),
|
|
|
|
PrimaryDatacenter: stringPtrOrNil(c.PrimaryDatacenter),
|
|
|
|
NodeName: stringPtrOrNil(c.NodeName),
|
2020-08-10 17:03:33 +00:00
|
|
|
// only output the SegmentName in the configuration if its non-empty
|
|
|
|
// this will avoid a warning later when parsing the persisted configuration
|
|
|
|
SegmentName: stringPtrOrNil(c.SegmentName),
|
2020-06-10 20:47:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if a := c.AutoEncrypt; a != nil {
|
2020-08-10 17:03:33 +00:00
|
|
|
result.AutoEncrypt = config.AutoEncrypt{
|
|
|
|
TLS: &a.TLS,
|
|
|
|
DNSSAN: a.DNSSAN,
|
|
|
|
IPSAN: a.IPSAN,
|
|
|
|
AllowTLS: &a.AllowTLS,
|
2020-06-26 18:53:07 +00:00
|
|
|
}
|
2020-06-10 20:47:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if a := c.ACL; a != nil {
|
2020-08-10 17:03:33 +00:00
|
|
|
result.ACL = config.ACL{
|
|
|
|
Enabled: &a.Enabled,
|
2020-08-31 17:12:17 +00:00
|
|
|
PolicyTTL: stringPtrOrNil(a.PolicyTTL),
|
|
|
|
RoleTTL: stringPtrOrNil(a.RoleTTL),
|
|
|
|
TokenTTL: stringPtrOrNil(a.TokenTTL),
|
|
|
|
DownPolicy: stringPtrOrNil(a.DownPolicy),
|
|
|
|
DefaultPolicy: stringPtrOrNil(a.DefaultPolicy),
|
2020-08-10 17:03:33 +00:00
|
|
|
EnableKeyListPolicy: &a.EnableKeyListPolicy,
|
2020-08-31 17:12:17 +00:00
|
|
|
DisabledTTL: stringPtrOrNil(a.DisabledTTL),
|
2020-08-10 17:03:33 +00:00
|
|
|
EnableTokenPersistence: &a.EnableTokenPersistence,
|
2020-06-10 20:47:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if t := c.ACL.Tokens; t != nil {
|
2020-08-10 17:03:33 +00:00
|
|
|
tokens := make([]config.ServiceProviderToken, 0, len(t.ManagedServiceProvider))
|
2020-06-10 20:47:35 +00:00
|
|
|
for _, mspToken := range t.ManagedServiceProvider {
|
2020-08-10 17:03:33 +00:00
|
|
|
tokens = append(tokens, config.ServiceProviderToken{
|
|
|
|
AccessorID: &mspToken.AccessorID,
|
|
|
|
SecretID: &mspToken.SecretID,
|
2020-06-10 20:47:35 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-08-10 17:03:33 +00:00
|
|
|
result.ACL.Tokens = config.Tokens{
|
|
|
|
Master: stringPtrOrNil(t.Master),
|
|
|
|
Replication: stringPtrOrNil(t.Replication),
|
|
|
|
AgentMaster: stringPtrOrNil(t.AgentMaster),
|
|
|
|
Default: stringPtrOrNil(t.Default),
|
|
|
|
Agent: stringPtrOrNil(t.Agent),
|
|
|
|
ManagedServiceProvider: tokens,
|
2020-06-26 18:53:07 +00:00
|
|
|
}
|
2020-06-10 20:47:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if g := c.Gossip; g != nil {
|
2020-08-10 17:03:33 +00:00
|
|
|
result.RetryJoinLAN = g.RetryJoinLAN
|
2020-06-10 20:47:35 +00:00
|
|
|
|
|
|
|
if e := c.Gossip.Encryption; e != nil {
|
2020-08-31 17:12:17 +00:00
|
|
|
result.EncryptKey = stringPtrOrNil(e.Key)
|
2020-08-10 17:03:33 +00:00
|
|
|
result.EncryptVerifyIncoming = &e.VerifyIncoming
|
|
|
|
result.EncryptVerifyOutgoing = &e.VerifyOutgoing
|
2020-06-10 20:47:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if t := c.TLS; t != nil {
|
2020-08-10 17:03:33 +00:00
|
|
|
result.VerifyOutgoing = &t.VerifyOutgoing
|
|
|
|
result.VerifyServerHostname = &t.VerifyServerHostname
|
|
|
|
result.TLSMinVersion = stringPtrOrNil(t.MinVersion)
|
|
|
|
result.TLSCipherSuites = stringPtrOrNil(t.CipherSuites)
|
|
|
|
result.TLSPreferServerCipherSuites = &t.PreferServerCipherSuites
|
2020-06-10 20:47:35 +00:00
|
|
|
}
|
|
|
|
|
2020-08-10 17:03:33 +00:00
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
func stringPtrOrNil(v string) *string {
|
|
|
|
if v == "" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return &v
|
2020-06-10 20:47:35 +00:00
|
|
|
}
|
2020-07-28 19:31:48 +00:00
|
|
|
|
|
|
|
func extractSignedResponse(resp *pbautoconf.AutoConfigResponse) (*structs.SignedResponse, error) {
|
|
|
|
roots, err := translateCARootsToStructs(resp.CARoots)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
cert, err := translateIssuedCertToStructs(resp.Certificate)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
out := &structs.SignedResponse{
|
|
|
|
IssuedCert: *cert,
|
|
|
|
ConnectCARoots: *roots,
|
|
|
|
ManualCARoots: resp.ExtraCACertificates,
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp.Config != nil && resp.Config.TLS != nil {
|
|
|
|
out.VerifyServerHostname = resp.Config.TLS.VerifyServerHostname
|
|
|
|
}
|
|
|
|
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// translateCARootsToStructs will create a structs.IndexedCARoots object from the corresponding
|
|
|
|
// protobuf struct. Those structs are intended to be identical so the conversion just uses
|
|
|
|
// mapstructure to go from one to the other.
|
|
|
|
func translateCARootsToStructs(in *pbconnect.CARoots) (*structs.IndexedCARoots, error) {
|
|
|
|
var out structs.IndexedCARoots
|
|
|
|
if err := mapstructureTranslateToStructs(in, &out); err != nil {
|
|
|
|
return nil, fmt.Errorf("Failed to re-encode CA Roots: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &out, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// translateIssuedCertToStructs will create a structs.IssuedCert object from the corresponding
|
|
|
|
// protobuf struct. Those structs are intended to be identical so the conversion just uses
|
|
|
|
// mapstructure to go from one to the other.
|
|
|
|
func translateIssuedCertToStructs(in *pbconnect.IssuedCert) (*structs.IssuedCert, error) {
|
|
|
|
var out structs.IssuedCert
|
|
|
|
if err := mapstructureTranslateToStructs(in, &out); err != nil {
|
|
|
|
return nil, fmt.Errorf("Failed to re-encode CA Roots: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &out, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func mapstructureTranslateToStructs(in interface{}, out interface{}) error {
|
|
|
|
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
|
|
|
DecodeHook: proto.HookPBTimestampToTime,
|
|
|
|
Result: out,
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return decoder.Decode(in)
|
|
|
|
}
|
2020-07-30 15:37:18 +00:00
|
|
|
|
|
|
|
func translateCARootsToProtobuf(in *structs.IndexedCARoots) (*pbconnect.CARoots, error) {
|
|
|
|
var out pbconnect.CARoots
|
|
|
|
if err := mapstructureTranslateToProtobuf(in, &out); err != nil {
|
|
|
|
return nil, fmt.Errorf("Failed to re-encode CA Roots: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &out, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func translateIssuedCertToProtobuf(in *structs.IssuedCert) (*pbconnect.IssuedCert, error) {
|
|
|
|
var out pbconnect.IssuedCert
|
|
|
|
if err := mapstructureTranslateToProtobuf(in, &out); err != nil {
|
|
|
|
return nil, fmt.Errorf("Failed to re-encode CA Roots: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &out, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func mapstructureTranslateToProtobuf(in interface{}, out interface{}) error {
|
|
|
|
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
|
|
|
DecodeHook: proto.HookTimeToPBTimestamp,
|
|
|
|
Result: out,
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return decoder.Decode(in)
|
|
|
|
}
|