Skip to content

Commit

Permalink
feat: add requiredClientCertificate on mutual TLS to make it optional
Browse files Browse the repository at this point in the history
Signed-off-by: zufardhiyaulhaq <zufardhiyaulhaq@gmail.com>
  • Loading branch information
zufardhiyaulhaq committed Apr 15, 2024
1 parent 8f2e175 commit 8952af1
Show file tree
Hide file tree
Showing 13 changed files with 171 additions and 1 deletion.
6 changes: 6 additions & 0 deletions api/v1alpha1/tls_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ const (
// to the Gateway.
// By default, no client specific configuration is validated.
type ClientValidationContext struct {
// RequiredClientCertificate set to true means that Envoy will reject connections without a valid client certificate.
//
// +kubebuilder:default=true
// +optional
RequiredClientCertificate bool `json:"requiredClientCertificate,omitempty"`

// CACertificateRefs contains one or more references to
// Kubernetes objects that contain TLS certificates of
// the Certificate Authorities that can be used
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,11 @@ spec:
type: object
maxItems: 8
type: array
requiredClientCertificate:
default: true
description: RequiredClientCertificate set to true means that
Envoy will reject connections without a valid client certificate.
type: boolean
type: object
ecdhCurves:
description: |-
Expand Down
1 change: 1 addition & 0 deletions internal/gatewayapi/clienttrafficpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,7 @@ func (t *Translator) translateListenerTLSParameters(policy *egv1a1.ClientTraffic

if len(irCACert.Certificate) > 0 {
httpIR.TLS.CACertificate = irCACert
httpIR.TLS.RequiredClientCertificate = tlsParams.ClientValidation.RequiredClientCertificate
}
}

Expand Down
2 changes: 2 additions & 0 deletions internal/ir/xds.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ type TLSConfig struct {
Certificates []TLSCertificate `json:"certificates,omitempty" yaml:"certificates,omitempty"`
// CACertificate to verify the client
CACertificate *TLSCACertificate `json:"caCertificate,omitempty" yaml:"caCertificate,omitempty"`
// RequiredClientCertificate to enforce client certificate
RequiredClientCertificate bool `json:"requiredClientCertificate,omitempty" yaml:"requiredClientCertificate,omitempty"`
// MinVersion defines the minimal version of the TLS protocol supported by this listener.
MinVersion *TLSVersion `json:"minVersion,omitempty" yaml:"version,omitempty"`
// MaxVersion defines the maximal version of the TLS protocol supported by this listener.
Expand Down
2 changes: 1 addition & 1 deletion internal/xds/translator/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ func buildXdsDownstreamTLSSocket(tlsConfig *ir.TLSConfig) (*corev3.TransportSock
}

if tlsConfig.CACertificate != nil {
tlsCtx.RequireClientCertificate = &wrappers.BoolValue{Value: true}
tlsCtx.RequireClientCertificate = &wrappers.BoolValue{Value: tlsConfig.RequiredClientCertificate}
tlsCtx.CommonTlsContext.ValidationContextType = &tlsv3.CommonTlsContext_ValidationContextSdsSecretConfig{
ValidationContextSdsSecretConfig: &tlsv3.SdsSecretConfig{
Name: tlsConfig.CACertificate.Name,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
http:
- name: "first-listener"
address: "0.0.0.0"
port: 10080
hostnames:
- "*"
path:
mergeSlashes: true
escapedSlashesAction: UnescapeAndRedirect
tls:
alpnProtocols:
- h2
- http/1.1
certificates:
- name: secret-1
# byte slice representation of "key-data"
serverCertificate: [99, 101, 114, 116, 45, 100, 97, 116, 97]
# byte slice representation of "key-data"
privateKey: [107, 101, 121, 45, 100, 97, 116, 97]
- name: secret-2
serverCertificate: [99, 101, 114, 116, 45, 100, 97, 116, 97]
privateKey: [107, 101, 121, 45, 100, 97, 116, 97]
caCertificate:
name: ca-cert
certificate: [99, 101, 114, 116, 45, 100, 97, 116, 97]
requiredClientCertificate: false
routes:
- name: "first-route"
hostname: "*"
destination:
name: "first-route-dest"
settings:
- endpoints:
- host: "1.2.3.4"
port: 50000
1 change: 1 addition & 0 deletions internal/xds/translator/testdata/in/xds-ir/mutual-tls.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ http:
caCertificate:
name: ca-cert
certificate: [99, 101, 114, 116, 45, 100, 97, 116, 97]
requiredClientCertificate: true
routes:
- name: "first-route"
hostname: "*"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
- circuitBreakers:
thresholds:
- maxRetries: 1024
commonLbConfig:
localityWeightedLbConfig: {}
connectTimeout: 10s
dnsLookupFamily: V4_ONLY
edsClusterConfig:
edsConfig:
ads: {}
resourceApiVersion: V3
serviceName: first-route-dest
lbPolicy: LEAST_REQUEST
name: first-route-dest
outlierDetection: {}
perConnectionBufferLimitBytes: 32768
type: EDS
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
- clusterName: first-route-dest
endpoints:
- lbEndpoints:
- endpoint:
address:
socketAddress:
address: 1.2.3.4
portValue: 50000
loadBalancingWeight: 1
loadBalancingWeight: 1
locality:
region: first-route-dest/backend/0
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
- address:
socketAddress:
address: 0.0.0.0
portValue: 10080
drainType: MODIFY_ONLY
filterChains:
- filters:
- name: envoy.filters.network.http_connection_manager
typedConfig:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
commonHttpProtocolOptions:
headersWithUnderscoresAction: REJECT_REQUEST
http2ProtocolOptions:
initialConnectionWindowSize: 1048576
initialStreamWindowSize: 65536
maxConcurrentStreams: 100
httpFilters:
- name: envoy.filters.http.router
typedConfig:
'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
suppressEnvoyHeaders: true
mergeSlashes: true
normalizePath: true
pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT
rds:
configSource:
ads: {}
resourceApiVersion: V3
routeConfigName: first-listener
serverHeaderTransformation: PASS_THROUGH
statPrefix: https
useRemoteAddress: true
transportSocket:
name: envoy.transport_sockets.tls
typedConfig:
'@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
commonTlsContext:
alpnProtocols:
- h2
- http/1.1
tlsCertificateSdsSecretConfigs:
- name: secret-1
sdsConfig:
ads: {}
resourceApiVersion: V3
- name: secret-2
sdsConfig:
ads: {}
resourceApiVersion: V3
validationContextSdsSecretConfig:
name: ca-cert
sdsConfig:
ads: {}
resourceApiVersion: V3
requireClientCertificate: false
name: first-listener
perConnectionBufferLimitBytes: 32768
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
- ignorePortInHostMatching: true
name: first-listener
virtualHosts:
- domains:
- '*'
name: first-listener/*
routes:
- match:
prefix: /
name: first-route
route:
cluster: first-route-dest
upgradeConfigs:
- upgradeType: websocket
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
- name: secret-1
tlsCertificate:
certificateChain:
inlineBytes: Y2VydC1kYXRh
privateKey:
inlineBytes: a2V5LWRhdGE=
- name: secret-2
tlsCertificate:
certificateChain:
inlineBytes: Y2VydC1kYXRh
privateKey:
inlineBytes: a2V5LWRhdGE=
- name: ca-cert
validationContext:
trustedCa:
inlineBytes: Y2VydC1kYXRh
4 changes: 4 additions & 0 deletions internal/xds/translator/translator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ func TestTranslateXds(t *testing.T) {
name: "mutual-tls",
requireSecrets: true,
},
{
name: "mutual-tls-required-client-certificate-disabled",
requireSecrets: true,
},
{
name: "http3",
requireSecrets: true,
Expand Down

0 comments on commit 8952af1

Please sign in to comment.