Skip to content

Commit

Permalink
Inline TLS cert code
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew Stucki committed Feb 16, 2023
1 parent e5afda5 commit 37502d4
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 74 deletions.
37 changes: 22 additions & 15 deletions agent/proxycfg/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,8 @@ type configSnapshotAPIGateway struct {
// Listeners is the original listener config from the api-gateway config
// entry to save us trying to pass fields through Upstreams
Listeners map[string]structs.APIGatewayListener
// this acts as an intermediary for inlining certificates
ListenerCertificates map[IngressListenerKey][]structs.InlineCertificateConfigEntry

BoundListeners map[string]structs.BoundAPIGatewayListener
}
Expand All @@ -751,6 +753,9 @@ func (c *configSnapshotAPIGateway) ToIngress(datacenter string) (configSnapshotI
watchedUpstreamEndpoints := make(map[UpstreamID]map[string]structs.CheckServiceNodes)
watchedGatewayEndpoints := make(map[UpstreamID]map[string]structs.CheckServiceNodes)

// reset the cached certificates
c.ListenerCertificates = make(map[IngressListenerKey][]structs.InlineCertificateConfigEntry)

for name, listener := range c.Listeners {
boundListener, ok := c.BoundListeners[name]
if !ok {
Expand Down Expand Up @@ -802,17 +807,18 @@ func (c *configSnapshotAPIGateway) ToIngress(datacenter string) (configSnapshotI
watchedGatewayEndpoints[id] = gatewayEndpoints
}

key := IngressListenerKey{
Port: listener.Port,
Protocol: string(listener.Protocol),
}

// Configure TLS for the ingress listener
tls, err := c.toIngressTLS(listener)
tls, err := c.toIngressTLS(key, listener, boundListener)
if err != nil {
return configSnapshotIngressGateway{}, err
}
ingressListener.TLS = tls

key := IngressListenerKey{
Port: listener.Port,
Protocol: string(listener.Protocol),
}
ingressListener.TLS = tls
ingressListeners[key] = ingressListener
ingressUpstreams[key] = upstreams
}
Expand Down Expand Up @@ -905,20 +911,21 @@ DOMAIN_LOOP:
return services, upstreams, compiled, err
}

func (c *configSnapshotAPIGateway) toIngressTLS(listener structs.APIGatewayListener) (*structs.GatewayTLSConfig, error) {
// TODO How do we handle multiple listener.TLS.Certificates?
var sds *structs.GatewayTLSSDSConfig
if len(listener.TLS.Certificates) > 0 {
sds = &structs.GatewayTLSSDSConfig{
ClusterName: "local_agent",
CertResource: listener.TLS.Certificates[0].String(),
func (c *configSnapshotAPIGateway) toIngressTLS(key IngressListenerKey, listener structs.APIGatewayListener, bound structs.BoundAPIGatewayListener) (*structs.GatewayTLSConfig, error) {
if len(listener.TLS.Certificates) == 0 {
return nil, nil
}

for _, certRef := range bound.Certificates {
cert, ok := c.Certificates.Get(certRef)
if !ok {
continue
}
c.ListenerCertificates[key] = append(c.ListenerCertificates[key], *cert)
}

return &structs.GatewayTLSConfig{
Enabled: true,
UseADS: true,
SDS: sds,
TLSMinVersion: listener.TLS.MinVersion,
TLSMaxVersion: listener.TLS.MaxVersion,
CipherSuites: listener.TLS.CipherSuites,
Expand Down
2 changes: 0 additions & 2 deletions agent/structs/config_entry_gateways.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,6 @@ type GatewayTLSConfig struct {
// Indicates that TLS should be enabled for this gateway or listener
Enabled bool

UseADS bool

// SDS allows configuring TLS certificate from an SDS service.
SDS *GatewayTLSSDSConfig `json:",omitempty"`

Expand Down
52 changes: 37 additions & 15 deletions agent/xds/listeners_ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/hashicorp/consul/agent/proxycfg"
"github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/lib"
"github.com/hashicorp/consul/types"
)

Expand All @@ -25,7 +26,12 @@ func (s *ResourceGenerator) makeIngressGatewayListeners(address string, cfgSnap
return nil, fmt.Errorf("no listener config found for listener on proto/port %s/%d", listenerKey.Protocol, listenerKey.Port)
}

tlsContext, err := makeDownstreamTLSContextFromSnapshotListenerConfig(cfgSnap, listenerCfg)
var certs []structs.InlineCertificateConfigEntry
if cfgSnap.APIGateway.ListenerCertificates != nil {
certs = cfgSnap.APIGateway.ListenerCertificates[listenerKey]
}

tlsContext, err := makeDownstreamTLSContextFromSnapshotListenerConfig(cfgSnap, listenerCfg, certs)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -160,10 +166,10 @@ func (s *ResourceGenerator) makeIngressGatewayListeners(address string, cfgSnap
return resources, nil
}

func makeDownstreamTLSContextFromSnapshotListenerConfig(cfgSnap *proxycfg.ConfigSnapshot, listenerCfg structs.IngressListener) (*envoy_tls_v3.DownstreamTlsContext, error) {
func makeDownstreamTLSContextFromSnapshotListenerConfig(cfgSnap *proxycfg.ConfigSnapshot, listenerCfg structs.IngressListener, certs []structs.InlineCertificateConfigEntry) (*envoy_tls_v3.DownstreamTlsContext, error) {
var downstreamContext *envoy_tls_v3.DownstreamTlsContext

tlsContext, err := makeCommonTLSContextFromSnapshotListenerConfig(cfgSnap, listenerCfg)
tlsContext, err := makeCommonTLSContextFromSnapshotListenerConfig(cfgSnap, listenerCfg, certs)
if err != nil {
return nil, err
}
Expand All @@ -181,7 +187,7 @@ func makeDownstreamTLSContextFromSnapshotListenerConfig(cfgSnap *proxycfg.Config
return downstreamContext, nil
}

func makeCommonTLSContextFromSnapshotListenerConfig(cfgSnap *proxycfg.ConfigSnapshot, listenerCfg structs.IngressListener) (*envoy_tls_v3.CommonTlsContext, error) {
func makeCommonTLSContextFromSnapshotListenerConfig(cfgSnap *proxycfg.ConfigSnapshot, listenerCfg structs.IngressListener, certs []structs.InlineCertificateConfigEntry) (*envoy_tls_v3.CommonTlsContext, error) {
var tlsContext *envoy_tls_v3.CommonTlsContext

// Enable connect TLS if it is enabled at the Gateway or specific listener
Expand All @@ -199,6 +205,10 @@ func makeCommonTLSContextFromSnapshotListenerConfig(cfgSnap *proxycfg.ConfigSnap
return nil, err
}

if len(certs) != 0 {
return makeInlineTLSContextFromGatewayTLSConfig(*tlsCfg, certs), nil
}

if tlsCfg.SDS != nil {
// Set up listener TLS from SDS
tlsContext = makeCommonTLSContextFromGatewayTLSConfig(*tlsCfg)
Expand Down Expand Up @@ -226,8 +236,6 @@ func resolveListenerTLSConfig(gatewayTLSCfg *structs.GatewayTLSConfig, listenerC
}

if listenerCfg.TLS != nil {
mergedCfg.UseADS = listenerCfg.TLS.UseADS

if listenerCfg.TLS.TLSMinVersion != types.TLSVersionUnspecified {
mergedCfg.TLSMinVersion = listenerCfg.TLS.TLSMinVersion
}
Expand Down Expand Up @@ -385,18 +393,33 @@ func makeTLSParametersFromGatewayTLSConfig(tlsCfg structs.GatewayTLSConfig) *env
return makeTLSParametersFromTLSConfig(tlsCfg.TLSMinVersion, tlsCfg.TLSMaxVersion, tlsCfg.CipherSuites)
}

func makeCommonTLSContextFromGatewayTLSConfig(tlsCfg structs.GatewayTLSConfig) *envoy_tls_v3.CommonTlsContext {

var secretConfigs []*envoy_tls_v3.SdsSecretConfig
if tlsCfg.UseADS {
secretConfigs = makeTLSCertificateSdsSecretConfigsFromSDSUsingADS(*tlsCfg.SDS)
} else {
secretConfigs = makeTLSCertificateSdsSecretConfigsFromSDS(*tlsCfg.SDS)
func makeInlineTLSContextFromGatewayTLSConfig(tlsCfg structs.GatewayTLSConfig, certs []structs.InlineCertificateConfigEntry) *envoy_tls_v3.CommonTlsContext {
tlsParams := makeTLSParametersFromGatewayTLSConfig(tlsCfg)
tlsCerts := []*envoy_tls_v3.TlsCertificate{}
for _, cert := range certs {
tlsCerts = append(tlsCerts, &envoy_tls_v3.TlsCertificate{
CertificateChain: &envoy_core_v3.DataSource{
Specifier: &envoy_core_v3.DataSource_InlineString{
InlineString: lib.EnsureTrailingNewline(cert.Certificate),
},
},
PrivateKey: &envoy_core_v3.DataSource{
Specifier: &envoy_core_v3.DataSource_InlineString{
InlineString: lib.EnsureTrailingNewline(cert.PrivateKey),
},
},
})
}
return &envoy_tls_v3.CommonTlsContext{
TlsParams: tlsParams,
TlsCertificates: tlsCerts,
}
}

func makeCommonTLSContextFromGatewayTLSConfig(tlsCfg structs.GatewayTLSConfig) *envoy_tls_v3.CommonTlsContext {
return &envoy_tls_v3.CommonTlsContext{
TlsParams: makeTLSParametersFromGatewayTLSConfig(tlsCfg),
TlsCertificateSdsSecretConfigs: secretConfigs,
TlsCertificateSdsSecretConfigs: makeTLSCertificateSdsSecretConfigsFromSDS(*tlsCfg.SDS),
}
}

Expand All @@ -421,7 +444,6 @@ func makeTLSCertificateSdsSecretConfigsFromSDSUsingADS(sdsCfg structs.GatewayTLS
}
}


func makeTLSCertificateSdsSecretConfigsFromSDS(sdsCfg structs.GatewayTLSSDSConfig) []*envoy_tls_v3.SdsSecretConfig {
return []*envoy_tls_v3.SdsSecretConfig{
{
Expand Down
44 changes: 2 additions & 42 deletions agent/xds/secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@ import (
"errors"
"fmt"

envoy_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
envoy_tls_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
"google.golang.org/protobuf/proto"

"github.com/hashicorp/consul/agent/proxycfg"
"github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/lib"
)

// secretsFromSnapshot returns the xDS API representation of the "secrets"
Expand All @@ -24,47 +21,10 @@ func (s *ResourceGenerator) secretsFromSnapshot(cfgSnap *proxycfg.ConfigSnapshot
case structs.ServiceKindConnectProxy,
structs.ServiceKindTerminatingGateway,
structs.ServiceKindMeshGateway,
structs.ServiceKindIngressGateway:
structs.ServiceKindIngressGateway,
structs.ServiceKindAPIGateway:
return nil, nil
// Only API gateways utilize secrets
case structs.ServiceKindAPIGateway:
return s.secretsFromSnapshotAPIGateway(cfgSnap)
default:
return nil, fmt.Errorf("Invalid service kind: %v", cfgSnap.Kind)
}
}

func (s *ResourceGenerator) secretsFromSnapshotAPIGateway(cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) {
resources := make([]proto.Message, 0, cfgSnap.APIGateway.Certificates.Len())

cfgSnap.APIGateway.Certificates.ForEachKey(func(ref structs.ResourceReference) bool {
cert, ok := cfgSnap.APIGateway.Certificates.Get(ref)
if !ok {
// inline-certificate not present in map for some reason, process others
return true
}

secret := &envoy_tls_v3.Secret{
Name: ref.String(),
Type: &envoy_tls_v3.Secret_TlsCertificate{
TlsCertificate: &envoy_tls_v3.TlsCertificate{
CertificateChain: &envoy_core_v3.DataSource{
Specifier: &envoy_core_v3.DataSource_InlineString{
InlineString: lib.EnsureTrailingNewline(cert.Certificate),
},
},
PrivateKey: &envoy_core_v3.DataSource{
Specifier: &envoy_core_v3.DataSource_InlineString{
InlineString: lib.EnsureTrailingNewline(cert.PrivateKey),
},
},
},
},
}

resources = append(resources, secret)
return true
})

return resources, nil
}

0 comments on commit 37502d4

Please sign in to comment.