Connect an external OPA via ASM security policy

更新时间:
复制 MD 格式

Service Mesh (ASM) simplifies security configuration by providing the ASM security policy feature, which abstracts Istio's native security resources. ASM integrates with Open Policy Agent (OPA), which allows you to define fine-grained access control policies for your applications. This guide explains how to connect your services to an external OPA execution engine by using an ASM security policy.

Prerequisites

How it works

By default, ASM deploys OPA in sidecar mode. When OPA is enabled, ASM injects an OPA container into the application Pod when the Pod restarts. All requests to the application container are then validated by the OPA sidecar. Because communication happens within the Pod, sidecar mode offers low latency and is suitable for latency-sensitive workloads.

However, sidecar mode has drawbacks, including higher resource consumption, required Pod restarts, and limited flexibility. A centralized OPA deployment complements the sidecar mode by offering lower resource usage, connecting applications without restarts, and allowing selective application of OPA policies to specific requests. This section describes how to deploy a centralized OPA authorization service and connect it to your application.

OPA部署方式.png

Step 1: Deploy OPA

  1. Create a file named asm-opa.yaml with the following content.

    This YAML manifest deploys an OPA Service, Deployment, and Secret.

    Kind

    Description

    Deployment

    • In the image path registry-vpc.cn-hangzhou.aliyuncs.com/acs/opa:0.46.1-istio-3-static, replace cn-hangzhou with your cluster's region ID.

    • This OPA execution engine enables decision logging by default (--set=decision_logs.console=true) to simplify debugging.

    Secret

    The Secret defines an OPA policy with the following rules:

    • Allow requests if the path is health.

    • Allow requests if the method is HEAD.

    • Allow requests if the username is alice.

      Note

      The username is extracted from the Authorization header, which must be in the format Authorization: Basic ${base64_encoded_username:password}.

    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. Run the following command to deploy OPA.

    kubectl apply -f asm-opa.yaml

Step 2: Connect to OPA via ASM security policy

  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 > ASMSecurityPolicy.

  3. On the ASMSecurityPolicy page, click Create. In the Create ASMSecurityPolicy dialog box, click the Custom Authorization Service card, and then click OK.

  4. Configure the custom authorization service.

    1. On the Create Custom Authorization Service page, configure the OPA authorization service that you deployed in Step 1, and then click Next.

      Set the following parameters: ASM Security Policy Name to opa, Protocol to GRPC, Service Address to asm-opa.default.svc.cluster.local, Service Port to 9191, and Timeout to 10 seconds.

    2. In the Workload and Match Rules wizard, click Add Workload Group. In the New Workload Group dialog box, enter a Workload Group Name and click Add Workload.

    3. In the Add Workload dialog box, select Workload Scope, set Namespaces to default, and set Workload Type to Service. In the Select workloads area, select httpbin, click the Dingtalk_20230302182310.png icon, and then click OK.

    4. In the New Workload Group dialog box, find the Match Rule List section. Set Match Mode to The selected request must be authenticated and Matching Rules to Custom Matching Rules. Turn on the Path switch, set the value to /status/*, and then click OK.

      This workload group is named httpbin, and its workload list contains the httpbin Service with the app:httpbin label.

    5. In the Workload and Match Rules wizard, click Submit.

      After the policy is created, a success message is displayed, along with the generated Istio resources: an ASMExtensionProvider (resource name grpcextauth-asmsecuritypolicy-opa) and an AuthorizationPolicy (resource name opa-ap-wg-httpbin-default-service-httpbin). You can click View YAML to check the resource details, and then click Done.

Step 3: Test httpbin access

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

    curl ${ASM_GATEWAY_IP}/ -I -X GET
    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 shows that the request is allowed because this path does not require authentication.

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

    curl ${ASM_GATEWAY_IP}/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 403 Forbidden response indicates the request was denied due to missing credentials.

  3. Run the following command to access the /status/201 path with valid credentials for the user alice.

    curl ${ASM_GATEWAY_IP}/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 201 Created response confirms the request was allowed, as user alice is authorized by the OPA policy.

Step 4: Update the OPA policy

You can update the OPA policy at runtime by calling the OPA engine's HTTP API.

  1. Run the following command to update the policy. The new policy allows access only for the user bob and denies access for alice.

    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 test access as the user bob.

    curl ${ASM_GATEWAY_IP}/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 201 Created response shows that the user bob can successfully access the path.

  3. Run the following command to test access as the user alice.

    curl ${ASM_GATEWAY_IP}/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 403 Forbidden response confirms that user alice is now denied access, validating the policy update.