diff --git a/cmd/contour/bootstrap.go b/cmd/contour/bootstrap.go index e91817a21b8..82e03e48517 100644 --- a/cmd/contour/bootstrap.go +++ b/cmd/contour/bootstrap.go @@ -34,6 +34,6 @@ func registerBootstrap(app *kingpin.Application) (*kingpin.CmdClause, *envoy.Boo bootstrap.Flag("envoy-cert-file", "Client certificate filename for Envoy secure xDS gRPC communication.").Envar("ENVOY_CERT_FILE").StringVar(&config.GrpcClientCert) bootstrap.Flag("envoy-key-file", "Client key filename for Envoy secure xDS gRPC communication.").Envar("ENVOY_KEY_FILE").StringVar(&config.GrpcClientKey) bootstrap.Flag("namespace", "The namespace the Envoy container will run in.").Envar("CONTOUR_NAMESPACE").Default("projectcontour").StringVar(&config.Namespace) - bootstrap.Flag("xds-resource-version", "The versions of the xDS resources to request from Contour.").Default("v2").StringVar((*string)(&config.XDSResourceVersion)) + bootstrap.Flag("xds-resource-version", "The versions of the xDS resources to request from Contour.").Default("v3").StringVar((*string)(&config.XDSResourceVersion)) return bootstrap, &config } diff --git a/cmd/contour/contour.go b/cmd/contour/contour.go index 878574726ae..634b1d5c514 100644 --- a/cmd/contour/contour.go +++ b/cmd/contour/contour.go @@ -18,10 +18,8 @@ import ( resource "github.com/envoyproxy/go-control-plane/pkg/resource/v2" "github.com/projectcontour/contour/internal/build" - envoy_v2 "github.com/projectcontour/contour/internal/envoy/v2" envoy_v3 "github.com/projectcontour/contour/internal/envoy/v3" "github.com/projectcontour/contour/internal/k8s" - "github.com/projectcontour/contour/pkg/config" "github.com/sirupsen/logrus" kingpin "gopkg.in/alecthomas/kingpin.v2" ) @@ -75,15 +73,8 @@ func main() { if err != nil { log.WithError(err).Fatal("failed to parse bootstrap args") } - switch bootstrapCtx.XDSResourceVersion { - case config.XDSv3: - if err := envoy_v3.WriteBootstrap(bootstrapCtx); err != nil { - log.WithError(err).Fatal("failed to write bootstrap configuration") - } - default: - if err := envoy_v2.WriteBootstrap(bootstrapCtx); err != nil { - log.WithError(err).Fatal("failed to write bootstrap configuration") - } + if err := envoy_v3.WriteBootstrap(bootstrapCtx); err != nil { + log.WithError(err).Fatal("failed to write bootstrap configuration") } case certgenApp.FullCommand(): doCertgen(certgenConfig, log) diff --git a/cmd/contour/serve.go b/cmd/contour/serve.go index 6e73df6fe74..2fffa4acc15 100644 --- a/cmd/contour/serve.go +++ b/cmd/contour/serve.go @@ -26,7 +26,6 @@ import ( "time" envoy_auth_v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" - envoy_server_v2 "github.com/envoyproxy/go-control-plane/pkg/server/v2" envoy_server_v3 "github.com/envoyproxy/go-control-plane/pkg/server/v3" contour_api_v1 "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/projectcontour/contour/internal/annotation" @@ -40,7 +39,6 @@ import ( "github.com/projectcontour/contour/internal/timeout" "github.com/projectcontour/contour/internal/workgroup" "github.com/projectcontour/contour/internal/xds" - contour_xds_v2 "github.com/projectcontour/contour/internal/xds/v2" contour_xds_v3 "github.com/projectcontour/contour/internal/xds/v3" "github.com/projectcontour/contour/internal/xdscache" xdscache_v2 "github.com/projectcontour/contour/internal/xdscache/v2" @@ -563,20 +561,8 @@ func doServe(log logrus.FieldLogger, ctx *serveContext) error { v3cache := contour_xds_v3.NewSnapshotCache(false, log) snapshotHandler.AddSnapshotter(v3cache) contour_xds_v3.RegisterServer(envoy_server_v3.NewServer(context.Background(), v3cache, nil), grpcServer) - - // Check an internal feature flag to disable xDS v2 endpoints. This is strictly for testing. - if config.GetenvOr("CONTOUR_INTERNAL_DISABLE_XDSV2", "N") == "N" { - v2cache := contour_xds_v2.NewSnapshotCache(false, log) - snapshotHandler.AddSnapshotter(v2cache) - contour_xds_v2.RegisterServer(envoy_server_v2.NewServer(context.Background(), v2cache, nil), grpcServer) - } case config.ContourServerType: contour_xds_v3.RegisterServer(contour_xds_v3.NewContourServer(log, xdscache.ResourcesOf(resources)...), grpcServer) - - // Check an internal feature flag to disable xDS v2 endpoints. This is strictly for testing. - if config.GetenvOr("CONTOUR_INTERNAL_DISABLE_XDSV2", "N") == "N" { - contour_xds_v2.RegisterServer(contour_xds_v2.NewContourServer(log, xdscache.ResourcesOf(resources)...), grpcServer) - } default: // This can't happen due to config validation. log.Fatalf("invalid xDS server type %q", ctx.Config.Server.XDSServerType) diff --git a/internal/envoy/bootstrap.go b/internal/envoy/bootstrap.go index cdae66057a5..2c15448674d 100644 --- a/internal/envoy/bootstrap.go +++ b/internal/envoy/bootstrap.go @@ -53,12 +53,12 @@ type BootstrapConfig struct { // Defaults to 127.0.0.1. XDSAddress string - // XDSGRPCPort is the management server port that provides the v2 gRPC API. + // XDSGRPCPort is the management server port that provides the v3 gRPC API. // Defaults to 8001. XDSGRPCPort int // XDSResourceVersion defines the XDS Server Version to use. - // Defaults to "v2" + // Defaults to "v3" XDSResourceVersion config.ResourceVersion // Namespace is the namespace where Contour is running diff --git a/internal/envoy/v2/bootstrap.go b/internal/envoy/v2/bootstrap.go deleted file mode 100644 index 6084da1b495..00000000000 --- a/internal/envoy/v2/bootstrap.go +++ /dev/null @@ -1,319 +0,0 @@ -// Copyright Project Contour Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package envoy contains APIs for translating between Contour -// objects and Envoy configuration APIs and types. - -package v2 - -import ( - "fmt" - "os" - "path" - "strconv" - "strings" - "time" - - api "github.com/envoyproxy/go-control-plane/envoy/api/v2" - envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" - clusterv2 "github.com/envoyproxy/go-control-plane/envoy/api/v2/cluster" - envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" - envoy_api_bootstrap "github.com/envoyproxy/go-control-plane/envoy/config/bootstrap/v2" - matcher "github.com/envoyproxy/go-control-plane/envoy/type/matcher" - "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes/any" - "github.com/projectcontour/contour/internal/envoy" - "github.com/projectcontour/contour/internal/protobuf" -) - -// WriteBootstrap writes bootstrap configuration to files. -func WriteBootstrap(c *envoy.BootstrapConfig) error { - // Create Envoy bootstrap config and associated resource files. - steps, err := bootstrap(c) - if err != nil { - return err - } - - if c.ResourcesDir != "" { - if err := os.MkdirAll(path.Join(c.ResourcesDir, "sds"), 0750); err != nil { - return err - } - } - - // Write all configuration files out to filesystem. - for _, step := range steps { - if err := envoy.WriteConfig(step(c)); err != nil { - return err - } - } - - return nil -} - -type bootstrapf func(*envoy.BootstrapConfig) (string, proto.Message) - -// bootstrap creates a new v2 bootstrap configuration and associated resource files. -func bootstrap(c *envoy.BootstrapConfig) ([]bootstrapf, error) { - steps := []bootstrapf{} - - if c.GrpcClientCert == "" && c.GrpcClientKey == "" && c.GrpcCABundle == "" { - steps = append(steps, - func(*envoy.BootstrapConfig) (string, proto.Message) { - return c.Path, bootstrapConfig(c) - }) - - return steps, nil - } - - for _, f := range []string{c.GrpcClientCert, c.GrpcClientKey, c.GrpcCABundle} { - // If any of of the TLS options is not empty, they all must be not empty. - if f == "" { - return nil, fmt.Errorf( - "you must supply all TLS parameters - %q, %q, %q, or none of them", - "--envoy-cafile", "--envoy-cert-file", "--envoy-key-file") - } - - if !c.SkipFilePathCheck { - // If the TLS secrets aren't set up properly, - // some files may not be present. In this case, - // envoy will reject the bootstrap configuration, - // but there is no way to detect and fix that. If - // we check and fail here, that is visible in the - // Pod lifecycle and therefore fixable. - fi, err := os.Stat(f) - if err != nil { - return nil, err - } - if fi.Size() == 0 { - return nil, fmt.Errorf("%q is empty", f) - } - } - } - - if c.ResourcesDir == "" { - // For backwards compatibility, the old behavior - // is to use direct certificate and key file paths in - // bootstrap config. Envoy does not support rotation - // of xDS certificate files in this case. - - steps = append(steps, - func(*envoy.BootstrapConfig) (string, proto.Message) { - b := bootstrapConfig(c) - b.StaticResources.Clusters[0].TransportSocket = UpstreamTLSTransportSocket( - upstreamFileTLSContext(c)) - return c.Path, b - }) - - return steps, nil - } - - // xDS certificate rotation is supported by Envoy by using SDS path based resource files. - // These files are JSON representation of the SDS protobuf messages that normally get sent over the xDS connection, - // but for xDS connection itself, bootstrapping is done by storing the SDS resources in a local filesystem. - // Envoy will monitor and reload the resource files and the certificate and key files referred from the SDS resources. - // - // Two files are written to ResourcesDir: - // - SDS resource for xDS client certificate and key for authenticating Envoy towards Contour. - // - SDS resource for trusted CA certificate for validating Contour server certificate. - sdsTLSCertificatePath := path.Join(c.ResourcesDir, envoy.SDSResourcesSubdirectory, envoy.SDSTLSCertificateFile) - sdsValidationContextPath := path.Join(c.ResourcesDir, envoy.SDSResourcesSubdirectory, envoy.SDSValidationContextFile) - - steps = append(steps, - func(*envoy.BootstrapConfig) (string, proto.Message) { - return sdsTLSCertificatePath, tlsCertificateSdsSecretConfig(c) - }, - func(*envoy.BootstrapConfig) (string, proto.Message) { - return sdsValidationContextPath, validationContextSdsSecretConfig(c) - }, - func(*envoy.BootstrapConfig) (string, proto.Message) { - b := bootstrapConfig(c) - b.StaticResources.Clusters[0].TransportSocket = UpstreamTLSTransportSocket( - upstreamSdsTLSContext(sdsTLSCertificatePath, sdsValidationContextPath)) - return c.Path, b - }, - ) - - return steps, nil -} - -func bootstrapConfig(c *envoy.BootstrapConfig) *envoy_api_bootstrap.Bootstrap { - return &envoy_api_bootstrap.Bootstrap{ - DynamicResources: &envoy_api_bootstrap.Bootstrap_DynamicResources{ - LdsConfig: ConfigSource("contour"), - CdsConfig: ConfigSource("contour"), - }, - StaticResources: &envoy_api_bootstrap.Bootstrap_StaticResources{ - Clusters: []*api.Cluster{{ - Name: "contour", - AltStatName: strings.Join([]string{c.Namespace, "contour", strconv.Itoa(c.GetXdsGRPCPort())}, "_"), - ConnectTimeout: protobuf.Duration(5 * time.Second), - ClusterDiscoveryType: ClusterDiscoveryType(api.Cluster_STRICT_DNS), - LbPolicy: api.Cluster_ROUND_ROBIN, - LoadAssignment: &api.ClusterLoadAssignment{ - ClusterName: "contour", - Endpoints: Endpoints( - SocketAddress(c.GetXdsAddress(), c.GetXdsGRPCPort()), - ), - }, - UpstreamConnectionOptions: &api.UpstreamConnectionOptions{ - TcpKeepalive: &envoy_api_v2_core.TcpKeepalive{ - KeepaliveProbes: protobuf.UInt32(3), - KeepaliveTime: protobuf.UInt32(30), - KeepaliveInterval: protobuf.UInt32(5), - }, - }, - Http2ProtocolOptions: new(envoy_api_v2_core.Http2ProtocolOptions), // enables http2 - CircuitBreakers: &clusterv2.CircuitBreakers{ - Thresholds: []*clusterv2.CircuitBreakers_Thresholds{{ - Priority: envoy_api_v2_core.RoutingPriority_HIGH, - MaxConnections: protobuf.UInt32(100000), - MaxPendingRequests: protobuf.UInt32(100000), - MaxRequests: protobuf.UInt32(60000000), - MaxRetries: protobuf.UInt32(50), - }, { - Priority: envoy_api_v2_core.RoutingPriority_DEFAULT, - MaxConnections: protobuf.UInt32(100000), - MaxPendingRequests: protobuf.UInt32(100000), - MaxRequests: protobuf.UInt32(60000000), - MaxRetries: protobuf.UInt32(50), - }}, - }, - }, { - Name: "service-stats", - AltStatName: strings.Join([]string{c.Namespace, "service-stats", strconv.Itoa(c.GetAdminPort())}, "_"), - ConnectTimeout: protobuf.Duration(250 * time.Millisecond), - ClusterDiscoveryType: ClusterDiscoveryType(api.Cluster_LOGICAL_DNS), - LbPolicy: api.Cluster_ROUND_ROBIN, - LoadAssignment: &api.ClusterLoadAssignment{ - ClusterName: "service-stats", - Endpoints: Endpoints( - SocketAddress(c.GetAdminAddress(), c.GetAdminPort()), - ), - }, - }}, - }, - Admin: &envoy_api_bootstrap.Admin{ - AccessLogPath: c.GetAdminAccessLogPath(), - Address: SocketAddress(c.GetAdminAddress(), c.GetAdminPort()), - }, - } -} - -func upstreamFileTLSContext(c *envoy.BootstrapConfig) *envoy_api_v2_auth.UpstreamTlsContext { - context := &envoy_api_v2_auth.UpstreamTlsContext{ - CommonTlsContext: &envoy_api_v2_auth.CommonTlsContext{ - TlsCertificates: []*envoy_api_v2_auth.TlsCertificate{{ - CertificateChain: &envoy_api_v2_core.DataSource{ - Specifier: &envoy_api_v2_core.DataSource_Filename{ - Filename: c.GrpcClientCert, - }, - }, - PrivateKey: &envoy_api_v2_core.DataSource{ - Specifier: &envoy_api_v2_core.DataSource_Filename{ - Filename: c.GrpcClientKey, - }, - }, - }}, - ValidationContextType: &envoy_api_v2_auth.CommonTlsContext_ValidationContext{ - ValidationContext: &envoy_api_v2_auth.CertificateValidationContext{ - TrustedCa: &envoy_api_v2_core.DataSource{ - Specifier: &envoy_api_v2_core.DataSource_Filename{ - Filename: c.GrpcCABundle, - }, - }, - // TODO(youngnick): Does there need to be a flag wired down to here? - MatchSubjectAltNames: []*matcher.StringMatcher{{ - MatchPattern: &matcher.StringMatcher_Exact{ - Exact: "contour", - }}, - }, - }, - }, - }, - } - return context -} - -func upstreamSdsTLSContext(certificateSdsFile, validationSdsFile string) *envoy_api_v2_auth.UpstreamTlsContext { - context := &envoy_api_v2_auth.UpstreamTlsContext{ - CommonTlsContext: &envoy_api_v2_auth.CommonTlsContext{ - TlsCertificateSdsSecretConfigs: []*envoy_api_v2_auth.SdsSecretConfig{{ - SdsConfig: &envoy_api_v2_core.ConfigSource{ - ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_Path{ - Path: certificateSdsFile, - }, - }, - }}, - ValidationContextType: &envoy_api_v2_auth.CommonTlsContext_ValidationContextSdsSecretConfig{ - ValidationContextSdsSecretConfig: &envoy_api_v2_auth.SdsSecretConfig{ - SdsConfig: &envoy_api_v2_core.ConfigSource{ - ConfigSourceSpecifier: &envoy_api_v2_core.ConfigSource_Path{ - Path: validationSdsFile, - }, - }, - }, - }, - }, - } - return context -} - -// tlsCertificateSdsSecretConfig creates DiscoveryResponse with file based SDS resource -// including paths to TLS certificates and key -func tlsCertificateSdsSecretConfig(c *envoy.BootstrapConfig) *api.DiscoveryResponse { - secret := &envoy_api_v2_auth.Secret{ - Type: &envoy_api_v2_auth.Secret_TlsCertificate{ - TlsCertificate: &envoy_api_v2_auth.TlsCertificate{ - CertificateChain: &envoy_api_v2_core.DataSource{ - Specifier: &envoy_api_v2_core.DataSource_Filename{ - Filename: c.GrpcClientCert, - }, - }, - PrivateKey: &envoy_api_v2_core.DataSource{ - Specifier: &envoy_api_v2_core.DataSource_Filename{ - Filename: c.GrpcClientKey, - }, - }, - }, - }, - } - - return &api.DiscoveryResponse{ - Resources: []*any.Any{protobuf.MustMarshalAny(secret)}, - } -} - -// validationContextSdsSecretConfig creates DiscoveryResponse with file based SDS resource -// including path to CA certificate bundle -func validationContextSdsSecretConfig(c *envoy.BootstrapConfig) *api.DiscoveryResponse { - secret := &envoy_api_v2_auth.Secret{ - Type: &envoy_api_v2_auth.Secret_ValidationContext{ - ValidationContext: &envoy_api_v2_auth.CertificateValidationContext{ - TrustedCa: &envoy_api_v2_core.DataSource{ - Specifier: &envoy_api_v2_core.DataSource_Filename{ - Filename: c.GrpcCABundle, - }, - }, - MatchSubjectAltNames: []*matcher.StringMatcher{{ - MatchPattern: &matcher.StringMatcher_Exact{ - Exact: "contour", - }}, - }, - }, - }, - } - - return &api.DiscoveryResponse{ - Resources: []*any.Any{protobuf.MustMarshalAny(secret)}, - } -} diff --git a/internal/envoy/v2/bootstrap_test.go b/internal/envoy/v2/bootstrap_test.go deleted file mode 100644 index 1084f0b0eed..00000000000 --- a/internal/envoy/v2/bootstrap_test.go +++ /dev/null @@ -1,1047 +0,0 @@ -// Copyright Project Contour Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package v2 - -import ( - "path" - "testing" - - api "github.com/envoyproxy/go-control-plane/envoy/api/v2" - envoy_api_bootstrap "github.com/envoyproxy/go-control-plane/envoy/config/bootstrap/v2" - "github.com/golang/protobuf/jsonpb" - "github.com/golang/protobuf/proto" - "github.com/projectcontour/contour/internal/envoy" - "github.com/projectcontour/contour/internal/protobuf" - "github.com/stretchr/testify/assert" -) - -func TestBootstrap(t *testing.T) { - tests := map[string]struct { - config envoy.BootstrapConfig - wantedBootstrapConfig string - wantedTLSCertificateConfig string - wantedValidationContextConfig string - wantedError bool - }{ - "default configuration": { - config: envoy.BootstrapConfig{ - Path: "envoy.json", - Namespace: "testing-ns"}, - wantedBootstrapConfig: `{ - "static_resources": { - "clusters": [ - { - "name": "contour", - "alt_stat_name": "testing-ns_contour_8001", - "type": "STRICT_DNS", - "connect_timeout": "5s", - "load_assignment": { - "cluster_name": "contour", - "endpoints": [ - { - "lb_endpoints": [ - { - "endpoint": { - "address": { - "socket_address": { - "address": "127.0.0.1", - "port_value": 8001 - } - } - } - } - ] - } - ] - }, - "circuit_breakers": { - "thresholds": [ - { - "priority": "HIGH", - "max_connections": 100000, - "max_pending_requests": 100000, - "max_requests": 60000000, - "max_retries": 50 - }, - { - "max_connections": 100000, - "max_pending_requests": 100000, - "max_requests": 60000000, - "max_retries": 50 - } - ] - }, - "http2_protocol_options": {}, - "upstream_connection_options": { - "tcp_keepalive": { - "keepalive_probes": 3, - "keepalive_time": 30, - "keepalive_interval": 5 - } - } - }, - { - "name": "service-stats", - "alt_stat_name": "testing-ns_service-stats_9001", - "type": "LOGICAL_DNS", - "connect_timeout": "0.250s", - "load_assignment": { - "cluster_name": "service-stats", - "endpoints": [ - { - "lb_endpoints": [ - { - "endpoint": { - "address": { - "socket_address": { - "address": "127.0.0.1", - "port_value": 9001 - } - } - } - } - ] - } - ] - } - } - ] - }, - "dynamic_resources": { - "lds_config": { - "api_config_source": { - "api_type": "GRPC", - "grpc_services": [ - { - "envoy_grpc": { - "cluster_name": "contour" - } - } - ] - } - }, - "cds_config": { - "api_config_source": { - "api_type": "GRPC", - "grpc_services": [ - { - "envoy_grpc": { - "cluster_name": "contour" - } - } - ] - } - } - }, - "admin": { - "access_log_path": "/dev/null", - "address": { - "socket_address": { - "address": "127.0.0.1", - "port_value": 9001 - } - } - } -}`, - }, - "--admin-address=8.8.8.8 --admin-port=9200": { - config: envoy.BootstrapConfig{ - Path: "envoy.json", - AdminAddress: "8.8.8.8", - AdminPort: 9200, - Namespace: "testing-ns", - }, - wantedBootstrapConfig: `{ - "static_resources": { - "clusters": [ - { - "name": "contour", - "alt_stat_name": "testing-ns_contour_8001", - "type": "STRICT_DNS", - "connect_timeout": "5s", - "load_assignment": { - "cluster_name": "contour", - "endpoints": [ - { - "lb_endpoints": [ - { - "endpoint": { - "address": { - "socket_address": { - "address": "127.0.0.1", - "port_value": 8001 - } - } - } - } - ] - } - ] - }, - "circuit_breakers": { - "thresholds": [ - { - "priority": "HIGH", - "max_connections": 100000, - "max_pending_requests": 100000, - "max_requests": 60000000, - "max_retries": 50 - }, - { - "max_connections": 100000, - "max_pending_requests": 100000, - "max_requests": 60000000, - "max_retries": 50 - } - ] - }, - "http2_protocol_options": {}, - "upstream_connection_options": { - "tcp_keepalive": { - "keepalive_probes": 3, - "keepalive_time": 30, - "keepalive_interval": 5 - } - } - }, - { - "name": "service-stats", - "alt_stat_name": "testing-ns_service-stats_9200", - "type": "LOGICAL_DNS", - "connect_timeout": "0.250s", - "load_assignment": { - "cluster_name": "service-stats", - "endpoints": [ - { - "lb_endpoints": [ - { - "endpoint": { - "address": { - "socket_address": { - "address": "8.8.8.8", - "port_value": 9200 - } - } - } - } - ] - } - ] - } - } - ] - }, - "dynamic_resources": { - "lds_config": { - "api_config_source": { - "api_type": "GRPC", - "grpc_services": [ - { - "envoy_grpc": { - "cluster_name": "contour" - } - } - ] - } - }, - "cds_config": { - "api_config_source": { - "api_type": "GRPC", - "grpc_services": [ - { - "envoy_grpc": { - "cluster_name": "contour" - } - } - ] - } - } - }, - "admin": { - "access_log_path": "/dev/null", - "address": { - "socket_address": { - "address": "8.8.8.8", - "port_value": 9200 - } - } - } -}`, - }, - "AdminAccessLogPath": { // TODO(dfc) doesn't appear to be exposed via contour bootstrap - config: envoy.BootstrapConfig{ - Path: "envoy.json", - AdminAccessLogPath: "/var/log/admin.log", - Namespace: "testing-ns", - }, - wantedBootstrapConfig: `{ - "static_resources": { - "clusters": [ - { - "name": "contour", - "alt_stat_name": "testing-ns_contour_8001", - "type": "STRICT_DNS", - "connect_timeout": "5s", - "load_assignment": { - "cluster_name": "contour", - "endpoints": [ - { - "lb_endpoints": [ - { - "endpoint": { - "address": { - "socket_address": { - "address": "127.0.0.1", - "port_value": 8001 - } - } - } - } - ] - } - ] - }, - "circuit_breakers": { - "thresholds": [ - { - "priority": "HIGH", - "max_connections": 100000, - "max_pending_requests": 100000, - "max_requests": 60000000, - "max_retries": 50 - }, - { - "max_connections": 100000, - "max_pending_requests": 100000, - "max_requests": 60000000, - "max_retries": 50 - } - ] - }, - "http2_protocol_options": {}, - "upstream_connection_options": { - "tcp_keepalive": { - "keepalive_probes": 3, - "keepalive_time": 30, - "keepalive_interval": 5 - } - } - }, - { - "name": "service-stats", - "alt_stat_name": "testing-ns_service-stats_9001", - "type": "LOGICAL_DNS", - "connect_timeout": "0.250s", - "load_assignment": { - "cluster_name": "service-stats", - "endpoints": [ - { - "lb_endpoints": [ - { - "endpoint": { - "address": { - "socket_address": { - "address": "127.0.0.1", - "port_value": 9001 - } - } - } - } - ] - } - ] - } - } - ] - }, - "dynamic_resources": { - "lds_config": { - "api_config_source": { - "api_type": "GRPC", - "grpc_services": [ - { - "envoy_grpc": { - "cluster_name": "contour" - } - } - ] - } - }, - "cds_config": { - "api_config_source": { - "api_type": "GRPC", - "grpc_services": [ - { - "envoy_grpc": { - "cluster_name": "contour" - } - } - ] - } - } - }, - "admin": { - "access_log_path": "/var/log/admin.log", - "address": { - "socket_address": { - "address": "127.0.0.1", - "port_value": 9001 - } - } - } -}`, - }, - "--xds-address=8.8.8.8 --xds-port=9200": { - config: envoy.BootstrapConfig{ - Path: "envoy.json", - XDSAddress: "8.8.8.8", - XDSGRPCPort: 9200, - Namespace: "testing-ns", - }, - wantedBootstrapConfig: `{ - "static_resources": { - "clusters": [ - { - "name": "contour", - "alt_stat_name": "testing-ns_contour_9200", - "type": "STRICT_DNS", - "connect_timeout": "5s", - "load_assignment": { - "cluster_name": "contour", - "endpoints": [ - { - "lb_endpoints": [ - { - "endpoint": { - "address": { - "socket_address": { - "address": "8.8.8.8", - "port_value": 9200 - } - } - } - } - ] - } - ] - }, - "circuit_breakers": { - "thresholds": [ - { - "priority": "HIGH", - "max_connections": 100000, - "max_pending_requests": 100000, - "max_requests": 60000000, - "max_retries": 50 - }, - { - "max_connections": 100000, - "max_pending_requests": 100000, - "max_requests": 60000000, - "max_retries": 50 - } - ] - }, - "http2_protocol_options": {}, - "upstream_connection_options": { - "tcp_keepalive": { - "keepalive_probes": 3, - "keepalive_time": 30, - "keepalive_interval": 5 - } - } - }, - { - "name": "service-stats", - "alt_stat_name": "testing-ns_service-stats_9001", - "type": "LOGICAL_DNS", - "connect_timeout": "0.250s", - "load_assignment": { - "cluster_name": "service-stats", - "endpoints": [ - { - "lb_endpoints": [ - { - "endpoint": { - "address": { - "socket_address": { - "address": "127.0.0.1", - "port_value": 9001 - } - } - } - } - ] - } - ] - } - } - ] - }, - "dynamic_resources": { - "lds_config": { - "api_config_source": { - "api_type": "GRPC", - "grpc_services": [ - { - "envoy_grpc": { - "cluster_name": "contour" - } - } - ] - } - }, - "cds_config": { - "api_config_source": { - "api_type": "GRPC", - "grpc_services": [ - { - "envoy_grpc": { - "cluster_name": "contour" - } - } - ] - } - } - }, - "admin": { - "access_log_path": "/dev/null", - "address": { - "socket_address": { - "address": "127.0.0.1", - "port_value": 9001 - } - } - } -}`, - }, - "--stats-address=8.8.8.8 --stats-port=9200": { - config: envoy.BootstrapConfig{ - Path: "envoy.json", - Namespace: "testing-ns", - }, - wantedBootstrapConfig: `{ - "static_resources": { - "clusters": [ - { - "name": "contour", - "alt_stat_name": "testing-ns_contour_8001", - "type": "STRICT_DNS", - "connect_timeout": "5s", - "load_assignment": { - "cluster_name": "contour", - "endpoints": [ - { - "lb_endpoints": [ - { - "endpoint": { - "address": { - "socket_address": { - "address": "127.0.0.1", - "port_value": 8001 - } - } - } - } - ] - } - ] - }, - "circuit_breakers": { - "thresholds": [ - { - "priority": "HIGH", - "max_connections": 100000, - "max_pending_requests": 100000, - "max_requests": 60000000, - "max_retries": 50 - }, - { - "max_connections": 100000, - "max_pending_requests": 100000, - "max_requests": 60000000, - "max_retries": 50 - } - ] - }, - "http2_protocol_options": {}, - "upstream_connection_options": { - "tcp_keepalive": { - "keepalive_probes": 3, - "keepalive_time": 30, - "keepalive_interval": 5 - } - } - }, - { - "name": "service-stats", - "alt_stat_name": "testing-ns_service-stats_9001", - "type": "LOGICAL_DNS", - "connect_timeout": "0.250s", - "load_assignment": { - "cluster_name": "service-stats", - "endpoints": [ - { - "lb_endpoints": [ - { - "endpoint": { - "address": { - "socket_address": { - "address": "127.0.0.1", - "port_value": 9001 - } - } - } - } - ] - } - ] - } - } - ] - }, - "dynamic_resources": { - "lds_config": { - "api_config_source": { - "api_type": "GRPC", - "grpc_services": [ - { - "envoy_grpc": { - "cluster_name": "contour" - } - } - ] - } - }, - "cds_config": { - "api_config_source": { - "api_type": "GRPC", - "grpc_services": [ - { - "envoy_grpc": { - "cluster_name": "contour" - } - } - ] - } - } - }, - "admin": { - "access_log_path": "/dev/null", - "address": { - "socket_address": { - "address": "127.0.0.1", - "port_value": 9001 - } - } - } -}`, - }, - "--envoy-cafile=CA.cert --envoy-client-cert=client.cert --envoy-client-key=client.key": { - config: envoy.BootstrapConfig{ - Path: "envoy.json", - Namespace: "testing-ns", - GrpcCABundle: "CA.cert", - GrpcClientCert: "client.cert", - GrpcClientKey: "client.key", - SkipFilePathCheck: true, - }, - wantedBootstrapConfig: `{ - "static_resources": { - "clusters": [ - { - "name": "contour", - "alt_stat_name": "testing-ns_contour_8001", - "type": "STRICT_DNS", - "connect_timeout": "5s", - "load_assignment": { - "cluster_name": "contour", - "endpoints": [ - { - "lb_endpoints": [ - { - "endpoint": { - "address": { - "socket_address": { - "address": "127.0.0.1", - "port_value": 8001 - } - } - } - } - ] - } - ] - }, - "circuit_breakers": { - "thresholds": [ - { - "priority": "HIGH", - "max_connections": 100000, - "max_pending_requests": 100000, - "max_requests": 60000000, - "max_retries": 50 - }, - { - "max_connections": 100000, - "max_pending_requests": 100000, - "max_requests": 60000000, - "max_retries": 50 - } - ] - }, - "http2_protocol_options": {}, - "upstream_connection_options": { - "tcp_keepalive": { - "keepalive_probes": 3, - "keepalive_time": 30, - "keepalive_interval": 5 - } - }, - "transport_socket": { - "name": "envoy.transport_sockets.tls", - "typed_config": { - "@type":"type.googleapis.com/envoy.api.v2.auth.UpstreamTlsContext", - "common_tls_context": { - "tls_certificates": [ - { - "certificate_chain": { - "filename": "client.cert" - }, - "private_key": { - "filename": "client.key" - } - } - ], - "validation_context": { - "trusted_ca": { - "filename": "CA.cert" - }, - "match_subject_alt_names": [ - { - "exact": "contour" - } - ] - } - } - } - } - }, - { - "name": "service-stats", - "alt_stat_name": "testing-ns_service-stats_9001", - "type": "LOGICAL_DNS", - "connect_timeout": "0.250s", - "load_assignment": { - "cluster_name": "service-stats", - "endpoints": [ - { - "lb_endpoints": [ - { - "endpoint": { - "address": { - "socket_address": { - "address": "127.0.0.1", - "port_value": 9001 - } - } - } - } - ] - } - ] - } - } - ] - }, - "dynamic_resources": { - "lds_config": { - "api_config_source": { - "api_type": "GRPC", - "grpc_services": [ - { - "envoy_grpc": { - "cluster_name": "contour" - } - } - ] - } - }, - "cds_config": { - "api_config_source": { - "api_type": "GRPC", - "grpc_services": [ - { - "envoy_grpc": { - "cluster_name": "contour" - } - } - ] - } - } - }, - "admin": { - "access_log_path": "/dev/null", - "address": { - "socket_address": { - "address": "127.0.0.1", - "port_value": 9001 - } - } - } -}`, - }, - "--resources-dir tmp --envoy-cafile=CA.cert --envoy-client-cert=client.cert --envoy-client-key=client.key": { - config: envoy.BootstrapConfig{ - Path: "envoy.json", - Namespace: "testing-ns", - ResourcesDir: "resources", - GrpcCABundle: "CA.cert", - GrpcClientCert: "client.cert", - GrpcClientKey: "client.key", - SkipFilePathCheck: true, - }, - wantedBootstrapConfig: `{ - "static_resources": { - "clusters": [ - { - "name": "contour", - "alt_stat_name": "testing-ns_contour_8001", - "type": "STRICT_DNS", - "connect_timeout": "5s", - "load_assignment": { - "cluster_name": "contour", - "endpoints": [ - { - "lb_endpoints": [ - { - "endpoint": { - "address": { - "socket_address": { - "address": "127.0.0.1", - "port_value": 8001 - } - } - } - } - ] - } - ] - }, - "circuit_breakers": { - "thresholds": [ - { - "priority": "HIGH", - "max_connections": 100000, - "max_pending_requests": 100000, - "max_requests": 60000000, - "max_retries": 50 - }, - { - "max_connections": 100000, - "max_pending_requests": 100000, - "max_requests": 60000000, - "max_retries": 50 - } - ] - }, - "http2_protocol_options": {}, - "transport_socket": { - "name": "envoy.transport_sockets.tls", - "typed_config": { - "@type": "type.googleapis.com/envoy.api.v2.auth.UpstreamTlsContext", - "common_tls_context": { - "tls_certificate_sds_secret_configs": [ - { - "sds_config": { - "path": "resources/sds/xds-tls-certificate.json" - } - } - ], - "validation_context_sds_secret_config": { - "sds_config": { - "path": "resources/sds/xds-validation-context.json" - } - } - } - } - }, - "upstream_connection_options": { - "tcp_keepalive": { - "keepalive_probes": 3, - "keepalive_time": 30, - "keepalive_interval": 5 - } - } - }, - { - "name": "service-stats", - "alt_stat_name": "testing-ns_service-stats_9001", - "type": "LOGICAL_DNS", - "connect_timeout": "0.250s", - "load_assignment": { - "cluster_name": "service-stats", - "endpoints": [ - { - "lb_endpoints": [ - { - "endpoint": { - "address": { - "socket_address": { - "address": "127.0.0.1", - "port_value": 9001 - } - } - } - } - ] - } - ] - } - } - ] - }, - "dynamic_resources": { - "lds_config": { - "api_config_source": { - "api_type": "GRPC", - "grpc_services": [ - { - "envoy_grpc": { - "cluster_name": "contour" - } - } - ] - } - }, - "cds_config": { - "api_config_source": { - "api_type": "GRPC", - "grpc_services": [ - { - "envoy_grpc": { - "cluster_name": "contour" - } - } - ] - } - } - }, - "admin": { - "access_log_path": "/dev/null", - "address": { - "socket_address": { - "address": "127.0.0.1", - "port_value": 9001 - } - } - } - }`, - wantedTLSCertificateConfig: `{ - "resources": [ - { - "@type": "type.googleapis.com/envoy.api.v2.auth.Secret", - "tls_certificate": { - "certificate_chain": { - "filename": "client.cert" - }, - "private_key": { - "filename": "client.key" - } - } - } - ] - }`, - wantedValidationContextConfig: `{ - "resources": [ - { - "@type": "type.googleapis.com/envoy.api.v2.auth.Secret", - "validation_context": { - "trusted_ca": { - "filename": "CA.cert" - }, - "match_subject_alt_names": [ - { - "exact": "contour" - } - ] - } - } - ] - }`, - }, - "return error when not providing all certificate related parameters": { - config: envoy.BootstrapConfig{ - Path: "envoy.json", - Namespace: "testing-ns", - ResourcesDir: "resources", - GrpcClientCert: "client.cert", - GrpcClientKey: "client.key", - }, - wantedError: true, - }} - - for name, tc := range tests { - t.Run(name, func(t *testing.T) { - steps, gotError := bootstrap(&tc.config) - assert.Equal(t, gotError != nil, tc.wantedError) - - gotConfigs := map[string]proto.Message{} - for _, step := range steps { - path, config := step(&tc.config) - gotConfigs[path] = config - } - - sdsTLSCertificatePath := path.Join(tc.config.ResourcesDir, envoy.SDSResourcesSubdirectory, envoy.SDSTLSCertificateFile) - sdsValidationContextPath := path.Join(tc.config.ResourcesDir, envoy.SDSResourcesSubdirectory, envoy.SDSValidationContextFile) - - if tc.wantedBootstrapConfig != "" { - want := new(envoy_api_bootstrap.Bootstrap) - unmarshal(t, tc.wantedBootstrapConfig, want) - protobuf.ExpectEqual(t, want, gotConfigs[tc.config.Path]) - delete(gotConfigs, tc.config.Path) - } - - if tc.wantedTLSCertificateConfig != "" { - want := new(api.DiscoveryResponse) - unmarshal(t, tc.wantedTLSCertificateConfig, want) - protobuf.ExpectEqual(t, want, gotConfigs[sdsTLSCertificatePath]) - delete(gotConfigs, sdsTLSCertificatePath) - } - - if tc.wantedValidationContextConfig != "" { - want := new(api.DiscoveryResponse) - unmarshal(t, tc.wantedValidationContextConfig, want) - protobuf.ExpectEqual(t, want, gotConfigs[sdsValidationContextPath]) - delete(gotConfigs, sdsValidationContextPath) - } - - if len(gotConfigs) > 0 { - t.Fatalf("got more configs than wanted: %s", gotConfigs) - } - }) - } -} - -func unmarshal(t *testing.T, data string, pb proto.Message) { - err := jsonpb.UnmarshalString(data, pb) - checkErr(t, err) -} - -func checkErr(t *testing.T, err error) { - t.Helper() - if err != nil { - t.Fatal(err) - } -} diff --git a/pkg/config/parameters.go b/pkg/config/parameters.go index 161f56f6607..b638db00e09 100644 --- a/pkg/config/parameters.go +++ b/pkg/config/parameters.go @@ -45,13 +45,12 @@ func (s ServerType) Validate() error { // ResourceVersion is a version of an xDS server. type ResourceVersion string -const XDSv2 ResourceVersion = "v2" const XDSv3 ResourceVersion = "v3" // Validate the xDS server versions. func (s ResourceVersion) Validate() error { switch s { - case XDSv2, XDSv3: + case XDSv3: return nil default: return fmt.Errorf("invalid xDS version %q", s) diff --git a/site/docs/main/configuration.md b/site/docs/main/configuration.md index 109433781fe..62bd0e76690 100644 --- a/site/docs/main/configuration.md +++ b/site/docs/main/configuration.md @@ -210,7 +210,7 @@ connects to Contour: | --envoy-cert-file | "" | Client certificate filename for Envoy secure xDS gRPC communication. | | --envoy-key-file | "" | Client key filename for Envoy secure xDS gRPC communication. | | --namespace | projectcontour | Namespace the Envoy container will run, also configured via ENV variable "CONTOUR_NAMESPACE". Namespace is used as part of the metric names on static resources defined in the bootstrap configuration file. | -| --xds-resource-version | v2 | Specify the xDS API resource version to use. Options are `v2` or `v3`. | +| --xds-resource-version | v3 | Currently, the only valid xDS API resource version is `v3`. | {: class="table thead-dark table-bordered"}