// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: BUSL-1.1 package proxystateconverter import ( "fmt" "github.com/hashicorp/go-hclog" "github.com/hashicorp/consul/agent/proxycfg" "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/xds/configfetcher" proxytracker "github.com/hashicorp/consul/internal/mesh/proxy-tracker" pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1" "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1/pbproxystate" ) // Converter converts a single snapshot into a ProxyState. type Converter struct { Logger hclog.Logger CfgFetcher configfetcher.ConfigFetcher proxyState *proxytracker.ProxyState } func NewConverter( logger hclog.Logger, cfgFetcher configfetcher.ConfigFetcher, ) *Converter { return &Converter{ Logger: logger, CfgFetcher: cfgFetcher, proxyState: &proxytracker.ProxyState{ ProxyState: &pbmesh.ProxyState{ Listeners: make([]*pbproxystate.Listener, 0), Clusters: make(map[string]*pbproxystate.Cluster), Routes: make(map[string]*pbproxystate.Route), Endpoints: make(map[string]*pbproxystate.Endpoints), }, }, } } func (g *Converter) ProxyStateFromSnapshot(cfgSnap *proxycfg.ConfigSnapshot) (*proxytracker.ProxyState, error) { err := g.resourcesFromSnapshot(cfgSnap) if err != nil { return nil, fmt.Errorf("failed to generate FullProxyState: %v", err) } return g.proxyState, nil } func (g *Converter) resourcesFromSnapshot(cfgSnap *proxycfg.ConfigSnapshot) error { err := g.tlsConfigFromSnapshot(cfgSnap) if err != nil { return err } err = g.listenersFromSnapshot(cfgSnap) if err != nil { return err } err = g.endpointsFromSnapshot(cfgSnap) if err != nil { return err } err = g.clustersFromSnapshot(cfgSnap) if err != nil { return err } err = g.routesFromSnapshot(cfgSnap) if err != nil { return err } //g.secretsFromSnapshot(cfgSnap) return nil } const localPeerKey = "local" func (g *Converter) tlsConfigFromSnapshot(cfgSnap *proxycfg.ConfigSnapshot) error { proxyStateTLS := &pbproxystate.TLS{} g.proxyState.TrustBundles = make(map[string]*pbproxystate.TrustBundle) g.proxyState.LeafCertificates = make(map[string]*pbproxystate.LeafCertificate) // Set the TLS in the top level proxyState g.proxyState.Tls = proxyStateTLS // Add local trust bundle g.proxyState.TrustBundles[localPeerKey] = &pbproxystate.TrustBundle{ TrustDomain: cfgSnap.Roots.TrustDomain, Roots: []string{cfgSnap.RootPEMs()}, } // Add peered trust bundles for remote peers that will dial this proxy. for _, peeringTrustBundle := range cfgSnap.PeeringTrustBundles() { g.proxyState.TrustBundles[peeringTrustBundle.PeerName] = &pbproxystate.TrustBundle{ TrustDomain: peeringTrustBundle.GetTrustDomain(), Roots: peeringTrustBundle.RootPEMs, } } // Add upstream peer trust bundles for dialing upstreams in remote peers. upstreamsSnapshot, err := cfgSnap.ToConfigSnapshotUpstreams() if err != nil { if !(cfgSnap.Kind == structs.ServiceKindMeshGateway || cfgSnap.Kind == structs.ServiceKindTerminatingGateway) { return err } } if upstreamsSnapshot != nil { upstreamsSnapshot.UpstreamPeerTrustBundles.ForEachKeyE(func(k proxycfg.PeerName) error { tbs, ok := upstreamsSnapshot.UpstreamPeerTrustBundles.Get(k) if ok { g.proxyState.TrustBundles[k] = &pbproxystate.TrustBundle{ TrustDomain: tbs.TrustDomain, Roots: tbs.RootPEMs, } } return nil }) } if cfgSnap.MeshConfigTLSOutgoing() != nil { proxyStateTLS.OutboundTlsParameters = makeTLSParametersFromTLSConfig(cfgSnap.MeshConfigTLSOutgoing().TLSMinVersion, cfgSnap.MeshConfigTLSOutgoing().TLSMaxVersion, cfgSnap.MeshConfigTLSOutgoing().CipherSuites) } if cfgSnap.MeshConfigTLSIncoming() != nil { proxyStateTLS.InboundTlsParameters = makeTLSParametersFromTLSConfig(cfgSnap.MeshConfigTLSIncoming().TLSMinVersion, cfgSnap.MeshConfigTLSIncoming().TLSMaxVersion, cfgSnap.MeshConfigTLSIncoming().CipherSuites) } return nil }