Merge branch 'main' into msiege2/docs-day

pull/11984/head
Matt Siegel 2022-01-11 16:16:41 -05:00 committed by GitHub
commit f8bb804d36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
99 changed files with 4798 additions and 22605 deletions

3
.changelog/11576.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:feature
ingress: allow setting TLS min version and cipher suites in ingress gateway config entries
```

4
.changelog/11979.txt Normal file
View File

@ -0,0 +1,4 @@
```release-note:bug
ui: Ensure partition query parameter is passed through to all OIDC related API
requests
```

View File

@ -122,7 +122,10 @@ func (s *HTTPHandlers) ACLPolicyCRUD(resp http.ResponseWriter, req *http.Request
return nil, MethodNotAllowedError{req.Method, []string{"GET", "PUT", "DELETE"}}
}
policyID := strings.TrimPrefix(req.URL.Path, "/v1/acl/policy/")
policyID, err := getPathSuffixUnescaped(req.URL.Path, "/v1/acl/policy/")
if err != nil {
return nil, err
}
if policyID == "" && req.Method != "PUT" {
return nil, BadRequestError{Reason: "Missing policy ID"}
}
@ -167,7 +170,10 @@ func (s *HTTPHandlers) ACLPolicyReadByName(resp http.ResponseWriter, req *http.R
return nil, aclDisabled
}
policyName := strings.TrimPrefix(req.URL.Path, "/v1/acl/policy/name/")
policyName, err := getPathSuffixUnescaped(req.URL.Path, "/v1/acl/policy/name/")
if err != nil {
return nil, err
}
if policyName == "" {
return nil, BadRequestError{Reason: "Missing policy Name"}
}
@ -302,7 +308,10 @@ func (s *HTTPHandlers) ACLTokenCRUD(resp http.ResponseWriter, req *http.Request)
return nil, MethodNotAllowedError{req.Method, []string{"GET", "PUT", "DELETE"}}
}
tokenID := strings.TrimPrefix(req.URL.Path, "/v1/acl/token/")
tokenID, err := getPathSuffixUnescaped(req.URL.Path, "/v1/acl/token/")
if err != nil {
return nil, err
}
if strings.HasSuffix(tokenID, "/clone") && req.Method == "PUT" {
tokenID = tokenID[:len(tokenID)-6]
fn = s.ACLTokenClone
@ -521,7 +530,10 @@ func (s *HTTPHandlers) ACLRoleCRUD(resp http.ResponseWriter, req *http.Request)
return nil, MethodNotAllowedError{req.Method, []string{"GET", "PUT", "DELETE"}}
}
roleID := strings.TrimPrefix(req.URL.Path, "/v1/acl/role/")
roleID, err := getPathSuffixUnescaped(req.URL.Path, "/v1/acl/role/")
if err != nil {
return nil, err
}
if roleID == "" && req.Method != "PUT" {
return nil, BadRequestError{Reason: "Missing role ID"}
}
@ -534,7 +546,10 @@ func (s *HTTPHandlers) ACLRoleReadByName(resp http.ResponseWriter, req *http.Req
return nil, aclDisabled
}
roleName := strings.TrimPrefix(req.URL.Path, "/v1/acl/role/name/")
roleName, err := getPathSuffixUnescaped(req.URL.Path, "/v1/acl/role/name/")
if err != nil {
return nil, err
}
if roleName == "" {
return nil, BadRequestError{Reason: "Missing role Name"}
}
@ -685,7 +700,10 @@ func (s *HTTPHandlers) ACLBindingRuleCRUD(resp http.ResponseWriter, req *http.Re
return nil, MethodNotAllowedError{req.Method, []string{"GET", "PUT", "DELETE"}}
}
bindingRuleID := strings.TrimPrefix(req.URL.Path, "/v1/acl/binding-rule/")
bindingRuleID, err := getPathSuffixUnescaped(req.URL.Path, "/v1/acl/binding-rule/")
if err != nil {
return nil, err
}
if bindingRuleID == "" && req.Method != "PUT" {
return nil, BadRequestError{Reason: "Missing binding rule ID"}
}
@ -829,7 +847,10 @@ func (s *HTTPHandlers) ACLAuthMethodCRUD(resp http.ResponseWriter, req *http.Req
return nil, MethodNotAllowedError{req.Method, []string{"GET", "PUT", "DELETE"}}
}
methodName := strings.TrimPrefix(req.URL.Path, "/v1/acl/auth-method/")
methodName, err := getPathSuffixUnescaped(req.URL.Path, "/v1/acl/auth-method/")
if err != nil {
return nil, err
}
if methodName == "" && req.Method != "PUT" {
return nil, BadRequestError{Reason: "Missing auth method name"}
}

View File

@ -3,7 +3,6 @@ package agent
import (
"fmt"
"net/http"
"strings"
metrics "github.com/armon/go-metrics"
"github.com/armon/go-metrics/prometheus"
@ -362,7 +361,11 @@ func (s *HTTPHandlers) catalogServiceNodes(resp http.ResponseWriter, req *http.R
}
// Pull out the service name
args.ServiceName = strings.TrimPrefix(req.URL.Path, pathPrefix)
var err error
args.ServiceName, err = getPathSuffixUnescaped(req.URL.Path, pathPrefix)
if err != nil {
return nil, err
}
if args.ServiceName == "" {
resp.WriteHeader(http.StatusBadRequest)
fmt.Fprint(resp, "Missing service name")
@ -435,7 +438,11 @@ func (s *HTTPHandlers) CatalogNodeServices(resp http.ResponseWriter, req *http.R
}
// Pull out the node name
args.Node = strings.TrimPrefix(req.URL.Path, "/v1/catalog/node/")
var err error
args.Node, err = getPathSuffixUnescaped(req.URL.Path, "/v1/catalog/node/")
if err != nil {
return nil, err
}
if args.Node == "" {
resp.WriteHeader(http.StatusBadRequest)
fmt.Fprint(resp, "Missing node name")
@ -498,7 +505,11 @@ func (s *HTTPHandlers) CatalogNodeServiceList(resp http.ResponseWriter, req *htt
}
// Pull out the node name
args.Node = strings.TrimPrefix(req.URL.Path, "/v1/catalog/node-services/")
var err error
args.Node, err = getPathSuffixUnescaped(req.URL.Path, "/v1/catalog/node-services/")
if err != nil {
return nil, err
}
if args.Node == "" {
resp.WriteHeader(http.StatusBadRequest)
fmt.Fprint(resp, "Missing node name")
@ -547,7 +558,11 @@ func (s *HTTPHandlers) CatalogGatewayServices(resp http.ResponseWriter, req *htt
}
// Pull out the gateway's service name
args.ServiceName = strings.TrimPrefix(req.URL.Path, "/v1/catalog/gateway-services/")
var err error
args.ServiceName, err = getPathSuffixUnescaped(req.URL.Path, "/v1/catalog/gateway-services/")
if err != nil {
return nil, err
}
if args.ServiceName == "" {
resp.WriteHeader(http.StatusBadRequest)
fmt.Fprint(resp, "Missing gateway name")

View File

@ -32,7 +32,11 @@ func (s *HTTPHandlers) configGet(resp http.ResponseWriter, req *http.Request) (i
if done := s.parse(resp, req, &args.Datacenter, &args.QueryOptions); done {
return nil, nil
}
pathArgs := strings.SplitN(strings.TrimPrefix(req.URL.Path, "/v1/config/"), "/", 2)
kindAndName, err := getPathSuffixUnescaped(req.URL.Path, "/v1/config/")
if err != nil {
return nil, err
}
pathArgs := strings.SplitN(kindAndName, "/", 2)
switch len(pathArgs) {
case 2:
@ -79,7 +83,11 @@ func (s *HTTPHandlers) configDelete(resp http.ResponseWriter, req *http.Request)
var args structs.ConfigEntryRequest
s.parseDC(req, &args.Datacenter)
s.parseToken(req, &args.Token)
pathArgs := strings.SplitN(strings.TrimPrefix(req.URL.Path, "/v1/config/"), "/", 2)
kindAndName, err := getPathSuffixUnescaped(req.URL.Path, "/v1/config/")
if err != nil {
return nil, err
}
pathArgs := strings.SplitN(kindAndName, "/", 2)
if len(pathArgs) != 2 {
resp.WriteHeader(http.StatusNotFound)

View File

@ -4,7 +4,6 @@ import (
"fmt"
"net/http"
"sort"
"strings"
"github.com/hashicorp/consul/agent/structs"
)
@ -103,7 +102,10 @@ func (s *HTTPHandlers) CoordinateNode(resp http.ResponseWriter, req *http.Reques
return nil, nil
}
node := strings.TrimPrefix(req.URL.Path, "/v1/coordinate/node/")
node, err := getPathSuffixUnescaped(req.URL.Path, "/v1/coordinate/node/")
if err != nil {
return nil, err
}
args := structs.NodeSpecificRequest{Node: node}
if done := s.parse(resp, req, &args.Datacenter, &args.QueryOptions); done {
return nil, nil

View File

@ -3,7 +3,6 @@ package agent
import (
"fmt"
"net/http"
"strings"
"time"
"github.com/mitchellh/mapstructure"
@ -19,7 +18,11 @@ func (s *HTTPHandlers) DiscoveryChainRead(resp http.ResponseWriter, req *http.Re
return nil, nil
}
args.Name = strings.TrimPrefix(req.URL.Path, "/v1/discovery-chain/")
var err error
args.Name, err = getPathSuffixUnescaped(req.URL.Path, "/v1/discovery-chain/")
if err != nil {
return nil, err
}
if args.Name == "" {
return nil, BadRequestError{Reason: "Missing chain name"}
}

View File

@ -1082,34 +1082,31 @@ func (l *State) updateSyncState() error {
continue
}
// to avoid a data race with the service struct,
// We copy the Service struct, mutate it and replace the pointer
svc := *ls.Service
// If our definition is different, we need to update it. Make a
// copy so that we don't retain a pointer to any actual state
// store info for in-memory RPCs.
if svc.EnableTagOverride {
svc.Tags = make([]string, len(rs.Tags))
copy(svc.Tags, rs.Tags)
if ls.Service.EnableTagOverride {
ls.Service.Tags = make([]string, len(rs.Tags))
copy(ls.Service.Tags, rs.Tags)
}
// Merge any tagged addresses with the consul- prefix (set by the server)
// back into the local state.
if !reflect.DeepEqual(svc.TaggedAddresses, rs.TaggedAddresses) {
if svc.TaggedAddresses == nil {
svc.TaggedAddresses = make(map[string]structs.ServiceAddress)
if !reflect.DeepEqual(ls.Service.TaggedAddresses, rs.TaggedAddresses) {
// Make a copy of TaggedAddresses to prevent races when writing
// since other goroutines may be reading from the map
m := make(map[string]structs.ServiceAddress)
for k, v := range ls.Service.TaggedAddresses {
m[k] = v
}
for k, v := range rs.TaggedAddresses {
if strings.HasPrefix(k, structs.MetaKeyReservedPrefix) {
svc.TaggedAddresses[k] = v
m[k] = v
}
}
ls.Service.TaggedAddresses = m
}
ls.InSync = svc.IsSame(rs)
// replace the service pointer to the new mutated struct
ls.Service = &svc
ls.InSync = ls.Service.IsSame(rs)
}
// Check which checks need syncing

View File

@ -373,36 +373,41 @@ func TestAgentAntiEntropy_Services_ConnectProxy(t *testing.T) {
// We should have 5 services (consul included)
assert.Len(services.NodeServices.Services, 5)
// All the services should match
// Check that virtual IPs have been set
vips := make(map[string]struct{})
srv1.TaggedAddresses = nil
srv2.TaggedAddresses = nil
for id, serv := range services.NodeServices.Services {
serv.CreateIndex, serv.ModifyIndex = 0, 0
for _, serv := range services.NodeServices.Services {
if serv.TaggedAddresses != nil {
serviceVIP := serv.TaggedAddresses[structs.TaggedAddressVirtualIP].Address
assert.NotEmpty(serviceVIP)
vips[serviceVIP] = struct{}{}
}
serv.TaggedAddresses = nil
}
assert.Len(vips, 4)
// All the services should match
// Retry to mitigate data races between local and remote state
retry.Run(t, func(r *retry.R) {
require.NoError(r, a.State.SyncFull())
for id, serv := range services.NodeServices.Services {
serv.CreateIndex, serv.ModifyIndex = 0, 0
switch id {
case "mysql-proxy":
assert.Equal(srv1, serv)
require.Equal(r, srv1, serv)
case "redis-proxy":
assert.Equal(srv2, serv)
require.Equal(r, srv2, serv)
case "web-proxy":
assert.Equal(srv3, serv)
require.Equal(r, srv3, serv)
case "cache-proxy":
assert.Equal(srv5, serv)
require.Equal(r, srv5, serv)
case structs.ConsulServiceID:
// ignore
default:
t.Fatalf("unexpected service: %v", id)
r.Fatalf("unexpected service: %v", id)
}
}
})
assert.Len(vips, 4)
assert.Nil(servicesInSync(a.State, 4, structs.DefaultEnterpriseMetaInDefaultPartition()))
assert.NoError(servicesInSync(a.State, 4, structs.DefaultEnterpriseMetaInDefaultPartition()))
// Remove one of the services
a.State.RemoveService(structs.NewServiceID("cache-proxy", nil))
@ -415,12 +420,6 @@ func TestAgentAntiEntropy_Services_ConnectProxy(t *testing.T) {
// All the services should match
for id, serv := range services.NodeServices.Services {
serv.CreateIndex, serv.ModifyIndex = 0, 0
if serv.TaggedAddresses != nil {
serviceVIP := serv.TaggedAddresses[structs.TaggedAddressVirtualIP].Address
assert.NotEmpty(serviceVIP)
vips[serviceVIP] = struct{}{}
}
serv.TaggedAddresses = nil
switch id {
case "mysql-proxy":
assert.Equal(srv1, serv)

View File

@ -9,6 +9,7 @@ import (
"github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/lib/stringslice"
"github.com/hashicorp/consul/types"
)
// IngressGatewayConfigEntry manages the configuration for an ingress service
@ -99,6 +100,13 @@ type GatewayTLSConfig struct {
// SDS allows configuring TLS certificate from an SDS service.
SDS *GatewayTLSSDSConfig `json:",omitempty"`
TLSMinVersion types.TLSVersion `json:",omitempty" alias:"tls_min_version"`
TLSMaxVersion types.TLSVersion `json:",omitempty" alias:"tls_max_version"`
// Define a subset of cipher suites to restrict
// Only applicable to connections negotiated via TLS 1.2 or earlier
CipherSuites []types.TLSCipherSuite `json:",omitempty" alias:"cipher_suites"`
}
type GatewayServiceTLSConfig struct {
@ -231,11 +239,49 @@ func (e *IngressGatewayConfigEntry) validateServiceSDS(lis IngressListener, svc
return nil
}
func validateGatewayTLSConfig(tlsCfg GatewayTLSConfig) error {
if tlsCfg.TLSMinVersion != types.TLSVersionUnspecified {
if err := types.ValidateTLSVersion(tlsCfg.TLSMinVersion); err != nil {
return err
}
}
if tlsCfg.TLSMaxVersion != types.TLSVersionUnspecified {
if err := types.ValidateTLSVersion(tlsCfg.TLSMaxVersion); err != nil {
return err
}
if tlsCfg.TLSMinVersion != types.TLSVersionUnspecified {
if err, maxLessThanMin := tlsCfg.TLSMaxVersion.LessThan(tlsCfg.TLSMinVersion); err == nil && maxLessThanMin {
return fmt.Errorf("configuring max version %s less than the configured min version %s is invalid", tlsCfg.TLSMaxVersion, tlsCfg.TLSMinVersion)
}
}
}
if len(tlsCfg.CipherSuites) != 0 {
if _, ok := types.TLSVersionsWithConfigurableCipherSuites[tlsCfg.TLSMinVersion]; !ok {
return fmt.Errorf("configuring CipherSuites is only applicable to conncetions negotiated with TLS 1.2 or earlier, TLSMinVersion is set to %s", tlsCfg.TLSMinVersion)
}
// NOTE: it would be nice to emit a warning but not return an error from
// here if TLSMaxVersion is unspecified, TLS_AUTO or TLSv1_3
if err := types.ValidateEnvoyCipherSuites(tlsCfg.CipherSuites); err != nil {
return err
}
}
return nil
}
func (e *IngressGatewayConfigEntry) Validate() error {
if err := validateConfigEntryMeta(e.Meta); err != nil {
return err
}
if err := validateGatewayTLSConfig(e.TLS); err != nil {
return err
}
validProtocols := map[string]bool{
"tcp": true,
"http": true,
@ -264,6 +310,12 @@ func (e *IngressGatewayConfigEntry) Validate() error {
listener.Port)
}
if listener.TLS != nil {
if err := validateGatewayTLSConfig(*listener.TLS); err != nil {
return err
}
}
declaredHosts := make(map[string]bool)
serviceNames := make(map[ServiceID]struct{})
for _, s := range listener.Services {

View File

@ -16,6 +16,7 @@ import (
"github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/agent/cache"
"github.com/hashicorp/consul/sdk/testutil"
"github.com/hashicorp/consul/types"
)
func TestConfigEntries_ACLs(t *testing.T) {
@ -1107,6 +1108,7 @@ func TestDecodeConfigEntry(t *testing.T) {
},
},
{
// TODO(rb): test SDS stuff here in both places (global/service)
name: "ingress-gateway: kitchen sink",
snake: `
kind = "ingress-gateway"
@ -1118,6 +1120,12 @@ func TestDecodeConfigEntry(t *testing.T) {
tls {
enabled = true
tls_min_version = "TLSv1_1"
tls_max_version = "TLSv1_2"
cipher_suites = [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
}
listeners = [
@ -1181,6 +1189,12 @@ func TestDecodeConfigEntry(t *testing.T) {
}
TLS {
Enabled = true
TLSMinVersion = "TLSv1_1"
TLSMaxVersion = "TLSv1_2"
CipherSuites = [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
}
Listeners = [
{
@ -1243,6 +1257,12 @@ func TestDecodeConfigEntry(t *testing.T) {
},
TLS: GatewayTLSConfig{
Enabled: true,
TLSMinVersion: types.TLSv1_1,
TLSMaxVersion: types.TLSv1_2,
CipherSuites: []types.TLSCipherSuite{
types.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
types.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
},
},
Listeners: []IngressListener{
{

View File

@ -186,7 +186,7 @@ func makePassthroughClusters(cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message,
ConnectTimeout: ptypes.DurationProto(5 * time.Second),
}
commonTLSContext := makeCommonTLSContextFromLeaf(cfgSnap, cfgSnap.Leaf())
commonTLSContext := makeCommonTLSContextFromLeafWithoutParams(cfgSnap, cfgSnap.Leaf())
err := injectSANMatcher(commonTLSContext, passthrough.SpiffeID)
if err != nil {
return nil, fmt.Errorf("failed to inject SAN matcher rules for cluster %q: %v", passthrough.SNI, err)
@ -550,7 +550,7 @@ func (s *ResourceGenerator) makeUpstreamClusterForPreparedQuery(upstream structs
}
// Enable TLS upstream with the configured client certificate.
commonTLSContext := makeCommonTLSContextFromLeaf(cfgSnap, cfgSnap.Leaf())
commonTLSContext := makeCommonTLSContextFromLeafWithoutParams(cfgSnap, cfgSnap.Leaf())
err = injectSANMatcher(commonTLSContext, spiffeIDs...)
if err != nil {
return nil, fmt.Errorf("failed to inject SAN matcher rules for cluster %q: %v", sni, err)
@ -728,7 +728,7 @@ func (s *ResourceGenerator) makeUpstreamClustersForDiscoveryChain(
c.Http2ProtocolOptions = &envoy_core_v3.Http2ProtocolOptions{}
}
commonTLSContext := makeCommonTLSContextFromLeaf(cfgSnap, cfgSnap.Leaf())
commonTLSContext := makeCommonTLSContextFromLeafWithoutParams(cfgSnap, cfgSnap.Leaf())
err = injectSANMatcher(commonTLSContext, spiffeIDs...)
if err != nil {
return nil, fmt.Errorf("failed to inject SAN matcher rules for cluster %q: %v", sni, err)

View File

@ -740,7 +740,7 @@ func injectHTTPFilterOnFilterChains(
func (s *ResourceGenerator) injectConnectTLSOnFilterChains(cfgSnap *proxycfg.ConfigSnapshot, listener *envoy_listener_v3.Listener) error {
for idx := range listener.FilterChains {
tlsContext := &envoy_tls_v3.DownstreamTlsContext{
CommonTlsContext: makeCommonTLSContextFromLeaf(cfgSnap, cfgSnap.Leaf()),
CommonTlsContext: makeCommonTLSContextFromLeafWithoutParams(cfgSnap, cfgSnap.Leaf()),
RequireClientCertificate: &wrappers.BoolValue{Value: true},
}
transportSocket, err := makeDownstreamTLSTransportSocket(tlsContext)
@ -1062,7 +1062,7 @@ func (s *ResourceGenerator) makeFilterChainTerminatingGateway(
protocol string,
) (*envoy_listener_v3.FilterChain, error) {
tlsContext := &envoy_tls_v3.DownstreamTlsContext{
CommonTlsContext: makeCommonTLSContextFromLeaf(cfgSnap, cfgSnap.TerminatingGateway.ServiceLeaves[service]),
CommonTlsContext: makeCommonTLSContextFromLeafWithoutParams(cfgSnap, cfgSnap.TerminatingGateway.ServiceLeaves[service]),
RequireClientCertificate: &wrappers.BoolValue{Value: true},
}
transportSocket, err := makeDownstreamTLSTransportSocket(tlsContext)
@ -1536,7 +1536,11 @@ func makeEnvoyHTTPFilter(name string, cfg proto.Message) (*envoy_http_v3.HttpFil
}, nil
}
func makeCommonTLSContextFromLeaf(cfgSnap *proxycfg.ConfigSnapshot, leaf *structs.IssuedCert) *envoy_tls_v3.CommonTlsContext {
func makeCommonTLSContextFromLeafWithoutParams(cfgSnap *proxycfg.ConfigSnapshot, leaf *structs.IssuedCert) *envoy_tls_v3.CommonTlsContext {
return makeCommonTLSContextFromLeaf(cfgSnap, leaf, nil)
}
func makeCommonTLSContextFromLeaf(cfgSnap *proxycfg.ConfigSnapshot, leaf *structs.IssuedCert, tlsParams *envoy_tls_v3.TlsParameters) *envoy_tls_v3.CommonTlsContext {
// Concatenate all the root PEMs into one.
if cfgSnap.Roots == nil {
return nil
@ -1547,8 +1551,12 @@ func makeCommonTLSContextFromLeaf(cfgSnap *proxycfg.ConfigSnapshot, leaf *struct
rootPEMS += ca.EnsureTrailingNewline(root.RootCert)
}
if tlsParams == nil {
tlsParams = &envoy_tls_v3.TlsParameters{}
}
return &envoy_tls_v3.CommonTlsContext{
TlsParams: &envoy_tls_v3.TlsParameters{},
TlsParams: tlsParams,
TlsCertificates: []*envoy_tls_v3.TlsCertificate{
{
CertificateChain: &envoy_core_v3.DataSource{

View File

@ -8,43 +8,26 @@ import (
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes/duration"
"github.com/golang/protobuf/ptypes/wrappers"
"github.com/hashicorp/consul/agent/proxycfg"
"github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/types"
)
func (s *ResourceGenerator) makeIngressGatewayListeners(address string, cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) {
var resources []proto.Message
for listenerKey, upstreams := range cfgSnap.IngressGateway.Upstreams {
var tlsContext *envoy_tls_v3.DownstreamTlsContext
listenerCfg, ok := cfgSnap.IngressGateway.Listeners[listenerKey]
if !ok {
return nil, fmt.Errorf("no listener config found for listener on port %d", listenerKey.Port)
}
// Enable connect TLS if it is enabled at the Gateway or specific listener
// level.
connectTLSEnabled := cfgSnap.IngressGateway.TLSConfig.Enabled ||
(listenerCfg.TLS != nil && listenerCfg.TLS.Enabled)
sdsCfg, err := resolveListenerSDSConfig(cfgSnap, listenerCfg)
tlsContext, err := makeDownstreamTLSContextFromSnapshotListenerConfig(cfgSnap, listenerCfg)
if err != nil {
return nil, err
}
if sdsCfg != nil {
// Set up listener TLS from SDS
tlsContext = &envoy_tls_v3.DownstreamTlsContext{
CommonTlsContext: makeCommonTLSContextFromSDS(*sdsCfg),
RequireClientCertificate: &wrappers.BoolValue{Value: false},
}
} else if connectTLSEnabled {
tlsContext = &envoy_tls_v3.DownstreamTlsContext{
CommonTlsContext: makeCommonTLSContextFromLeaf(cfgSnap, cfgSnap.Leaf()),
RequireClientCertificate: &wrappers.BoolValue{Value: false},
}
}
if listenerKey.Protocol == "tcp" {
// We rely on the invariant of upstreams slice always having at least 1
// member, because this key/value pair is created only when a
@ -154,21 +137,116 @@ func (s *ResourceGenerator) makeIngressGatewayListeners(address string, cfgSnap
return resources, nil
}
func resolveListenerSDSConfig(cfgSnap *proxycfg.ConfigSnapshot, listenerCfg structs.IngressListener) (*structs.GatewayTLSSDSConfig, error) {
func makeDownstreamTLSContextFromSnapshotListenerConfig(cfgSnap *proxycfg.ConfigSnapshot, listenerCfg structs.IngressListener) (*envoy_tls_v3.DownstreamTlsContext, error) {
var downstreamContext *envoy_tls_v3.DownstreamTlsContext
tlsContext, err := makeCommonTLSContextFromSnapshotListenerConfig(cfgSnap, listenerCfg)
if err != nil {
return nil, err
}
if tlsContext != nil {
downstreamContext = &envoy_tls_v3.DownstreamTlsContext{
CommonTlsContext: tlsContext,
RequireClientCertificate: &wrappers.BoolValue{Value: false},
}
}
return downstreamContext, nil
}
func makeCommonTLSContextFromSnapshotListenerConfig(cfgSnap *proxycfg.ConfigSnapshot, listenerCfg structs.IngressListener) (*envoy_tls_v3.CommonTlsContext, error) {
var tlsContext *envoy_tls_v3.CommonTlsContext
// Enable connect TLS if it is enabled at the Gateway or specific listener
// level.
gatewayTLSCfg := cfgSnap.IngressGateway.TLSConfig
// It is not possible to explicitly _disable_ TLS on a listener if it's
// enabled on the gateway, because false is the zero-value of the struct field
// and therefore indistinguishable from it being unspecified.
connectTLSEnabled := gatewayTLSCfg.Enabled ||
(listenerCfg.TLS != nil && listenerCfg.TLS.Enabled)
tlsCfg, err := resolveListenerTLSConfig(&gatewayTLSCfg, listenerCfg)
if err != nil {
return nil, err
}
if tlsCfg.SDS != nil {
// Set up listener TLS from SDS
tlsContext = makeCommonTLSContextFromGatewayTLSConfig(*tlsCfg)
} else if connectTLSEnabled {
tlsContext = makeCommonTLSContextFromLeaf(cfgSnap, cfgSnap.Leaf(), makeTLSParametersFromGatewayTLSConfig(*tlsCfg))
}
return tlsContext, nil
}
func resolveListenerTLSConfig(gatewayTLSCfg *structs.GatewayTLSConfig, listenerCfg structs.IngressListener) (*structs.GatewayTLSConfig, error) {
var mergedCfg structs.GatewayTLSConfig
resolvedSDSCfg, err := resolveListenerSDSConfig(gatewayTLSCfg.SDS, listenerCfg.TLS, listenerCfg.Port)
if err != nil {
return nil, err
}
mergedCfg.SDS = resolvedSDSCfg
if gatewayTLSCfg != nil {
mergedCfg.TLSMinVersion = gatewayTLSCfg.TLSMinVersion
mergedCfg.TLSMaxVersion = gatewayTLSCfg.TLSMaxVersion
mergedCfg.CipherSuites = gatewayTLSCfg.CipherSuites
}
if listenerCfg.TLS != nil {
if listenerCfg.TLS.TLSMinVersion != types.TLSVersionUnspecified {
mergedCfg.TLSMinVersion = listenerCfg.TLS.TLSMinVersion
}
if listenerCfg.TLS.TLSMaxVersion != types.TLSVersionUnspecified {
mergedCfg.TLSMaxVersion = listenerCfg.TLS.TLSMaxVersion
}
if len(listenerCfg.TLS.CipherSuites) != 0 {
mergedCfg.CipherSuites = listenerCfg.TLS.CipherSuites
}
}
var TLSVersionsWithConfigurableCipherSuites = map[types.TLSVersion]struct{}{
// Remove these two if Envoy ever sets TLS 1.3 as default minimum
types.TLSVersionUnspecified: {},
types.TLSVersionAuto: {},
types.TLSv1_0: {},
types.TLSv1_1: {},
types.TLSv1_2: {},
}
// Validate. Configuring cipher suites is only applicable to connections negotiated
// via TLS 1.2 or earlier. Other cases shouldn't be possible as we validate them at
// input but be resilient to bugs later.
if len(mergedCfg.CipherSuites) != 0 {
if _, ok := TLSVersionsWithConfigurableCipherSuites[mergedCfg.TLSMinVersion]; !ok {
return nil, fmt.Errorf("configuring CipherSuites is only applicable to connections negotiated with TLS 1.2 or earlier, TLSMinVersion is set to %s in listener or gateway config", mergedCfg.TLSMinVersion)
}
}
return &mergedCfg, nil
}
func resolveListenerSDSConfig(gatewaySDSCfg *structs.GatewayTLSSDSConfig, listenerTLSCfg *structs.GatewayTLSConfig, listenerPort int) (*structs.GatewayTLSSDSConfig, error) {
var mergedCfg structs.GatewayTLSSDSConfig
gwSDS := cfgSnap.IngressGateway.TLSConfig.SDS
if gwSDS != nil {
mergedCfg.ClusterName = gwSDS.ClusterName
mergedCfg.CertResource = gwSDS.CertResource
if gatewaySDSCfg != nil {
mergedCfg.ClusterName = gatewaySDSCfg.ClusterName
mergedCfg.CertResource = gatewaySDSCfg.CertResource
}
if listenerCfg.TLS != nil && listenerCfg.TLS.SDS != nil {
if listenerCfg.TLS.SDS.ClusterName != "" {
mergedCfg.ClusterName = listenerCfg.TLS.SDS.ClusterName
if listenerTLSCfg != nil && listenerTLSCfg.SDS != nil {
if listenerTLSCfg.SDS.ClusterName != "" {
mergedCfg.ClusterName = listenerTLSCfg.SDS.ClusterName
}
if listenerCfg.TLS.SDS.CertResource != "" {
mergedCfg.CertResource = listenerCfg.TLS.SDS.CertResource
if listenerTLSCfg.SDS.CertResource != "" {
mergedCfg.CertResource = listenerTLSCfg.SDS.CertResource
}
}
@ -183,10 +261,10 @@ func resolveListenerSDSConfig(cfgSnap *proxycfg.ConfigSnapshot, listenerCfg stru
return &mergedCfg, nil
case mergedCfg.ClusterName == "" && mergedCfg.CertResource != "":
return nil, fmt.Errorf("missing SDS cluster name for listener on port %d", listenerCfg.Port)
return nil, fmt.Errorf("missing SDS cluster name for listener on port %d", listenerPort)
case mergedCfg.ClusterName != "" && mergedCfg.CertResource == "":
return nil, fmt.Errorf("missing SDS cert resource for listener on port %d", listenerCfg.Port)
return nil, fmt.Errorf("missing SDS cert resource for listener on port %d", listenerPort)
}
return &mergedCfg, nil
@ -260,7 +338,7 @@ func makeSDSOverrideFilterChains(cfgSnap *proxycfg.ConfigSnapshot,
}
tlsContext := &envoy_tls_v3.DownstreamTlsContext{
CommonTlsContext: makeCommonTLSContextFromSDS(*svc.TLS.SDS),
CommonTlsContext: makeCommonTLSContextFromGatewayServiceTLSConfig(*svc.TLS),
RequireClientCertificate: &wrappers.BoolValue{Value: false},
}
@ -284,10 +362,49 @@ func makeSDSOverrideFilterChains(cfgSnap *proxycfg.ConfigSnapshot,
return chains, nil
}
func makeCommonTLSContextFromSDS(sdsCfg structs.GatewayTLSSDSConfig) *envoy_tls_v3.CommonTlsContext {
var envoyTLSVersions = map[types.TLSVersion]envoy_tls_v3.TlsParameters_TlsProtocol{
types.TLSVersionAuto: envoy_tls_v3.TlsParameters_TLS_AUTO,
types.TLSv1_0: envoy_tls_v3.TlsParameters_TLSv1_0,
types.TLSv1_1: envoy_tls_v3.TlsParameters_TLSv1_1,
types.TLSv1_2: envoy_tls_v3.TlsParameters_TLSv1_2,
types.TLSv1_3: envoy_tls_v3.TlsParameters_TLSv1_3,
}
func makeTLSParametersFromGatewayTLSConfig(tlsCfg structs.GatewayTLSConfig) *envoy_tls_v3.TlsParameters {
tlsParams := envoy_tls_v3.TlsParameters{}
if tlsCfg.TLSMinVersion != types.TLSVersionUnspecified {
if minVersion, ok := envoyTLSVersions[tlsCfg.TLSMinVersion]; ok {
tlsParams.TlsMinimumProtocolVersion = minVersion
}
}
if tlsCfg.TLSMaxVersion != types.TLSVersionUnspecified {
if maxVersion, ok := envoyTLSVersions[tlsCfg.TLSMaxVersion]; ok {
tlsParams.TlsMaximumProtocolVersion = maxVersion
}
}
if len(tlsCfg.CipherSuites) != 0 {
tlsParams.CipherSuites = types.MarshalEnvoyTLSCipherSuiteStrings(tlsCfg.CipherSuites)
}
return &tlsParams
}
func makeCommonTLSContextFromGatewayTLSConfig(tlsCfg structs.GatewayTLSConfig) *envoy_tls_v3.CommonTlsContext {
return &envoy_tls_v3.CommonTlsContext{
TlsParams: makeTLSParametersFromGatewayTLSConfig(tlsCfg),
TlsCertificateSdsSecretConfigs: makeTLSCertificateSdsSecretConfigsFromSDS(*tlsCfg.SDS),
}
}
func makeCommonTLSContextFromGatewayServiceTLSConfig(tlsCfg structs.GatewayServiceTLSConfig) *envoy_tls_v3.CommonTlsContext {
return &envoy_tls_v3.CommonTlsContext{
TlsParams: &envoy_tls_v3.TlsParameters{},
TlsCertificateSdsSecretConfigs: []*envoy_tls_v3.SdsSecretConfig{
TlsCertificateSdsSecretConfigs: makeTLSCertificateSdsSecretConfigsFromSDS(*tlsCfg.SDS),
}
}
func makeTLSCertificateSdsSecretConfigsFromSDS(sdsCfg structs.GatewayTLSSDSConfig) []*envoy_tls_v3.SdsSecretConfig {
return []*envoy_tls_v3.SdsSecretConfig{
{
Name: sdsCfg.CertResource,
SdsConfig: &envoy_core_v3.ConfigSource{
@ -312,6 +429,5 @@ func makeCommonTLSContextFromSDS(sdsCfg structs.GatewayTLSSDSConfig) *envoy_tls_
ResourceApiVersion: envoy_core_v3.ApiVersion_V3,
},
},
},
}
}

View File

@ -519,6 +519,30 @@ func TestListenersFromSnapshot(t *testing.T) {
create: proxycfg.TestConfigSnapshotIngressWithTLSListener,
setup: nil,
},
{
name: "ingress-with-tls-listener-min-version",
create: proxycfg.TestConfigSnapshotIngressWithTLSListener,
setup: func(snap *proxycfg.ConfigSnapshot) {
snap.IngressGateway.TLSConfig.TLSMinVersion = types.TLSv1_3
},
},
{
name: "ingress-with-tls-listener-max-version",
create: proxycfg.TestConfigSnapshotIngressWithTLSListener,
setup: func(snap *proxycfg.ConfigSnapshot) {
snap.IngressGateway.TLSConfig.TLSMaxVersion = types.TLSv1_2
},
},
{
name: "ingress-with-tls-listener-cipher-suites",
create: proxycfg.TestConfigSnapshotIngressWithTLSListener,
setup: func(snap *proxycfg.ConfigSnapshot) {
snap.IngressGateway.TLSConfig.CipherSuites = []types.TLSCipherSuite{
types.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
types.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
}
},
},
{
name: "ingress-with-tls-mixed-listeners",
// Use SDS helper even though we aren't testing SDS since it already sets
@ -572,6 +596,215 @@ func TestListenersFromSnapshot(t *testing.T) {
}
},
},
{
name: "ingress-with-tls-min-version-listeners-gateway-defaults",
create: proxycfg.TestConfigSnapshotIngressWithTLSListener,
setup: func(snap *proxycfg.ConfigSnapshot) {
snap.IngressGateway.TLSConfig.TLSMinVersion = types.TLSv1_2
// One listener disables TLS, one inherits TLS minimum version from the gateway
// config, two others set different versions
snap.IngressGateway.Upstreams = map[proxycfg.IngressListenerKey]structs.Upstreams{
{Protocol: "http", Port: 8080}: {
{
DestinationName: "s1",
LocalBindPort: 8080,
},
},
{Protocol: "http", Port: 8081}: {
{
DestinationName: "s2",
LocalBindPort: 8081,
},
},
{Protocol: "http", Port: 8082}: {
{
DestinationName: "s3",
LocalBindPort: 8082,
},
},
{Protocol: "http", Port: 8083}: {
{
DestinationName: "s4",
LocalBindPort: 8083,
},
},
{Protocol: "http", Port: 8084}: {
{
DestinationName: "s4",
LocalBindPort: 8084,
},
},
}
snap.IngressGateway.Listeners = map[proxycfg.IngressListenerKey]structs.IngressListener{
// Omits listener TLS config, should default to gateway TLS config
{Protocol: "http", Port: 8080}: {
Port: 8080,
Services: []structs.IngressService{
{
Name: "s1",
},
},
},
// Explicitly sets listener TLS config to nil, should default to gateway TLS config
{Protocol: "http", Port: 8081}: {
Port: 8081,
Services: []structs.IngressService{
{
Name: "s2",
},
},
TLS: nil,
},
// Explicitly enables TLS config, but with no listener default TLS params,
// should default to gateway TLS config
{Protocol: "http", Port: 8082}: {
Port: 8082,
Services: []structs.IngressService{
{
Name: "s3",
},
},
TLS: &structs.GatewayTLSConfig{
Enabled: true,
},
},
// Explicitly unset gateway default TLS min version in favor of proxy default
{Protocol: "http", Port: 8083}: {
Port: 8083,
Services: []structs.IngressService{
{
Name: "s3",
},
},
TLS: &structs.GatewayTLSConfig{
Enabled: true,
TLSMinVersion: types.TLSVersionAuto,
},
},
// Disables listener TLS
{Protocol: "http", Port: 8084}: {
Port: 8084,
Services: []structs.IngressService{
{
Name: "s4",
},
},
TLS: &structs.GatewayTLSConfig{
Enabled: false,
},
},
}
},
},
{
name: "ingress-with-single-tls-listener",
create: proxycfg.TestConfigSnapshotIngress,
setup: func(snap *proxycfg.ConfigSnapshot) {
// One listener should inherit non-TLS gateway config, another
// listener configures TLS with an explicit minimum version
snap.IngressGateway.Upstreams = map[proxycfg.IngressListenerKey]structs.Upstreams{
{Protocol: "http", Port: 8080}: {
{
DestinationName: "s1",
LocalBindPort: 8080,
},
},
{Protocol: "http", Port: 8081}: {
{
DestinationName: "s2",
LocalBindPort: 8081,
},
},
}
snap.IngressGateway.Listeners = map[proxycfg.IngressListenerKey]structs.IngressListener{
{Protocol: "http", Port: 8080}: {
Port: 8080,
Services: []structs.IngressService{
{
Name: "s1",
},
},
},
{Protocol: "http", Port: 8081}: {
Port: 8081,
Services: []structs.IngressService{
{
Name: "s2",
},
},
TLS: &structs.GatewayTLSConfig{
Enabled: true,
TLSMinVersion: types.TLSv1_2,
},
},
}
},
},
{
name: "ingress-with-tls-mixed-min-version-listeners",
create: proxycfg.TestConfigSnapshotIngressWithTLSListener,
setup: func(snap *proxycfg.ConfigSnapshot) {
snap.IngressGateway.TLSConfig.TLSMinVersion = types.TLSv1_2
// One listener should inherit TLS minimum version from the gateway config,
// two others each set explicit TLS minimum versions
snap.IngressGateway.Upstreams = map[proxycfg.IngressListenerKey]structs.Upstreams{
{Protocol: "http", Port: 8080}: {
{
DestinationName: "s1",
LocalBindPort: 8080,
},
},
{Protocol: "http", Port: 8081}: {
{
DestinationName: "s2",
LocalBindPort: 8081,
},
},
{Protocol: "http", Port: 8082}: {
{
DestinationName: "s3",
LocalBindPort: 8082,
},
},
}
snap.IngressGateway.Listeners = map[proxycfg.IngressListenerKey]structs.IngressListener{
{Protocol: "http", Port: 8080}: {
Port: 8080,
Services: []structs.IngressService{
{
Name: "s1",
},
},
},
{Protocol: "http", Port: 8081}: {
Port: 8081,
Services: []structs.IngressService{
{
Name: "s2",
},
},
TLS: &structs.GatewayTLSConfig{
Enabled: true,
TLSMinVersion: types.TLSv1_0,
},
},
{Protocol: "http", Port: 8082}: {
Port: 8082,
Services: []structs.IngressService{
{
Name: "s3",
},
},
TLS: &structs.GatewayTLSConfig{
Enabled: true,
TLSMinVersion: types.TLSv1_3,
},
},
}
},
},
{
name: "ingress-with-sds-listener-gw-level",
create: proxycfg.TestConfigSnapshotIngressWithGatewaySDS,
@ -1208,7 +1441,7 @@ func TestResolveListenerSDSConfig(t *testing.T) {
listenerCfg = lisCfg
}
got, err := resolveListenerSDSConfig(snap, listenerCfg)
got, err := resolveListenerSDSConfig(snap.IngressGateway.TLSConfig.SDS, listenerCfg.TLS, listenerCfg.Port)
if tc.wantErr != "" {
require.Error(t, err)
require.Contains(t, err.Error(), tc.wantErr)

View File

@ -0,0 +1,120 @@
{
"versionInfo": "00000001",
"resources": [
{
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
"name": "http:1.2.3.4:8080",
"address": {
"socketAddress": {
"address": "1.2.3.4",
"portValue": 8080
}
},
"filterChains": [
{
"filters": [
{
"name": "envoy.filters.network.http_connection_manager",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
"statPrefix": "ingress_upstream_8080",
"rds": {
"configSource": {
"ads": {
},
"resourceApiVersion": "V3"
},
"routeConfigName": "8080"
},
"httpFilters": [
{
"name": "envoy.filters.http.router"
}
],
"tracing": {
"randomSampling": {
}
}
}
}
]
}
],
"trafficDirection": "OUTBOUND"
},
{
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
"name": "http:1.2.3.4:8081",
"address": {
"socketAddress": {
"address": "1.2.3.4",
"portValue": 8081
}
},
"filterChains": [
{
"filters": [
{
"name": "envoy.filters.network.http_connection_manager",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
"statPrefix": "ingress_upstream_8081",
"rds": {
"configSource": {
"ads": {
},
"resourceApiVersion": "V3"
},
"routeConfigName": "8081"
},
"httpFilters": [
{
"name": "envoy.filters.http.router"
}
],
"tracing": {
"randomSampling": {
}
}
}
}
],
"transportSocket": {
"name": "tls",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
"commonTlsContext": {
"tlsParams": {
"tlsMinimumProtocolVersion": "TLSv1_2"
},
"tlsCertificates": [
{
"certificateChain": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
},
"privateKey": {
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
}
}
],
"validationContext": {
"trustedCa": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
}
}
},
"requireClientCertificate": false
}
}
}
],
"trafficDirection": "OUTBOUND"
}
],
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
"nonce": "00000001"
}

View File

@ -0,0 +1,62 @@
{
"versionInfo": "00000001",
"resources": [
{
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
"name": "db:1.2.3.4:9191",
"address": {
"socketAddress": {
"address": "1.2.3.4",
"portValue": 9191
}
},
"filterChains": [
{
"filters": [
{
"name": "envoy.filters.network.tcp_proxy",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
"statPrefix": "upstream.db.default.default.dc1",
"cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
}
}
],
"transportSocket": {
"name": "tls",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
"commonTlsContext": {
"tlsParams": {
"cipherSuites": [
"ECDHE-ECDSA-AES128-GCM-SHA256",
"ECDHE-ECDSA-CHACHA20-POLY1305"
]
},
"tlsCertificates": [
{
"certificateChain": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
},
"privateKey": {
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
}
}
],
"validationContext": {
"trustedCa": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
}
}
},
"requireClientCertificate": false
}
}
}
],
"trafficDirection": "OUTBOUND"
}
],
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
"nonce": "00000001"
}

View File

@ -0,0 +1,59 @@
{
"versionInfo": "00000001",
"resources": [
{
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
"name": "db:1.2.3.4:9191",
"address": {
"socketAddress": {
"address": "1.2.3.4",
"portValue": 9191
}
},
"filterChains": [
{
"filters": [
{
"name": "envoy.filters.network.tcp_proxy",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
"statPrefix": "upstream.db.default.default.dc1",
"cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
}
}
],
"transportSocket": {
"name": "tls",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
"commonTlsContext": {
"tlsParams": {
"tlsMaximumProtocolVersion": "TLSv1_2"
},
"tlsCertificates": [
{
"certificateChain": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
},
"privateKey": {
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
}
}
],
"validationContext": {
"trustedCa": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
}
}
},
"requireClientCertificate": false
}
}
}
],
"trafficDirection": "OUTBOUND"
}
],
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
"nonce": "00000001"
}

View File

@ -0,0 +1,59 @@
{
"versionInfo": "00000001",
"resources": [
{
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
"name": "db:1.2.3.4:9191",
"address": {
"socketAddress": {
"address": "1.2.3.4",
"portValue": 9191
}
},
"filterChains": [
{
"filters": [
{
"name": "envoy.filters.network.tcp_proxy",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
"statPrefix": "upstream.db.default.default.dc1",
"cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
}
}
],
"transportSocket": {
"name": "tls",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
"commonTlsContext": {
"tlsParams": {
"tlsMinimumProtocolVersion": "TLSv1_3"
},
"tlsCertificates": [
{
"certificateChain": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
},
"privateKey": {
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
}
}
],
"validationContext": {
"trustedCa": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
}
}
},
"requireClientCertificate": false
}
}
}
],
"trafficDirection": "OUTBOUND"
}
],
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
"nonce": "00000001"
}

View File

@ -0,0 +1,357 @@
{
"versionInfo": "00000001",
"resources": [
{
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
"name": "http:1.2.3.4:8080",
"address": {
"socketAddress": {
"address": "1.2.3.4",
"portValue": 8080
}
},
"filterChains": [
{
"filters": [
{
"name": "envoy.filters.network.http_connection_manager",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
"statPrefix": "ingress_upstream_8080",
"rds": {
"configSource": {
"ads": {
},
"resourceApiVersion": "V3"
},
"routeConfigName": "8080"
},
"httpFilters": [
{
"name": "envoy.filters.http.router"
}
],
"tracing": {
"randomSampling": {
}
}
}
}
],
"transportSocket": {
"name": "tls",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
"commonTlsContext": {
"tlsParams": {
"tlsMinimumProtocolVersion": "TLSv1_2"
},
"tlsCertificates": [
{
"certificateChain": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
},
"privateKey": {
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
}
}
],
"validationContext": {
"trustedCa": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
}
}
},
"requireClientCertificate": false
}
}
}
],
"trafficDirection": "OUTBOUND"
},
{
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
"name": "http:1.2.3.4:8081",
"address": {
"socketAddress": {
"address": "1.2.3.4",
"portValue": 8081
}
},
"filterChains": [
{
"filters": [
{
"name": "envoy.filters.network.http_connection_manager",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
"statPrefix": "ingress_upstream_8081",
"rds": {
"configSource": {
"ads": {
},
"resourceApiVersion": "V3"
},
"routeConfigName": "8081"
},
"httpFilters": [
{
"name": "envoy.filters.http.router"
}
],
"tracing": {
"randomSampling": {
}
}
}
}
],
"transportSocket": {
"name": "tls",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
"commonTlsContext": {
"tlsParams": {
"tlsMinimumProtocolVersion": "TLSv1_2"
},
"tlsCertificates": [
{
"certificateChain": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
},
"privateKey": {
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
}
}
],
"validationContext": {
"trustedCa": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
}
}
},
"requireClientCertificate": false
}
}
}
],
"trafficDirection": "OUTBOUND"
},
{
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
"name": "http:1.2.3.4:8082",
"address": {
"socketAddress": {
"address": "1.2.3.4",
"portValue": 8082
}
},
"filterChains": [
{
"filters": [
{
"name": "envoy.filters.network.http_connection_manager",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
"statPrefix": "ingress_upstream_8082",
"rds": {
"configSource": {
"ads": {
},
"resourceApiVersion": "V3"
},
"routeConfigName": "8082"
},
"httpFilters": [
{
"name": "envoy.filters.http.router"
}
],
"tracing": {
"randomSampling": {
}
}
}
}
],
"transportSocket": {
"name": "tls",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
"commonTlsContext": {
"tlsParams": {
"tlsMinimumProtocolVersion": "TLSv1_2"
},
"tlsCertificates": [
{
"certificateChain": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
},
"privateKey": {
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
}
}
],
"validationContext": {
"trustedCa": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
}
}
},
"requireClientCertificate": false
}
}
}
],
"trafficDirection": "OUTBOUND"
},
{
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
"name": "http:1.2.3.4:8083",
"address": {
"socketAddress": {
"address": "1.2.3.4",
"portValue": 8083
}
},
"filterChains": [
{
"filters": [
{
"name": "envoy.filters.network.http_connection_manager",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
"statPrefix": "ingress_upstream_8083",
"rds": {
"configSource": {
"ads": {
},
"resourceApiVersion": "V3"
},
"routeConfigName": "8083"
},
"httpFilters": [
{
"name": "envoy.filters.http.router"
}
],
"tracing": {
"randomSampling": {
}
}
}
}
],
"transportSocket": {
"name": "tls",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
"commonTlsContext": {
"tlsParams": {
},
"tlsCertificates": [
{
"certificateChain": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
},
"privateKey": {
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
}
}
],
"validationContext": {
"trustedCa": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
}
}
},
"requireClientCertificate": false
}
}
}
],
"trafficDirection": "OUTBOUND"
},
{
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
"name": "http:1.2.3.4:8084",
"address": {
"socketAddress": {
"address": "1.2.3.4",
"portValue": 8084
}
},
"filterChains": [
{
"filters": [
{
"name": "envoy.filters.network.http_connection_manager",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
"statPrefix": "ingress_upstream_8084",
"rds": {
"configSource": {
"ads": {
},
"resourceApiVersion": "V3"
},
"routeConfigName": "8084"
},
"httpFilters": [
{
"name": "envoy.filters.http.router"
}
],
"tracing": {
"randomSampling": {
}
}
}
}
],
"transportSocket": {
"name": "tls",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
"commonTlsContext": {
"tlsParams": {
"tlsMinimumProtocolVersion": "TLSv1_2"
},
"tlsCertificates": [
{
"certificateChain": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
},
"privateKey": {
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
}
}
],
"validationContext": {
"trustedCa": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
}
}
},
"requireClientCertificate": false
}
}
}
],
"trafficDirection": "OUTBOUND"
}
],
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
"nonce": "00000001"
}

View File

@ -0,0 +1,217 @@
{
"versionInfo": "00000001",
"resources": [
{
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
"name": "http:1.2.3.4:8080",
"address": {
"socketAddress": {
"address": "1.2.3.4",
"portValue": 8080
}
},
"filterChains": [
{
"filters": [
{
"name": "envoy.filters.network.http_connection_manager",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
"statPrefix": "ingress_upstream_8080",
"rds": {
"configSource": {
"ads": {
},
"resourceApiVersion": "V3"
},
"routeConfigName": "8080"
},
"httpFilters": [
{
"name": "envoy.filters.http.router"
}
],
"tracing": {
"randomSampling": {
}
}
}
}
],
"transportSocket": {
"name": "tls",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
"commonTlsContext": {
"tlsParams": {
"tlsMinimumProtocolVersion": "TLSv1_2"
},
"tlsCertificates": [
{
"certificateChain": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
},
"privateKey": {
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
}
}
],
"validationContext": {
"trustedCa": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
}
}
},
"requireClientCertificate": false
}
}
}
],
"trafficDirection": "OUTBOUND"
},
{
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
"name": "http:1.2.3.4:8081",
"address": {
"socketAddress": {
"address": "1.2.3.4",
"portValue": 8081
}
},
"filterChains": [
{
"filters": [
{
"name": "envoy.filters.network.http_connection_manager",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
"statPrefix": "ingress_upstream_8081",
"rds": {
"configSource": {
"ads": {
},
"resourceApiVersion": "V3"
},
"routeConfigName": "8081"
},
"httpFilters": [
{
"name": "envoy.filters.http.router"
}
],
"tracing": {
"randomSampling": {
}
}
}
}
],
"transportSocket": {
"name": "tls",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
"commonTlsContext": {
"tlsParams": {
"tlsMinimumProtocolVersion": "TLSv1_0"
},
"tlsCertificates": [
{
"certificateChain": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
},
"privateKey": {
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
}
}
],
"validationContext": {
"trustedCa": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
}
}
},
"requireClientCertificate": false
}
}
}
],
"trafficDirection": "OUTBOUND"
},
{
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
"name": "http:1.2.3.4:8082",
"address": {
"socketAddress": {
"address": "1.2.3.4",
"portValue": 8082
}
},
"filterChains": [
{
"filters": [
{
"name": "envoy.filters.network.http_connection_manager",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
"statPrefix": "ingress_upstream_8082",
"rds": {
"configSource": {
"ads": {
},
"resourceApiVersion": "V3"
},
"routeConfigName": "8082"
},
"httpFilters": [
{
"name": "envoy.filters.http.router"
}
],
"tracing": {
"randomSampling": {
}
}
}
}
],
"transportSocket": {
"name": "tls",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
"commonTlsContext": {
"tlsParams": {
"tlsMinimumProtocolVersion": "TLSv1_3"
},
"tlsCertificates": [
{
"certificateChain": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
},
"privateKey": {
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
}
}
],
"validationContext": {
"trustedCa": {
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
}
}
},
"requireClientCertificate": false
}
}
}
],
"trafficDirection": "OUTBOUND"
}
],
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
"nonce": "00000001"
}

View File

@ -43,6 +43,13 @@ type GatewayTLSConfig struct {
// SDS allows configuring TLS certificate from an SDS service.
SDS *GatewayTLSSDSConfig `json:",omitempty"`
TLSMinVersion string `json:",omitempty" alias:"tls_min_version"`
TLSMaxVersion string `json:",omitempty" alias:"tls_max_version"`
// Define a subset of cipher suites to restrict
// Only applicable to connections negotiated via TLS 1.2 or earlier
CipherSuites []string `json:",omitempty" alias:"cipher_suites"`
}
type GatewayServiceTLSConfig struct {

View File

@ -27,6 +27,7 @@ func TestAPI_ConfigEntries_IngressGateway(t *testing.T) {
Name: "bar",
TLS: GatewayTLSConfig{
Enabled: true,
TLSMinVersion: "TLSv1_2",
},
}

View File

@ -945,6 +945,7 @@ func TestDecodeConfigEntry(t *testing.T) {
},
},
{
// TODO(rb): test SDS stuff here in both places (global/service)
name: "ingress-gateway",
body: `
{
@ -955,7 +956,13 @@ func TestDecodeConfigEntry(t *testing.T) {
"gir": "zim"
},
"Tls": {
"Enabled": true
"Enabled": true,
"TLSMinVersion": "TLSv1_1",
"TLSMaxVersion": "TLSv1_2",
"CipherSuites": [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
},
"Listeners": [
{
@ -993,6 +1000,12 @@ func TestDecodeConfigEntry(t *testing.T) {
},
TLS: GatewayTLSConfig{
Enabled: true,
TLSMinVersion: "TLSv1_1",
TLSMaxVersion: "TLSv1_2",
CipherSuites: []string{
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
},
},
Listeners: []IngressListener{
{

View File

@ -2096,6 +2096,7 @@ func TestParseConfigEntry(t *testing.T) {
},
},
{
// TODO(rb): test SDS stuff here in both places (global/service)
name: "ingress-gateway: kitchen sink",
snake: `
kind = "ingress-gateway"
@ -2106,6 +2107,12 @@ func TestParseConfigEntry(t *testing.T) {
}
tls {
enabled = true
tls_min_version = "TLSv1_1"
tls_max_version = "TLSv1_2"
cipher_suites = [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
}
listeners = [
{
@ -2133,6 +2140,12 @@ func TestParseConfigEntry(t *testing.T) {
}
Tls {
Enabled = true
TLSMinVersion = "TLSv1_1"
TLSMaxVersion = "TLSv1_2"
CipherSuites = [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
}
Listeners = [
{
@ -2160,7 +2173,13 @@ func TestParseConfigEntry(t *testing.T) {
"gir": "zim"
},
"tls": {
"enabled": true
"enabled": true,
"tls_min_version": "TLSv1_1",
"tls_max_version": "TLSv1_2",
"cipher_suites": [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
},
"listeners": [
{
@ -2188,8 +2207,14 @@ func TestParseConfigEntry(t *testing.T) {
"foo": "bar",
"gir": "zim"
},
"Tls": {
"Enabled": true
"TLS": {
"Enabled": true,
"TLSMinVersion": "TLSv1_1",
"TLSMaxVersion": "TLSv1_2",
"CipherSuites": [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
},
"Listeners": [
{
@ -2218,6 +2243,12 @@ func TestParseConfigEntry(t *testing.T) {
},
TLS: api.GatewayTLSConfig{
Enabled: true,
TLSMinVersion: "TLSv1_1",
TLSMaxVersion: "TLSv1_2",
CipherSuites: []string{
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
},
},
Listeners: []api.IngressListener{
{

3
package-lock.json generated Normal file
View File

@ -0,0 +1,3 @@
{
"lockfileVersion": 1
}

View File

@ -1,43 +1,42 @@
package types
import (
"encoding/json"
"fmt"
"strings"
)
// TLSVersion is a strongly-typed int used for relative comparison
// (minimum, maximum, greater than, less than) of TLS versions
type TLSVersion int
// TLSVersion is a strongly-typed string for TLS versions
type TLSVersion string
const (
// Error value, excluded from lookup maps
TLSVersionInvalid TLSVersion = iota - 1
TLSVersionInvalid TLSVersion = "TLS_INVALID"
// Explicit unspecified zero-value to avoid overwriting parent defaults
TLSVersionUnspecified
TLSVersionUnspecified TLSVersion = ""
// Explictly allow implementation to select TLS version
// May be useful to supercede defaults specified at a higher layer
TLSVersionAuto
TLSVersionAuto TLSVersion = "TLS_AUTO"
_ // Placeholder for SSLv3, hopefully we won't have to add this
// TLS versions
TLSv1_0
TLSv1_1
TLSv1_2
TLSv1_3
TLSv1_0 TLSVersion = "TLSv1_0"
TLSv1_1 TLSVersion = "TLSv1_1"
TLSv1_2 TLSVersion = "TLSv1_2"
TLSv1_3 TLSVersion = "TLSv1_3"
)
var (
TLSVersions = map[string]TLSVersion{
"TLS_AUTO": TLSVersionAuto,
"TLSv1_0": TLSv1_0,
"TLSv1_1": TLSv1_1,
"TLSv1_2": TLSv1_2,
"TLSv1_3": TLSv1_3,
tlsVersions = map[TLSVersion]struct{}{
TLSVersionAuto: {},
TLSv1_0: {},
TLSv1_1: {},
TLSv1_2: {},
TLSv1_3: {},
}
// NOTE: This interface is deprecated in favor of TLSVersions
// NOTE: This interface is deprecated in favor of tlsVersions
// and should be eventually removed in a future release.
DeprecatedConsulAgentTLSVersions = map[string]TLSVersion{
"": TLSVersionAuto,
@ -46,24 +45,10 @@ var (
"tls12": TLSv1_2,
"tls13": TLSv1_3,
}
HumanTLSVersionStrings = map[TLSVersion]string{
TLSVersionAuto: "Allow implementation to select TLS version",
TLSv1_0: "TLS 1.0",
TLSv1_1: "TLS 1.1",
TLSv1_2: "TLS 1.2",
TLSv1_3: "TLS 1.3",
}
ConsulConfigTLSVersionStrings = func() map[TLSVersion]string {
inverted := make(map[TLSVersion]string, len(TLSVersions))
for k, v := range TLSVersions {
inverted[v] = k
}
return inverted
}()
// NOTE: these currently map to the deprecated config strings to support the
// deployment pattern of upgrading servers first. This map should eventually
// be removed and any lookups updated to use ConsulConfigTLSVersionStrings
// with newer config strings instead in a future release.
// be removed and any lookups updated to instead use the TLSVersion string
// values directly in a future release.
ConsulAutoConfigTLSVersionStrings = map[TLSVersion]string{
TLSVersionAuto: "",
TLSv1_0: "tls10",
@ -71,33 +56,51 @@ var (
TLSv1_2: "tls12",
TLSv1_3: "tls13",
}
TLSVersionsWithConfigurableCipherSuites = map[TLSVersion]struct{}{
// NOTE: these two are implementation-dependent, but it is not expected that
// either Go or Envoy would default to TLS 1.3 as a minimum version in the
// near future
TLSVersionUnspecified: {},
TLSVersionAuto: {},
TLSv1_0: {},
TLSv1_1: {},
TLSv1_2: {},
}
)
func (v TLSVersion) String() string {
return ConsulConfigTLSVersionStrings[v]
func (v *TLSVersion) String() string {
return string(*v)
}
func (v TLSVersion) MarshalJSON() ([]byte, error) {
return json.Marshal(v.String())
var tlsVersionComparison = map[TLSVersion]uint{
TLSv1_0: 1,
TLSv1_1: 2,
TLSv1_2: 3,
TLSv1_3: 4,
}
func (v *TLSVersion) UnmarshalJSON(bytes []byte) error {
versionStr := string(bytes)
if n := len(versionStr); n > 1 && versionStr[0] == '"' && versionStr[n-1] == '"' {
versionStr = versionStr[1 : n-1] // trim surrounding quotes
// Will only return true for concrete versions and won't catch
// implementation-dependent conflicts with TLSVersionAuto or unspecified values
func (a TLSVersion) LessThan(b TLSVersion) (error, bool) {
for _, v := range []TLSVersion{a, b} {
if _, ok := tlsVersionComparison[v]; !ok {
return fmt.Errorf("can't compare implementation-dependent values"), false
}
}
return nil, tlsVersionComparison[a] < tlsVersionComparison[b]
}
func ValidateTLSVersion(v TLSVersion) error {
if _, ok := tlsVersions[v]; !ok {
return fmt.Errorf("no matching TLS version found for %s", v.String())
}
if version, ok := TLSVersions[versionStr]; ok {
*v = version
return nil
}
*v = TLSVersionInvalid
return fmt.Errorf("no matching TLS Version found for %s", versionStr)
}
// IANA cipher suite constants and values as defined at
// IANA cipher suite string constants as defined at
// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml
// This is the total list of TLS 1.2-style cipher suites
// which are currently supported by either Envoy 1.21 or the Consul agent
@ -106,67 +109,49 @@ func (v *TLSVersion) UnmarshalJSON(bytes []byte) error {
// and as supported cipher suites in the Go runtime change.
//
// The naming convention for cipher suites changed in TLS 1.3
// but constant values should still be globally unqiue
// Handling validation on a subset of TLSCipherSuite constants
// would be a future exercise if cipher suites for TLS 1.3 ever
// become configurable in BoringSSL, Envoy, or other implementation
type TLSCipherSuite uint16
// but constant values should still be globally unqiue.
//
// Handling validation on distinct sets of TLS 1.3 and TLS 1.2 TLSCipherSuite
// constants would be a future exercise if cipher suites for TLS 1.3 ever
// become configurable in BoringSSL, Envoy, or other implementation.
type TLSCipherSuite string
const (
// Envoy cipher suites also used by Consul agent
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLSCipherSuite = 0xc02b
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xcca9 // Not used by Consul agent yet
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xc02f
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xcca8 // Not used by Consul agent yet
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xc009
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xc013
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xc02c
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xc030
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xc00a
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xc014
// Cipher suites used by both Envoy and Consul agent
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"
// Older cipher suites not supported for Consul agent TLS, will eventually be removed from Envoy defaults
TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009c
TLS_RSA_WITH_AES_128_CBC_SHA = 0x002f
TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009d
TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035
// Additional cipher suites used by Consul agent but not Envoy
// TODO: these are both explicitly listed as insecure and disabled in the Go source, should they be removed?
// https://cs.opensource.google/go/go/+/refs/tags/go1.17.3:src/crypto/tls/cipher_suites.go;l=329-330
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0x0023
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xc027
// Older cipher suites not supported for Consul agent TLS,
// will eventually be removed from Envoy defaults
TLS_RSA_WITH_AES_128_GCM_SHA256 = "TLS_RSA_WITH_AES_128_GCM_SHA256"
TLS_RSA_WITH_AES_128_CBC_SHA = "TLS_RSA_WITH_AES_128_CBC_SHA"
TLS_RSA_WITH_AES_256_GCM_SHA384 = "TLS_RSA_WITH_AES_256_GCM_SHA384"
TLS_RSA_WITH_AES_256_CBC_SHA = "TLS_RSA_WITH_AES_256_CBC_SHA"
)
var (
TLSCipherSuites = map[string]TLSCipherSuite{
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256": TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256": TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
consulAgentTLSCipherSuites = map[TLSCipherSuite]struct{}{
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: {},
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: {},
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: {},
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: {},
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: {},
"TLS_RSA_WITH_AES_128_GCM_SHA256": TLS_RSA_WITH_AES_128_GCM_SHA256,
"TLS_RSA_WITH_AES_128_CBC_SHA": TLS_RSA_WITH_AES_128_CBC_SHA,
"TLS_RSA_WITH_AES_256_GCM_SHA384": TLS_RSA_WITH_AES_256_GCM_SHA384,
"TLS_RSA_WITH_AES_256_CBC_SHA": TLS_RSA_WITH_AES_256_CBC_SHA,
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: {},
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: {},
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: {},
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: {},
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: {},
}
HumanTLSCipherSuiteStrings = func() map[TLSCipherSuite]string {
inverted := make(map[TLSCipherSuite]string, len(TLSCipherSuites))
for k, v := range TLSCipherSuites {
inverted[v] = k
}
return inverted
}()
EnvoyTLSCipherSuiteStrings = map[TLSCipherSuite]string{
envoyTLSCipherSuiteStrings = map[TLSCipherSuite]string{
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: "ECDHE-ECDSA-AES128-GCM-SHA256",
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: "ECDHE-ECDSA-CHACHA20-POLY1305",
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: "ECDHE-RSA-AES128-GCM-SHA256",
@ -183,3 +168,50 @@ var (
TLS_RSA_WITH_AES_256_CBC_SHA: "AES256-SHA",
}
)
func (c *TLSCipherSuite) String() string {
return string(*c)
}
func ValidateConsulAgentCipherSuites(cipherSuites []TLSCipherSuite) error {
var unmatched []string
for _, c := range cipherSuites {
if _, ok := consulAgentTLSCipherSuites[c]; !ok {
unmatched = append(unmatched, c.String())
}
}
if len(unmatched) > 0 {
return fmt.Errorf("no matching Consul Agent TLS cipher suite found for %s", strings.Join(unmatched, ","))
}
return nil
}
func ValidateEnvoyCipherSuites(cipherSuites []TLSCipherSuite) error {
var unmatched []string
for _, c := range cipherSuites {
if _, ok := envoyTLSCipherSuiteStrings[c]; !ok {
unmatched = append(unmatched, c.String())
}
}
if len(unmatched) > 0 {
return fmt.Errorf("no matching Envoy TLS cipher suite found for %s", strings.Join(unmatched, ","))
}
return nil
}
func MarshalEnvoyTLSCipherSuiteStrings(cipherSuites []TLSCipherSuite) []string {
cipherSuiteStrings := []string{}
for _, c := range cipherSuites {
if s, ok := envoyTLSCipherSuiteStrings[c]; ok {
cipherSuiteStrings = append(cipherSuiteStrings, s)
}
}
return cipherSuiteStrings
}

View File

@ -7,14 +7,12 @@ import (
"github.com/stretchr/testify/require"
)
func TestTLSVersion_PartialEq(t *testing.T) {
require.Greater(t, TLSv1_3, TLSv1_2)
require.Greater(t, TLSv1_2, TLSv1_1)
require.Greater(t, TLSv1_1, TLSv1_0)
require.Less(t, TLSv1_2, TLSv1_3)
require.Less(t, TLSv1_1, TLSv1_2)
require.Less(t, TLSv1_0, TLSv1_1)
func TestTLSVersion_Valid(t *testing.T) {
require.NoError(t, ValidateTLSVersion("TLS_AUTO"))
require.NoError(t, ValidateTLSVersion("TLSv1_0"))
require.NoError(t, ValidateTLSVersion("TLSv1_1"))
require.NoError(t, ValidateTLSVersion("TLSv1_2"))
require.NoError(t, ValidateTLSVersion("TLSv1_3"))
}
func TestTLSVersion_Invalid(t *testing.T) {
@ -33,16 +31,19 @@ func TestTLSVersion_Zero(t *testing.T) {
func TestTLSVersion_ToJSON(t *testing.T) {
var tlsVersion TLSVersion
err := tlsVersion.UnmarshalJSON([]byte(`"foo"`))
require.Error(t, err)
require.Equal(t, tlsVersion, TLSVersionInvalid)
for str, version := range TLSVersions {
// Unmarshalling won't catch invalid version strings,
// must be checked in config or config entry validation
err := json.Unmarshal([]byte(`"foo"`), &tlsVersion)
require.NoError(t, err)
for version := range tlsVersions {
str := version.String()
versionJSON, err := json.Marshal(version)
require.NoError(t, err)
require.Equal(t, versionJSON, []byte(`"`+str+`"`))
err = tlsVersion.UnmarshalJSON([]byte(`"` + str + `"`))
err = json.Unmarshal([]byte(`"`+str+`"`), &tlsVersion)
require.NoError(t, err)
require.Equal(t, tlsVersion, version)
}

View File

@ -154,7 +154,7 @@ as |TabState IgnoredGuard IgnoredAction tabDispatch tabState|>
@nspace={{or this.value.Namespace @nspace}}
@partition={{or this.value.Partition @partition}}
@type={{if this.value.Name 'oidc' 'secret'}}
@value={{if this.value.Name this.value.Name this.value}}
@value={{this.value}}
@onchange={{queue (action dispatch "RESET") @onsubmit}}
@onerror={{queue (action (mut this.error) value="error.errors.firstObject") (action dispatch "ERROR")}}
/>

View File

@ -21,6 +21,15 @@ This component **does not store the resulting token**, it only emits it via
its `onchange` argument/event handler. Errors are emitted via the `onerror`
argument/event handler.
## Potential improvements
We could decide to remove the `@type` argument and always require an object
passed to `@value` instead of a `String|Object`. Alternatively we could still
allow `String|Object`. Then inside the component we could decide whether to
use the Consul or SSO depending on the shape of the `@value` argument. All in
all this means we can remove the `@type` argument making a slimmer component
API.
```hbs preview-template
<figure>
<figcaption>Provide a widget to login with</figcaption>
@ -75,7 +84,7 @@ argument/event handler.
| `nspace` | `String` | | The name of the current namespace |
| `partition` | `String` | | The name of the current partition |
| `type` | `String` | | `secret` or `oidc`. `secret` is just traditional login, whereas `oidc` uses the users OIDC provider |
| `value` | `String` | | When `type` is `secret` this should be the users secret. When `type` is `oidc` this should be the name of the `AuthMethod` to use for authentication |
| `value` | `String|Object` | | When `type` is `secret` this should be the users secret. When `type` is `oidc` this should be object returned by Consul's AuthMethod HTTP API endpoint |
| `onchange` | `Function` | | The action to fire when the data changes. Emits an Event-like object with a `data` property containing the jwt data, in this case the autorizationCode and the status |
| `onerror` | `Function` | | The action to fire when an error occurs. Emits ErrorEvent object with an `error` property containing the Error. |

View File

@ -7,10 +7,10 @@ as |State Guard Action dispatch state|>
@cond={{this.isSecret}}
/>
{{#let
(uri '/${partition}/{$nspace}/${dc}'
(uri '/${partition}/${nspace}/${dc}'
(hash
partition=@partition
nspace=@nspace
partition=(or @value.Partition @partition)
nspace=(or @value.Namespace @nspace)
dc=@dc
)
)
@ -30,7 +30,7 @@ as |State Guard Action dispatch state|>
<DataSource
@src={{uri (concat path '/oidc/provider/${value}')
(hash
value=@value
value=@value.Name
)
}}
@onchange={{queue (action (mut this.provider) value="data") (action dispatch "SUCCESS")}}

View File

@ -29,7 +29,22 @@
<TopologyMetrics::SourceType @source='routing-config' />
{{/if}}
<div class="details">
{{#if (and (env 'CONSUL_NSPACES_ENABLED') (not-eq @item.Namespace @service.Namespace))}}
{{#if (and (can 'use partitions') (can 'use nspaces'))}}
<div class={{if (not-eq @item.Partition @service.Partition) 'group'}}>
{{#if (not-eq @item.Partition @service.Partition)}}
<dl class="partition">
<dt>
<Tooltip>
Admin Partition
</Tooltip>
</dt>
<dd>
{{@item.Partition}}
</dd>
</dl>
{{/if}}
<span></span>
{{#if (or (not-eq @item.Partition @service.Partition) (not-eq @item.Namespace @service.Namespace))}}
<dl class="nspace">
<dt>
<Tooltip>
@ -41,6 +56,8 @@
</dd>
</dl>
{{/if}}
</div>
{{/if}}
{{#if (not-eq @item.Source 'routing-config')}}

View File

@ -23,7 +23,6 @@
padding: 12px !important;
}
div {
display: inline-flex;
dl {
display: inline-flex;
margin-right: 8px;
@ -42,11 +41,8 @@
.health dt::before {
margin-top: 2px;
}
.nspace dt::before {
@extend %with-folder-outline-mask, %as-pseudo;
}
.health dt::before {
@extend %with-help-circle-outline-mask, %as-pseudo;
.partition dt::before {
@extend %with-user-team-mask, %as-pseudo;
}
.nspace dt::before {
@extend %with-folder-outline-mask, %as-pseudo;
@ -54,6 +50,10 @@
.health dt::before {
@extend %with-help-circle-outline-mask, %as-pseudo;
}
.health dt::before {
@extend %with-help-circle-outline-mask, %as-pseudo;
}
.partition dt::before,
.nspace dt::before,
.health dt::before {
background-color: rgb(var(--tone-gray-500));
@ -77,5 +77,34 @@
}
.details {
padding: 0 12px 12px 12px;
> *:not(:last-child) {
padding-bottom: 6px;
}
.group {
display: grid;
grid-template-columns: 20px 1fr;
grid-template-rows: repeat(2, 1fr);
grid-template-areas:
'partition partition'
'union namespace';
span {
display: inline-block;
grid-area: union;
padding-left: 7px;
margin-right: 0px;
}
span::before {
margin-right: 0px;
@extend %with-union-mask, %as-pseudo;
background-color: rgb(var(--tone-gray-500));
}
dl:first-child {
grid-area: partition;
padding-bottom: 6px;
}
dl:nth-child(2) {
grid-area: namespace;
}
}
}
}

View File

@ -39,13 +39,6 @@
#upstream-container {
padding: 12px;
}
#downstream-container div:first-child {
display: inline-flex;
span::before {
@extend %with-info-circle-outline-mask, %as-pseudo;
margin-left: 4px;
}
}
#upstream-column #upstream-container:not(:last-child) {
margin-bottom: 8px;
}

View File

@ -16,7 +16,7 @@
#upstream-container {
background-color: rgb(var(--tone-gray-100));
}
#downstream-container div:first-child {
#downstream-container > div:first-child {
display: inline-flex;
span::before {
@extend %with-info-circle-outline-mask, %as-pseudo;

View File

@ -22,6 +22,7 @@ export default class OidcSerializer extends Serializer {
cb(headers, {
Name: query.id,
Namespace: query.ns,
Partition: query.partition,
...body,
})
),

View File

@ -40,7 +40,7 @@ export default class OidcProviderService extends RepositoryService {
// with an empty `ns=` Consul will use the namespace that is assigned to
// the token, and when we get the response we can pick that back off the
// responses `Namespace` property. As we don't receive a `Namespace`
// property here, we have to figure this out ourselves. Biut we also want
// property here, we have to figure this out ourselves. But we also want
// to make this completely invisible to 'the application engineer/a
// template engineer'. This feels like the best place/way to do it as we
// are already in a asynchronous method, and we avoid adding extra 'just
@ -54,6 +54,7 @@ export default class OidcProviderService extends RepositoryService {
const token = (await this.settings.findBySlug('token')) || {};
return super.findBySlug({
ns: params.ns || token.Namespace || 'default',
partition: params.partition || token.Partition || 'default',
dc: params.dc,
id: params.id,
});

File diff suppressed because one or more lines are too long

View File

@ -9448,6 +9448,16 @@
mask-image: var(--unfold-open-24-svg);
}
%with-union-icon {
@extend %with-icon, %union-svg;
background-image: var(--union-svg);
}
%with-union-mask {
@extend %with-mask, %union-svg;
-webkit-mask-image: var(--union-svg);
mask-image: var(--union-svg);
}
%with-unlock-16-icon {
@extend %with-icon, %unlock-16-svg-prop;
background-image: var(--unlock-16-svg);

View File

@ -5,6 +5,11 @@
typeof location.search.ns !== 'undefined' ? location.search.ns :
typeof http.body.Namespace !== 'undefined' ? http.body.Namespace : 'default'
}",
"Partition": "${
typeof location.search.partition !== 'undefined' ?
location.search.partition :
typeof http.body.Partition !== 'undefined' ? http.body.Partition : 'default'
}",
"Local": false,
"Description": "AuthMethod: ${http.body.AuthMethod}; Code: ${http.body.Code}; State: ${http.body.State}; - ${fake.lorem.sentence()}",
"Policies": [

View File

@ -16,8 +16,8 @@ return `
"Name": "${name.split(' ').join('-').toLowerCase()}",
"DisplayName": "${name}",
"Kind": "${fake.helpers.randomize(['no-icon', 'google', 'okta', 'auth0', 'microsoft'])}",
"Namespace": "default",
"Partition": "default"
"Namespace": "${typeof location.search.ns !== 'undefined' ? location.search.ns : 'default'}",
"Partition": "${typeof location.search.partition !== 'undefined' ? location.search.partition : 'default'}"
}
`})
}

View File

@ -7,10 +7,12 @@ ${
fake.seed(num);
return range(num).map(i => {
const nspace = i === 0 ? `default` : `${fake.hacker.noun()}-ns-${i}`;
const partition = i === 0 ? `default` : `${fake.hacker.noun()}-partition`;
return {
Name: `service-${fake.random.number({min:0, max:99})}`,
Datacenter: `${dc}`,
Namespace: `${nspace}`
Namespace: `${nspace}`,
Partition: `${partition}`
}
})
};
@ -72,6 +74,7 @@ ${(Math.random(1) > 0.3) ? `
"Name": "${item.Name}",
"Datacenter": "${item.Datacenter}",
"Namespace": "${item.Namespace}",
"Partition": "${item.Partition}",
"ChecksPassing":${fake.random.number({min: 1, max: env('CONSUL_CHECK_COUNT', fake.random.number(10))})},
"ChecksWarning":${fake.random.number({min: 0, max: env('CONSUL_CHECK_COUNT', fake.random.number(10))})},
"ChecksCritical":${fake.random.number({min: 0, max: env('CONSUL_CHECK_COUNT', fake.random.number(10))})},
@ -101,6 +104,7 @@ ${(Math.random(1) > 0.3) ? `
"Name": "${item.Name}",
"Datacenter": "${item.Datacenter}",
"Namespace": "${item.Namespace}",
"Partition": "${item.Partition}",
"ChecksPassing":${fake.random.number({min: 1, max: env('CONSUL_CHECK_COUNT', fake.random.number(10))})},
"ChecksWarning":${fake.random.number({min: 0, max: env('CONSUL_CHECK_COUNT', fake.random.number(10))})},
"ChecksCritical":${fake.random.number({min: 0, max: env('CONSUL_CHECK_COUNT', fake.random.number(10))})},

View File

@ -19,3 +19,33 @@ Feature: login
headers:
X-Consul-Token: something
---
@onlyNamespaceable
Scenario: Logging in via SSO
Given 1 datacenter model with the value "dc-1"
And SSO is enabled
And partitions are enabled
And 1 oidcProvider model from yaml
---
- DisplayName: Okta
Name: okta
Kind: okta
---
When I visit the services page for yaml
---
dc: dc-1
---
And the "okta" oidcProvider responds with from yaml
---
state: state-123456789/abcdefghijklmnopqrstuvwxyz
code: code-abcdefghijklmnopqrstuvwxyz/123456789
---
And I click login on the navigation
And I click "[data-test-tab=tab_sso] button"
And I type "partition" into "[name=partition]"
And I click ".oidc-select button"
Then a GET request was made to "/v1/internal/ui/oidc-auth-methods?dc=dc-1&ns=@namespace&partition=partition"
And I click ".okta-oidc-provider"
Then a POST request was made to "/v1/acl/oidc/auth-url?dc=dc-1&ns=@!namespace&partition=partition"
And a POST request was made to "/v1/acl/oidc/callback?dc=dc-1&ns=@!namespace&partition=partition"
And "[data-notification]" has the "notification-authorize" class
And "[data-notification]" has the "success" class

View File

@ -43,6 +43,9 @@ export default function(type, value, doc = document) {
case 'authMethod':
key = 'CONSUL_AUTH_METHOD_COUNT';
break;
case 'oidcProvider':
key = 'CONSUL_OIDC_PROVIDER_COUNT';
break;
case 'nspace':
key = 'CONSUL_NSPACE_COUNT';
break;

View File

@ -40,6 +40,9 @@ export default function(type) {
case 'authMethod':
requests = ['/v1/acl/auth-methods', '/v1/acl/auth-method/'];
break;
case 'oidcProvider':
requests = ['/v1/internal/ui/oidc-auth-methods'];
break;
case 'nspace':
requests = ['/v1/namespaces', '/v1/namespace/'];
break;

View File

@ -103,9 +103,16 @@ export default function({
let location = context.owner.lookup(`location:${locationType}`);
return location.getURLFrom();
};
const oidcProvider = function(name, response) {
const context = helpers.getContext();
const provider = context.owner.lookup('torii-provider:oidc-with-url');
provider.popup.open = async function() {
return response;
};
};
models(library, create, setCookie);
http(library, respondWith, setCookie);
http(library, respondWith, setCookie, oidcProvider);
visit(library, pages, utils.setCurrentPage, reset);
click(library, utils.find, helpers.click);
form(library, utils.find, helpers.fillIn, helpers.triggerKeyEvent, utils.getCurrentPage);

View File

@ -1,4 +1,4 @@
export default function(scenario, respondWith, set) {
export default function(scenario, respondWith, set, oidc) {
// respondWith should set the url to return a certain response shape
scenario
.given(['the url "$endpoint" responds with a $status status'], function(url, status) {
@ -12,6 +12,9 @@ export default function(scenario, respondWith, set) {
}
respondWith(url, data);
})
.given(['the "$provider" oidcProvider responds with from yaml\n$yaml'], function(name, data) {
oidc(name, data);
})
.given('a network latency of $number', function(number) {
set('CONSUL_LATENCY', number);
});

View File

@ -38,6 +38,14 @@ export default function(scenario, create, set, win = window, doc = document) {
.given(['ACLs are disabled'], function() {
doc.cookie = `CONSUL_ACLS_ENABLE=0`;
})
.given(['SSO is enabled'], function() {
doc.cookie = `CONSUL_SSO_ENABLE=1`;
set('CONSUL_SSO_ENABLE', 1);
})
.given(['partitions are enabled'], function() {
doc.cookie = `CONSUL_PARTITIONS_ENABLE=1`;
set('CONSUL_PARTITIONS_ENABLE', 1);
})
.given(['the default ACL policy is "$policy"'], function(policy) {
set('CONSUL_ACL_POLICY', policy);
})

View File

@ -128,7 +128,8 @@ $ curl \
"ReplicatedIndex": 1976,
"ReplicatedTokenIndex": 2018,
"LastSuccess": "2018-11-03T06:28:58Z",
"LastError": "2016-11-03T06:28:28Z"
"LastError": "2016-11-03T06:28:28Z",
"LastErrorMessage": "failed to retrieve ACL policy updates: RPC rate limit exceeded"
}
```
@ -179,6 +180,9 @@ $ curl \
replication process is not in a good state. A zero value of
"0001-01-01T00:00:00Z" will be present if no sync has resulted in an error.
- `LastErrorMessage` - The last error message produced at the time of `LastError`.
An empty string indicates that no sync has resulted in an error.
## Translate Rules
-> **Deprecated** - This endpoint was removed in Consul 1.11.0.

View File

@ -18,14 +18,16 @@ replication between datacenters, please view the
~> Values in the KV store cannot be larger than 512kb.
For multi-key updates, please consider using [transaction](/api/txn).
In order to perform atomic operations on multiple KV pairs (up to a limit of 64)
please consider using [transactions](/api/txn) instead.
## Read Key
This endpoint returns the specified key. If no key exists at the given path, a
404 is returned instead of a 200 response.
For multi-key reads, please consider using [transaction](/api/txn).
For multi-key reads (up to a limit of 64 KV operations) please consider using
[transactions](/api/txn) instead.
| Method | Path | Produces |
| ------ | ---------- | ------------------ |

View File

@ -14,6 +14,12 @@ store at the given key name. If no key exists with that name, an error is
returned. If a key exists with that name but has no data, nothing is returned.
A key name or prefix is required.
-> **Note**: When reading many entries under a given prefix, it may be worth
considering [`kv export`](/commands/kv/export) instead. The kv export output
can be used with [`kv import`](/commands/kv/import) to move entire trees between
Consul clusters. Alternatively, the [transaction API](/api-docs/txn) provides
support for performing up to 64 KV operations atomically.
The table below shows this command's [required ACLs](/api#authentication). Configuration of
[blocking queries](/api/features/blocking) and [agent caching](/api/features/caching)
are not supported from commands, but may be from the corresponding HTTP endpoint.
@ -63,17 +69,27 @@ Usage: `consul kv get [options] [KEY_OR_PREFIX]`
To retrieve the value for the key named "redis/config/connections" in the
KV store:
```shell-session
```shell-session hideClipboard
$ consul kv get redis/config/connections
5
```
This will return the original, raw value stored in Consul. To view detailed
information about the key, specify the "-detailed" flag. This will output all
known metadata about the key including ModifyIndex and any user-supplied
flags:
This will return the original raw value stored in Consul.
```shell-session
If the key with the given name does not exist, an error is returned.
```shell-session hideClipboard
$ consul kv get not-a-real-key
Error! No key exists at: not-a-real-key
```
### Detailed Output
To view detailed information about the key, specify the `-detailed` flag.
This will output all known metadata about the key including `ModifyIndex`
and any user-supplied flags:
```shell-session hideClipboard
$ consul kv get -detailed redis/config/connections
CreateIndex 336
Flags 0
@ -84,26 +100,22 @@ Session -
Value 5
```
If the key with the given name does not exist, an error is returned:
### Recursively Reading By Prefix
```shell-session
$ consul kv get not-a-real-key
Error! No key exists at: not-a-real-key
```
To treat the path as a prefix and list all entries which start with the given
prefix, specify the `-recurse` flag:
To treat the path as a prefix and list all keys which start with the given
prefix, specify the "-recurse" flag:
```shell-session
```shell-session hideClipboard
$ consul kv get -recurse redis/
redis/config/connections:5
redis/config/cpu:128
redis/config/memory:512
```
Or list detailed information about all pairs under a prefix:
Alternatively, combine with the `-detailed` flag to list detailed information
about all entries under a prefix:
```shell-session
```shell-session hideClipboard
$ consul kv get -recurse -detailed redis
CreateIndex 336
Flags 0
@ -130,10 +142,12 @@ Session -
Value 512
```
To just list the keys which start with the specified prefix, use the "-keys"
### Listing Keys
To just list the keys which start with the specified prefix, use the `-keys`
option instead. This is more performant and results in a smaller payload:
```shell-session
```shell-session hideClipboard
$ consul kv get -keys redis/config/
redis/config/connections
redis/config/cpu
@ -144,7 +158,7 @@ By default, the `-keys` operation uses a separator of "/", meaning it will not
recurse beyond that separator. You can choose a different separator by setting
`-separator="<string>"`.
```shell-session
```shell-session hideClipboard
$ consul kv get -keys -separator="c" redis
redis/c
```
@ -152,7 +166,7 @@ redis/c
Alternatively, you can disable the separator altogether by setting it to the
empty string:
```shell-session
```shell-session hideClipboard
$ consul kv get -keys -separator="" redis
redis/config/connections
redis/config/cpu
@ -161,7 +175,7 @@ redis/config/memory
To list all keys at the root, simply omit the prefix parameter:
```shell-session
```shell-session hideClipboard
$ consul kv get -keys
memcached/
redis/

View File

@ -11,6 +11,11 @@ Corresponding HTTP API Endpoint: [\[PUT\] /v1/kv/:key](/api-docs/kv#create-updat
The `kv put` command writes the data to the given path in the KV store.
-> **Note**: When writing multiple entries at once, consider using
[`kv import`](/commands/kv/import) instead. Alternatively, the
[transaction API](/api-docs/txn) provides support for performing up to
64 KV operations atomically.
The table below shows this command's [required ACLs](/api#authentication). Configuration of
[blocking queries](/api/features/blocking) and [agent caching](/api/features/caching)
are not supported from commands, but may be from the corresponding HTTP endpoint.
@ -67,57 +72,76 @@ Usage: `consul kv put [options] KEY [DATA]`
To insert a value of "5" for the key named "redis/config/connections" in the
KV store:
```shell-session
```shell-session hideClipboard
$ consul kv put redis/config/connections 5
Success! Data written to: redis/config/connections
```
If no data is specified, the key will be created with empty data:
```shell-session
```shell-session hideClipboard
$ consul kv put redis/config/connections
Success! Data written to: redis/config/connections
```
If the `-base64` flag is set, the data will be decoded before writing:
!> **Be careful of overwriting data!** The above operation would overwrite
any existing value at the key to the empty value.
```shell-session
### Base64 Encoded Values
If the `-base64` flag is set, the given data will be Base64-decoded before writing:
```shell-session hideClipboard
$ consul kv put -base64 foo/encoded aGVsbG8gd29ybGQK
Success! Data written to: foo/encoded
```
!> **Be careful when overwriting data!** The above operation would overwrite
the value at the key to the empty value.
### Longer or Sensitive Values
For longer or sensitive values, it is possible to read from a file by prefixing
with the `@` symbol:
For longer or sensitive values, it is possible to read from a file by
supplying its path prefixed with the `@` symbol:
```shell-session
```shell-session hideClipboard
$ consul kv put redis/config/password @password.txt
Success! Data written to: redis/config/connections
Success! Data written to: redis/config/password
```
Or read values from stdin by specifying the `-` symbol:
```shell-session
$ echo "5" | consul kv put redis/config/password -
```shell-session hideClipboard
$ echo "5" | consul kv put redis/config/connections -
Success! Data written to: redis/config/connections
```
$ consul kv put redis/config/password -
```shell-session hideClipboard
$ consul kv put redis/config/connections -
5
<CTRL+D>
Success! Data written to: redis/config/connections
```
~> For secret and sensitive values, you should consider using a secret
management solution like **[HashiCorp's Vault](https://www.vaultproject.io/)**.
While it is possible to secure values in Consul's KV store, Vault provides a
more robust interface for secret management.
```shell-session hideClipboard
$ consul kv put leaderboard/scores - <<EOF
{
"user-a": 100,
"user-b": 250,
"user-c": 75
}
EOF
Success! Data written to: leaderboard/scores
```
~> **Warning**: For secret and sensitive values, you should consider using a
secret management solution like **[HashiCorp's Vault](https://learn.hashicorp.com/tutorials/vault/static-secrets?in=vault/secrets-management)**.
While it is possible to encrpyt data before writing it to Consul's KV store,
Consul provides no built-in support for encryption at-rest.
### Atomic Check-And-Set (CAS)
To only update a key if it has not been modified since a given index, specify
the `-cas` and `-modify-index` flags:
```shell-session
```shell-session hideClipboard
$ consul kv get -detailed redis/config/connections | grep ModifyIndex
ModifyIndex 456
@ -128,24 +152,18 @@ $ consul kv put -cas -modify-index=456 redis/config/connections 10
Success! Data written to: redis/config/connections
```
To specify flags on the key, use the `-flags` option. These flags are completely
controlled by the user:
```shell-session
$ consul kv put -flags=42 redis/config/password s3cr3t
Success! Data written to: redis/config/password
```
### Locking Primitives
To create or tune a lock, use the `-acquire` and `-session` flags. The session must already exist (this command will not create it or manage it):
```shell-session
```shell-session hideClipboard
$ consul kv put -acquire -session=abc123 redis/lock/update
Success! Lock acquired on: redis/lock/update
```
When you are finished, release the lock:
```shell-session
```shell-session hideClipboard
$ consul kv put -release -session=acb123 redis/lock/update
Success! Lock released on: redis/lock/update
```
@ -154,3 +172,13 @@ Success! Lock released on: redis/lock/update
low-level primitives, you may want to look at the [<tt>consul
lock</tt>](/commands/lock) command. It provides higher-level
functionality without exposing the internal APIs of Consul.
### Flags
To set user-defined flags on the entry, use the `-flags` option. These flags
are completely controlled by the user and have no special meaning to Consul:
```shell-session hideClipboard
$ consul kv put -flags=42 redis/config/password s3cr3t
Success! Data written to: redis/config/password
```

View File

@ -51,7 +51,7 @@ See [Kubernetes Custom Resource Definitions](/docs/k8s/crds).
Configuration entries outside of Kubernetes should be managed with the Consul
[CLI](/commands/config) or [API](/api/config). Additionally, as a
convenience for initial cluster bootstrapping, configuration entries can be
specified in all of the Consul servers's
specified in the Consul servers agent's
[configuration files](/docs/agent/options#config_entries_bootstrap)
### Managing Configuration Entries with the CLI

View File

@ -136,7 +136,7 @@ $ consul agent -data-dir=/tmp/consul
- **Server**: This indicates whether the agent is running in server or client
mode.
Running an agent in server mode requires additional overhead. This is because they participate in the consensus quorum, store cluster state, and handle queries. A server may also be
in ["bootstrap"](/docs/agent/options#_bootstrap_expect) mode, which enables the server to elect itselft as the Raft leader. Multiple servers cannot be in bootstrap mode because it would put the cluster in an inconsistent state.
in ["bootstrap"](/docs/agent/options#_bootstrap_expect) mode, which enables the server to elect itself as the Raft leader. Multiple servers cannot be in bootstrap mode because it would put the cluster in an inconsistent state.
- **Client Addr**: This is the address used for client interfaces to the agent.
This includes the ports for the HTTP and DNS interfaces. By default, this
@ -193,11 +193,9 @@ The following settings are commonly used in the configuration file (also called
The following example configuration is for a server agent named "`consul-server`". The server is [bootstrapped](/docs/agent/options#_bootstrap) and the Consul GUI is enabled.
The reason this server agent is configured for a service mesh is that the `connect` configuration is enabled. Connect is Consul's service mesh component that provides service-to-service connection authorization and encryption using mutual Transport Layer Security (TLS). Applications can use sidecar proxies in a service mesh configuration to establish TLS connections for inbound and outbound connections without being aware of Connect at all. See [Connect](/docs/connect) for details.
<Tabs>
<Tab heading="HCL">
<CodeTabs>
```hcl
node_name = "consul-server"
server = true
bootstrap = true
@ -215,8 +213,6 @@ connect {
}
```
</Tab>
<Tab heading="JSON">
```json
{
@ -238,19 +234,16 @@ connect {
}
```
</Tab>
</Tabs>
</CodeTabs>
### Server Node with Encryption Enabled
The following example shows a server node configured with encryption enabled.
Refer to the [Security](/docs/security) chapter for additional information about how to configure security options for Consul.
<Tabs>
<Tab heading="HCL">
<CodeTabs>
```hcl
node_name = "consul-server"
server = true
ui_config {
@ -274,8 +267,6 @@ key_file = "/consul/config/certs/dc1-server-consul-0-key.pem"
```
</Tab>
<Tab heading="JSON">
```json
{
@ -299,19 +290,16 @@ key_file = "/consul/config/certs/dc1-server-consul-0-key.pem"
}
```
</Tab>
</Tabs>
</CodeTabs>
### Client Node Registering a Service
Using Consul as a central service registry is a common use case.
The following example configuration includes common settings to register a service with a Consul agent and enable health checks (see [Checks](/docs/discovery/checks) to learn more about health checks):
<Tabs>
<Tab heading="HCL">
<CodeTabs>
```hcl
node_name = "consul-client"
server = false
datacenter = "dc1"
@ -335,9 +323,6 @@ service {
```
</Tab>
<Tab heading="JSON">
```json
{
"node_name": "consul-client",
@ -363,8 +348,58 @@ service {
}
```
</Tab>
</Tabs>
</CodeTabs>
## Client Node with Multiple Interfaces or IP addresses
The following example shows how to configure Consul to listen on multiple interfaces or IP addresses using a [go-sockaddr template].
The `bind_addr` is used for internal RPC and Serf communication ([read the Agent Configuration for more information](/docs/agent/options#bind_addr)).
The `client_addr` configuration specifies IP addresses used for HTTP, HTTPS, DNS and gRPC servers. ([read the Agent Configuration for more information](/docs/agent/options#client_addr)).
<CodeTabs>
```hcl
node_name = "consul-server"
server = true
bootstrap = true
ui_config {
enabled = true
}
datacenter = "dc1"
data_dir = "consul/data"
log_level = "INFO"
# used for internal RPC and Serf
bind_addr = "0.0.0.0"
# Used for HTTP, HTTPS, DNS, and gRPC addresses.
# loopback is not included in GetPrivateInterfaces because it is not routable.
client_addr = "{{ GetPrivateInterfaces | exclude \"type\" \"ipv6\" | join \"address\" \" \" }} {{ GetAllInterfaces | include \"flags\" \"loopback\" | join \"address\" \" \" }}"
# advertises gossip and RPC interface to other nodes
advertise_addr = "{{ GetInterfaceIP \"en0\" }}"
```
```json
{
"node_name": "consul-server",
"server": true,
"bootstrap": true,
"ui_config": {
"enabled": true
},
"datacenter": "dc1",
"data_dir": "consul/data",
"log_level": "INFO",
"bind_addr": "{{ GetPrivateIP }}",
"client_addr": "{{ GetPrivateInterfaces | exclude \"type\" \"ipv6\" | join \"address\" \" \" }} {{ GetAllInterfaces | include \"flags\" \"loopback\" | join \"address\" \" \" }}",
"advertise_addr": "{{ GetInterfaceIP \"en0\"}}"
}
```
</CodeTabs>
## Stopping an Agent
@ -402,3 +437,7 @@ from the load balancer pool.
The [`skip_leave_on_interrupt`](/docs/agent/options#skip_leave_on_interrupt) and
[`leave_on_terminate`](/docs/agent/options#leave_on_terminate) configuration
options allow you to adjust this behavior.
<!-- list of reference-style links -->
[go-sockaddr template]: https://godoc.org/github.com/hashicorp/go-sockaddr/template

View File

@ -54,6 +54,8 @@ information.
## Command-line Options ((#commandline_options))
-> **Note:** Some CLI arguments may be different from HCL keys. See [Configuration Key Reference](#config_key_reference) for equivalent HCL Keys.
The options below are all specified on the command-line.
- `-advertise` ((#\_advertise)) - The advertise address is used to change
@ -64,6 +66,15 @@ The options below are all specified on the command-line.
state as other nodes will treat the non-routability as a failure. In Consul 1.1.0 and later this can be dynamically defined with a [go-sockaddr]
template that is resolved at runtime.
<CodeBlockConfig>
```shell
# Using a static network interface name
$ consul agent -advertise '{{ GetInterfaceIP "eth0" }}'
```
</CodeBlockConfig>
- `-advertise-wan` ((#\_advertise-wan)) - The advertise WAN address is used
to change the address that we advertise to server nodes joining through the WAN.
This can also be set on client agents when used in combination with the [`translate_wan_addrs`](#translate_wan_addrs) configuration option. By default, the [`-advertise`](#_advertise) address
@ -137,11 +148,35 @@ The options below are all specified on the command-line.
capture, it is possible to use [`discard_check_output`](#discard_check_output).
- `-client` ((#\_client)) - The address to which Consul will bind client
interfaces, including the HTTP and DNS servers. By default, this is "127.0.0.1",
interfaces, including the HTTP, HTTPS, gRPC and DNS servers. By default, this is "127.0.0.1",
allowing only loopback connections. In Consul 1.0 and later this can be set to
a space-separated list of addresses to bind to, or a [go-sockaddr]
template that can potentially resolve to multiple addresses.
<CodeBlockConfig hideClipboard heading="Bind consul client interfaces to private IPv4 interfaces">
```shell
$ consul agent -dev -client '{{ GetPrivateInterfaces | exclude "type" "ipv6" | join "address" " " }}'
```
</CodeBlockConfig>
<CodeBlockConfig hideClipboard heading="Bind consul client interfaces to private IP addresses and loopback">
```shell
$ consul agent -dev -client '{{ GetPrivateInterfaces | join "address" " " }} {{ GetAllInterfaces | include "flags" "loopback" | join "address" " " }}'
```
</CodeBlockConfig>
<CodeBlockConfig hideClipboard heading="Exclude private interfaces that start with 'br-'">
```shell
$ consul agent -dev -client '{{ GetPrivateInterfaces | exclude "name" "br.*" | join "address" " " }}'
```
</CodeBlockConfig>
- `-config-file` ((#\_config_file)) - A configuration file to load. For
more information on the format of this file, read the [Configuration Files](#configuration_files)
section. This option can be specified multiple times to load multiple configuration
@ -566,7 +601,7 @@ definitions support being updated during a reload.
}
```
#### Configuration Key Reference
#### Configuration Key Reference ((#config_key_reference))
-> **Note:** All the TTL values described below are parsed by Go's `time` package, and have the following
[formatting specification](https://golang.org/pkg/time/#ParseDuration): "A

View File

@ -350,8 +350,8 @@ These metrics are used to monitor the health of the Consul servers.
| `consul.raft.boltdb.logSize` | Measures the size of logs being written to the db. | bytes | sample |
| `consul.raft.boltdb.numFreePages` | Represents the number of free pages within the raft.db file. | pages | gauge |
| `consul.raft.boltdb.numPendingPages` | Represents the number of pending pages within the raft.db that will soon become free. | pages | gauge |
| `consul.raft.boltdb.openReadTxn` | Represents the number of open read transactions against the db | transactions | guage |
| `consul.raft.boltdb.totalReadTxn` | Represents the total number of started read transactions against the db | transactions | guage |
| `consul.raft.boltdb.openReadTxn` | Represents the number of open read transactions against the db | transactions | gauge |
| `consul.raft.boltdb.totalReadTxn` | Represents the total number of started read transactions against the db | transactions | gauge |
| `consul.raft.boltdb.storeLogs` | Measures the amount of time spent writing logs to the db. | ms | timer |
| `consul.raft.boltdb.txstats.cursorCount` | Counts the number of cursors created since Consul was started. | cursors | counter |
| `consul.raft.boltdb.txstats.nodeCount` | Counts the number of node allocations within the db since Consul was started. | allocations | counter |
@ -398,7 +398,7 @@ These metrics are used to monitor the health of the Consul servers.
| `consul.raft.state.leader` | Increments whenever a Consul server becomes a leader. If there are frequent leadership changes this may be indication that the servers are overloaded and aren't meeting the soft real-time requirements for Raft, or that there are networking problems between the servers. | leadership transitions / interval | counter |
| `consul.raft.state.follower` | Counts the number of times an agent has entered the follower mode. This happens when a new agent joins the cluster or after the end of a leader election. | follower state entered / interval | counter |
| `consul.raft.transition.heartbeat_timeout` | The number of times an agent has transitioned to the Candidate state, after receive no heartbeat messages from the last known leader. | timeouts / interval | counter |
| `consul.raft.verify_leader` | Counts the number of times an agent checks whether it is still the leader or not | checks / interval | Counter |
| `consul.raft.verify_leader` | This metric doesn't have a direct correlation to the leader change. It just counts the number of times an agent checks if it is still the leader or not. For example, during every consistent read, the check is done. Depending on the load in the system, this metric count can be high as it is incremented each time a consistent read is completed. | checks / interval | Counter |
| `consul.rpc.accept_conn` | Increments when a server accepts an RPC connection. | connections | counter |
| `consul.catalog.register` | Measures the time it takes to complete a catalog register operation. | ms | timer |
| `consul.catalog.deregister` | Measures the time it takes to complete a catalog deregister operation. | ms | timer |

View File

@ -48,22 +48,30 @@ Computing the estimated network round trip time between any two nodes is simple
once you have their coordinates. Here's a sample coordinate, as returned from the
[Coordinate endpoint](/api/coordinate).
```
<CodeBlockConfig heading="Sample coordinate from Coordinate endpoint" hideClipboard>
```json
...
"Coord": {
"Adjustment": 0.1,
"Error": 1.5,
"Height": 0.02,
"Vec": [0.34,0.68,0.003,0.01,0.05,0.1,0.34,0.06]
}
...
```
</CodeBlockConfig>
All values are floating point numbers in units of seconds, except for the error
term which isn't used for distance calculations.
Here's a complete example in Go showing how to compute the distance between two
coordinates:
```
<CodeBlockConfig heading="Computing distance between two coordinates with Go">
```go
import (
"math"
"time"
@ -97,3 +105,5 @@ func dist(a *coordinate.Coordinate, b *coordinate.Coordinate) time.Duration {
return time.Duration(rtt * secondsToNanoseconds)
}
```
</CodeBlockConfig>

View File

@ -23,6 +23,12 @@ and discovery terminates.
- Service resolver config entries are a component of [L7 Traffic
Management](/docs/connect/l7-traffic-management).
## UI
Once a `service-resolver` is successfully entered, you can view it in the UI. Service routers, service splitters, and service resolvers can all be viewed by clicking on your service then switching to the *routing* tab.
![screenshot of service resolver in the UI](/img/l7-routing/Resolver.png)
## Sample Config Entries
### Filter on service version
@ -116,9 +122,9 @@ spec:
</CodeTabs>
### Datacenter failover
### Failover
Enable failover for subset 'v2' to 'dc2', and all other subsets to dc3 or dc4:
Enable failover for subset `v2` to `dc2`, and all other subsets to `dc3` or `dc4`:
<CodeTabs tabs={[ "HCL", "Kubernetes YAML", "JSON" ]}>
@ -168,6 +174,104 @@ spec:
</CodeTabs>
<EnterpriseAlert product="consul">
Failover to another datacenter and namespace for all service subsets.
</EnterpriseAlert>
<CodeTabs tabs={[ "HCL", "Kubernetes YAML", "JSON" ]}>
```hcl
Kind = "service-resolver"
Name = "product-api"
Namespace = "primary"
ConnectTimeout = "0s"
Failover = {
"*" = {
Datacenters = ["dc2"]
Namespace = "secondary"
}
}
```
```yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceResolver
metadata:
name: product-api
namespace: primary
spec:
connectTimeout: 0s
failover:
namespace: 'secondary'
datacenters: ['dc2']
```
```json
{
"Kind": "service-resolver",
"Name": "product-api",
"Namespace": "primary",
"ConnectTimeout": "0s",
"Failover": {
"*": {
"Datacenters": ["dc2"],
"Namespace": "secondary"
}
}
}
```
</CodeTabs>
<EnterpriseAlert product="consul">
Failover within a datacenter and a different namespace.
</EnterpriseAlert>
<CodeTabs tabs={[ "HCL", "Kubernetes YAML", "JSON" ]}>
```hcl
Kind = "service-resolver"
Name = "product-api"
Namespace = "primary"
ConnectTimeout = "0s"
Failover = {
"*" = {
Service = "product-api-backup"
Namespace = "secondary"
}
}
```
```yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceResolver
metadata:
name: product-api
namespace: primary
spec:
connectTimeout: 0s
failover:
service: 'product-api-backup'
namespace: 'secondary'
```
```json
{
"Kind": "service-resolver",
"Name": "product-api",
"Namespace": "primary",
"ConnectTimeout": "0s",
"Failover": {
"*": {
"Service": "product-api-backup",
"Namespace": "secondary"
}
}
}
```
</CodeTabs>
### Consistent load balancing
Apply consistent load balancing for requests based on `x-user-id` header:

View File

@ -36,6 +36,13 @@ service of the same name.
to any configured
[`service-resolver`](/docs/connect/config-entries/service-resolver).
## UI
Once a `service-router` is successfully entered, you can view it in the UI. Service routers, service splitters, and service resolvers can all be viewed by clicking on your service then switching to the *routing* tab.
![screenshot of service router in the UI](/img/l7-routing/Router.png)
## Sample Config Entries
### Path prefix matching

View File

@ -39,6 +39,12 @@ resolution stage.
to any configured
[`service-resolver`](/docs/connect/config-entries/service-resolver).
## UI
Once a `service-splitter` is successfully entered, you can view it in the UI. Service routers, service splitters, and service resolvers can all be viewed by clicking on your service then switching to the *routing* tab.
![screenshot of service splitter in the UI](/img/l7-routing/Splitter.png)
## Sample Config Entries
### Two subsets of same service

View File

@ -0,0 +1,240 @@
---
layout: docs
page_title: Distributed Tracing
description: >-
Distributed tracing is a way to track and correlate requests across microservices.
---
# Distributed Tracing
Distributed tracing is a way to track and correlate requests across microservices. Distributed tracing must first
be implemented in each application, it cannot be added by Consul. Once implemented in your applications, adding
distributed tracing to Consul will add the sidecar proxies as spans in the request path.
## Application Changes
Consul alone cannot implement distributed tracing for your applications. Each application must propagate the required
headers. Typically this is done using a tracing library such as:
- https://github.com/opentracing/opentracing-go
- https://github.com/DataDog/dd-trace-go
- https://github.com/openzipkin/zipkin-go
## Configuration
Once your applications have been instrumented with a tracing library, you are ready to configure Consul to add sidecar
proxy spans to the trace. Your eventual config will look something like:
<CodeTabs tabs={[ "HCL", "Kubernetes YAML", "JSON" ]}>
```hcl
Kind = "proxy-defaults"
Name = "global"
Config {
protocol = "http"
envoy_tracing_json = <<EOF
{
"http":{
"name":"envoy.tracers.zipkin",
"typedConfig":{
"@type":"type.googleapis.com/envoy.config.trace.v3.ZipkinConfig",
"collector_cluster":"collector_cluster_name",
"collector_endpoint_version":"HTTP_JSON",
"collector_endpoint":"/api/v2/spans",
"shared_span_context":false
}
}
}
EOF
envoy_extra_static_clusters_json = <<EOF
{
"connect_timeout":"3.000s",
"dns_lookup_family":"V4_ONLY",
"lb_policy":"ROUND_ROBIN",
"load_assignment":{
"cluster_name":"collector_cluster_name",
"endpoints":[
{
"lb_endpoints":[
{
"endpoint":{
"address":{
"socket_address":{
"address":"collector-url",
"port_value":9411,
"protocol":"TCP"
}
}
}
}
]
}
]
},
"name":"collector_cluster_name",
"type":"STRICT_DNS"
}
EOF
}
```
```yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ProxyDefaults
metadata:
name: global
spec:
config:
protocol: http
envoy_tracing_json: |
{
"http":{
"name":"envoy.tracers.zipkin",
"typedConfig":{
"@type":"type.googleapis.com/envoy.config.trace.v3.ZipkinConfig",
"collector_cluster":"collector_cluster_name",
"collector_endpoint_version":"HTTP_JSON",
"collector_endpoint":"/api/v2/spans",
"shared_span_context":false
}
}
}
envoy_extra_static_clusters_json: |
{
"connect_timeout":"3.000s",
"dns_lookup_family":"V4_ONLY",
"lb_policy":"ROUND_ROBIN",
"load_assignment":{
"cluster_name":"collector_cluster_name",
"endpoints":[
{
"lb_endpoints":[
{
"endpoint":{
"address":{
"socket_address":{
"address":"collector-url",
"port_value":9411,
"protocol":"TCP"
}
}
}
}
]
}
]
},
"name":"collector_cluster_name",
"type":"STRICT_DNS"
}
```
```json
{
"Kind": "ProxyDefaults",
"Name": "global",
"Config": {
"protocol": "http",
"envoy_tracing_json": "{\"http\":{\"name\":\"envoy.tracers.zipkin\",\"typedConfig\":{\"@type\":\"type.googleapis.com/envoy.config.trace.v3.ZipkinConfig\",\"collector_cluster\":\"collector_cluster_name\",\"collector_endpoint_version\":\"HTTP_JSON\",\"collector_endpoint\":\"/api/v2/spans\",\"shared_span_context\":false}}}",
"envoy_extra_static_clusters_json": "{\"connect_timeout\":\"3.000s\",\"dns_lookup_family\":\"V4_ONLY\",\"lb_policy\":\"ROUND_ROBIN\",\"load_assignment\":{\"cluster_name\":\"collector_cluster_name\",\"endpoints\":[{\"lb_endpoints\":[{\"endpoint\":{\"address\":{\"socket_address\":{\"address\":\"collector-url\",\"port_value\":9411,\"protocol\":\"TCP\"}}}}]}]},\"name\":\"collector_cluster_name\",\"type\":\"STRICT_DNS\"}"
}
}
```
</CodeTabs>
-> **NOTE:** This example uses a [proxy defaults](/docs/connect/config-entries/proxy-defaults) config entry which will apply to all proxies
but you can also apply this config in the
[proxy service registration](/docs/connect/registration/service-registration#proxy-parameters) (not supported on Kubernetes).
Within the config there are two keys you need to customize:
1. [`envoy_tracing_json`](/docs/connect/proxies/envoy#envoy_tracing_json): Sets the tracing configuration for your specific tracing type.
See the [Envoy tracers documentation](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/trace/trace) for your
specific collector's configuration. This configuration will reference the cluster name defined in `envoy_extra_static_clusters_json`.
1. [`envoy_extra_static_clusters_json`](/docs/connect/proxies/envoy#envoy_extra_static_clusters_json): Defines the address
of your tracing collector where Envoy will send its spans. In this example the URL was `collector-url:9411`.
## Applying the configuration
This configuration only applies when proxies are _restarted_ since it changes the _bootstrap_ config for Envoy
which can only be applied on startup. This means you must restart all your proxies for changes to this
config to take effect.
-> **Note:** On Kubernetes this is a matter of restarting your deployments, e.g. `kubectl rollout restart deploy/deploy-name`.
## Considerations
1. Distributed tracing is only supported for HTTP and gRPC services. You must specify the protocol either globally
via a proxy defaults config entry:
<CodeTabs tabs={[ "HCL", "Kubernetes YAML", "JSON" ]}>
```hcl
Kind = "proxy-defaults"
Name = "global"
Config {
protocol = "http"
}
```
```yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ProxyDefaults
metadata:
name: global
spec:
config:
protocol: http
```
```json
{
"Kind": "proxy-defaults",
"Name": "global",
"Config": {
"protocol": "http"
}
}
```
</CodeTabs>
Or via a service defaults config entry for each service:
<CodeTabs tabs={[ "HCL", "Kubernetes YAML", "JSON" ]}>
```hcl
Kind = "service-defaults"
Name = "service-name"
Protocol = "http"
```
```yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ProxyDefaults
metadata:
name: service-name
spec:
protocol: http
```
```json
{
"Kind": "service-defaults",
"Name": "service-name",
"Protocol": "http"
}
```
</CodeTabs>
1. Requests through [Ingress Gateways](/docs/connect/gateways/ingress-gateway) will not be traced unless the header
`x-client-trace-id: 1` is set (see [hashicorp/consul#6645](https://github.com/hashicorp/consul/issues/6645)).
1. Consul does not currently support interoperation with [OpenTelemetry](https://opentelemetry.io/) libraries due to
Envoy not yet having support.
1. Tracing is only supported with Envoy proxies, not the built-in proxy.

View File

@ -13,6 +13,8 @@ This topic provides an overview of the gateway features shipped with Consul. Gat
- [Ingress gateways](#ingress-gateways) enable services to accept traffic from outside the Consul service mesh.
- [Terminating gateways](#terminating-gateways) enable you to route traffic from services in the Consul service mesh to external services.
[![Gateway Architecture](/img/consul-connect/svgs/consul_gateway_overview_wide.svg)](/img/consul-connect/svgs/consul_gateway_overview_wide.svg)
## Mesh Gateways
-> **1.6.0+:** This feature is available in Consul versions 1.6.0 and newer.
@ -25,9 +27,9 @@ They operate by sniffing and extracting the server name indication (SNI) header
Mesh gateways enable the following scenarios:
* **Federate multiple datacenters across a WAN**. Since Consul 1.8.0, mesh gateways can forward gossip and RPC traffic between Consul servers. See [WAN federation via mesh gateways](/docs/connect/gateways/wan-federation-via-mesh-gateways) for additional information.
* **Service-to-service communication across datacenters**. Refer to [Enabling Service-to-service Traffic Accross Datacenters](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters) for additional information.
* **Service-to-service communication across admin partitions**. Since Consul 1.11.0, you can create administrative boundaries for single Consul deployements called "admin partitions". You can use mesh gateways to facilitate cross-partition communication. Refer to [Enabling Service-to-service Traffic Accross Admin Partitions](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-partitions) for additional information.
- **Federate multiple datacenters across a WAN**. Since Consul 1.8.0, mesh gateways can forward gossip and RPC traffic between Consul servers. See [WAN federation via mesh gateways](/docs/connect/gateways/wan-federation-via-mesh-gateways) for additional information.
- **Service-to-service communication across datacenters**. Refer to [Enabling Service-to-service Traffic Across Datacenters](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-datacenters) for additional information.
- **Service-to-service communication across admin partitions**. Since Consul 1.11.0, you can create administrative boundaries for single Consul deployments called "admin partitions". You can use mesh gateways to facilitate cross-partition communication. Refer to [Enabling Service-to-service Traffic Across Admin Partitions](/docs/connect/gateways/mesh-gateway/service-to-service-traffic-partitions) for additional information.
-> **Mesh gateway tutorial**: Follow the [mesh gateway tutorial](https://learn.hashicorp.com/tutorials/consul/service-mesh-gateways) to learn concepts associated with mesh gateways.

View File

@ -10,7 +10,7 @@ description: >-
-> **Consul Enterprise 1.11.0+:** Admin partitions are supported in Consul Enterprise versions 1.11.0 and newer.
Mesh gateways enable you to route service mesh traffic between different Consul [admin partitions](/docs/enteprise/admin-partitions).
Mesh gateways enable you to route service mesh traffic between different Consul [admin partitions](/docs/enterprise/admin-partitions).
Partitions can reside in different clouds or runtime environments where general interconnectivity between all services
in all partitions isn't feasible.
@ -170,7 +170,7 @@ service:
### Enabling Gateways for a Proxy Upstream
The following service definition will enable gateways in `local` mode for three different partitions. Note that each service exists in the same namepace, but are separated by admin partition.
The following service definition will enable gateways in `local` mode for three different partitions. Note that each service exists in the same namespace, but are separated by admin partition.
<CodeTabs heading="Example: Enabling gateways for a proxy upstream.">

View File

@ -49,26 +49,17 @@ target destination. After verifying the TLS client certificate, the cached
intentions should be consulted for each incoming connection/request to
determine if it should be accepted or rejected.
The default intention behavior is defined by the default [ACL
policy](/docs/agent/options#acl_default_policy). If the default ACL policy is
"allow all", then all Connect connections are allowed by default. If the
default ACL policy is "deny all", then all Connect connections or requests are
denied by default.
The default intention behavior is defined by the [`default_policy`](/docs/agent/options#acl_default_policy) configuration.
If the configuration is set `allow`, then all service mesh Connect connections will be allowed by default.
If is set to `deny`, then all connections or requests will be denied by default.
## Intention Basics
Intentions are managed primarily via
[`service-intentions`](/docs/connect/config-entries/service-intentions) config
entries or the UI. Some simpler tasks can also be achieved with the older
[API](/api-docs/connect/intentions) or [CLI](/commands/intention). Please see
the respective documentation for each for full details on options, flags, etc.
You can define a [`service-intentions`](/docs/connect/config-entries/service-intentions) configuration entry to create and manage intentions, as well as manage intentions through the Consul UI. You can also perform some intention-related tasks using the API and CLI commands. Refer to the [API](/api-docs/connect/intentions) and [CLI](/commands/intention) documentation for details.
Below is an example of a basic
[`service-intentions`](/docs/connect/config-entries/service-intentions) config
entry representing two simple intentions. The full data model complete with
more examples can be found in the
[`service-intentions`](/docs/connect/config-entries/service-intentions) config
entry documentation.
The following example shows a `service-intentions` configuration entry that specifies two intentions. Refer to the [`service-intentions`](/docs/connect/config-entries/service-intentions) documentation for the full data model and additional examples.
<CodeTabs>
```hcl
Kind = "service-intentions"
@ -85,20 +76,41 @@ Sources = [
]
```
This config entry defines two intentions with a common destination of "db". The
first intention above is a deny intention with a source of "web". This says
```json
{
"Kind": "service-intentions",
"Name": "db",
"Sources": [
{
"Action": "deny",
"Name": "web"
},
{
"Action": "allow",
"Name": "api"
}
]
}
```
</CodeTabs>
This configuration entry defines two intentions with a common destination of `db`. The
first intention above is a deny intention with a source of `web`. This says
that connections from web to db are not allowed and the connection will be
rejected. The second intention is an allow intention with a source of "api".
rejected. The second intention is an allow intention with a source of `api`.
This says that connections from api to db are allowed and connections will be
accepted.
### Wildcard Intentions
You can use the `*` wildcard when defining an intention source or destination. The wildcard matches _any_ value and can serve as a "catch-all" entry for intentions that should have a wide scope.
You can use the `*` wildcard to match service names when defining an intention source or destination. The wildcard matches _any_ value, which enables you to set a wide initial scope when configuring intentions.
You can use a wildcard to match service names. If you are using Consul Enterprise, you can also use a wildcard to match a namespace.
The wildcard is supported in Consul Enterprise `namespace` fields (see [Namespaces](/docs/enterprise/namespaces) for additional information), but it _is not supported_ in `partition` fields (see [Admin Partitions](/docs/enterprise/admin-partitions) for additional information).
This example says that the "web" service cannot connect to _any_ service:
In the following example, the `web` service cannot connect to _any_ service:
<CodeTabs>
```hcl
Kind = "service-intentions"
@ -111,7 +123,24 @@ Sources = [
]
```
And this example says that _no_ service can connect to the "db" service:
```json
{
"Kind": "service-intentions",
"Name": "*",
"Sources": [
{
"Action": "deny",
"Name": "web"
}
]
}
```
</CodeTabs>
The `db` service is configured to deny all connection in the following example:
<CodeTabs>
```hcl
Kind = "service-intentions"
@ -124,8 +153,25 @@ Sources = [
]
```
<EnterpriseAlert inline /> This example grants Prometheus
access to any service in any namespace.
```json
{
"Kind": "service-intentions",
"Name": "db",
"Sources": [
{
"Action": "deny",
"Name": "*"
}
]
}
```
</CodeTabs>
<EnterpriseAlert inline /> This example grants Prometheus access to any service in
any namespace.
<CodeTabs>
```hcl
Kind = "service-intentions"
@ -140,6 +186,23 @@ Sources = [
]
```
```json
{
"Kind": "service-intentions",
"Name": "*",
"Namespace": "*",
"Sources": [
{
"Action": "allow",
"Name": "prometheus",
"Namespace": "monitoring"
}
]
}
```
</CodeTabs>
### Enforcement
For services that define their [protocol] as TCP, intentions mediate the
@ -177,7 +240,7 @@ top to bottom, with larger numbers being evaluated first.
The precedence value can be read from a
[field](/docs/connect/config-entries/service-intentions#precedence) on the
`service-intentions` config entry after it is modified. Precedence cannot be
`service-intentions` configuration entry after it is modified. Precedence cannot be
manually overridden today.
The numbers in the table above are not stable. Their ordering will remain
@ -201,12 +264,30 @@ for its own service name in order to know whether or not to authorize
connections. The following ACL policy will implicitly grant `intentions:read`
(note _read_) for service `web`.
<CodeTabs>
```hcl
service "web" {
policy = "write"
}
```
```json
{
"service": [
{
"web": [
{
"policy": "write"
}
]
}
]
}
```
</CodeTabs>
It is possible to explicitly specify intention permissions. For example,
the following policy will allow a service to be discovered without granting
access to read intentions for it.

View File

@ -33,7 +33,7 @@ Connect proxy upstreams are discovered using a series of stages: routing,
splitting, and resolution. These stages represent different ways of managing L7
traffic.
![diagram showing l7 traffic discovery stages: routing to splitting to resolution](/img/l7-traffic-stages.svg)
![screenshot of L7 traffic visualization in the UI](/img/l7-routing/full.png)
Each stage of this discovery process can be dynamically reconfigured via various
[configuration entries](/docs/agent/config-entries). When a configuration
@ -44,6 +44,8 @@ entry is missing, that stage will fall back on reasonable default behavior.
A [`service-router`](/docs/connect/config-entries/service-router) config
entry kind is the first configurable stage.
![screenshot of service router in the UI](/img/l7-routing/Router.png)
A router config entry allows for a user to intercept traffic using L7 criteria
such as path prefixes or http headers, and change behavior such as by sending
traffic to a different service or service subset.
@ -59,6 +61,8 @@ can be found in the `service-router` documentation.
A [`service-splitter`](/docs/connect/config-entries/service-splitter) config
entry kind is the next stage after routing.
![screenshot of service splitter in the UI](/img/l7-routing/Splitter.png)
A splitter config entry allows for a user to choose to split incoming requests
across different subsets of a single service (like during staged canary
rollouts), or perhaps across different services (like during a v2 rewrite or
@ -84,6 +88,8 @@ can be found in the `service-splitter` documentation.
A [`service-resolver`](/docs/connect/config-entries/service-resolver) config
entry kind is the last stage.
![screenshot of service resolver in the UI](/img/l7-routing/Resolver.png)
A resolver config entry allows for a user to define which instances of a
service should satisfy discovery requests for the provided name.

View File

@ -27,7 +27,7 @@ URLs](#configuring-dashboard-urls).
It is possible to configure the UI to fetch basic metrics from your metrics
provider storage to augment the visualization as displayed below.
![Consul UI Service Mesh Visualization](/img/ui-service-topology-view.png)
![Consul UI Service Mesh Visualization](/img/ui-service-topology-view-hover.png)
Consul has built-in support for overlaying metrics from a
[Prometheus](https://prometheus.io) backend. Alternative metrics providers may

View File

@ -55,7 +55,7 @@ $ curl http://<host-ip>:8500/v1/agent/connect/ca/roots
After validating the client certificate from the caller, the proxy can authorize the entire connection (L4) or each request (L7). Depending upon the [protocol] of the proxied service, authorization is performed either on a per-connection (L4) or per-request (L7) basis. Authentication is based on "service identity" (TLS), and is implemented at the
transport layer.
-> **Note:** Some features, such as (local) rate limiting or max connections, are expected to be proxy-level configurations enforced separately when authorization calls are made. Proxies can enforce the configurations based on information about request rates and other states that should already be availabe.
-> **Note:** Some features, such as (local) rate limiting or max connections, are expected to be proxy-level configurations enforced separately when authorization calls are made. Proxies can enforce the configurations based on information about request rates and other states that should already be available.
The proxy can authorize the connection by either calling the [`/v1/agent/connect/authorize`](/api/agent/connect) API endpoint or by querying the [intention match API](/api/connect/intentions#list-matching-intentions) endpoint.

View File

@ -97,14 +97,14 @@ Sidecar proxies are co-located with the single service instance they represent a
Specify the following parameters in the `proxy` code block to configure a sidecar proxy in its own service registration:
* `destination_service_id`: String value that specifies the ID of the service being proxied. Refer to the [proxy parameters reference](#destination-service-id) for details.
* `local_service_port`: Integer value that specifes the port that the proxy should use to connect to the _local_ service instance. Refer to the [proxy parameters reference](#local-service-port) for details.
* `local_service_port`: Integer value that specifies the port that the proxy should use to connect to the _local_ service instance. Refer to the [proxy parameters reference](#local-service-port) for details.
* `local_service_address`: String value that specifies the IP address or hostname that the proxy should use to connect to the _local_ service. Refer to the [proxy parameters reference](#local-service-address) for details.
See (Sidecar Service Registration)[/docs/connect/registration/sidecar-service] for additional information about configuring service mesh proxies as sidecars.
### Complete Configuration Example
The following example includes values for all availble options when registering a proxy instance.
The following example includes values for all available options when registering a proxy instance.
<CodeTabs heading="Example that includes all configuration options when registering a proxy instance">
<CodeBlockConfig>
@ -160,7 +160,7 @@ The following table describes all parameters that can be defined in the `proxy`
| Parameter | Description | Required | Default |
| --- | --- | --- | --- |
| `destination_service_id` <a name="destination-service-id"/>| String value that specifies the ID of a single service instance represented by the proxy. <br/>This parameter is only applicable for sidecar proxies that run on the same node as the service. <br/>Consul checks for the proxied service on the same agent. <br/>The ID is unique and may differ from its `name` value. <br/>Specifying this parameter helps tools identify which sidecar proxy instances are associated with which application instance, as well as enable fine-grained analysis of the metrics coming from the proxy.| Required when registering proxy as a sidecar | None |
| `local_service_port` <a name="local-service-port"/>| Integer value that specifes the port that a sidecar proxy should use to connect to the _local_ service instance. | Required when registering proxy as a sidecar | Port advertised by the service instance configured in `destination_service_id` |
| `local_service_port` <a name="local-service-port"/>| Integer value that specifies the port that a sidecar proxy should use to connect to the _local_ service instance. | Required when registering proxy as a sidecar | Port advertised by the service instance configured in `destination_service_id` |
| `local_service_address` <a name="local-service-address"/>| String value that specifies the IP address or hostname that a sidecar proxy should use to connect to the _local_ service. | Optional | `127.0.0.1` |
| `destination_service_name` | String value that specifies the _name_ of the service the instance is proxying. The name is used during service discovery to route to the correct proxy instances for a given service name. | Required | None |
| `local_service_socket_path` | String value that specifies the path of a Unix domain socket for connecting to the local application instance. <br/>This parameter value is created by the application and conflicts with `local_service_address` and `local_service_port`. <br/>Supported when using Envoy for the proxy. | Optional | None |
@ -175,23 +175,23 @@ The following table describes all parameters that can be defined in the `proxy`
You can configure the service mesh proxy to create listeners for upstream services. The listeners enable the upstream service to accept requests. You can specify the following parameters to configure upstream service listeners.
| Parameter | Description | Required | Defautl |
| Parameter | Description | Required | Default |
| --- | --- | --- | --- |
|`destination_name` | String value that specifies the name of the service or prepared query to route the service mesh to. The prepared query should be the name or the ID of the prepared query. | Required | None |
| `destination_namespace` | String value that specifies the namespace containing the upstream service. <EnterpriseAlert inline /> | Optional | `default` |
| `destination_partition` | String value that specifies the name of the admin partition containing the upstream service. | Optional | `default` |
| `local_bind_port` | Integer value that specifies the port to bind a local listener to. The application will make outbound connections to the upstream from the local port. | Required | None |
| `local_bind_address` | String value that specifies the address to bind a local listener to. The application will make outbound connecttions to the upstream service from the local bind address. | Optional | `127.0.0.1` |
| `local_bind_address` | String value that specifies the address to bind a local listener to. The application will make outbound connections to the upstream service from the local bind address. | Optional | `127.0.0.1` |
| `local_bind_socket_path` | String value that specifies the path at which to bind a Unix domain socket listener. The application will make outbound connections to the upstream from the local bind socket path. <br/>This parameter conflicts with the `local_bind_port` or `local_bind_address` parameters. <br/>Supported when using Envoy as a proxy. | Optional | None|
| `local_bind_socket_mode` | String value that specifies a Unix octal that configures file permissions for the socket. | Optional | None |
| `destination_type` | String value that specifies the type of discovery query the proxy should use for finding service mesh instances. The following values are supported: <li>`service`: Queries for upstream `service` types. </li><li> `prepared_query`: Queries for upstream prepared queries.</li> | Optional | `service` |
| `datacenter` | String value that specifies the datacenter to issue the discovery query to. | Optional | Defaults to the local datacenter. |
| `config` | Object value that specifies opaque configuration options that will be provided to the proxy instance for the upstream. <br/>Valid JSON objects are also suppported. <br/>The `config` parameter can specify timeouts, retries, and other proxy-specific features for the given upstream. <br/>See the [built-in proxy configuration reference](/docs/connect/proxies/built-in#proxy-upstream-config-key-reference) for configuration options when using the built-in proxy. <br/>If using Envoy as a proxy, see [Envoy configuration reference](/docs/connect/proxies/envoy#proxy-upstream-config-options) | Optional | None |
| `config` | Object value that specifies opaque configuration options that will be provided to the proxy instance for the upstream. <br/>Valid JSON objects are also supported. <br/>The `config` parameter can specify timeouts, retries, and other proxy-specific features for the given upstream. <br/>See the [built-in proxy configuration reference](/docs/connect/proxies/built-in#proxy-upstream-config-key-reference) for configuration options when using the built-in proxy. <br/>If using Envoy as a proxy, see [Envoy configuration reference](/docs/connect/proxies/envoy#proxy-upstream-config-options) | Optional | None |
| `mesh_gateway` | Object that defines the mesh gateway configuration for the proxy. Refer to the [Mesh Gateway Configuration Reference](#mesh-gateway-configuration-reference) for configuration details. | Optional | None |
### Upstream Configuration Examples
Upstreams support multiple destination types. The following examples include information about each implmentation.
Upstreams support multiple destination types. The following examples include information about each implementation.
-> **Snake case**: The examples in this topic use `snake_case` because the syntax is supported in configuration files and API registrations. See [Service Definition Parameter Case](/docs/agent/services#service-definition-parameter-case) for additional information.

View File

@ -142,6 +142,19 @@ There are several different kinds of checks:
A script check:
<CodeTabs heading="Script Check">
```hcl
check = {
id = "mem-util"
name = "Memory utilization"
args = ["/usr/local/bin/check_mem.py", "-limit", "256MB"]
interval = "10s"
timeout = "1s"
}
```
```json
{
"check": {
@ -154,8 +167,29 @@ A script check:
}
```
</CodeTabs>
A HTTP check:
<CodeTabs heading="HTTP Check">
```hcl
check = {
id = "api"
name = "HTTP API on port 5000"
http = "https://localhost:5000/health"
tls_server_name = ""
tls_skip_verify = false
method = "POST"
header = {
Content-Type = ["application/json"]
}
body = "{\"method\":\"health\"}"
interval = "10s"
timeout = "1s"
}
```
```json
{
"check": {
@ -173,8 +207,23 @@ A HTTP check:
}
```
</CodeTabs>
A TCP check:
<CodeTabs heading="TCP Check">
```hcl
check = {
id = "ssh"
name = "SSH TCP on port 22"
tcp = "localhost:22"
interval = "10s"
timeout = "1s"
}
```
```json
{
"check": {
@ -187,8 +236,21 @@ A TCP check:
}
```
</CodeTabs>
A TTL check:
<CodeTabs heading="TTL Check">
```hcl
check = {
id = "web-app"
name = "Web App Status"
notes = "Web app does a curl internally every 10 seconds"
ttl = "30s"
}
```
```json
{
"check": {
@ -200,8 +262,23 @@ A TTL check:
}
```
</CodeTabs>
A Docker check:
<CodeTabs heading="Docker Check">
```hcl
check = {
id = "mem-util"
name = "Memory utilization"
docker_container_id = "f972c95ebf0e"
shell = "/bin/bash"
args = ["/usr/local/bin/check_mem.py"]
interval = "10s"
}
```
```json
{
"check": {
@ -215,8 +292,22 @@ A Docker check:
}
```
</CodeTabs>
A gRPC check for the whole application:
<CodeTabs heading="gRPC Check">
```hcl
check = {
id = "mem-util"
name = "Service health status"
grpc = "127.0.0.1:12345"
grpc_use_tls = true
interval = "10s"
}
```
```json
{
"check": {
@ -229,8 +320,22 @@ A gRPC check for the whole application:
}
```
</CodeTabs>
A gRPC check for the specific `my_service` service:
<CodeTabs heading="gRPC Specific Service Check">
```hcl
check = {
id = "mem-util"
name = "Service health status"
grpc = "127.0.0.1:12345/my_service"
grpc_use_tls = true
interval = "10s"
}
```
```json
{
"check": {
@ -243,8 +348,22 @@ A gRPC check for the specific `my_service` service:
}
```
</CodeTabs>
A h2ping check:
<CodeTabs heading="H2ping Check">
```hcl
check = {
id = "h2ping-check"
name = "h2ping"
h2ping = "localhost:22222"
interval = "10s"
h2ping_use_tls = false
}
```
```json
{
"check": {
@ -257,8 +376,19 @@ A h2ping check:
}
```
</CodeTabs>
An alias check for a local service:
<CodeTabs heading="Alias Check">
```hcl
check = {
id = "web-alias"
alias_service = "web"
}
```
```json
{
"check": {
@ -268,6 +398,8 @@ An alias check for a local service:
}
```
</CodeTabs>
~> Configuration info: The alias check configuration expects the alias to be
registered on the same agent as the one you are aliasing. If the service is
not registered with the same agent, `"alias_node": "<node_id>"` must also be
@ -342,6 +474,17 @@ to be healthy. In certain cases, it may be desirable to specify the initial
state of a health check. This can be done by specifying the `status` field in a
health check definition, like so:
<CodeTabs heading="Status Field Example">
```hcl
check = {
"id": "mem",
"args": ["/bin/check_mem", "-limit", "256MB"]
"interval": "10s"
"status": "passing"
}
```
```json
{
"check": {
@ -353,6 +496,8 @@ health check definition, like so:
}
```
</CodeTabs>
The above service definition would cause the new "mem" check to be
registered with its initial state set to "passing".
@ -363,6 +508,17 @@ that the status of the health check will only affect the health status of the
given service instead of the entire node. Service-bound health checks may be
provided by adding a `service_id` field to a check configuration:
<CodeTabs heading="Status Field Example">
```hcl
check = {
id = "web-app"
name = "Web App Status"
service_id = "web-app"
ttl = "30s"
}
```
```json
{
"check": {
@ -374,6 +530,8 @@ provided by adding a `service_id` field to a check configuration:
}
```
</CodeTabs>
In the above configuration, if the web-app health check begins failing, it will
only affect the availability of the web-app service. All other services
provided by the node will remain unchanged.
@ -389,6 +547,32 @@ to use the agent's credentials when configured for TLS.
Multiple check definitions can be defined using the `checks` (plural)
key in your configuration file.
<CodeTabs heading="Multiple Checks Example">
```hcl
checks = [
{
id = "chk1"
name = "mem"
args = ["/bin/check_mem", "-limit", "256MB"]
interval = "5s"
},
{
id = "chk2"
name = "/health"
http = "http://localhost:5000/health"
interval = "15s"
},
{
id = "chk3"
name = "cpu"
args = ["/bin/check_cpu"]
interval = "10s"
},
...
]
```
```json
{
"checks": [
@ -415,6 +599,8 @@ key in your configuration file.
}
```
</CodeTabs>
## Success/Failures before passing/warning/critical
To prevent flapping health checks, and limit the load they cause on the cluster,
@ -427,7 +613,7 @@ The status will not transition states until the configured threshold is reached.
- `failures_before_warning` - Number of consecutive unsuccessful results required
before check status transitions to warning. Defaults to the same value as that of
`failures_before_critical` to maintain the expected behavior of not changing the
status of serivce checks to `warning` before `critical` unless configured to do so.
status of service checks to `warning` before `critical` unless configured to do so.
Values higher than `failures_before_critical` are invalid. Added in Consul 1.11.0.
- `failures_before_critical` - Number of consecutive unsuccessful results required
before check status transitions to critical. Defaults to `0`. Added in Consul 1.7.0.
@ -436,6 +622,22 @@ This feature is available for HTTP, TCP, gRPC, Docker & Monitor checks.
By default, both passing and critical thresholds will be set to 0 so the check
status will always reflect the last check result.
<CodeTabs heading="Flapping Prevention Example">
```hcl
checks = [
{
name = "HTTP TCP on port 80"
tcp = "localhost:80"
interval = "10s"
timeout = "1s"
success_before_passing = 3
failures_before_warning = 1
failures_before_critical = 3
}
]
```
```json
{
"checks": [
@ -451,3 +653,5 @@ status will always reflect the last check result.
]
}
```
</CodeTabs>

View File

@ -32,7 +32,91 @@ Send a `SIGHUP` to the running agent or use [`consul reload`](/commands/reload)
update existing services. Alternatively, the service can be [registered dynamically](/api-docs/agent/service#register-service)
using the [HTTP API](/api).
A service definition contains a set of parameters that specify various aspects of the service, including how it is discovered by other services in the network. All possible parameters are included in the following example, but only the top-level `service` parameter and its `name` parameter child are required by default.
A service definition contains a set of parameters that specify various aspects of the service, including how it is discovered by other services in the network.
All possible parameters are included in the following example, but only the top-level `service` parameter and its `name` parameter child are required by default.
<CodeTabs heading="Service Definition">
```hcl
service {
name = "redis"
id = "redis"
port = 80
tags = ["primary"]
meta = {
custom_meta_key = "custom_meta_value"
}
tagged_addresses = {
lan = {
address = "192.168.0.55"
port = 8000
}
wan = {
address = "198.18.0.23"
port = 80
}
}
port = 8000
socket_path = "/tmp/redis.sock"
enable_tag_override = false
checks = [
{
args = ["/usr/local/bin/check_redis.py"]
interval = "10s"
}
]
kind = "connect-proxy"
proxy_destination = "redis"
proxy = {
destination_service_name = "redis"
destination_service_id = "redis1"
local_service_address = "127.0.0.1"
local_service_port = 9090
local_service_socket_path = "/tmp/redis.sock"
mode = "transparent"
transparent_proxy {
outbound_listener_port = 22500
}
mesh_gateway = {
mode = "local"
}
expose = {
checks = true
paths = [
{
path = "/healthz"
local_path_port = 8080
listener_port = 21500
protocol = "http2"
}
]
}
}
connect = {
native = false
}
weights = {
passing = 5
warning = 1
}
token = "233b604b-b92e-48c8-a253-5f11514e4b50"
namespace = "foo"
}
```
```json
{
@ -110,6 +194,8 @@ A service definition contains a set of parameters that specify various aspects o
}
```
</CodeTabs>
The following table describes the available parameters for service definitions.
### `service`
@ -504,6 +590,51 @@ Multiple services definitions can be provided at once when registering services
via the agent configuration by using the plural `services` key (registering
multiple services in this manner is not supported using the HTTP API).
<CodeTabs heading="Multiple Service Definitions">
<CodeBlockConfig filename="redis-services.hcl">
```hcl
services {
id = "red0"
name = "redis"
tags = [
"primary"
]
address = ""
port = 6000
checks = [
{
args = ["/bin/check_redis", "-p", "6000"]
interval = "5s"
timeout = "20s"
}
]
}
services {
id = "red1"
name = "redis"
tags = [
"delayed",
"secondary"
]
address = ""
port = 7000
checks = [
{
args = ["/bin/check_redis", "-p", "7000"]
interval = "30s"
timeout = "60s"
}
]
}
```
</CodeBlockConfig>
<CodeBlockConfig filename="redis-services.json">
```json
{
"services": [
@ -545,43 +676,8 @@ multiple services in this manner is not supported using the HTTP API).
}
```
In HCL you can specify the plural `services` key (although not `service`) multiple times:
```hcl
services {
id = "red0"
name = "redis"
tags = [
"primary"
]
address = ""
port = 6000
checks = [
{
args = ["/bin/check_redis", "-p", "6000"]
interval = "5s"
timeout = "20s"
}
]
}
services {
id = "red1"
name = "redis"
tags = [
"delayed",
"secondary"
]
address = ""
port = 7000
checks = [
{
args = ["/bin/check_redis", "-p", "7000"]
interval = "30s"
timeout = "60s"
}
]
}
```
</CodeBlockConfig>
</CodeTabs>
## Service and Tag Names with DNS

View File

@ -15,10 +15,15 @@ From this page you can download various tools for Consul. These tools are mainta
These Consul tools are created and managed by the dedicated engineers at HashiCorp:
- [Envconsul](https://github.com/hashicorp/envconsul) - Read and set environmental variables for processes from Consul.
- [Consul API Gateway](https://github.com/hashicorp/consul-api-gateway/) - dedicated ingress solution for intelligently routing traffic to applications running on a Consul Service Mesh.
- [Consul ESM](https://github.com/hashicorp/consul-esm) - Provides external service monitoring for Consul. A tutorial is available on [HashiCorp Learn](https://learn.hashicorp.com/tutorials/consul/service-registration-external-services).
- [Consul Migrate](https://github.com/hashicorp/consul-migrate) - Data migration tool to handle Consul upgrades to 0.5.1+
- [Consul Replicate](https://github.com/hashicorp/consul-replicate) - Consul cross-DC KV replication daemon.
- [Consul Template](https://github.com/hashicorp/consul-template) - Generic template rendering and notifications with Consul. A step by step tutorial is available on [HashiCorp Learn](https://learn.hashicorp.com/tutorials/consul/consul-template).
- [Consul-Terraform Sync](https://github.com/hashicorp/consul-terraform-sync) -
enables dynamic updates to network infrastructure devices triggered by service
changes. A tutorial is available on [HashiCorp
Learn](https://learn.hashicorp.com/collections/consul/network-infrastructure-automation?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS)
## Community Tools

View File

@ -25,6 +25,6 @@ There are several ways to get started with Consul with ECS.
* The [Serverless Consul Service Mesh with ECS and HCP](https://learn.hashicorp.com/tutorials/cloud/consul-ecs-hcp?in=consul/cloud-integrations) learn guide shows how to use Terraform to run Consul service mesh applications on ECS with managed Consul servers running in HashiCorp Cloud Platform (HCP).
* The [Service Mesh with ECS and Consul on EC2](https://learn.hashicorp.com/tutorials/consul/consul-ecs-ec2?in=consul/cloud-integrations) learn guide shows how to use Terraform to run Consul service mesh applications on ECS with Consul servers running on EC2 instances.
* The [Consul with Dev Server on Fargate](https://registry.terraform.io/modules/hashicorp/consul-ecs/aws/latest/examples/dev-server-fargate) example installation deploys a sample application in ECS using the Fargate launch type.
* The [Consul with Dev Server on EC2](https://registry.terraform.io/modules/hashicorp/consul-ecs/aws/latest/examples/dev-server-ec2) example installation deploys a sample applciation in ECS using the EC2 launch type.
* The [Consul with Dev Server on EC2](https://registry.terraform.io/modules/hashicorp/consul-ecs/aws/latest/examples/dev-server-ec2) example installation deploys a sample application in ECS using the EC2 launch type.
See the [Requirements](/docs/ecs/get-started/requirements) and the full [Install Guide](/docs/ecs/get-started/install) when you're ready to install Consul on an existing ECS cluster and add existing tasks to the service mesh.

View File

@ -1,7 +1,7 @@
---
layout: docs
page_title: Consul Enterprise Admin Partitions
description: Consul Enterprise enables you to create paritions that can be administrated across namespaces.
description: Consul Enterprise enables you to create partitions that can be administrated across namespaces.
---
# Consul Enterprise Admin Partitions

View File

@ -112,7 +112,7 @@ Consuls built-in UI has a topology visualization for services part of the Con
The diagram below illustrates how the UI displays service metrics for a sample application:
[![UI Topology View](/img/ui-topology.png)](/img/ui-topology.png)
![UI Topology View](/img/ui-service-topology-view-hover.png)
The topology view is configured under `ui.metrics`. This will enable the Consul UI to query the provider specified by
`ui.metrics.provider` at the URL of the Prometheus server `ui.metrics.baseURL` to display sidecar proxy metrics for the

View File

@ -441,7 +441,7 @@ to retrieve the bootstrap token mentioned in the UI documentation.
With the UI open, you'll be able to switch between datacenters via the dropdown
in the top left:
![Consul Datacenter Dropdown](/img/consul-datacenter-dropdown.png 'Consul Datacenter Dropdown')
![Consul Datacenter Dropdown](/img/data-center-dropdown.png 'Consul Datacenter Dropdown')
## Next Steps

View File

@ -41,7 +41,7 @@ Prior to creating Vault auth roles for the Consul servers and clients, ensure th
$ vault auth enable kubernetes
```
After enabling the Kubernetes auth method, in Vault, ensure that you have configured the Kubernetes Auth method properly as described in [Kubernetes Auth Method Configuration](https://www.vaultproject.io/docs/auth/kubernetes#configuration). The command should look simliar to the following with a custom `kubernetes_host` config provided from the information provided via `kubectl cluster-info`.
After enabling the Kubernetes auth method, in Vault, ensure that you have configured the Kubernetes Auth method properly as described in [Kubernetes Auth Method Configuration](https://www.vaultproject.io/docs/auth/kubernetes#configuration). The command should look similar to the following with a custom `kubernetes_host` config provided from the information provided via `kubectl cluster-info`.
```shell-session
$ vault write auth/kubernetes/config \
@ -52,7 +52,7 @@ $ vault write auth/kubernetes/config \
### Vault KV Secrets Engine - Version 2
In order to utlize Vault as a secrets backend, we must enable thne [Vault KV secrets engine - Version 2](https://www.vaultproject.io/docs/secrets/kv/kv-v2).
In order to utilize Vault as a secrets backend, we must enable the [Vault KV secrets engine - Version 2](https://www.vaultproject.io/docs/secrets/kv/kv-v2).
```shell-session
$ vault secrets enable -path=consul kv-v2

View File

@ -9,7 +9,7 @@ description: >-
To use Vault to issue Server TLS certificates the following will be needed:
1. Bootstrap the Vault PKI engine and boostrap it with any configuration required for your infrastructure.
1. Bootstrap the Vault PKI engine and bootstrap it with any configuration required for your infrastructure.
1. Create Vault Policies that will allow the Consul server to access the certificate issuing url.
1. Create Vault Policies that will allow the Consul components, e.g. ingress gateways, controller, to access the CA url.
1. Create Kubernetes auth roles that link these policies to the Kubernetes service accounts of the Consul components.
@ -130,7 +130,7 @@ vault write auth/kubernetes/role/consul-ca \
```
The above Vault Roles will now be your Helm values for `global.secretsBackend.vault.consulServerRole` and
`global.secretsBAckend.vault.consulCARole` respectively.
`global.secretsBackend.vault.consulCARole` respectively.
## Deploying the Consul Helm chart

View File

@ -88,9 +88,9 @@ The following options are available.
| `-config-file` | String value that specifies the path to a file containing custom installation configurations, e.g., Consul Helm chart values file. <br/> You can use the `-config-file` flag multiple times to specify multiple files. | none | Optional |
| `-namespace` | String value that specifies the namespace of the Consul installation. | `consul` | Optional |
| `-preset` | String value that installs Consul based on a preset configuration. You can specify the following values: <br/> `demo`: Installs a single replica server with sidecar injection enabled; useful for testing service mesh functionality. <br/> `secure`: Installs a single replica server with sidecar injection, ACLs, and TLS enabled; useful for testing service mesh functionality. | Configuration of the Consul Helm chart. | Optional |
| `-set` | String value that enables you to set a customizeable value. This flag is comparable to the `helm install --set` flag. <br/> You can use the `-set` flag multiple times to set multiple values. <br/> Consul Helm chart values are supported. | none | Optional |
| `-set-file` | String value that specifies the name of an arbitrary config file. This flag is comparable to the `helm install --set-file` <br/> flag. The contents of the file will be used to set a customizeable value. You can use the `-set-file` flag multiple times to specify multiple files. <br/> Consul Helm chart values are supported. | none | Optional |
| `-set-string` | String value that enables you to set a customizeable string value. This flag is comparable to the `helm install --set-string` <br/> flag. You can use the `-set-string` flag multiple times to specify multiple strings. <br/> Consul Helm chart values are supported. | none | Optional |
| `-set` | String value that enables you to set a customizable value. This flag is comparable to the `helm install --set` flag. <br/> You can use the `-set` flag multiple times to set multiple values. <br/> Consul Helm chart values are supported. | none | Optional |
| `-set-file` | String value that specifies the name of an arbitrary config file. This flag is comparable to the `helm install --set-file` <br/> flag. The contents of the file will be used to set a customizable value. You can use the `-set-file` flag multiple times to specify multiple files. <br/> Consul Helm chart values are supported. | none | Optional |
| `-set-string` | String value that enables you to set a customizable string value. This flag is comparable to the `helm install --set-string` <br/> flag. You can use the `-set-string` flag multiple times to specify multiple strings. <br/> Consul Helm chart values are supported. | none | Optional |
| `-timeout` | Specifies how long to wait for the installation process to complete before timing out. The value is specified with an integer and string value indicating a unit of time. <br/> The following units are supported: <br/> `ms` (milliseconds)<br/>`s` (seconds)<br/>`m` (minutes) <br/>In the following example, installation will timeout after one minute:<br/> `consul-k8s install -timeout 1m` | `10m` | Optional |
| `-wait` | Boolean value that determines if Consul should wait for resources in the installation to be ready before exiting the command. | `true` | Optional |
| `-verbose`, `-v` | Boolean value that specifies whether to output verbose logs from the install command with the status of resources being installed. | `false` | Optional |
@ -133,7 +133,7 @@ The following options are available.
| `-name` | String value for the name of the installation to remove. | none | Optional |
| `-namespace` | String value that specifies the namespace of the Consul installation to remove. | `consul` | Optional |
| `-timeout` | Specifies how long to wait for the removal process to complete before timing out. The value is specified with an integer and string value indicating a unit of time. <br/> The following units are supported: <br/> `ms` (milliseconds)<br/>`s` (seconds)<br/>`m` (minutes) <br/>`h` (hours) <br/>In the following example, removal will timeout after one minute:<br/> `consul-k8s uninstall -timeout 1m` | `10m` | Optional |
| `-wipe-data` | Boolan value that deletes PVCs and secrets associated with the Consul installation during installation. <br/> Data will be removed without a verification prompt if the `-auto-approve` flag is set to `true`. | `false` <br/> Instructions for removing data will be printed to the console. | Optional |
| `-wipe-data` | Boolean value that deletes PVCs and secrets associated with the Consul installation during installation. <br/> Data will be removed without a verification prompt if the `-auto-approve` flag is set to `true`. | `false` <br/> Instructions for removing data will be printed to the console. | Optional |
| `--help` | Prints usage information for this option. | none | Optional |
See [Global Options](#global-options) for additional commands that you can use when uninstalling Consul from Kubernetes.
@ -210,11 +210,11 @@ The following options are available.
| `-config-file` | String value that specifies the path to a file containing custom upgrade configurations, e.g., Consul Helm chart values file. <br/> You can use the `-config-file` flag multiple times to specify multiple files. | none | Optional |
| `-namespace` | String value that specifies the namespace of the Consul installation. | `consul` | Optional |
| `-preset` | String value that upgrades Consul based on a preset configuration. | Configuration of the Consul Helm chart. | Optional |
| `-set` | String value that enables you to set a customizeable value. This flag is comparable to the `helm upgrade --set` flag. <br/> You can use the `-set` flag multiple times to set multiple values. <br/> Consul Helm chart values are supported. | none | Optional |
| `-set-file` | String value that specifies the name of an arbitrary config file. This flag is comparable to the `helm upgrade --set-file` <br/> flag. The contents of the file will be used to set a customizeable value. You can use the `-set-file` flag multiple times to specify multiple files. <br/> Consul Helm chart values are supported. | none | Optional |
| `-set-string` | String value that enables you to set a customizeable string value. This flag is comparable to the `helm upgrade --set-string` <br/> flag. You can use the `-set-string` flag multiple times to specify multiple strings. <br/> Consul Helm chart values are supported. | none | Optional |
| `-set` | String value that enables you to set a customizable value. This flag is comparable to the `helm upgrade --set` flag. <br/> You can use the `-set` flag multiple times to set multiple values. <br/> Consul Helm chart values are supported. | none | Optional |
| `-set-file` | String value that specifies the name of an arbitrary config file. This flag is comparable to the `helm upgrade --set-file` <br/> flag. The contents of the file will be used to set a customizable value. You can use the `-set-file` flag multiple times to specify multiple files. <br/> Consul Helm chart values are supported. | none | Optional |
| `-set-string` | String value that enables you to set a customizable string value. This flag is comparable to the `helm upgrade --set-string` <br/> flag. You can use the `-set-string` flag multiple times to specify multiple strings. <br/> Consul Helm chart values are supported. | none | Optional |
| `-timeout` | Specifies how long to wait for the upgrade process to complete before timing out. The value is specified with an integer and string value indicating a unit of time. <br/> The following units are supported: <br/> `ms` (milliseconds)<br/>`s` (seconds)<br/>`m` (minutes) <br/>In the following example, the upgrade will timeout after one minute:<br/> `consul-k8s upgrade -timeout 1m` | `10m` | Optional |
| `-wait` | Boolean value that determines if Consul should wait for resources in the upgtrade to be ready before exiting the command. | `true` | Optional |
| `-wait` | Boolean value that determines if Consul should wait for resources in the upgrade to be ready before exiting the command. | `true` | Optional |
| `-verbose`, `-v` | Boolean value that specifies whether to output verbose logs from the upgrade command with the status of resources being upgraded. | `false` | Optional |
| `--help` | Prints usage information for this option. | none | Optional |

View File

@ -10,7 +10,7 @@ You can uninstall Consul using Helm commands or the Consul K8s CLI.
## Consul K8s CLI
Issue the `consul-k8s uninstall` command to remove Consul on Kubernetes. You can specify the installation name, namespace, and data retention behavior using the applicable options. By default, the uninstallation preserves the secrets and PVCs that are provisioned by Consul on Kubernetes.
Issue the `consul-k8s uninstall` command to remove Consul on Kubernetes. You can specify the installation name, namespace, and data retention behavior using the applicable options. By default, the uninstall preserves the secrets and PVCs that are provisioned by Consul on Kubernetes.
```shell-session
$ consul-k8s uninstall <OPTIONS>
@ -29,6 +29,11 @@ Refer to the [Consul K8s CLI reference](/docs/k8s/k8s-cli#uninstall) topic for d
Run the `helm uninstall` **and** manually remove resources that Helm does not delete.
1. Although the Helm chart automates the deletion of CRDs upon the uninstallation of the Helm chart, sometimes the finalizers tied to those CRDs may not complete because the deletion of the CRDs rely on the Consul K8s controller running. Ensure that previously created CRDs for Consul on Kubernetes are deleted, so subsequent installs of Consul on Kubernetes on the same Kubernetes cluster do not get blocked.
```shell-session
$ kubectl delete crd --selector app=consul
```
1. (Optional) If Consul is installed in a dedicated namespace, set the kubeConfig context to the `consul` namespace. Otherwise, subsequent commands will need to include `-n consul`.
@ -36,6 +41,7 @@ Run the `helm uninstall` **and** manually remove resources that Helm does not de
kubectl config set-context --current --namespace=consul
```
1. Run the `helm uninstall <release-name>` command and specify the release name you've installed Consul with, e.g.,:
```shell-session
@ -43,6 +49,7 @@ Run the `helm uninstall` **and** manually remove resources that Helm does not de
release "consul" uninstalled
```
1. After deleting the Helm release, you need to delete the `PersistentVolumeClaim`'s
for the persistent volumes that store Consul's data. A [bug](https://github.com/helm/helm/issues/5156) in Helm prevents PVCs from being deleted. Issue the following commands:
@ -102,3 +109,9 @@ Run the `helm uninstall` **and** manually remove resources that Helm does not de
$ kubectl delete serviceaccount consul-tls-init
serviceaccount "consul-tls-init" deleted
```
1. (Optional) Delete the namespace (i.e. `consul` in the following example) that you have dedicated for installing Consul on Kubernetes.
```shell-session
$ kubectl delete ns consul
```

View File

@ -16,6 +16,8 @@ as first-class Kubernetes services. This functionality is provided by the
automatically installed and configured using the
[Consul Helm chart](/docs/k8s/installation/install).
![screenshot of a Kubernetes service in the UI](/img/k8s-service.png)
**Why sync Kubernetes services to Consul?** Kubernetes services synced to the
Consul catalog enable Kubernetes services to be accessed by any node that
is part of the Consul cluster, including other distinct Kubernetes clusters.

View File

@ -7,8 +7,21 @@ description: >-
# Consul-Terraform-Sync Enterprise
Consul-Terraform-Sync Enterprise features address organization complexities of collaboration, operations, scale, and governance. Please see the sidebar navigation on the left to view all enterprise features.
Consul-Terraform-Sync (CTS) Enterprise is available with [Consul Enterprise](https://www.hashicorp.com/products/consul) and requires a Consul [license](/docs/nia/enterprise/license) to be applied.
Enterprise features require a Consul [license](/docs/nia/enterprise/license) to be applied.
Enterprise features of CTS address organization complexities of collaboration, operations, scale, and governance. CTS Enterprise supports an official integration with [Terraform Cloud](https://www.terraform.io/cloud) and [Terraform Enterprise](https://www.terraform.io/enterprise), the self-hosted distribution, to extend insight into dynamic updates of your network infrastructure.
These features are part of Consul-Terraform-Sync Enterprise which is part of [Consul Enterprise](https://www.hashicorp.com/products/consul).
| Features | Open Source | Enterprise |
|----------|-------------|------------|
| Consul Namespace | Default namespace only | Filter task triggers by any namespace |
| Automation Driver | Terraform OSS | Terraform OSS, Terraform Cloud, or Terraform Enterprise |
| Terraform Workspaces | Local | Local workspaces with the Terraform driver or [remote workspaces](https://www.terraform.io/cloud-docs/workspaces) with the Terraform Cloud driver |
| Terraform Backend Options | [azurerm](https://www.terraform.io/docs/backends/types/azurerm.html), [consul](https://www.terraform.io/docs/backends/types/consul.html), [cos](https://www.terraform.io/docs/backends/types/cos.html), [gcs](https://www.terraform.io/docs/backends/types/gcs.html), [kubernetes](https://www.terraform.io/docs/backends/types/kubernetes.html), [local](https://www.terraform.io/docs/backends/types/local.html), [manta](https://www.terraform.io/docs/backends/types/manta.html), [pg](https://www.terraform.io/docs/backends/types/pg.html), and [s3](https://www.terraform.io/docs/backends/types/s3.html) with the Terraform driver | The supported backends for CTS with the Terraform driver or Terraform Cloud with the Terraform Cloud driver |
| Terraform Version | One Terraform version for all tasks | Optional Terraform version per task when using the Terraform Cloud driver |
| Terraform Run Output | CTS logs | CTS logs or Terraform output organized by Terraform Cloud remote workspaces |
| Credentials and secrets | On disk as `.tfvars` files or in shell environment | Secured variables stored in remote workspace |
| Audit | | Terraform audit logs ([Terraform Cloud](https://www.terraform.io/cloud-docs/api-docs/audit-trails) or [Terraform Enterprise](https://www.terraform.io/enterprise/admin/infrastructure/logging)) |
| Collaboration | | Run [history](https://www.terraform.io/docs/cloud/run/manage.html), [triggers](https://www.terraform.io/docs/cloud/workspaces/run-triggers.html), and [notifications](https://www.terraform.io/docs/cloud/workspaces/notifications.html) supported on Terraform Cloud |
| Governance | | [Sentinel](https://www.terraform.io/docs/cloud/sentinel/index.html) to enforce governance policies as code |
The [Terraform Cloud driver](/docs/nia/configuration#terraform-cloud-driver) enables CTS Enterprise to integrate with Terraform Cloud or Terraform Enterprise. The [Terraform Cloud driver](/docs/nia/network-drivers/terraform-cloud) page provides an overview of how the integration works within CTS.

View File

@ -11,6 +11,8 @@ Network Infrastructure Automation (NIA) enables dynamic updates to network infra
Consul-Terraform-Sync executes one or more automation tasks with the most recent service variable values from the Consul service catalog. Each task consists of a runbook automation written as a Consul-Terraform-Sync compatible Terraform module using resources and data sources for the underlying network infrastructure. The `consul-terraform-sync` daemon runs on the same node as a Consul agent.
CTS is available as an open source and enterprise distribution. Follow the [Network Infrastructure Automation introduction tutorial](https://learn.hashicorp.com/tutorials/consul/consul-terraform-sync-intro?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) to get started with CTS OSS or read more about [CTS Enterprise](/docs/nia/enterprise).
## Use Cases
**Application teams must wait for manual changes in the network to release, scale up/down and re-deploy their applications.** This creates a bottleneck, especially in frequent workflows related to scaling up/down the application, breaking the DevOps goal of self-service enablement. Consul-Terraform-Sync automates this process, thus decreasing the possibility of human error in manually editing configuration files, as well as decreasing the overall time taken to push out configuration changes.
@ -19,7 +21,7 @@ Consul-Terraform-Sync executes one or more automation tasks with the most recent
## Glossary
**Condition** - A task-level defined environmental requirement. When a tasks condition is met, Consul-Terraform-Sync executes that task to update network infrastructure. Depending on the condition type, the condition definition may also define and enable the source input that the task provides to the configured Terraform Module.
**Condition** - A task-level defined environmental requirement. When a tasks condition is met, Consul-Terraform-Sync executes that task to update network infrastructure. Depending on the condition type, the condition definition may also define and enable the source input that the task provides to the configured Terraform module.
**Consul-Terraform-Sync** - [GitHub repo](https://github.com/hashicorp/consul-terraform-sync) and binary/CLI name for the project that is used to perform Network Infrastructure Automation.
@ -33,10 +35,12 @@ Consul-Terraform-Sync executes one or more automation tasks with the most recent
-> **Note:** The terminology "tasks" used throughout the documentation refers to all types of tasks except when specifically stated otherwise.
**Source Input** - A source input defines objects that provide values or metadata to the Terraform module. See [source input](/docs/nia/terraform-modules#source-input) for the supported metadata and values. For example, a user can configure a Consul KV source input to provide KV pairs as variables to their respective Terraform Module. The source input can be included in two ways. It can be specified as a parameter in a condition using `source_includes_var` and also by using the `source_input` block.
**Source Input** - A source input defines objects that provide values or metadata to the Terraform module. See [source input](/docs/nia/terraform-modules#source-input) for the supported metadata and values. For example, a user can configure a Consul KV source input to provide KV pairs as variables to their respective Terraform module. The source input can be included in two ways. It can be specified as a parameter in a condition using `source_includes_var` and also by using the `source_input` block.
**Network Infrastructure Automation (NIA)** - Enables dynamic updates to network infrastructure devices triggered when specific conditions, such as service changes and registration, are met.
**Services** - A service in CTS represents a service that is registered with Consul for service discovery. Services are grouped by their service names. There may be more than one instance of a particular service, each with its own unique ID. CTS monitors services based on service names and can provide service instance details to a Terraform module for network automation.
**Tasks** - A task is the translation of dynamic service information from the Consul Catalog into network infrastructure changes downstream.
**Terraform Cloud** - Per the [Terraform documentation](https://www.terraform.io/docs/cloud/index.html), "Terraform Cloud" describes both Terraform Cloud and Terraform Enterprise, which are different distributions of the same application. Documentation will apply to both distributions unless specifically stated otherwise.

View File

@ -9,36 +9,88 @@ description: >-
Refer to the [introduction](https://learn.hashicorp.com/tutorials/consul/consul-terraform-sync-intro?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial for details about installing, configuring, and running Consul-Terraform-Sync on your local machine with the Terraform driver.
## Installing Consul-Terraform-Sync
## Install Consul-Terraform-Sync
To install Consul-Terraform-Sync, find the [appropriate package](https://releases.hashicorp.com/consul-terraform-sync/) for your system and download it as a zip archive. Unzip the package to extract the binary named consul-terraform-sync. Move the consul-terraform-sync binary to a location available on your PATH.
<Tabs>
<Tab heading="Pre-compiled binary">
To install Consul-Terraform-Sync, find the [appropriate package](https://releases.hashicorp.com/consul-terraform-sync/) for your system and download it as a zip archive. For the CTS Enterprise binary, download a zip archive with the `+ent` metadata. [CTS Enterprise requires a Consul Enterpise license](/docs/nia/enterprise/license) to run.
Unzip the package to extract the binary named `consul-terraform-sync`. Move the `consul-terraform-sync` binary to a location available on your `PATH`.
Example:
```shell-session
$ mv ~/Downloads/consul-terraform-sync /usr/local/bin/consul-terraform-sync
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
$ mv ./consul-terraform-sync /usr/local/bin/consul-terraform-sync
```
You can also install Consul-Terraform-Sync as a [Docker container](https://hub.docker.com/u/hashicorp/consul-terraform-sync) or build the binary from [source](https://github.com/hashicorp/consul-terraform-sync).
Once installed, verify the installation works by prompting the help option.
Once installed, verify the installation works by prompting the `-version` or `-help` option. The version outputed for the CTS Enterpise binary includes the `+ent` metadata.
```shell-session
$ consul-terraform-sync -h
Usage of consul-terraform-sync:
-config-dir value
A directory to load files for configuring Sync. Configuration files
require an .hcl or .json file extention in order to specify their format.
This option can be specified multiple times to load different directories.
-config-file value
A file to load for configuring Sync. Configuration file requires an
.hcl or .json extension in order to specify their format. This option can
be specified multiple times to load different configuration files.
-once
Render templates and run tasks once. Does not run the process as a daemon
and disables wait timers.
-version
Print the version of this daemon.
$ consul-terraform-sync -version
```
</Tab>
<Tab heading="Docker">
Install and run Consul-Terraform-Sync as a [Docker container](https://hub.docker.com/r/hashicorp/consul-terraform-sync).
For the CTS Enterprise, use the Docker image [`hashicorp/consul-terraform-sync-enterprise`](https://hub.docker.com/r/hashicorp/consul-terraform-sync-enterprise).
```shell-session
$ docker pull hashicorp/consul-terraform-sync
```
Once installed, verify the installation works by prompting the `-version` or `-help` option. The version outputed for the CTS Enterpise image includes the `+ent` metadata.
```shell-session
$ docker run --rm hashicorp/consul-terraform-sync -version
```
</Tab>
<Tab heading="Homewbrew on OS X">
The CTS OSS binary is available in the HashiCorp tap, which is a repository of all our Homebrew packages.
```shell-session
$ brew tap hashicorp/tap
$ brew install hashicorp/tap/consul-terraform-sync
```
Run the following command to update to the latest version:
```shell-session
$ brew upgrade hashicorp/tap/consul-terraform-sync
```
Once installed, verify the installation works by prompting the `-version` or `-help` option.
```shell-session
$ consul-terraform-sync -version
```
</Tab>
<Tab heading="Build from source">
Clone the repository from GitHub [`hashicorp/consul-terraform-sync`](https://github.com/hashicorp/consul-terraform-sync) to build and install the CTS OSS binary in your path `$GOPATH/bin`. Building from source requires `git` and [Golang](https://go.dev/).
```shell-session
$ git clone https://github.com/hashicorp/consul-terraform-sync.git
$ cd consul-terraform-sync
$ git checkout tags/<vX.Y.Z>
$ go install
```
Once installed, verify the installation works by prompting the `-version` or `-help` option.
```shell-session
$ consul-terraform-sync -version
```
</Tab>
</Tabs>
## Connect your Consul Cluster
Consul-Terraform-Sync connects with your Consul cluster in order to monitor the Consul catalog for service changes. These service changes lead to downstream updates to your network devices. You can configure your Consul cluster in Consul-Terraform-Sync with the [Consul block](/docs/nia/configuration#consul). Below is an example:

View File

@ -16,7 +16,7 @@ The following table highlights some of the additional features Terraform and Ter
| Network Driver | Description | Features |
| -------------- | ----------- | -------- |
| [Terraform driver](/docs/nia/network-drivers/terraform) | Consul-Terraform-Sync automates a local installation of the [Terraform CLI](https://www.terraform.io/) | - Local Terraform execution <br/> - Local workspace directories <br/> - [Backend options](/docs/nia/configuration#backend) available for state storage <br/> |
| [Terraform Cloud driver](/docs/nia/network-drivers/terraform-cloud) | Consul-Terraform-Sync Enterprise automates remote workspaces on [Terraform Cloud](https://www.terraform.io/docs/cloud/index.html) | - [Remote Terraform execution](https://www.terraform.io/docs/cloud/run/index.html) <br/> - Concurrent runs <br/> - [Secured variables](https://www.terraform.io/docs/cloud/workspaces/variables.html) <br/> - [State versions](https://www.terraform.io/docs/cloud/workspaces/state.html) <br/> - [Sentinel](https://www.terraform.io/docs/cloud/sentinel/index.html) to enforce governance policies as code <br/> - Audit [logs](https://www.terraform.io/docs/enterprise/admin/logging.html) and [trails](https://www.terraform.io/docs/cloud/api/audit-trails.html) <br/> - Run [history](https://www.terraform.io/docs/cloud/run/manage.html), [triggers](https://www.terraform.io/docs/cloud/workspaces/run-triggers.html) and [notifications](https://www.terraform.io/docs/cloud/workspaces/notifications.html) <br/> - [Terraform Cloud Agents](https://www.terraform.io/docs/cloud/agents/index.html) |
| [Terraform Cloud driver](/docs/nia/network-drivers/terraform-cloud) | Consul-Terraform-Sync Enterprise automates remote workspaces on [Terraform Cloud](https://www.terraform.io/docs/cloud/index.html) | - [Remote Terraform execution](https://www.terraform.io/docs/cloud/run/index.html) <br/> - Concurrent runs <br/> - [Secured variables](https://www.terraform.io/docs/cloud/workspaces/variables.html) <br/> - [State versions](https://www.terraform.io/docs/cloud/workspaces/state.html) <br/> - [Sentinel](https://www.terraform.io/docs/cloud/sentinel/index.html) to enforce governance policies as code <br/> - Audit [logs](https://www.terraform.io/docs/enterprise/admin/logging.html) and [trails](https://www.terraform.io/docs/cloud/api/audit-trails.html) <br/> - Run [history](https://www.terraform.io/docs/cloud/run/manage.html), [triggers](https://www.terraform.io/docs/cloud/workspaces/run-triggers.html), and [notifications](https://www.terraform.io/docs/cloud/workspaces/notifications.html) <br/> - [Terraform Cloud Agents](https://www.terraform.io/docs/cloud/agents/index.html) |
## Understanding Terraform Automation

View File

@ -22,7 +22,7 @@ Once all workspaces are set up, Consul-Terraform-Sync monitors the Consul catalo
Within the Consul-Terraform-Sync configuration for a task, practitioners can select the desired module to run for the task as well as set the condition to execute the task. Each task executed by the Terraform driver corresponds to an automated root module that calls the selected module in an isolated Terraform environment. Consul-Terraform-Sync will manage concurrent execution of these tasks.
Autogenerated root modules for tasks are mantained in local subdirectories of the Consul-Terraform-Sync working directory. Each subdirectory represents the local workspace for a task. By default, the working directory `sync-tasks` is created in the current directory. To configure where Terraform configuration files are stored, set [`working_dir`](/docs/nia/configuration#working_dir) to the desired path or configure the [`task.working_dir`](/docs/nia/configuration#working_dir-1) individually.
Autogenerated root modules for tasks are maintained in local subdirectories of the Consul-Terraform-Sync working directory. Each subdirectory represents the local workspace for a task. By default, the working directory `sync-tasks` is created in the current directory. To configure where Terraform configuration files are stored, set [`working_dir`](/docs/nia/configuration#working_dir) to the desired path or configure the [`task.working_dir`](/docs/nia/configuration#working_dir-1) individually.
~> **Note:** Although Terraform state files for task workspaces are independent, this does not guarantee the infrastructure changes from concurrent task executions are independent. Ensure that modules across all tasks are not modifying the same resource objects or have overlapping changes that may result in race conditions during automation.

View File

@ -68,7 +68,7 @@ The following syntax describes how to include a resource label in the rule:
</CodeBlockConfig>
</CodeTabs>
Labels provide operators with more granular control over access to the resouce, but the following resource types do not take a label:
Labels provide operators with more granular control over access to the resource, but the following resource types do not take a label:
* `acl`
* `keyring`
@ -102,7 +102,7 @@ Use the `policy` keyword and one of the following access levels to set a policy
- `write`: Allows the resource to be read and modified.
- `deny`: Denies read and write access to the resource.
The special `list` access level provices access to all keys with the specified resource label in the Consul KV. The `list` access level can only be used with the `key_prefix` resource. The [`acl.enable_key_list_policy`](/docs/agent/options#acl_enable_key_list_policy) setting must be set to `true`.
The special `list` access level provides access to all keys with the specified resource label in the Consul KV. The `list` access level can only be used with the `key_prefix` resource. The [`acl.enable_key_list_policy`](/docs/agent/options#acl_enable_key_list_policy) setting must be set to `true`.
### Matching and Prefix Values
@ -295,7 +295,7 @@ $ curl \
}' http://127.0.0.1:8500/v1/acl/policy?token=<management token>
```
The policy configuration is returned when the call is succesfully performaed:
The policy configuration is returned when the call is successfully performed:
```json
{

View File

@ -14,7 +14,7 @@ description: >-
This guide explains how to best upgrade a single Consul Enterprise datacenter to v1.10.0
from a version of Consul that is forward compatible with v1.10. If you are on a major
version of Consul prior to 1.8, you will need to complete and [upgrade to 1.8.13](/docs/upgrading/instructions)
version of Consul prior to 1.8, you will need to complete and [upgrade to 1.8.13](/docs/upgrading/instructions/upgrade-to-1-8-x)
or higher before continuing with this guide. If you are already on a major version of 1.8 or 1.9, then
this guide will go over the procedures required for upgrading to v1.10. This process
will require intermediate version upgrades to a forward-compatible release of v1.8 or v1.9,
@ -210,7 +210,7 @@ to the latest 1.8.x or 1.9.x before the next steps. Otherwise, this step can be
**6.** Update the value of `global.image` in the values file to the latest 1.8.x or 1.9.x image.
Additionally, ensure that the Kuberenetes secret with the license is specified in the
Additionally, ensure that the Kubernetes secret with the license is specified in the
values `server.enterpriseLicense.secretName` and `server.enterpriseLicense.secretKey`.
**7.** Upgrade the cluster.

View File

@ -16,6 +16,13 @@ upgrade flow.
## Consul 1.11.0
### 1.10 Compatibility <EnterpriseAlert inline />
Consul Enterprise versions 1.10.0 through 1.10.4 contain a latent bug that
causes those client or server agents to deregister their own services or health
checks when some of the servers have been upgraded to 1.11. Before upgrading Consul Enterprise servers to 1.11, all Consul agents should first
be upgraded to 1.10.6 or higher to ensure forward compatibility and prevent
flapping of catalog registrations.
### Deprecated Agent Config Options
Consul 1.11.0 is compiled with Go 1.17 and now the ordering of

View File

@ -269,6 +269,10 @@
"title": "Connectivity Tasks",
"path": "connect/connectivity-tasks"
},
{
"title": "Distributed Tracing",
"path": "connect/distributed-tracing"
},
{
"title": "Gateways",
"routes": [

20090
website/package-lock.json generated

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 334 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 334 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB