diff --git a/bookinfo-example/README.md b/bookinfo-example/README.md index 0bb45f34..4491ce0d 100644 --- a/bookinfo-example/README.md +++ b/bookinfo-example/README.md @@ -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. @@ -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 @@ -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:///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` - ### - -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:///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:///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 @@ -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: @@ -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). diff --git a/bookinfo-example/authservice/templates/ext-authz.yaml b/bookinfo-example/authservice/templates/ext-authz.yaml index 318660ab..584bf174 100644 --- a/bookinfo-example/authservice/templates/ext-authz.yaml +++ b/bookinfo-example/authservice/templates/ext-authz.yaml @@ -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: @@ -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 @@ -31,4 +32,23 @@ spec: protocol: grpc resolution: STATIC endpoints: - - address: 127.0.0.1 \ No newline at end of file + - 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 }} \ No newline at end of file diff --git a/bookinfo-example/authservice/templates/gateway.yaml b/bookinfo-example/authservice/templates/gateway.yaml index f54a545f..420b574a 100644 --- a/bookinfo-example/authservice/templates/gateway.yaml +++ b/bookinfo-example/authservice/templates/gateway.yaml @@ -1,7 +1,6 @@ # # A simple example of a gateway for the bookinfo app. # - --- apiVersion: networking.istio.io/v1alpha3 kind: Gateway diff --git a/bookinfo-example/authservice/values.yaml b/bookinfo-example/authservice/values.yaml index 0c23aaef..ff109ca2 100644 --- a/bookinfo-example/authservice/values.yaml +++ b/bookinfo-example/authservice/values.yaml @@ -1,6 +1,10 @@ authservice: + image: ghcr.io/istio-ecosystem/authservice/authservice:0.4.1 # TODO(incfly): change to a proper project wide container registry. - image: gcr.io/jianfeih-images-pub/authservice/authservice:0.4.1 + # image: gcr.io/jianfeih-images-pub/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