Authorization (RBAC)

- Thomas Jungbauer Thomas Jungbauer ( Lastmod: 2024-05-05 ) - 3 min read

Per default all requests inside a Service Mesh are allowed, which can be a problem security-wise. To solve this, authorization, which verifies if the user is allowed to perform a certain action, is required. Istio’s authorization provides access control on mesh-level, namespace-level and workload-level.

With the resource AuthorizationPolicy granular policies can be defined. These policies are loaded to and verified by the Envoy Proxy which then authorizes a request.

Implicit enablement

To enable authorization the only thing you need is to do is to define the AuthorizationPolicy. If the resource is not defined, then no access control will be used, instead any traffic is allowed. If AuthorizationPolicy is applied to a workload, then by default any traffic is denied unless it is explicitly allowed.

This is applicable to Service Mesh version 1.1+

Preparing Environment

The following steps will configure an example Role Based Access Control (RBAC). It will start from scratch. If you just want to quickly configure the authorization and have anything else in place, you can start form here: Configure Authentication Policy

  1. Create a new project

    oc new-project tutorial
  2. Be sure that a Service Mesh Member Roll exists for this new project

    cat <<'EOF' > memberroll.yaml
    apiVersion: maistra.io/v1
    kind: ServiceMeshMemberRoll
    metadata:
      name: default
    spec:
      members:
        - tutorial
    EOF
    
    oc apply -f memberroll.yaml -n istio-system
  3. Clone and install the example application

    git clone https://github.com/redhat-developer-demos/istio-tutorial/ istio-tutorial
    
    oc apply -f istio-tutorial/customer/kubernetes/Deployment.yml -n tutorial
    oc apply -f istio-tutorial/customer/kubernetes/Service.yml -n tutorial
    oc expose service customer
    oc apply -f istio-tutorial/preference/kubernetes/Deployment.yml -n tutorial
    oc apply -f istio-tutorial/preference/kubernetes/Service.yml -n tutorial
    oc apply -f istio-tutorial/recommendation/kubernetes/Deployment.yml -n tutorial
    oc apply -f istio-tutorial/recommendation/kubernetes/Service.yml -n tutorial

    Wait until all pods are running. There should be 2 containers for all pods:

    oc get pods -w
  4. Create Gateway and VirtualService

    cat <<'EOF' > Gateway_VirtualService.yaml
    apiVersion: networking.istio.io/v1alpha3
    kind: Gateway
    metadata:
      name: customer-gateway
    spec:
      selector:
        istio: ingressgateway # use istio default controller
      servers:
      - port:
          number: 80
          name: http
          protocol: HTTP
        hosts:
        - "*"
    ---
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: customer-gateway
    spec:
      hosts:
      - "*"
      gateways:
      - customer-gateway
      http:
      - match:
        - uri:
            prefix: /customer
        rewrite:
          uri: /
        route:
        - destination:
            host: customer
            port:
              number: 8080
    EOF
    
    oc apply -f Gateway_VirtualService.yaml -n tutorial
  5. Verify if the application is working You can either use the run.sh from previous tutorials, or simply try the following curl

    export GATEWAY_URL=$(oc -n istio-system get route istio-ingressgateway -o jsonpath='{.spec.host}'); echo $GATEWAY_URL
    curl $GATEWAY_URL/customer

    This should return the following line:

    customer => preference => recommendation v1 from 'f11b097f1dd0': 1
  6. Optionally check the connection from inside the customer container

    get pods name and enter it:

    oc get pods
    NAME                                 READY   STATUS    RESTARTS   AGE
    customer-6948b8b959-dhsm9            2/2     Running   0          177m
    preference-v1-7fdb89c86b-dvzs9       2/2     Running   0          177m
    recommendation-v1-69db8d6c48-cjcpn   2/2     Running   0          177m

    Connect into the container pod and try to reach the different microservices

    oc rsh customer-6948b8b959-dhsm9
    
    sh-4.4$ curl customer:8080
    customer => preference => recommendation v1 from 'f11b097f1dd0': 2
    
    sh-4.4$ curl preference:8080
    preference => recommendation v1 from 'f11b097f1dd0': 3
    
    sh-4.4$ curl recommendation:8080
    recommendation v1 from 'f11b097f1dd0': 4

Configure Authentication Policy

  1. Enabling User-End authentication

    cat <<'EOF' > authentication-policy.yaml
    apiVersion: "authentication.istio.io/v1alpha1"
    kind: "Policy"
    metadata:
      name: "customerjwt"
    spec:
      targets:
        - name: customer
        - name: preference
        - name: recommendation
      origins:
        - jwt:
            issuer: "testing@secure.istio.io"
            jwksUri: "https://gist.githubusercontent.com/lordofthejars/7dad589384612d7a6e18398ac0f10065/raw/ea0f8e7b729fb1df25d4dc60bf17dee409aad204/jwks.json"
      principalBinding: USE_ORIGIN
    
    EOF
    
    oc apply -f authentication-policy.yaml -n tutorial
  2. Access should be denied after a few seconds

    curl $GATEWAY_URL/customer
    Origin authentication failed.%
  3. Use token to authenticate

    token=$(curl https://gist.githubusercontent.com/lordofthejars/a02485d70c99eba70980e0a92b2c97ed/raw/f16b938464b01a2e721567217f672f11dc4ef565/token.simple.jwt -s)
    curl -H "Authorization: Bearer $token" $GATEWAY_URL/customer

    This will result in a correct response

    customer => preference => recommendation v1 from 'f11b097f1dd0': 5

Configure Role Based Access Control (RBAC)

  1. Create the resource AuthorizationPolicy

    This is a new resources, supported since Service Mesh 1.1. It will allow GET method when the role equals to "customer"

    cat <<'EOF' > AuthorizationPolicy.yaml
    apiVersion: "security.istio.io/v1beta1"
    kind: "AuthorizationPolicy"
    metadata:
      name: "customer"
    spec:
      rules:
      - to:
        - operation:
            methods: ["GET"]
        when:
        - key: request.auth.claims[role]
          values: ["customer"]
    EOF
    
    oc apply -f AuthorizationPolicy.yaml -n tutorial
  2. Get a token for the role and retry to connect to the service,

    token=$(curl https://gist.githubusercontent.com/lordofthejars/f590c80b8d83ea1244febb2c73954739/raw/21ec0ba0184726444d99018761cf0cd0ece35971/token.role.jwt -s)
    curl -H "Authorization: Bearer $token" $GATEWAY_URL/customer

    This results in:

    customer => preference => recommendation v1 from 'f11b097f1dd0': 8
  3. Let’s verify the setting and change the AuthorizationPolicy. This will break the authorization, since the token provides roles=customer and we set the Policy to "whereistherole"

    cat <<'EOF' > AuthorizationPolicy-Hack.yaml
    apiVersion: "security.istio.io/v1beta1"
    kind: "AuthorizationPolicy"
    metadata:
      name: "customer"
    spec:
      rules:
      - to:
        - operation:
            methods: ["GET"]
        when:
        - key: request.auth.claims[role]
          values: ["whereistherole"]
    EOF
    
    oc replace -f AuthorizationPolicy-Hack.yaml -n tutorial

    If you now try to access the service, with the token, which provides "customer" as role, it will lead to an error:

    token=$(curl https://gist.githubusercontent.com/lordofthejars/f590c80b8d83ea1244febb2c73954739/raw/21ec0ba0184726444d99018761cf0cd0ece35971/token.role.jwt -s)
    curl -H "Authorization: Bearer $token" $GATEWAY_URL/customer
    
    RBAC: access denied