Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update values.yaml for different oidc enforcing mode. #152

Merged
merged 2 commits into from
Aug 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 41 additions & 131 deletions bookinfo-example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ create one.
kubectl label namespace default istio-injection=enabled --overwrite
```

### Install and Enable Authservice

1. In our example, we use a self signed certificate at localhost for easy setup.
This is used to terminate HTTPS at the ingress gateway since OIDC requires client callback
URI to be hosted on a protected endpoint.
Expand Down Expand Up @@ -67,6 +69,10 @@ URI to be hosted on a protected endpoint.

At your browser visit the page at https://localhost:8443/productpage.

By default the Helm packages adds the OIDC integration at ingress gateway proxy. You can change
[values.yaml](https://github.com/istio-ecosystem/authservice/blob/2931c4cc05ecc6f0a2efec7a97dfcfbe5305a602/bookinfo-example/authservice/values.yaml#L7)
`authservice.enforcingMode=productpage` to see how to enable this application sidecar.

### Further Protect via RequestAuthentication and Authorization Policy

Istio native RequestAuthentication and Authorization policy can be used configure which end user
Expand All @@ -77,106 +83,44 @@ to only allow authenticated request to access productpage service.
kubectl apply -f ./config/productpage-authn-authz.yaml
```

## Configure OIDC flow at Ingress Gateway

TODO(incfly): write it up with sample config and setup.
### Other Authservice Deployment Mode

You can also deploy authservice as a container in the ingress or application pod. This could help
reducing the latencies for the external authz check request. Instead of sending `Check` request to
a Kubernetes service (`authservice.default.svc.cluster.local`), the request is sent to
`localhost:10003` within the pod. This requires to change the application pod spec.
See `config/bookinfo-with-authservice-template.yaml` for an example.

## How It Works

The browser should redirect to the OIDC provider's login page. Upon login, the authenticated user should
be redirected back and gain access to the `productpage`.

This works because the Authservice is involved in every request to the `productpage` service.
1. On the first request, the Authservice detected that the user is unauthenticated
1. The Authservice redirected the browser to the OIDC Provider's authorization endpoint, which redirected the browser
again to the OIDC Provider's login page
1. After the user logged in, the OIDC provider redirected the browser back to the `productpage` service with an
authorization code as a query parameter
1. The Authservice intercepted this OIDC provider callback redirect and captured the authorization code from
the query parameter
1. The Authservice exchanged the authorization code for tokens by making a call from the Authservice directly to the
OIDC provider (as a "backend-to-backend request", rather than another browser redirect)
1. The Authservice redirected the browser back to the originally requested path of the `productpage` service
1. The Authservice received the request to the `productpage` and injected the OIDC ID token into the `Authentication`
http request header of that request before allowing the request to continue on to the `productpage`
1. Before the request continues to the `productpage`, the Istio authentication policy validated the token
from the `Authentication` request header and, since it was valid, allowed the request to go to the `productpage`
1. The `productpage` renders its UI in the http response and the browser shows the UI

The Authservice sets a session ID cookie on user's browser, so future `productpage` page loads in the browser
will not require authentication until the OIDC tokens expire. To log out and remove the current user's session immediately,
point the browser to `https://<INGRESS_HOST>/authservice_logout` (this path is configurable in the Authservice's
`ConfigMap`).

## :warning: The REST documnetation needs updates.

## Deploy Bookinfo Using the Authservice for Token Acquisition (Sidecar integration)

The goal of these steps is the protect the `productpage` service with OIDC authentication provided by the mesh.

These steps demonstrate how to:

1. Configure the Authservice to provide token acquisition for end-users of the `productpage` service
1. Deploy the Authservice along with the Bookinfo sample app, in the same pod as the `productpage` service
1. Configure Istio authentication for the `productpage` service, using standard Istio features
1. Activate the Authservice by adding it to the data path of the `productpage` service

To keep things simple, we deploy everything into the default namespace and we don't enable authentication for the
other services of the Bookinfo app aside from `productpage`.

1. Prepare your OIDC provider configuration. For our example, we are using Google as IdP.
Follow [instructions](https://developers.google.com/identity/protocols/oauth2/openid-connect) to create one
if needed.

1. Setup a `ConfigMap` for Authservice. Fill in [`config/authservice-configmap-template-for-authn.yaml`](config/authservice-configmap-template-for-authn.yaml)
to include the OIDC provider's configurations. Currently, only the `oidc` filter can be configured in the
`ConfigMap`. See [here](../docs/README.md) for the description of each field. Once the values
have been substituted, apply the `ConfigMap`.

`kubectl apply -f config/authservice-configmap-template-for-authn.yaml`
### <a name="authservice-image"></a>

1. Apply the authservice deployment.

`kubectl apply -f config/bookinfo-with-authservice-template.yaml`

Wait for the new pods to be in `Running` state.

Note that the Authservice will be deployed in the same Pod as `productpage`.

1. Configure the product page to enable authservice via a `CUSTOM` action authorization policy.

```shell
kubectl apply -f ./config/ext-authz-productpage.yaml
```

1. If the `callback` or `logout` paths in [`config/authservice-configmap-template-for-authn.yaml`](config/authservice-configmap-template-for-authn.yaml)
were edited in a previous step, then edit those same paths in [`config/bookinfo-gateway.yaml`](config/bookinfo-gateway.yaml).
Otherwise, no edit is needed. When ready, apply the file to create the ingress gateway and routing rules for Bookinfo:

`kubectl apply -f config/bookinfo-gateway.yaml`

Note that session affinity (via Istio `DestinationRule`) is required when you deploy multiple instances of `productpage`,
which ensures that the requests from the same user-agent reach the same instance of `productpage`.
This is required because Authservice currently only supports in-memory session storage.

1. Next confirm that the Bookinfo app is running.
After determining the [ingress IP and port](https://istio.io/docs/tasks/traffic-management/ingress/ingress-control/#determining-the-ingress-ip-and-ports),
use a browser to navigate to the `productpage` UI, substituting the ingress host: `https://<INGRESS_HOST>/productpage`.

Note that at this point, the Bookinfo sample apps are deployed without any authentication,
and without activating the Authservice, so the `productpage` UI should show in the browser without being
asked to authenticate.

1. We're ready to put the Authservice into the data path for `productpage` by
using an [Istio ExternalAuthorization](https://istio.io/latest/docs/tasks/security/authorization/authz-custom/).

`kubectl apply -f config/productpage-external-authz-envoyfilter-sidecar.yaml`

1. Access the application at the `localhost:8443` via port forwarding, https://localhost:8443/productpage.

```shell
kubectl port-forward service/istio-ingressgateway 8443:443 -n istio-system
```

The browser should redirect to the OIDC provider's login page. Upon login, the authenticated user should
be redirected back and gain access to the `productpage`.

This works because the Authservice is involved in every request to the `productpage` service.
1. On the first request, the Authservice detected that the user is unauthenticated
1. The Authservice redirected the browser to the OIDC Provider's authorization endpoint, which redirected the browser
again to the OIDC Provider's login page
1. After the user logged in, the OIDC provider redirected the browser back to the `productpage` service with an
authorization code as a query parameter
1. The Authservice intercepted this OIDC provider callback redirect and captured the authorization code from
the query parameter
1. The Authservice exchanged the authorization code for tokens by making a call from the Authservice directly to the
OIDC provider (as a "backend-to-backend request", rather than another browser redirect)
1. The Authservice redirected the browser back to the originally requested path of the `productpage` service
1. The Authservice received the request to the `productpage` and injected the OIDC ID token into the `Authentication`
http request header of that request before allowing the request to continue on to the `productpage`
1. Before the request continues to the `productpage`, the Istio authentication policy validated the token
from the `Authentication` request header and, since it was valid, allowed the request to go to the `productpage`
1. The `productpage` renders its UI in the http response and the browser shows the UI

The Authservice sets a session ID cookie on user's browser, so future `productpage` page loads in the browser
will not require authentication until the OIDC tokens expire. To log out and remove the current user's session immediately,
point the browser to `https://<INGRESS_HOST>/authservice_logout` (this path is configurable in the Authservice's
`ConfigMap`).

## Deploy Bookinfo Using the Authservice for Token Acquisition + Authorization (Sidecar integration)

The authentication tokens acquired using the Authservice can also be used for authorization, provided that they contain
Expand Down Expand Up @@ -294,9 +238,6 @@ scopes. This section demonstrates how to leverage the Authservice to relay the a

For a full list of Authservice configuration options, see the [configuration docs](../docs/README.md).

## Istio Ingress-gateway integration

One might prefer to use the Authservice at the gateway level to provide a single login flow for all applications inside an Istio mesh, rather than using it at the sidecar level.

### Additional Pre-requisites:

Expand All @@ -319,39 +260,8 @@ containers:
...
```

### Notes:
The steps of using Authservice at the Ingress-gateway are roughly the same as the Sidecar integration steps detailed above except for these major differences:
1. The Istio Authentication Policy will have to target the Ingress-gateway, which will result in a JWT AuthN filter being added to the gateway.
1. The `ConfigMap` should be created in the `istio-system` namespace to make it accessible to the authservice container in the `istio-ingressgateway` pod.
1. The `ext_authz` envoy filter will have to be inserted into the gateway's filter chain. E.g.:
```
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: ingress-token-service-filter
namespace: istio-system # note: the namespace has changed
spec:
workloadSelector:
labels:
istio: ingressgateway # note: target gateway pod's label
configPatches:
- applyTo: HTTP_FILTER
match:
context: GATEWAY
# ... the rest is the same as before
```
1. The Authservice will no longer be required to be deployed at the Sidecar level alongside the application.
1. The path part of the configured `callback_uri`, and if configured, the `logout.path`, must be paths that are routable to the app by the ingress gateway's `VirtualService`, or else the Authservice at the gateway will not receieve those requests and will not be able to process them. This is a perhaps counter-intuitive since the Authservice container is no longer running in the app's pod, so it may not feel like this is needed, but it is required.

Better user experience and more sample configs will be added in the future.

## FAQ

Where I can find the authservice images?

1. The Github Package Registry does not work seamlessly with k8s until [issue #870](https://github.com/kubernetes-sigs/kind/issues/870)
is fixed and released. As a workaround, manually `docker pull` the latest authservice image from
[https://github.com/istio-ecosystem/authservice/packages](https://github.com/istio-ecosystem/authservice/packages)
and push it to an accessible image registry (e.g. Docker Hub).
See the ["Using the authservice docker image" section in the README.md](https://github.com/istio-ecosystem/authservice/blob/master/README.md#using-the-authservice-docker-image)
for more information.
We use Github packages to host [authservice images](https://github.com/istio-ecosystem/authservice/pkgs/container/authservice%2Fauthservice).
24 changes: 22 additions & 2 deletions bookinfo-example/authservice/templates/ext-authz.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{{ if eq .Values.authservice.enforcingMode "productpage" }}
# Configuration for OIDC termination at application mode.
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
Expand All @@ -15,7 +17,6 @@ spec:
- operation:
notPaths: ["/public"] # enable all except /public paths.
---
# TODO(incfly): enable if else check for including this only for sidecar mode.
# Istio requires the external authz provider to be available in the service registry.
# See https://github.com/istio/istio/issues/34622.
apiVersion: networking.istio.io/v1beta1
Expand All @@ -31,4 +32,23 @@ spec:
protocol: grpc
resolution: STATIC
endpoints:
- address: 127.0.0.1
- address: 127.0.0.1
{{ else }}
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: ext-authz
namespace: istio-system
spec:
selector:
matchLabels:
app: istio-ingressgateway
action: CUSTOM
provider:
# The provider name must match the extension provider defined in the mesh config.
name: authservice-grpc
rules:
- to:
- operation:
notPaths: ["/public"] # enable all except /public paths.
{{ end }}
1 change: 0 additions & 1 deletion bookinfo-example/authservice/templates/gateway.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#
# A simple example of a gateway for the bookinfo app.
#

---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
Expand Down
6 changes: 4 additions & 2 deletions bookinfo-example/authservice/values.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
authservice:
# TODO(incfly): change to a proper project wide container registry.
image: gcr.io/jianfeih-images-pub/authservice/authservice:0.4.1
image: ghcr.io/istio-ecosystem/authservice/authservice:0.4.1
# How the authservice will be enabled and enforced.
# This can be at ingress (by default) or at application sidecar.
enforcingMode: ingress

oidc:
idpURL: https://account.google.com
Expand Down