Skip to content

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 type FrontendTLSValidation 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 within FrontendTLSValidation 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 within FrontendTLSValidation with the following values:
  • Request
  • RequireAny
  • VerifyIfGiven
  • RequireAndVerify
  • Introduce a ObjectReference structure that can be used to specify caCertificateRefs 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

  1. 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
  1. 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
  1. Setting frontendValidation.caCertificateRefs at the Gateway level and frontendValidation.mode at the Listener level so client connections for foo-https would be subject to the RequireAndVerify mode and client connections for bar-https would be subject to the VerifyIfGiven 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
  1. 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 within FrontendTLSValidation 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

References