Skip to content

solsson/istio-access-control

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Authorization example using Keycloak and Istio

First we show an example of plain istio authentication and access control using JWT. After that we try to apply the same to Knative services. To make the example self hosted, but still realistic, we use Keycloak.

  1. Install Istio
  2. Set up a sample pad
  3. Block access for unauthenticated users
  4. Install Keycloak
  5. Set up a Realm and OpenID Connect client
  6. Retrieve access token
  7. Gain access to the test pod using Bearer token
  8. Lock ourselves out again using Istio authorization
  9. Log in as the user that is granted access

A special thanks goes to Keycloak's blog post about Istio.

Preparations

A few things will vary depending on your cluster setup. You might be able to access the istio-ingressgateway over NodePort or an actual public IP/FQDN. If not you can run tests in-cluster, using an alias or function.

# maybe
function istiocurl() {
  kubectl run --restart=Never -t -i --rm --image=solsson/curl istiocurl -- --connect-to :80:istio-ingressgateway.istio-system.svc.cluster.local:80 $@
}
# or maybe
alias istiocurl="curl --connect-to :80:$(minikube ip):31380"

Soon enough you'll get to verify that your alias works.

Install istio

We're using Knative's Istio configuration.

kubectl apply -f https://github.com/knative/serving/releases/download/v0.2.1/istio-crds.yaml
kubectl apply -f https://github.com/knative/serving/releases/download/v0.2.1/istio.yaml

Sample pod

We use the Istio Authentication Policy example, but without the mutual TLS part.

kubectl apply -f ./02-istio-httpbin/
istioctl kube-inject -f ./02-istio-httpbin/httpbin.yaml | kubectl -n foo apply -f -

If Istio injection worked you'll have three containers in the pod. Try kubectl -n foo logs -l app=httpbin -c istio-proxy. Check that the service responds through Istio

$ istiocurl http://x/headers -w '\n'
{
  "headers": {
    ...
    "X-Envoy-Decorator-Operation": "httpbin.foo.svc.cluster.local:8000/*",
    ...

Require authentication

We already exposed httpbin to the public, so let's hurry up with:

kubectl apply -f ./03-authentication

Note in the Policy that we're refering to the Keycloak service that is yet to be created.

Now, once the policy has propagated to you sidecars, access should be denied

$ istiocurl http://x/headers -w '\n'
Origin authentication failed.

Install Keycloak

Any installation is fine, but let's use the helm chart because it can automatically create an admin user:

helm install --namespace keycloak --name demo stable/keycloak \
  --set keycloak.ingress.enabled=true \
  --set keycloak.service.type=NodePort \
  --set keycloak.service.nodePort="30080" \
  --set keycloak.username=admin \
  --set keycloak.password=password

Use kubectl -n keycloak get service demo-keycloak-http to verify existence of the service that the authentication step (above) depends on.

Use appropriate means of accessing the UI in a browser, for example the NodePort enabled by the helm options above (minikube service -n keycloak demo-keycloak-http). The Keycloak UI tends to malfunction over kubectl port-forward.

You should see a login page where the username and password generated above works.

Set up a login

  • Create a realm named demo.
  • Under the Login tab Require SSL select none to allow plain http.
  • Create two users test1 and test2 and use the Credentials tab to set their passwords to test with Temporary set to OFF.
  • Create an OpenID Connect "client" named myapp in your demo realm.
    • Any "Root URL" is fine for this example
  • In the client make sure "Acces Type" is public. We want this demo setup is as insecure as possible 🙂.

Authenticate

Finally there's some excitement! You may test browser login first, but we can do even better and brute force it (assuming $(minikube ip):30080 is your keycloak host):

$ curl -X POST "http://$(minikube ip):30080/auth/realms/demo/protocol/openid-connect/token" \
  -H "Host: demo-keycloak-http.keycloak" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d 'username=test1&password=test&grant_type=password&client_id=myapp' -s \
  | jq -r '.access_token'  
# a long base64 string

Try the same command for user test2, as you'll need to alternate between these logins shortly.

You can inspect and verify tokens using for example jwt.io. It'll need the key: echo "-----BEGIN RSA PUBLIC KEY-----"; curl -s http://$(minikube ip):30080/auth/realms/demo | jq -r '.public_key'; echo "-----END RSA PUBLIC KEY-----";.

Curl using the access token

Tokens expire after a while so you may want these two lines, together with the alias created during preparations.

$ TOKEN=$(<the curl + jq above>)
$ istiocurl http://x/headers -w '\n' -H "Authorization: Bearer $TOKEN"
{ ... }

Now, does authentication only apply when going through Istio's gateway?

kubectl run --restart=Never -t -i --rm --image=gcr.io/cloud-builders/curl testcurl -- http://httpbin.foo:8000/  -w '\n' -H "Authorization: Bearer $TOKEN"

Indeed not.

Require a specific claim

See your decoded token for what you can use as claims. Here we try the user (UU)ID from keycloak. Dig into the Authorization spec for details. And don't forget the RbacConfig or your ServiceRole+binding will have zero effect.

kubectl apply -f ./08-authorization
# And then update the RBAC to allow one of your users in (see decoded token)
kubectl -n foo edit servicerolebinding jwt-binding

At this stage the Debugging Authorization section in Istio docs is a recommended read, in particular how to access logs. For example if you enable debug logging and run kubectl logs as described, but with | grep auth | grep key instead you can see requests to keycloak.

Summary

You should now be blocked when using one user's token and allowed in when using the other.

You can keep editing the Keycloak User (and/or Realm) and the ServiceRoleBinding to test other Properties for authorization.

Clean up

kubectl delete namespace keycloak
kubectl 

About

Explores Knative + Istio + OAuth/JWT/OIDC

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published