首页 > 解决方案 > OPA(作为主机级别的单独服务运行)策略在调用 API 时不会通过特使强制执行

问题描述

我的场景 - 通过 K8s 集群中的 Nodeport 公开的一个示例应用服务。该服务有一辆特使边车。OPA 在同一节点上作为单独的服务运行。

我的应用程序部署规范 -

apiVersion: apps/v1
kind: Deployment
metadata:
  name: example-app
  labels:
    app: example-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: example-app
  template:
    metadata:
      labels:
        app: example-app
    spec:
      initContainers:
        - name: proxy-init
          image: openpolicyagent/proxy_init:v5
          # Configure the iptables bootstrap script to redirect traffic to the
          # Envoy proxy on port 8000, specify that Envoy will be running as user
          # 1111, and that we want to exclude port 8282 from the proxy for the
          # OPA health checks. These values must match up with the configuration
          # defined below for the "envoy" and "opa" containers.
          args: ["-p", "8000", "-u", "1111"]
          securityContext:
            capabilities:
              add:
                - NET_ADMIN
            runAsNonRoot: false
            runAsUser: 0
      containers:
        - name: app
          image: openpolicyagent/demo-test-server:v1
          ports:
            - containerPort: 8080

        - name: envoy
          image: envoyproxy/envoy:v1.14.4
          securityContext:
            runAsUser: 1111
          volumeMounts:
            - readOnly: true
              mountPath: /config
              name: proxy-config
          args:
            - "envoy"
            - "--config-path"
            - "/config/envoy.yaml"
      volumes:
        - name: proxy-config
          configMap:
            name: proxy-config

我的 Envoy 规格(通过配置映射加载)-

static_resources:
  listeners:
    - address:
        socket_address:
          address: 0.0.0.0
          port_value: 8000
      filter_chains:
        - filters:
            - name: envoy.filters.network.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                codec_type: auto
                stat_prefix: ingress_http
                route_config:
                  name: local_route
                  virtual_hosts:
                    - name: backend
                      domains:
                        - "*"
                      routes:
                        - match:
                            prefix: "/"
                          route:
                            cluster: service
                http_filters:
                  - name: envoy.filters.http.ext_authz
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
                      grpc_service:
                       envoy_grpc:
                        cluster_name: opa
                       timeout: 0.250s
                  - name: envoy.filters.http.router
                    typed_config: {}
  clusters:
    - name: service
      connect_timeout: 0.25s
      type: strict_dns
      lb_policy: round_robin
      load_assignment:
        cluster_name: service
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: 127.0.0.1
                      port_value: 8080
    - name: opa
      connect_timeout: 0.250s
      type: STRICT_DNS
      lb_policy: ROUND_ROBIN
      http2_protocol_options: {}
      load_assignment:
       cluster_name: opa
       endpoints:
        - lb_endpoints:
           - endpoint:
               address:
                 socket_address:
                  address: opa
                  port_value: 9191
admin:
  access_log_path: "/dev/null"
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 8001

OPA 部署规范(通过 nodeport 作为服务公开):-

apiVersion: apps/v1
kind: Deployment
metadata:
  name: opa
  labels:
    app: opa
spec:
  replicas: 1
  selector:
    matchLabels:
      app: opa
  template:
    metadata:
      labels:
        app: opa
      name: opa
    spec:
      containers:
      - name: opa
        image: openpolicyagent/opa:latest-envoy
        ports:
        - name: http
          containerPort: 8181
        securityContext:
          runAsUser: 1111
        args:
        - "run"
        - "--server"
        - "--log-level=info"
        - "--log-format=json-pretty"
        - "--set=decision_logs.console=true"
        - "--set=plugins.envoy_ext_authz_grpc.addr=:9191"
        - "--set=plugins.envoy_ext_authz_grpc.query=data.envoy.authz.allow"
        - "--ignore=.*"
        - "/policy/policy.rego"
        volumeMounts:
        - readOnly: true
          mountPath: /policy
          name: opa-policy
      volumes:
      - name: opa-policy
        configMap:
         name: opa-policy

示例 policy.rego(通过 configmap 加载)-

package envoy.authz

import input.attributes.request.http as http_request

default allow = false

token = {"valid": valid, "payload": payload} {
    [_, encoded] := split(http_request.headers.authorization, " ")
    [valid, _, payload] := io.jwt.decode_verify(encoded, {"secret": "secret"})
}

allow {
    is_token_valid
    action_allowed
}

is_token_valid {
  token.valid
  now := time.now_ns() / 1000000000
  token.payload.nbf <= now
  now < token.payload.exp
}

action_allowed {
  http_request.method == "GET"
  token.payload.role == "guest"
  glob.match("/people*", [], http_request.path)
}

action_allowed {
  http_request.method == "GET"
  token.payload.role == "admin"
  glob.match("/people*", [], http_request.path)
}

action_allowed {
  http_request.method == "POST"
  token.payload.role == "admin"
  glob.match("/people", [], http_request.path)
  lower(input.parsed_body.firstname) != base64url.decode(token.payload.sub)
}

在调用 REST API 时得到以下响应 -

curl -i -H "Authorization: Bearer $ALICE_TOKEN" http://$SERVICE_URL/people
HTTP/1.1 403 Forbidden
date: Sat, 13 Feb 2021 08:50:29 GMT
server: envoy
content-length: 0

OPA 决策日志 -

{
  "addrs": [
    ":8181"
  ],
  "diagnostic-addrs": [],
  "level": "info",
  "msg": "Initializing server.",
  "time": "2021-02-13T08:48:27Z"
}
{
  "level": "info",
  "msg": "Starting decision logger.",
  "plugin": "decision_logs",
  "time": "2021-02-13T08:48:27Z"
}
{
  "addr": ":9191",
  "dry-run": false,
  "enable-reflection": false,
  "level": "info",
  "msg": "Starting gRPC server.",
  "path": "",
  "query": "data.envoy.authz.allow",
  "time": "2021-02-13T08:48:27Z"
}

我在这里做错了什么?对于我对 API 的其余调用,决策日志中没有任何内容。OPA 策略应通过未发生的特使过滤器调用。

请帮忙 。

标签: serviceenvoyproxyopen-policy-agent

解决方案


推荐阅读