Using AuthorizationPolicy for access control of legacy clients located outside of Istio

We enabled mTLS in an Istio Cluster with multiple namespaces operated by different teams.

The teams are using AuthorizationPolicy to control which other applications can access resources on their apps by specifying the service account names running those applications. Something like:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: myapp-acl
spec:
  selector:
    matchLabels:
      app: myapp
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/other-team-namespace/sa/other-app-account"]
    to:
    - operation:
        methods: ["GET", "DELETE", "POST"]

Now we have legacy applications not running on Kubernetes that need to communicate with some Istio managed applications.

We setup an Istio Gateway that requires mTLS and are now looking for a way how teams can configure a policy in their namespace so that they can somehow specify SubjectDNs of external client certificates which are allowed to access their apps through the central Istio gateway.

The istio gateway adds a x-forwarded-client-cert request header to incoming requests, so we tried to apply a policy condition on that header:

  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"]
    when:
    - key: request.headers[x-forwarded-client-cert]
      values: ["*;Subject=\"CN=other-app,OU=Services,O=Example\";*"]

This does not seem work. Apparently only request header begins-with (value: ["SOMEVALUE*"]) and request header ends-with (value: ["*SOMEVALUE"]) rules are implemented but not request header contains (value: ["*SOMEVALUE*"]).

  1. Is it possible to configure the Istio Gateway in a way that it puts the Subject CN of the client certificate in a separate request header, e.g. something like x-forwarded-client-cert-cn so we can use an exact match rule on that header in an AuthorizationPolicy ?
  2. Any other ideas how to achieve this kind of access control? We don’t want to directly put the ACL on the Istio Gateway but on the pod level.

Thanks for any thoughts in advance!

We found a possible solution using an envoy filter.

We deploy an envoy filter that adds an x-forwarded-client-cert-subject-dn request header to all incoming requests on our istio gateway.

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: lua-request-filter
  namespace: istio-system
spec:
  workloadSelector:
    labels:
      istio: ingressgateway
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: GATEWAY
        listener:
          filterChain:
            filter:
              name: "envoy.filters.network.http_connection_manager"
              subFilter:
                name: "envoy.filters.http.router"
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.filters.http.lua
          typed_config:
            "@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
            inline_code: |
              function envoy_on_request(request)
                local conn = request:streamInfo():downstreamSslConnection()
                request:headers():replace("x-forwarded-client-cert-subject-dn", conn:subjectPeerCertificate())
              end

Then we can use an Authorization Policy like this to enforce ACLs on cluster internal and external clients:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: backend-acl
spec:
  selector:
    matchLabels:
      stack: backend
  rules:
  # ACL restrict access for a client located inside the cluster:
  - from:
    - source:
        principals: ["cluster.local/ns/other-team-namespace/sa/other-app-account"]
    to:
    - operation:
        methods: ["GET", "DELETE", "POST"]

  # ACL restrict access for a client located outside the cluster:
  - from:
    - source:
        principals: ["cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"]
    to:
    - operation:
        methods: ["GET", "DELETE", "POST"]
    when:
    - key: request.headers[x-forwarded-client-cert-subject-dn]
      values: ["CN=other-app,OU=Services,O=Example"]

@YangminZhu Could u take a look? Thanks.