How make AuthorizationPolicy work?

Hi all,

I’m trying to make AuthorizationPolicy without success.
I have defined the following deployments for hostname and downstream services, where hostname service accesses downstream service via a HTTP call to / at port 80 with service account attached to hostname deployment:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: hostname-serviceaccount
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hostname-deployment-v1
  labels:
    app: hostname
    version: v1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hostname
      version: v1
  template:
    metadata:
      labels:
        app: hostname
        version: v1
    spec:
      serviceAccountName: hostname-serviceaccount
      containers:
      - name: hostname
        image: hostname:0.2
        ports:
        - containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: downstream-deployment-v1
  labels:
    app: downstream
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: downstream
      version: v1
  template:
    metadata:
      labels:
        app: downstream
        version: v1
    spec:
      containers:
      - name: downstream
        image: downstream:0.1
        ports:
        - containerPort: 80

This all works (hostname service obviously can connect to downstream service).
Now when I try to apply the following

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: downstream-authorizationpolicy-default-deny-all
spec:
 selector:
   matchLabels:
     app: downstream
 action: DENY
 rules:
  # This denies all traffic
  - {}
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: downstream-authorizationpolicy-allow-from-hostname
spec:
 selector:
   matchLabels:
     app: downstream
 action: ALLOW
 rules:
  - from:
    - source:
       principals: ["cluster.local/ns/default/sa/hostname-serviceaccount"]
  - to:
    - operation:
       ports: ["80"]
       methods: ["GET"]

It blocks the traffic to downstream service with “RBAC: access denied” for all hosts and services (including traffic from hostname service).

When I try to enable mTLS with:

apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
  name: "default"
  namespace: "istio-system"
spec:
  mtls:
    mode: STRICT

I get “empty reply from server”. When I try to force it to use https (with NodePort exposed to host on port 30000 to hostname:80) I get:

curl -v -k https://localhost:30000
* Rebuilt URL to: https://localhost:30000/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 30000 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Unknown (8):
* TLSv1.3 (IN), TLS handshake, Request CERT (13):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Client hello (1):
* TLSv1.3 (OUT), TLS Unknown, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Certificate (11):
* TLSv1.3 (OUT), TLS Unknown, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: [NONE]
*  start date: Jun 22 10:42:22 2020 GMT
*  expire date: Jun 23 10:42:22 2020 GMT
*  issuer: O=cluster.local
*  SSL certificate verify result: self signed certificate in certificate chain (19), continuing anyway.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* Using Stream ID: 1 (easy handle 0x55dce5cd5580)
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
> GET / HTTP/2
> Host: localhost:30000
> User-Agent: curl/7.58.0
> Accept: */*
>
* TLSv1.3 (IN), TLS Unknown, Unknown (21):
* TLSv1.3 (IN), TLS alert, Server hello (2):
* OpenSSL SSL_read: error:1409445C:SSL routines:ssl3_read_bytes:tlsv13 alert certificate required, errno 0
* Failed receiving HTTP2 data
* Connection #0 to host localhost left intact
curl: (56) OpenSSL SSL_read: error:1409445C:SSL routines:ssl3_read_bytes:tlsv13 alert certificate required, errno 0

EDIT

After some experiments I’ve noticed that now I don’t get the “empty reply from server” when applying the mTLS
PeerAuthentication rule but even with it I still get the RBAC access denied after applying AuthorizationPolicies

EDIT

My understanding is that enabling mTLS with the above PerrAuthentication will “do the trick” and there’s nothing else required.

For reference I have the following defined:

kubectl describe peerauthentications.security.istio.io default
Name:         default
Namespace:    default
Labels:       <none>
Annotations:  API Version:  security.istio.io/v1beta1
Kind:         PeerAuthentication
Metadata:
  Creation Timestamp:  2020-06-22T11:49:39Z
  Generation:          2
  Managed Fields:
    API Version:  security.istio.io/v1beta1
    Fields Type:  FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .:
          f:kubectl.kubernetes.io/last-applied-configuration:
      f:spec:
        .:
        f:mtls:
          .:
          f:mode:
    Manager:         kubectl
    Operation:       Update
    Time:            2020-06-22T11:50:43Z
  Resource Version:  771334
  Self Link:         /apis/security.istio.io/v1beta1/namespaces/default/peerauthentications/default
  UID:               550f3903-5776-4716-97b7-d7560bf40c2b
Spec:
  Mtls:
    Mode:  PERMISSIVE
Events:    <none>

EDIT

One more thing is that when I exec the following in one of hostname’s pods I don’t see the X-Forwarded-Client-Cert header mentioned in https://istio.io/latest/docs/tasks/security/authentication/authn-policy/#auto-mutual-tls

kubectl -it exec hostname-deployment-v1-964588564-j5qzd -c hostname -- curl -v downstream-service
*   Trying 10.107.31.0:80...
* TCP_NODELAY set
* Connected to downstream-service (10.107.31.0) port 80 (#0)
> GET / HTTP/1.1
> Host: downstream-service
> User-Agent: curl/7.67.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< date: Mon, 22 Jun 2020 13:04:50 GMT
< content-length: 132
< content-type: text/plain; charset=utf-8
< x-envoy-upstream-service-time: 3
< server: envoy
<

So first I hope to reproduce the error , I am wondering if you are following the task to do all the steps you mentioned above?

https://istio.io/latest/docs/tasks/security/authentication/authn-policy/?_ga=2.214993822.882299681.1592779213-997904654.1587679186#auto-mutual-tls.

@William_Li I guess so. I’m loosely reading docs and trying to come up with a similar setup (as described in the original post).
Anything particular I should pay attention to from the task?

One thing it would be good to clarify is: in which namespace the PeerAuthentification should reside granted that all the services I have are in default ns? I guess that should be in default ns as well but some docs mentioned istio-system hence my definition as above

Hi @pmalek

am i understanding right you apply both deny and allow Authorization policy? if i.e the case then deny policy have the higher priority then the allow policy.therefore deny policy is evaluated first.
see here for more information https://istio.io/latest/docs/concepts/security/#authorization-policies

And the peerAuthentication you apply here its means that you enable mtls in the mesh.
(for communication in the mesh). if you also enable mtls for particular namespace or workload. see here for more information Istio / Security

May this will help you.

Thanks for your post. So, it seems that most of my problems came from an incorrect yaml syntax.

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: downstream-authorizationpolicy-allow-from-hostname
spec:
 selector:
   matchLabels:
     app: downstream
 action: ALLOW
 rules:
  - from:
    - source:
       principals: ["cluster.local/ns/default/sa/hostname-serviceaccount"]
    to: # <- There should be no dash preceding 'to' 
    - operation:
       ports: ["80"]
       methods: ["GET"]

Also another important bit is (as denoted in the SO answer below):

no need to explicitly create a DENY policy. When you create an ALLOW one, it automatically denies everything else.

The answer here explains it: authorization - How to deny default but allow HTTP and TCP traffic in istio kubernetes cluster? - Stack Overflow