Integrate a gRPC custom authorization service

Updated at:

To enforce fine-grained access control for services communicating via the gRPC protocol, use a custom authorization service. This lets you build a custom authorization mechanism based on your business needs and adds an authorization process to service-to-service communication. This ensures that only authenticated and authorized requests can access service resources, enhancing the security of communication between services.

Prerequisites

The cluster is added to the ASM instance..

Step 1: Deploy the custom authorization service

Deploy a custom authorization service in your cluster. This service must implement Istio's external authorization API, which supports both the HTTP and gRPC protocols, to handle custom authorization logic. The sample service used in this topic requires that requests include thex-ext-authz: allow request header to pass authorization.

Note

This topic provides a sample custom authorization service. You can also create your own custom authorization service by using the code from this sample application as a reference. For more information, see Custom authorization.

  1. Create an ext-authz.yaml file with the following content.

    ext-authz.yaml

    # Copyright Istio Authors
    #
    #   Licensed under the Apache License, Version 2.0 (the "License");
    #   you may not use this file except in compliance with the License.
    #   You may obtain a copy of the License at
    #
    #       http://www.apache.org/licenses/LICENSE-2.0
    #
    #   Unless required by applicable law or agreed to in writing, software
    #   distributed under the License is distributed on an "AS IS" BASIS,
    #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    #   See the License for the specific language governing permissions and
    #   limitations under the License.
    
    # Example configurations for deploying ext-authz server separately in the mesh.
    
    apiVersion: v1
    kind: Service
    metadata:
      name: ext-authz
      labels:
        app: ext-authz
    spec:
      ports:
      - name: http
        port: 8000
        targetPort: 8000
      - name: grpc
        port: 9000
        targetPort: 9000
      selector:
        app: ext-authz
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: ext-authz
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: ext-authz
      template:
        metadata:
          labels:
            app: ext-authz
        spec:
          containers:
          - image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/asm-ext-authz-example:0.6
            imagePullPolicy: IfNotPresent
            name: ext-authz
            ports:
            - containerPort: 8000
            - containerPort: 9000
    ---
  2. Connect to the cluster using kubectl and run the following command to deploy the custom authorization service.

    To learn how to connect to the cluster using kubectl, see Obtain the kubeconfig file of a cluster and use kubectl to connect to the cluster.

    kubectl apply -f ext-authz.yaml

    Expected output:

    service/ext-authz created
    deployment.apps/ext-authz created
  3. Run the following command to verify that the application is running correctly.

    kubectl logs "$(kubectl get pod -l app=ext-authz -n default -o jsonpath={.items..metadata.name})" -n default -c ext-authz

    Expected output:

    2023/12/20 08:15:39 Starting gRPC server at [::]:9000
    2023/12/20 08:15:39 Starting HTTP server at [::]:8000

    The output confirms that the custom authorization service is deployed successfully.

  4. Obtain the gRPC port of the ext-authz application.

    1. Log on to the ACK console. In the left navigation pane, click Clusters.

    2. On the Clusters page, click the name of your cluster. In the left navigation pane, click Network > Services.

    3. On the Services page, click ext-authz.

      In the Endpoint section, the gRPC port is 9000.

Step 2: Deploy the sample applications

  1. Create an httpbin.yaml file with the following content.

    httpbin.yaml

    # Copyright Istio Authors
    #
    #   Licensed under the Apache License, Version 2.0 (the "License");
    #   you may not use this file except in compliance with the License.
    #   You may obtain a copy of the License at
    #
    #       http://www.apache.org/licenses/LICENSE-2.0
    #
    #   Unless required by applicable law or agreed to in writing, software
    #   distributed under the License is distributed on an "AS IS" BASIS,
    #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    #   See the License for the specific language governing permissions and
    #   limitations under the License.
    
    ##################################################################################################
    # httpbin service
    ##################################################################################################
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: httpbin
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: httpbin
      labels:
        app: httpbin
        service: httpbin
    spec:
      ports:
      - name: http
        port: 8000
        targetPort: 80
      selector:
        app: httpbin
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: httpbin
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: httpbin
          version: v1
      template:
        metadata:
          labels:
            app: httpbin
            version: v1
        spec:
          serviceAccountName: httpbin
          containers:
          - image: docker.io/kennethreitz/httpbin
            imagePullPolicy: IfNotPresent
            name: httpbin
            ports:
            - containerPort: 80
                            
  2. Run the following command to deploy the httpbin application in the cluster.

    kubectl apply -f httpbin.yaml
  3. Create a sleep.yaml file with the following content.

    sleep.yaml

    # Copyright Istio Authors
    #
    #   Licensed under the Apache License, Version 2.0 (the "License");
    #   you may not use this file except in compliance with the License.
    #   You may obtain a copy of the License at
    #
    #       http://www.apache.org/licenses/LICENSE-2.0
    #
    #   Unless required by applicable law or agreed to in writing, software
    #   distributed under the License is distributed on an "AS IS" BASIS,
    #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    #   See the License for the specific language governing permissions and
    #   limitations under the License.
    
    ##################################################################################################
    # Sleep service
    ##################################################################################################
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: sleep
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: sleep
      labels:
        app: sleep
        service: sleep
    spec:
      ports:
      - port: 80
        name: http
      selector:
        app: sleep
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: sleep
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: sleep
      template:
        metadata:
          labels:
            app: sleep
        spec:
          terminationGracePeriodSeconds: 0
          serviceAccountName: sleep
          containers:
          - name: sleep
            image: curlimages/curl
            command: ["/bin/sleep", "3650d"]
            imagePullPolicy: IfNotPresent
            volumeMounts:
            - mountPath: /etc/sleep/tls
              name: secret-volume
          volumes:
          - name: secret-volume
            secret:
              secretName: sleep-secret
              optional: true
    ---
                            
  4. Run the following command to deploy the sleep application in the cluster.

    kubectl apply -f sleep.yaml

Step 3: Register the gRPC authorization service

Register the service that you deployed in Step 1 with Service Mesh. This enables the Service Mesh to use the service for authorization.

  1. Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.

  2. On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose Mesh Security Center > External Authorization Service. On the page that appears, click Define External Authorization Service.

  3. On the Register External Authorization Service page, click the Custom authorization service (HTTP or gRPC protocol) implemented based on envoy.ext_authz tab, configure the parameters, and then click Create.

    Type

    Parameter

    Description

    Required parameters

    Protocol

    Select the protocol for the custom authorization application. In this example, select GRPC.

    Name

    The name of the custom authorization service. In this example, enter test.

    Service Address

    Enter the service address of the custom authorization application, which is in the format of <application name>.<namespace name>.svc.<cluster domain>. In this topic, the value is set to ext-authz.default.svc.cluster.local.

    Port(1 - 65535)

    Enter the service port of the custom authorization application. In this example, enter 9000.

    Timeout(second)

    If the authorization service fails to respond within this timeout period, it is considered unavailable. In this example, set the timeout to 10 seconds.

    Optional parameters

    Skip authentication while authorization service is unavailable

    Specifies whether to allow requests if the authorization service is unavailable.

    Error code returned by asm proxy while Auth-Service is not available

    This option is available only when Skip authentication while authorization service is unavailable is disabled. If you enable this option, you must specify an error code. When the authorization service is unavailable, this error code is returned to the client.

    Carry origin request body within auth request

    When this option is enabled, specify the maximum length of the request body for the authorization request. If you also enable the Allow send incomplete message to Auth-Service(HTTP 413 will be returned if request body size beyond limitation and this option is disabled) option, the system truncates any request body exceeding the specified length and sends the truncated part to the authorization service. Otherwise, the system rejects oversized requests with an HTTP 413 error.

Step 4: Create an authorization policy

Create an authorization policy to specify which requests require authorization.

  1. Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.

  2. On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose Mesh Security Center > AuthorizationPolicy. On the page that appears, click Create.

  3. On the Create page, configure the parameters and then click Create.

    Parameter

    Description

    Name

    Enter a name for the custom authorization policy. In this example, enter test1.

    Policy Type

    Select Custom Authorization Service.

    Custom Authorization Service

    Select grpcextauth-test(GRPC).

    Namespace

    On the Workload Scope tab, select the default namespace.

    Effective Scope

    Select Service.

    Workload

    Select httpbin.

    Request Matching Rules

    In the Add Request Target section, enable Paths and set the value to /headers.

Step 5: Verify custom authorization

  1. Run the following command to access httpbin.default:8000/ip.

    kubectl exec "$(kubectl get pod -l app=sleep -n default -o jsonpath={.items..metadata.name})" -c sleep -n default -- curl "http://httpbin.default:8000/ip" -s -o /dev/null -w "%{http_code}\n"

    An HTTP status code of 200 is returned, indicating that authorization was not triggered.

  2. Run the following command to send a request with the x-ext-authz: deny request header to httpbin.default:8000/headers.

    kubectl exec "$(kubectl get pod -l app=sleep -n default -o jsonpath={.items..metadata.name})" -c sleep -ndefault -- curl "http://httpbin.default:8000/headers" -H "x-ext-authz: deny" -s

    Expected output:

    denied by ext_authz for not found header `x-ext-authz: allow` in the request

    The output indicates the request triggered authorization but was denied.

  3. Run the following command to send a request with the x-ext-authz: allow request header to httpbin.default:8000/headers.

    kubectl exec "$(kubectl get pod -l app=sleep -n default -o jsonpath={.items..metadata.name})" -c sleep -n default -- curl "http://httpbin.default:8000/headers" -H "x-ext-authz: allow" -s

    Expected output:

    {
      "headers": {
        "Accept": "*/*",
        "Host": "httpbin.default:8000",
        "User-Agent": "curl/8.5.0",
        "X-Envoy-Attempt-Count": "1",
        "X-Ext-Authz": "allow",
        "X-Ext-Authz-Check-Result": "allowed",
        "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/default/sa/httpbin;Hash=c3e5364e87add0f4f69e6b0d029f5961b404c8f209bf9004b3d21a82cf67****;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/sleep"
      }
    }

    The output shows that the request triggered authorization and was allowed. Successfully accessing httpbin.default:8000/headers requires the x-ext-authz: allow header, confirming the custom authorization is correctly configured.

Related operations