All Products
Search
Document Center

Alibaba Cloud Service Mesh:Integrate an OPA engine with an ingress gateway

Last Updated:Mar 07, 2024

When dynamic access control is required, you can integrate an Open Policy Agent (OPA) engine in an ingress gateway to customize authorization policies based on user identities or request content and control communication between services in real time. This effectively prevents unauthorized access, reduces the risks of data breach, and enhances the security of applications in a Service Mesh (ASM) instance. This topic describes how to use an OPA engine to authenticate and authorize requests that are received by an ingress gateway. In this example, requests flow through the ingress gateway to access the HTTPBin application.

Prerequisites

Step 1: Deploy an OPA engine

  1. Create a file named asm-opa.yaml and copy the following content to the file.

    The YAML code deploys an OPA Service, an OPA Deployment, and a Secret.

    Kind

    Description

    Deployment

    • Replace the region ID in the image registry-vpc.cn-hangzhou.aliyuncs.com/acs/opa:0.46.1-istio-3-static with the ID of the region where your cluster is deployed.

    • By default, logging is enabled for the OPA engine (--set=decision_logs.console=true). This facilitates debugging.

    Secret

    The Secret defines the following OPA policies:

    • If the path of a request is health, the request is allowed.

    • If the method of a request is HEAD, the request is allowed.

    • If the user name of a request is alice, the request is allowed.

      Note

      The user name is carried in the Authorization header of the request, in the form of Authorization: Basic ${user name: Base64-encoded password string}.

    Show the content of asm-opa.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: asm-opa
      labels:
        app: opa
    spec:
      ports:
        - name: grpc
          port: 9191
          targetPort: 9191
          protocol: TCP
        - name: http
          port: 8181
          targetPort: 8181
          protocol: TCP
      selector:
        app: opa
    ---
    kind: Deployment
    apiVersion: apps/v1
    metadata:
      name: opa
      labels:
        app: opa
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: opa
      template:
        metadata:
          labels:
            app: opa
          annotations:
            sidecar.istio.io/inject: "false"
        spec:
          containers:
            - name: opa
              image: registry-vpc.cn-hangzhou.aliyuncs.com/acs/opa:0.46.1-istio-3-static
              securityContext:
                runAsUser: 1111
              volumeMounts:
                - readOnly: true
                  mountPath: /policy
                  name: opa-policy
              args:
                - "run"
                - "--server"
                - "--addr=0.0.0.0:8181"
                - "--diagnostic-addr=0.0.0.0:8282"
                - "--set=plugins.envoy_ext_authz_grpc.addr=:9191"
                - "--set=plugins.envoy_ext_authz_grpc.path=asm/authz/allow"
                - "--set=decision_logs.console=true"
                - "--ignore=.*"
                - "/policy/policy.rego"
              ports:
                - containerPort: 9191
                  protocol: TCP
              resources:
                limits:
                  cpu: "0"
                  memory: "0"
          volumes:
            - name: opa-policy
              secret:
                secretName: opa-policy
    ---
    apiVersion: v1
    kind: Secret
    metadata:
      name: opa-policy
    type: Opaque
    stringData:
      policy.rego: |
        package asm.authz
    
        import future.keywords
    
        import input.attributes.request.http as http_request
        import input.parsed_path
    
        default allow := false
    
        allow if {
          parsed_path[0] == "health"
        }
    
        allow if {
          http_request.method == "HEAD"
        }
    
        allow if {
          user_name == "alice"
        }
    
        user_name := parsed if {
          [_, encoded] := split(http_request.headers.authorization, " ")
          [parsed, _] := split(base64url.decode(encoded), ":")
        }
    
  2. Use kubectl to connect to the Container Service for Kubernetes (ACK) cluster based on the information in the kubeconfig file and run the following command to deploy OPA:

    kubectl apply -f asm-opa.yaml

Step 2: Use the external authorization feature of the ingress gateway to integrate the OPA engine with the ingress gateway

  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 ASM Gateways > Ingress Gateway.

  3. On the Ingress Gateway page, click Gateway security next to the ingress gateway with which you want to integrate the OPA engine.

  4. In the left-side navigation pane, choose Gateway Security > Custom Authorization Service.

  5. Configure a custom authorization service.

    1. In the Custom Authorization Service Configuration step, configure the OPA engine as the custom authorization service for the ingress gateway and click Next.

      image.png

    2. In the Matching Rules step, configure a request matching rule, specify which requests must be authenticated and authorized by the OPA engine, and then click Submit.

      image.png

      The following figure shows the page after the custom authorization service is created.

      image.png

Step 3: Test the access to the HTTPBin application

  1. Run the following command to access the / path:

    curl ${IP address of the ASM gateway}/ -I -X GET

    Expected output:

    HTTP/1.1 200 OK
    server: istio-envoy
    date: Tue, 25 Jul 2023 08:30:58 GMT
    content-type: text/html; charset=utf-8
    content-length: 9593
    access-control-allow-origin: *
    access-control-allow-credentials: true
    x-envoy-upstream-service-time: 2

    The output indicates that authentication is not required for the access requests to the path.

  2. Run the following command to access the /status/201 path without valid parameters:

    curl ${IP address of the ASM gateway}/status/201 -I -X GET

    Expected output:

    HTTP/1.1 403 Forbidden
    date: Tue, 25 Jul 2023 08:31:18 GMT
    server: istio-envoy
    content-length: 0
    x-envoy-upstream-service-time: 1

    The output indicates that the access request without valid parameters is rejected.

  3. Run the following command to access the /status/201 path with valid parameters:

    curl ${IP address of the ASM gateway}/status/201 -I -X GET --user alice:testpassword

    Expected output:

    HTTP/1.1 201 Created
    server: istio-envoy
    date: Tue, 25 Jul 2023 08:31:38 GMT
    content-type: text/html; charset=utf-8
    access-control-allow-origin: *
    access-control-allow-credentials: true
    content-length: 0
    x-envoy-upstream-service-time: 3

    The output indicates that the access request with valid parameters is allowed.

Step 4: Update the OPA policy

Call the HTTP API of the OPA engine to update the OPA policy.

  1. Run the following commands to allow only the user named bob to access the HTTPBin application over HTTP and reject the user named alice from accessing the HTTPBin application over HTTP.

    kubectl exec deployment/httpbin -c istio-proxy -- curl asm-opa:8181/v1/policies/policy/policy.rego -XPUT --data-binary 'package asm.authz
    
    import future.keywords
    import input.attributes.request.http as http_request
    import input.parsed_path
    
    default allow := false
    
    allow if {
      parsed_path[0] == "health"
    }
    
    allow if {
      http_request.method == "HEAD"
    }
    
    allow if {
      user_name == "bob"
    }
    
    user_name := parsed if {
      [_, encoded] := split(http_request.headers.authorization, " ")
      [parsed, _] := split(base64url.decode(encoded), ":")
    }'
  2. Run the following command to access the HTTPBin application by using the user named bob:

    curl ${IP address of the ASM gateway}/status/201 -I -X GET --user bob:testpassword

    Expected output:

    HTTP/1.1 201 Created
    server: istio-envoy
    date: Tue, 25 Jul 2023 08:32:16 GMT
    content-type: text/html; charset=utf-8
    access-control-allow-origin: *
    access-control-allow-credentials: true
    content-length: 0
    x-envoy-upstream-service-time: 3

    The output indicates that the access of the user named bob is successful.

  3. Run the following command to access the HTTPBin application by using the user named alice:

    curl ${IP address of the ASM gateway}/status/201 -I -X GET --user alice:testpassword

    Expected output:

    HTTP/1.1 403 Forbidden
    date: Tue, 25 Jul 2023 08:32:49 GMT
    server: istio-envoy
    content-length: 0
    x-envoy-upstream-service-time: 1

    The output indicates that the access of the user named alice is forbidden.