Version 1.9

Configuring Anthos Service Mesh user authentication

Anthos Service Mesh user authentication is an integrated solution for browser-based end-user authentication and access control to your deployed workloads. It lets you integrate with existing Identity Providers (IDP) for user authentication and uses Istio APIs and authorization policies for access management. It is a user-friendly alternative to Istio JSON Web Token (JWT) authentication.

A typical use-case is when an organization uses Anthos Service Mesh to host a web application for its workforce to access via a web browser. In addition, the organization needs to use their existing identity provider to manage user identities. Anthos Service Mesh user authentication makes it easy for users to authenticate using a standard web-based OpenID Connect (OIDC) login and consent flow. When the user authenticates, Anthos Service Mesh enforces Istio authorization policies, and on successful authorization, it transmits the identity to workloads in a secure credential format.

How it works

Anthos Service Mesh user authentication introduces a new component, authservice. This component integrates with the Envoy-based ingress as an external authorization service that intercepts all the incoming requests for authentication. authservice implements the client-side of the OIDC protocol and enables user access to applications via a browser, where users complete an interactive authentication and consent flow to establish a short-lived session. authservice implements industry standard protocols to integrate with any identity provider that can act as a OIDC authorization server. When the user is authenticated, the principal information is encapsulated in an RCToken in JWT format, signed by authservice which it forwards to the Istio authorization layer in the ingress. This model provides perimeter access control for traffic into the mesh. If the user is authorized to access a resource, this RCToken is also forwarded to the microservices to obtain principal information and enforce fine-grained access control.

The following diagram shows the location of authservice in the mesh and how it relates to the other parts of the mesh, such as the ingress, workloads, user's browser, and any existing IDP.

end user authentication

Administrators can install authservice as an add-on over an Anthos Service Mesh installation. When installed, authservice reads the OIDC endpoint configuration and other associated settings defined in the UserAuth custom resource. The administrator can use Anthos Service Mesh ExternalAuthorization APIs to configure auth_server as a filter on the ingress.

Install the user authentication service

The following steps explain how to configure the authservice.

Prerequisites

Before you begin, you must have one cluster with Anthos Service Mesh installed according to the instructions in Installing Anthos Service Mesh. In addition, you should have an existing workload for which to enable user authentication or deploy the Online Boutique sample application.

Prepare the OIDC client configuration

Set your OIDC client configuration using the following steps. This guide uses Google as an IDP, but you can use any IDP that supports OIDC authentication.

  1. In the Cloud Console, go to API & Services > Credentials.

    Go to Credentials

  2. Go to Create Credentials, then choose OAuth client ID. If required, set your OAuth consent screen options, then configure the following options:

    • Set Application type to Web application.
    • Set Authorized redirect URI to https://localhost:8443/_gcp_anthos_callback.

    Then, click Save.

  3. In addition, save your client ID and client secret to use later:

    export OIDC_CLIENT_ID='<your-client-id>'
    export OIDC_CLIENT_SECRET='<your-client-secret>'
    export OIDC_ISSUER_URI='https://accounts.google.com'
    

Get the kpt packages

Use the following steps to install the recommended authservice configuration from the public repository. These commands will retrieve the latest authservice container and start it as a Pod in the asm-user-auth namespace. It will also configure the ingress to intercept all requests.

  1. Get the kpt package:

    kpt pkg get https://github.com/GoogleCloudPlatform/asm-user-auth@release-0.1 .
    cd asm-user-auth/
    

Set the redirection URL and secret for ingress gateway

OAuth2 requires a redirection URL hosted on an HTTPS-protected endpoint. These commands are for example purposes and simplify setup by generating a self-signed certificate for the Istio ingress gateway. A production deployment would not use self-signed certificates.

  1. Generate a self-signed certificate:

    openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem \
     -days 365 -nodes -subj '/CN=localhost'
    
  2. Create a secret for the ingress gateway to host HTTPS traffic:

    kubectl create -n istio-system secret tls userauth-tls-cert --key=key.pem \
    --cert=cert.pem
    

Apply the encryption and signing keys

The authservice needs two sets of keys to operate successfully. The first is a symmetric key for encryption and decryption. This key is used for encrypting the session state before setting that as a cookie.

The second set of keys is a public/private key pair. This key is used to sign the authenticated user information in JWT format as an RCToken. The public key from this pair is published at a predefined endpoint that the sidecars can use to validate the JWT.

The user authentication kpt package contains two sample keys for quick setup. However, you can use your preferred key management system to generate the these keys instead.

  1. After you generate your keys, put the key data in the same format:

    cat ./samples/rctoken_signing_key.json
    {
      "keys":[
         {
            "kty":"RSA",
            "kid":"rsa-signing-key",
            "K":"YOUR_KEY", # k contains a Base64 encoded PEM format RSA signing key.
            "useAfter": 1612813735, # unix timestamp
         }
      ]
    }
    
    cat ./samples/cookie_encryption_key.json
    {
      "keys":[
         {
            "kty":"oct",
            "kid":"key-0",
            "K":"YOUR_KEY",
            "useAfter": 1612813735
         }
      ]
    }
    
  2. Create the kubernetes secret, which authservice will mount into its own file system.

    kubectl create namespace asm-user-auth
    kubectl label namespace asm-user-auth  istio-injection=enabled istio.io/rev=default --overwrite
    kubectl create secret generic secret-key  \
        --from-file="session_cookie.key"="./samples/cookie_encryption_key.json" \
        --from-file="rctoken.key"="./samples/rctoken_signing_key.json"  \
        --namespace=asm-user-auth
    

Deploy the user authentication service

The following commands create the user authentication service and deployment in the asm-user-auth namespace.

  1. Set the oauth variables:

    kpt cfg set pkg anthos.servicemesh.user-auth.oidc.clientID ${OIDC_CLIENT_ID}
    kpt cfg set pkg anthos.servicemesh.user-auth.oidc.clientSecret ${OIDC_CLIENT_SECRET}
    kpt cfg set pkg anthos.servicemesh.user-auth.oidc.issuerURI ${OIDC_ISSUER_URI}
    
  2. Apply the kpt package:

    kubectl apply -f ./pkg/asm_user_auth_config_v1alpha1.yaml
    kubectl apply -f ./pkg
    

The authservice consumes the UserAuthConfig CRD to provide end user authentication. UserAuthConfig is configurable in the run time, and you can update it to change the authservice behavior and configure it with endpoints for any OIDC authorization server. It contains these fields:

cat pkg/user_auth_config.yaml
apiVersion: security.anthos.io/v1alpha1
kind: UserAuthConfig
metadata:
  name: auth-config
  namespace: user-auth
spec:
  authentication:
  - oidc:
      clientID: "${OIDC_CLIENT_ID}"
      clientSecret: "${OIDC_CLIENT_SECRET}"
      issuerURI: "${OIDC_ISSUER_URI}"
      scopes: allatclaim,group
      groupsClaim: "groups"
      redirectURIHost: https://localhost:8443
      redirectURIPath: "/_gcp_anthos_callback"
  outputJWTAudience: "test_audience"

See user authentication configuration details for detailed descriptions of the user_auth_config.yaml fields.

Perform post-install tasks

The following tasks are required after you finish the previous installation steps.

Enable user authentication for your applications

This section demonstrates how to enable user authentication, by using the Online Boutique sample application as an example.

Anthos Service Mesh user authentication uses a CUSTOM typed authorization policy to trigger the OIDC flow.

  1. Configure the MeshConfig for the ExternalAuthorization provider:

    kubectl edit configmap istio -n istio-system
    
  2. In the mesh configuration, add the user authentication service as the authorization provider:

    data:
     mesh: |-
       defaultConfig:
         discoveryAddress: istiod.istio-system.svc:15012
       extensionProviders:
       - envoyExtAuthzGrpc:
           port: "10003"
           service: authservice.asm-user-auth.svc.cluster.local
         name: asm-userauth-grpc
    

    The user authentication kpt packages already create an AuthorizationPolicy to reference the external authorization provider specified by pkg/ext-authz.yaml.

    The installation process also creates an Istio gateway to serve HTTPS traffic using the TLS certificate you created in pkg/gateway.yaml.

    apiVersion: networking.istio.io/v1beta1
    kind: Gateway
    metadata:
     name: userauth
     namespace: asm-user-auth
    spec:
     selector:
       istio: ingressgateway
     servers:
     - hosts:
       - '*'
       port:
         name: https
         number: 443
         protocol: HTTPS
       tls:
         mode: SIMPLE
         credentialName: userauth-tls-cert
    ---
    # This ensures the OIDC endpoint has at least some route defined.
    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
     name: userauth-oidc
     namespace: asm-user-auth
    spec:
     gateways:
     - userauth
     hosts:
     - '*'
     http:
     - match:
       - uri:
           prefix: /status
       - uri:
           prefix: /_gcp_anthos_callback
       name: user-auth-route
       route:
       - destination:
           host: authservice
           port:
             number: 10004
    
  3. Update the Online Boutique application to use this gateway to serve HTTPS traffic, and use port forwarding to access the application locally:

    kubectl apply -f./samples/boutique-route.yaml -n demo
    kubectl port-forward service/istio-ingressgateway 8443:443 -n istio-system
    

    The ingress gateway on port 8443 will be forwarded to localhost to make the application accessible locally.

  4. Verify that the Online Boutique sample application is accessible at https://localhost:8443/.

Verify user authentication

The Online Boutique application services now require end user to login via their Google accounts.

  1. Verify that you see the OIDC login page by visiting https://localhost:8443/.

  2. After you login, click Next and verify that it redirects you to the Online Boutique home page.

Configure authorization policies

After you finish the configuration in the previous steps, each user will be redirected through a web-based authentication flow. When the flow completes, the authservice will generate an RCToken in JWT format, which it uses to transmit the authenticated user information.

  1. Add Istio authorization policies at the ingress to ensure that an authorization check occurs for each authenticated user:

    kubectl apply -f ./samples/rctoken-authz.yaml
    
  2. The rctoken-authz.yaml file configures the ingress gateway to validate the RC token issued by authservice, and only authorize when the JWT contains the desired fields, such as audiences and issuers.

    See the following example authorization policy:

    apiVersion: security.istio.io/v1beta1
    kind: RequestAuthentication
    metadata:
     name: require-rc-token
     namespace: istio-system
    spec:
     selector:
       matchLabels:
         istio: ingressgateway
     jwtRules:
     - issuer: "authservice.asm-user-auth.svc.cluster.local"
       audiences:
       - "test_audience"
       jwksUri: "http://authservice.asm-user-auth.svc.cluster.local:10004/_gcp_user_auth/jwks"
       fromHeaders:
       - name: X-ASM-RCTOKEN
       forwardOriginalToken: true
    ---
    apiVersion: security.istio.io/v1beta1
    kind: AuthorizationPolicy
    metadata:
     name: require-rc-token
     namespace: istio-system
    spec:
     selector:
       matchLabels:
         istio: ingressgateway
     action: ALLOW
     rules:
     - when:
       - key: request.auth.claims[iss]
         values:
         - authservice.asm-user-auth.svc.cluster.local
       - key: request.auth.claims[aud]
         values:
         - test_audience
    

Configure environment-specific settings

The previous steps use localhost and a self-signed HTTPS certificate for quick setup. For real production use, use your own domain, such as example.com.

In addition, ensure the tokenEndpoint and authorizationEndpoint configured in the UserAuthConfig CRD has a route configured in VirtualService. The previous installation steps set this in asm-user-auth/userauth-oidc VirtualService.

Manage and rotate keys

There are two sets of keys used by authservice. You can rotate each key independently. However, before you rotate the keys, it is important to understand how the rotation works.

Both keys are in JSON format. The useAfter field specifies the timestamp since when the key will be considered to use. During a key rotation, you should include both old and new keys in the JSON. For example, in the following example, new-key will only be used after timestamp 1712813735.

{
   "keys":[
      {
         "kty":"RSA",
         "kid":"old-key",
         "K":"...", # k contains a Base64 encoded PEM format RSA signing key.
         "useAfter": 1612813735, # unix timestamp
      }
      {
      "kty":"RSA",
         "kid":"new-key",
         "K":"...", # k contains a Base64 encoded PEM format RSA signing key.
         "useAfter": 1712813735, # unix timestamp
      }
   ]
}

Anthos Service Mesh uses the symmetric key for encrypting session data that is stored in browser cookies. To ensure validity of existing sessions, authservice attempts decryption with all keys in the key set. On rotation, the authservice will use the new key for encrypting new sessions, and will continue to attempt decryption with the old keys.

The public/private key pair is used to sign RCToken. The public key is transmitted to the sidecars by istiod for JWT verification. It is crucial for sidecars to receive the new public key before authservice starts using the new private key to sign the RCToken. To that end, authservice starts publishing the public key immediately after the key is added, but waits a significant amount of time before starting to use that to sign RCToken.

User authentication configuration details

The following table describes each field in the CRD:

Field name Description
authentication.oidc This section holds the OIDC endpoint configuration and the parameters used in OIDC flow.
authentication.oidc.certificateAuthorityData This is the SSL certificate of the domain of the OIDC authorization server.
authentication.oidc.clientID The OAuth client ID to use for the OIDC authentication flow.
authentication.oidc.clientSecret The OAuth client secret to use for the OIDC authentication flow.
authentication.oidc.issuerURI The URI to use as the issuer in the output RCToken.
authentication.oidc.redirectURIHost and authentication.oidc.redirectURIPath The endpoint where `authservice` will terminate the OAuth flow. You should register this URI as an authorized redirect URI in the authorization server for the authentication.oidc.clientID.
In addition, this URI should be served from the same service mesh and ingress where `authservice` is enabled.
authentication.oidc.scopes The OAuth scope that should be requested in the authentication request.
authentication.oidc.groupsClaim If the `idtoken` contains a groups claim, use this field to indicate its name. If specified, the service will pass on the data in this claim into the `groups` claim in the output RCToken.
authentication.outputJWTAudience The audience of the RCToken generated by `authservice`. The sidecars can validate the incoming RCToken against this audience value.