kuadrant-operator icon indicating copy to clipboard operation
kuadrant-operator copied to clipboard

Support direct TLS/mTLS from Gateway to data plane components without mesh/sidecars

Open KevFan opened this issue 6 months ago • 3 comments

Description: Currently, Kuadrant assumes mTLS between the gateway and data plane components (like Authorino) is handled via sidecars in a service mesh. There is no officially documented or supported way to enable direct TLS from the gateway to these components when a mesh is not present. Attempts to configure this manually fail because Kuadrant-managed EnvoyFilters conflict with custom TLS setups.

Problem:

  • Users cannot directly enable TLS/mTLS from Gateway API pods to Authorino or other data plane components without relying on sidecars.
  • The current setup requires deleting or patching Kuadrant-managed EnvoyFilters and manually mounting certificates, which is unsupported and error-prone.

Proposed Feature / Enhancement:

  • Provide a supported mechanism for enabling direct TLS/mTLS from the gateway to data plane components without requiring a full mesh.

  • Kuadrant should:

    • Automatically adjust EnvoyFilter configuration when a user applies TLS/mTLS settings to Authorino.
    • Avoid conflicts with default Kuadrant-managed EnvoyFilters.
    • Optionally, allow mounting custom CA certificates for non-mesh deployments in a supported way.

Expected Outcome:

  • Gateway pods can securely communicate with Authorino or other data plane components via TLS/mTLS without sidecars.
  • Users do not need to manually patch EnvoyFilters or deployments to achieve this.

Current Workaround / Guide

While direct TLS is not officially supported yet, the following steps allow it to work:

  1. Enable TLS in Authorino
apiVersion: operator.authorino.kuadrant.io/v1beta1
kind: Authorino
metadata:
  name: authorino
  namespace: my-gateways
spec:
  listener:
    tls:
      enabled: true
      certSecretRef:
        name: toystore-local-tls
  1. Create a custom EnvoyFilter to trust Authorino TLS
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: authorino-tls-custom
  namespace: my-gateways
spec:
  configPatches:
    - applyTo: CLUSTER
      match:
        cluster:
          service: authorino-authorino-authorization.my-gateways.svc.cluster.local
      patch:
        operation: ADD
        value:
          name: kuadrant-auth-service
          type: STRICT_DNS
          connect_timeout: 1s
          lb_policy: ROUND_ROBIN
          http2_protocol_options: {}
          load_assignment:
            cluster_name: kuadrant-auth-service
            endpoints:
              - lb_endpoints:
                  - endpoint:
                      address:
                        socket_address:
                          address: authorino-authorino-authorization.my-gateways.svc.cluster.local
                          port_value: 50051
          transport_socket:
            name: envoy.transport_sockets.tls
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
              common_tls_context:
                validation_context:
                  trusted_ca:
                    filename: /etc/ssl/certs/tls.crt
  targetRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: prod-web
  1. Patch Gateway/Envoy pod to mount the Authorino CA
kubectl patch deployment prod-web-istio -n my-gateways \
  --type='json' \
  -p='[
    {             
      "op": "add",   
      "path": "/spec/template/spec/volumes/-",
      "value": {
        "name": "authorino-ca",
        "secret": { 
          "secretName": "toystore-local-tls"
        }     
      }                                                                         
    },    
    {                 
      "op": "add",
      "path": "/spec/template/spec/containers/0/volumeMounts/-",
      "value": {                           
        "mountPath": "/etc/ssl/certs/tls.crt",
        "name": "authorino-ca",                                                                      
        "subPath": "tls.crt",  
        "readOnly": true         
      }                    
    }                                             
  ]'
  1. Delete the Kuadrant-managed EnvoyFilter
kubectl delete envoyfilter kuadrant-auth-prod-web -n my-gateways
  • This ensures the custom EnvoyFilter with TLS configuration takes precedence.

After these steps, Gateway pods can communicate securely with Authorino over TLS without relying on a mesh. Requests return 401/403 according to AuthPolicy and do not require manual sidecar manipulation.

KevFan avatar Sep 01 '25 08:09 KevFan

If you are using OpenShift, you can use its serving certificate functionality instead of generating your own. This approach also removes the need to mount the CA certificate to the gateway pod because OpenShift's internal CAs are trusted by default.


## 1. Annotate the Authorino Service

Annotate the Authorino service to request a certificate from OpenShift's service CA operator.

oc annotate svc/authorino-authorino-authorization service.beta.openshift.io/serving-cert-secret-name=authorino-server-cert -n kuadrant-system

## 2. Patch Authorino to Use the New Certificate

Update the Authorino custom resource to use the secret created by the annotation.

kubectl apply -f - <<EOF
apiVersion: operator.authorino.kuadrant.io/v1beta1
kind: Authorino
metadata:
  name: authorino
  namespace: kuadrant-system
spec:
  replicas: 1
  clusterWide: true
  listener:
    tls:
      enabled: true
      certSecretRef:
        name: authorino-server-cert
  oidcServer:
    tls:
      enabled: false
EOF

## 3. Apply a Custom EnvoyFilter

Create an EnvoyFilter that configures the gateway to trust the default, auto-mounted OpenShift service CA bundle when connecting to Authorino.

kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: authorino-tls
  namespace: api-gateway
spec:
  configPatches:
    - applyTo: CLUSTER
      match:
        cluster:
          service: authorino-authorino-authorization.api-gateway.svc.cluster.local
      patch:
        operation: ADD
        value:
          name: kuadrant-auth-service
          type: STRICT_DNS
          connect_timeout: 1s
          lb_policy: ROUND_ROBIN
          http2_protocol_options: {}
          load_assignment:
            cluster_name: kuadrant-auth-service
            endpoints:
              - lb_endpoints:
                  - endpoint:
                      address:
                        socket_address:
                          address: authorino-authorino-authorization.api-gateway.svc.cluster.local
                          port_value: 50051
          transport_socket:
            name: envoy.transport_sockets.tls
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
              common_tls_context:
                validation_context:
                  trusted_ca:
                    # Point to the default, auto-mounted CA bundle
                    filename: /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt
  targetRefs:
  - group: gateway.networking.k8s.io
    kind: Gateway
    name: prod-web
EOF

## 4. Ensure Custom Filter Takes Precedence

Delete the default Kuadrant-managed EnvoyFilter so that your custom filter is used instead.

kubectl delete envoyfilter kuadrant-auth-openshift-ai-inference -n openshift-ingress

KevFan avatar Sep 01 '25 08:09 KevFan

\cc @maleck13 @alexsnaps @Jooho

KevFan avatar Sep 01 '25 08:09 KevFan

@KevFan with the priority field mentioned yesterday, I think it is no longer need to remove the old EnvoyFilter also can inline the CA cert to avoid the mounting step

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: authorino-cluster-tls
  namespace: ${GATEWAY_NAMESPACE}
spec:
  priority: 1
  workloadSelector:
    labels:
      app: [PLACEHOLDER]
  configPatches:
  - applyTo: CLUSTER
    match:
      context: ${CONTEXT_NAME}
      cluster:
        name: ${CLUSTER_NAME}
    patch:
      operation: MERGE
      value:
        transport_socket:
          name: envoy.transport_sockets.tls
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
            common_tls_context:
              validation_context:
                trusted_ca:
                  inline_string: "${CA_CERT}"
            sni: ${SNI}

maleck13 avatar Sep 02 '25 06:09 maleck13