GEP-91: Client Certificate Validation for TLS terminating at the Gateway¶
- Issue: #91
- Status: Implementable
(See definitions in GEP States.)
TLDR¶
This GEP proposes a way to validate the TLS certificate presented by the frontend client to the server (Gateway in this case) during a TLS Handshake Protocol.
Goals¶
- Define an API field to specify the CA Certificate within the Gateway configuration that can be used as a trust anchor to validate the certificates presented by the client. This use case has been highlighted in the TLS Configuration GEP under segment 1 and in the Gateway API TLS Use Cases document under point 7.
- Introduce explicit client certificate validation modes that reflect common TLS behaviors (e.g., optional vs. required client certs)
- Ensure the configuration mitigates the authentication bypass risks associated with HTTP/2 connection coalesing as described in GEP-3567.
Non-Goals¶
- Define other fields that can be used to verify the client certificate such as the Certificate Hash.
API¶
- Introduce a
FrontendValidation
field of typeFrontendTLSValidation
within GatewayTLSConfig that can be used to validate the peer (frontend) with which the TLS connection is being made. - This new field is separate from the existing BackendTLSPolicy configuration. BackendTLSPolicy controls TLS certificate validation for connections from the Gateway to the backend service.
This proposal adds the ability to validate the TLS certificate presented by the client connecting to the Gateway (the frontend). These two validation mechanisms operate independently and can be used simultaneously. - Introduce a
caCertificateRefs
field withinFrontendTLSValidation
that can be used to specify a list of CA Certificates that can be used as a trust anchor to validate the certificates presented by the client. - Add a new
FrontendValidationModeType
enum withinFrontendTLSValidation
with the following values: Request
RequireAny
VerifyIfGiven
RequireAndVerify
- Introduce a
ObjectReference
structure that can be used to specifycaCertificateRefs
references. - Introduce a
tls
field within the Gateway Spec to allow for a common TLS configuration to apply across all listeners.
GO¶
// ObjectReference identifies an API object including its namespace.
//
// The API object must be valid in the cluster; the Group and Kind must
// be registered in the cluster for this reference to be valid.
//
// References to objects with invalid Group and Kind are not valid, and must
// be rejected by the implementation, with appropriate Conditions set
// on the containing object.
type ObjectReference struct {
// Group is the group of the referent. For example, "gateway.networking.k8s.io".
// When unspecified or empty string, core API group is inferred.
Group Group `json:"group"`
// Kind is kind of the referent. For example "ConfigMap" or "Service".
Kind Kind `json:"kind"`
// Name is the name of the referent.
Name ObjectName `json:"name"`
// Namespace is the namespace of the referenced object. When unspecified, the local
// namespace is inferred.
//
// Note that when a namespace different than the local namespace is specified,
// a ReferenceGrant object is required in the referent namespace to allow that
// namespace's owner to accept the reference. See the ReferenceGrant
// documentation for details.
//
// Support: Core
//
// +optional
Namespace *Namespace `json:"namespace,omitempty"`
}
// GatewayTLSConfig describes a TLS configuration that can be applied to a Gateway.
type GatewayTLSConfig struct {
// FrontendValidation holds configuration information for validating the frontend (client).
// Setting this field will require clients to send a client certificate
// required for validation during the TLS handshake. In browsers this may result in a dialog appearing
// that requests a user to specify the client certificate.
// The maximum depth of a certificate chain accepted in verification is Implementation specific.
//
// Each field may be overidden by an equivalent setting applied at the Listener level.
//
// Support: Extended
//
// +optional
// <gateway:experimental>
FrontendValidation *FrontendTLSValidation `json:"frontendValidation,omitempty"`
}
// FrontendTLSValidation holds configuration information that can be used to validate
// the frontend initiating the TLS connection
type FrontendTLSValidation struct {
// CACertificateRefs contains one or more references to
// Kubernetes objects that contain TLS certificates of
// the Certificate Authorities that can be used
// as a trust anchor to validate the certificates presented by the client.
//
// A single CA certificate reference to a Kubernetes ConfigMap
// has "Core" support.
// Implementations MAY choose to support attaching multiple CA certificates to
// a Listener, but this behavior is implementation-specific.
//
// Support: Core - A single reference to a Kubernetes ConfigMap
// with the CA certificate in a key named `ca.crt`.
//
// Support: Implementation-specific (More than one reference, or other kinds
// of resources).
//
// References to a resource in a different namespace are invalid UNLESS there
// is a ReferenceGrant in the target namespace that allows the certificate
// to be attached. If a ReferenceGrant does not allow this reference, the
// "ResolvedRefs" condition MUST be set to False for this listener with the
// "RefNotPermitted" reason.
//
// +kubebuilder:validation:MaxItems=8
// +kubebuilder:validation:MinItems=0
CACertificateRefs []ObjectReference `json:"caCertificateRefs,omitempty"`
// FrontendValidationMode defines the mode for validating the client certificate.
// There are four possible modes:
//
// - Request: In this mode, a client certificate is requested
// during the TLS handshake but does not require one.
// - RequireAny: In this mode, a client certificate is required during
// the handshake, but the connection is permitted even when the
// client certificate verification fails.
// - VerifyIfGiven: In this mode, a client certificate is requested
// but not required. If presented, the certificate must be valid.
// - RequireAndVerify: In this mode, a valid client certificate must be
// presented during the handshake and validated
// using CA certificates defined in CACertificateRefs.
//
// Defaults to RequireAndVerify.
//
// Support: Core
//
// +optional
// +kubebuilder:default=RequireAndVerify
Mode *FrontendValidationModeType `json:"mode,omitempty"`
}
// FrontendValidationModeType type defines how a Gateway or Listener validates client certificates.
//
// +kubebuilder:validation:Enum=Request;RequireAny;VerifyIfGiven;RequireAndVerify
type FrontendValidationModeType string
const (
// Request indicates that a client certificate is requested
// during the TLS handshake but does not require one.
Request FrontendValidationModeType = "Request"
// RequireAny indicates that a client certificate is required during
// the handshake, but the connection is permitted even when the
// client certificate verification fails.
RequireAny FrontendValidationModeType = "RequireAny"
// VerifyIfGiven indicates that a client certificate is requested
// but not required. If presented, the certificate must be valid.
VerifyIfGiven FrontendValidationModeType = "VerifyIfGiven"
// RequireAndVerify indicates that a valid client certificate must be
// presented during the handshake and validated
// using CA certificates defined in CACertificateRefs.
RequireAndVerify FrontendValidationModeType = "RequireAndVerify"
)
YAML¶
- Setting
frontendValidation
at the Gateway level
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
name: client-validation-basic
spec:
gatewayClassName: acme-lb
tls:
frontendValidation:
caCertificateRefs:
- kind: ConfigMap
group: ""
name: foo-example-com-ca-cert
listeners:
- name: foo-https
protocol: HTTPS
port: 443
hostname: foo.example.com
tls:
certificateRefs:
- kind: Secret
group: ""
name: foo-example-com-cert
- Setting
frontendValidation
at the Listener level
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
name: client-validation-basic
spec:
gatewayClassName: acme-lb
listeners:
- name: foo-https
protocol: HTTPS
port: 443
hostname: foo.example.com
tls:
certificateRefs:
- kind: Secret
group: ""
name: foo-example-com-cert
frontendValidation:
mode: VerifyIfGiven
caCertificateRefs:
- kind: ConfigMap
group: ""
name: foo-example-com-ca-cert
- Setting
frontendValidation.caCertificateRefs
at the Gateway level andfrontendValidation.mode
at the Listener level so client connections forfoo-https
would be subject to theRequireAndVerify
mode and client connections forbar-https
would be subject to theVerifyIfGiven
mode.
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
name: client-validation-basic
spec:
gatewayClassName: acme-lb
tls:
frontendValidation:
caCertificateRefs:
- kind: ConfigMap
group: ""
name: example-com-ca-cert
listeners:
- name: foo-https
protocol: HTTPS
port: 443
hostname: foo.example.com
tls:
certificateRefs:
- kind: Secret
group: ""
name: foo-example-com-cert
- name: bar-https
protocol: HTTPS
port: 443
hostname: bar.example.com
tls:
certificateRefs:
- kind: Secret
group: ""
name: bar-example-com-cert
frontendValidation:
mode: VerifyIfGiven
- Setting
frontendValidation.caCertificateRefs
at the listener level when connection coalescing is detected between two listeners should reject the overlapping listeners.
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
name: client-validation-basic
spec:
gatewayClassName: acme-lb
listeners:
- name: acme-https
protocol: HTTPS
port: 443
hostname: acme.com
tls:
certificateRefs:
- kind: Secret
group: ""
name: acme-com-cert
- name: foo-https
protocol: HTTPS
port: 443
hostname: foo.example.com
tls:
certificateRefs:
- kind: Secret
group: ""
name: foo-example-com-cert
- name: example-https
protocol: HTTPS
port: 443
hostname: *.example.com
tls:
certificateRefs:
- kind: Secret
group: ""
name: example-com-cert
frontendValidation:
caCertificateRefs:
- kind: ConfigMap
group: ""
name: example-com-ca-cert
status:
listeners:
- attachedRoutes: 0
conditions:
- lastTransitionTime: null
message: Sending translated listener configuration to the data plane
reason: Programmed
status: "True"
type: Programmed
- lastTransitionTime: null
message: Listener has been successfully translated
reason: Accepted
status: "True"
type: Accepted
- lastTransitionTime: null
message: Listener references have been resolved
reason: ResolvedRefs
status: "True"
type: ResolvedRefs
name: acme-https
supportedKinds:
- group: gateway.networking.k8s.io
kind: HTTPRoute
- group: gateway.networking.k8s.io
kind: GRPCRoute
- attachedRoutes: 0
conditions:
- lastTransitionTime: null
message: Frontend TLS Validation has been bypassed due to the detection of connection coalescing.
reason: FrontendTLSValidationBypassed
status: "False"
type: Accepted
- lastTransitionTime: null
message: Listener references have been resolved
reason: ResolvedRefs
status: "True"
type: ResolvedRefs
- lastTransitionTime: null
message: The certificate SAN *.example.com overlaps with the certificate SAN
foo.example.com in listener example-https.
reason: OverlappingCertificates
status: "True"
type: OverlappingTLSConfig
name: foo-https
supportedKinds:
- group: gateway.networking.k8s.io
kind: HTTPRoute
- group: gateway.networking.k8s.io
kind: GRPCRoute
- attachedRoutes: 0
conditions:
message: Frontend TLS Validation has been bypassed due to the detection of connection coalescing.
reason: FrontendTLSValidationBypassed
status: "False"
type: Accepted
- lastTransitionTime: null
message: Listener references have been resolved
reason: ResolvedRefs
status: "True"
type: ResolvedRefs
- lastTransitionTime: null
message: The certificate SAN foo.example.com overlaps with the certificate
SAN *.example.com in listener foo-https.
reason: OverlappingCertificates
status: "True"
type: OverlappingTLSConfig
name: example-https
Deferred¶
This section highlights use cases that may be covered in a future iteration of this GEP
- Using system CA certificates as the trust anchor to validate the certificates presented by the frontend client.
- Supporting an optional
subjectAltNames
field withinFrontendTLSValidation
that can be used to specify one or more alternate names to verify the subject identity in the certificate presented by the client. This field falls under Authorization, the initial focus here is on Client Authentication and will be revisited when Authorization is tackled as a whole in the project. - Specifying the verification depth in the client certificate chain. This is being deferred because the default verification depth differs across implementations.
Existing support in Implementations¶
This feature is already widely supported by implementations that conform to the Gateway API. The table below summarizes current support. Please feel free to add any implementations that are missing. This GEP aims to standardize this behavior as an official part of the upstream specification.
Implementation | Support | Granularity | Inline vs Policy |
---|---|---|---|
Acnodal EPIC | |||
Airlock Microgateway | SidecarGateway.spec.applications[].downstream.tls.clientCertificate | Per Listener | Inline |
Amazon Elastic Kubernetes Service | |||
Apache APISIX | ApisixTls.Client.CASecret | Per SNI | |
Avi Kubernetes Operator | |||
Azure Application Gateway for Containers | FrontendTLSPolicy | Per Gateway & Per Listener | Policy |
Cilium | |||
Contour | HTTPProxy.Spec.VirtualHost.Tls.ClientValidation.CASecret | Per SNI | Inline |
Easegress | |||
Emissary Ingress | TlSContext.Spec.CASecret | Per SNI | Policy |
Envoy Gateway | ClientTrafficPolicy.Spec.TLS.ClientValidation | Per Gateway & Per Listener | Policy |
Flomesh Service Mesh | |||
Gloo Gateway | VirtualService.Spec.SSLConfig.SecretRef | Per SNI | Inline |
Google Cloud Service Mesh | |||
Google Kubernetes Engine | |||
HAProxy Ingress | |||
HAProxy Kubernetes Ingress Controller | ca-file | Per SNI | Inline |
HashiCorp Consul | file-system-certificate | Per Listener | Policy |
Istio | Gateway.Spec.Servers.TLS.Mode | Per Server | Inline |
kgateway | |||
Kong Kubernetes Ingress Controller | mTLS Plugin | Per HTTP Proxy (Host/Port) | Policy |
Kong Gateway Operator | mTLS Plugin | Per HTTP Proxy (Host/Port) | Policy |
Kuma | |||
Linkerd | |||
LiteSpeed Ingress Controller | |||
LoxiLB | |||
NGINX Gateway Fabric | ingressMTLS | Per Listener | Policy |
ngrok Kubernetes Operator | TrafficPolicy.Terminate-TLS.Config.MutualTLSCertificateAuthorities | Per Endpoint (Host:Port) | Policy |
STUNner | |||
Traefik Proxy | TLSOption.Spec.ClientAuth | Per EntryPoint | Inline |
Tyk | Enable Client Certificate | Per Gateway | Policy |
WSO2 APK | Authentication.Spec.Default.AuthTypes.MTLS | Per API | Policy |
Ingress-NGINX | nginx.ingress.kubernetes.io/auth-tls-verify-client | Per Ingress | Inline |