Security - Auth Policy

Return to Workshop

Authorizing and Authenticating Access via Policy

In the previous labs we secured and verified the service-to-service communication. But what about user-to-service communication (aka origin authentication)? The service mesh can help with that too. To do this, we need to bring in an identity provider that will issue JSON Web Tokens (JWTs) to signed in users. JWTs are an open, industry standard (RFC 7519) way of sharing identity. The app-ui service will pass those JWTs along with it’s API requests. This lets the service mesh’s sidecar proxies can verify, get role data, and enforce access.

Let’s walk through a basic example of restricting service access via Authentication and Authorization policies.

Authenticated Users Only

We can lock down the service entirely and only let authenticated users access it.

Apply a new authentication policy and service entry with the following commands:
 sed "s|keycloak-sso-shared.apps.cluster.domain.com|$SSO_SVC|" ./istio-configuration/policy-boards-jwt.yaml | oc apply -f -
 sed "s|keycloak-sso-shared.apps.cluster.domain.com|$SSO_SVC|" ./istio-configuration/serviceentry-keycloak.yaml | oc apply -f -

The policy specifies the requirements for traffic to the boards service to have a JWT with specific properties. It looks like this:

apiVersion: authentication.istio.io/v1alpha1
kind: Policy
metadata:
  name: boards-jwt
spec:
  targets:
  - name: boards
  origins:
  - jwt:
      issuer: "https://keycloak-sso-shared.apps.leonardo.nub3s.io/auth/realms/microservices-demo"
      jwksUri: "https://keycloak-sso-shared.apps.leonardo.nub3s.io/auth/realms/microservices-demo/protocol/openid-connect/certs"
      triggerRules:
      - excludedPaths:
        - exact: /health_check
        - prefix: /status/
  principalBinding: USE_ORIGIN

We mentioned earlier that JWT shares identity info, the JWKS endpoint gives us keys to verify the data of the JWT is from our trusted source.

Don't worry about the service entry for now - we'll explain that in another lab.


Goto your webapp and click the Shared navigation button
Refresh the page a few times and try to add something to the shared board

It will fail with the following error (once it takes effect).



Login as user "demo" with password "demo"
Try to access the page again

You should now see a list of shared items


You might need to refresh the page a few times before it takes effect



Only The Cool Kids

In this scenario we want to further secure access to the shared boards list so only a certain group of users can post to it. And we will do this this purely via the Service Mesh configuration. It’s pretty straightforward to do.

Apply an authorization policy with the following command:
sed "s|microservices-demo|$PROJECT_NAME|" ./istio-configuration/authorization-boards-shared-lockdown.yaml | oc apply -f -

That configuration looks like this:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: boards-shared-lockdown
  namespace: microservices-demo
spec:
  selector:
    matchLabels:
      app: boards
      deploymentconfig: boards
  rules:
  - from:
    - source:
        requestPrincipals: ["*"]
    to:
    - operation:
        methods: ["POST"]
        paths: ["*/shareditems"]
    when:
    - key: request.auth.claims[realm_access_roles]
      values: ["cool-kids"]
  - from:
    - source:
        requestPrincipals: ["*"]
    to:
    - operation:
        methods: ["GET"]
    when:
    - key: request.auth.claims[scope]
      values: ["openid"]

An authorization policy includes a selector and a list of rules. The selector specifies the target that the policy applies to - in this case our boards microservice. While the rules specify who (from) is allowed to do what (to) under which (when) conditions - in this case any source can POST as long as they have the “cool-kids” role listed in their JWT payload.

So, now that we’ve applied it, let’s try to access your boards service when you’re not in the cool kids club.


Goto your webapp and shared page of the website
Try to add something to the shared board

You should be able to see the items, but posting will fail with the following error.



Now login as user "theterminator" with password "illbeback"
Try again to add something to the shared board

Your new item should show in the shared list



Now let's put things back to normal:
oc delete authorizationpolicy/boards-shared-lockdown
oc delete policy/boards-jwt
oc delete serviceentry/keycloak-egress
SSO_SVC=$(oc get route keycloak-alt --template='{{.spec.host}}')
oc set env dc/app-ui FAKE_USER=true SSO_SVC_HOST=$SSO_SVC

How it Works

Our app-ui microservice gets the JWT from the Keycloak SSO whenever a user logs in. If logged in, the JWT is always passed (in the request header) from the app-ui to any services it calls. All our services have Envoy sidecar proxies running and are seeing the traffic, including the JWT in app-ui request headers. So the configuration we applied is used to inform sidecar proxies to follow the policies we set. When we weren’t logged in there was no JWT to pass along so our call requests failed. Only after we were logged in with as a valid user did we pass along a valid JWT. And each user’s JWT was different, so the when conditions only matched for theterminator, allowing him able to POST to the shared board.

If you have the time and want to dig deeper, you should read more about configuring Keycloak and about JWTs.

Check out high-level diagrams of the flows we executed below:


*Fail Case*

*Success Case*

Note: these diagrams have been simplified for discussion purposes

Authorization Policy Summary

If you have used RBAC prior to 1.4 of Istio you might have noticed that it’s a lot easier now. Here’s a blog post outlining the differences: https://istio.io/blog/2019/v1beta1-authorization-policy/


Workshop Details

Domain Red Hat Logo
Workshop
Student ID

Return to Workshop