How to force an httproute to use TLSOption?

My use case is that we want to have 2 TLSOptions. One enforces client cert verification (MTLS), while the other does not.

We are setting the former as default - i.e. we are checking client certs by default. So in the case we dont want a particular route to verify client certs, we should be able to associate our latter TLSOption with the httproute, which will not check client certs.

I see that, in the case of ingress routes, we can add an annotation to force the route to use a given TLSOption: traefik.ingress.kubernetes.io/router.tls.options: traefik-nomtls@kubernetescrd

Is there any such way to force an httproute to use a particular TLSOption?

1 Like

Hello Folks!

I have the same problem, just I'd also like to use a Middleware in addition to pass the client cert to the same backend service. I'm using traefik helm chart 35.1.0 with app version v3.3.6.

my traefik values.yaml:

providers:
  kubernetesIngress:
    enabled: false
  # Enable the GatewayAPI provider
  kubernetesGateway:
    enabled: true
  kubernetesCRD:
    enabled: true

gateway:
  # -- When providers.kubernetesGateway.enabled, deploy a default gateway
  enabled: false

gatewayClass:
  # -- When providers.kubernetesGateway.enabled and gateway.enabled, deploy a default gatewayClass
  enabled: true
  # -- Set a custom name to GatewayClass
  name: gwc-provided-by-traefik
  # -- Additional gatewayClass labels (e.g. for filtering gateway objects by custom labels)
  labels: {}

ports:
  web:
    ## -- Enable this entrypoint as a default entrypoint. When a service doesn't explicitly set an entrypoint it will only use this entrypoint.
    # asDefault: true
    port: 8000
  websecure:
    ## -- Enable this entrypoint as a default entrypoint. When a service doesn't explicitly set an entrypoint it will only use this entrypoint.
    # asDefault: true
    port: 8443
    # -- One can apply Middlewares on an entrypoint
    # https://doc.traefik.io/traefik/middlewares/overview/
    # https://doc.traefik.io/traefik/routing/entrypoints/#middlewares
    # -- /!\ It introduces here a link between your static configuration and your dynamic configuration /!\
    # It follows the provider naming convention: https://doc.traefik.io/traefik/providers/overview/#provider-namespace
    #   - namespace-name1@kubernetescrd
    #   - namespace-name2@kubernetescrd
    middlewares: [] # have to add mtls-middleware here as well? not helm friendly

My gateway:

# Gateway
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway
  namespace: my-gateway-namespace
spec:
  gatewayClassName: gwc-provided-by-traefik
  listeners:
  - name: http
    port: 8000
    protocol: HTTP
    hostname: {{ printf "*.%s" .Values.domain | quote }}
    allowedRoutes:
      namespaces:
          from: All
  - name: https
    port: 8443
    protocol: HTTPS
    hostname: {{ printf "*.%s" .Values.domain | quote }}
    allowedRoutes:
      namespaces:
          from: All
    tls:
      mode: Terminate
      certificateRefs:
        - kind: Secret
          name: {{ printf "%s-%s" .Values.environment.name .Values.domain | replace "." "-" }}
          group: ""
          namespace: my-gateway-namespace
      ## https://gateway-api.sigs.k8s.io/reference/spec/#gatewaytlsconfig states:
      ## 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...
      ## Still in Proposed status: https://gateway-api.sigs.k8s.io/geps/gep-2907/#1-validate-client-certificate-provided-by-frontend
      # frontendValidation:
      #   caCertificateRefs:
      #     - kind: Secret
      #       name: I dont want to use this though since the "RequireAnyClientCert"
      #       group: ""
      #       namespace: my-gateway-namespace

My HTTPRoute, TLSOption and Middleware:

# HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: my-httproute
  namespace: my-namespace
  # annotations:
    # traefik.ingress.kubernetes.io/router.tls.options: my-namespace-mtls-options@kubernetescrd
    # traefik.ingress.kubernetes.io/router.middlewares: my-namespace-mtls-middleware@kubernetescrd
spec:
  parentRefs:
    - name: my-gateway
      namespace: my-gateway-namespace
  # ...hostnames for this route...
  rules:
    - matches:
      - path:
          type: PathPrefix
          value: /path
      filters:
        - type: URLRewrite
          urlRewrite:
            path:
              type: ReplacePrefixMatch
              replacePrefixMatch: /
        - type: ExtensionRef
          extensionRef:
            group: traefik.io
            kind: Middleware
            name: mtls-middleware
      backendRefs:
        - name: my-backend
          namespace: my-namespace
          port: 80
---
# TLSOption for mTLS
apiVersion: traefik.io/v1alpha1
kind: TLSOption
metadata:
  name: mtls-options
  namespace: my-namespace
spec:
  clientAuth:
    # requires a certificate but does not verify if it is signed by a CA listed in clientAuth.caFiles or in clientAuth.secretNames
    clientAuthType: RequireAnyClientCert
    secretNames:
      # traefik pod logs a warning, but I wouldn't expect it to cause any issues due to the lack of cert verification
      - not-used-does-not-exist
---
# Middleware for mTLS
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: mtls-middleware
  namespace: my-namespace
spec:
  passTLSClientCert:
    pem: true

I've tried several combinations besides the above configs, eg. enabling ingress in the values.yaml, using the commented annotations, etc...
Effect: client cert not required, and in case I force use one with curl, its PEM content not getting forwarded.

If I name the TLSOption to default, it works as expected. (w/ chart v35.2.0)