外部授权 (ext_authz) 过滤器

外部授权沙箱演示了 Envoy 的 ext_authz 过滤器 功能,通过 Envoy 将传入请求的授权委托给外部服务。

虽然 ext_authz 也可以用作网络过滤器,但此沙箱仅限于展示 ext_authz HTTP 过滤器,该过滤器支持调用 HTTP 或 gRPC 服务。

此沙箱的设置与前端代理部署非常相似,但是对代理后面上游服务的调用将由外部 HTTP 或 gRPC 服务进行检查。在此沙箱中,对于每个授权调用,外部授权服务都会向原始请求标头添加额外的 x-current-user 标头条目,以转发到上游服务。

步骤 1:启动所有容器

更改到 examples/ext_authz 目录。

要构建此沙箱示例并启动示例服务,请运行以下命令

$ pwd
envoy/examples/ext_authz
$ docker compose pull
$ docker compose up --build -d
$ docker compose ps

               Name                             Command               State                   Ports
--------------------------------------------------------------------------------------------------------------------
ext_authz_ext_authz-grpc-service_1   /app/server -users /etc/us       Up
ext_authz_ext_authz-http-service_1   docker-entrypoint.sh node        Up
ext_authz_front-envoy_1              /docker-entrypoint.sh /bin       Up           10000/tcp, 0.0.0.0:8000->8000/tcp
ext_authz_upstream-service_1         python3 /code/service.py         Up (healthy)

注意

此沙箱有多个设置,由 FRONT_ENVOY_YAML 环境变量控制,该变量指向要使用的有效 Envoy 配置。 FRONT_ENVOY_YAML 的默认值可以在 .env 文件中定义,或者在运行 docker compose up 命令时内联提供。

有关更多信息,请查看 Compose 文档中的环境变量

默认情况下, FRONT_ENVOY_YAML 指向 config/grpc-service/v3.yaml 文件,该文件使用具有 gRPC 服务 V3 的 ext_authz HTTP 过滤器引导前端 Envoy(这由 transport_api_version 字段 指定)。

FRONT_ENVOY_YAML 的可能值可以在 config 目录中找到。

例如,要使用具有 HTTP 服务的 ext_authz HTTP 过滤器运行 Envoy,将使用

$ pwd
envoy/examples/ext_authz
$ docker compose pull
$ # Tearing down the currently running setup
$ docker compose down
$ FRONT_ENVOY_YAML=config/http-service.yaml docker compose up --build -d
$ # Or you can update the .env file with the above FRONT_ENVOY_YAML value, so you don't have to specify it when running the "up" command.

步骤 4:访问 Front Envoy 后面的上游服务

您现在可以尝试通过前端 Envoy 向上游服务发送请求,如下所示

$ curl -v localhost:8000/service
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /service HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 403 Forbidden
< date: Fri, 19 Jun 2020 15:02:24 GMT
< server: envoy
< content-length: 0

如观察到的,该请求失败,状态代码为 403 Forbidden。发生这种情况是因为 Envoy 使用的 ext_authz 过滤器拒绝了调用。要让请求到达上游服务,您需要通过 Authorization 标头提供 Bearer 令牌。

注意

用户完整列表在 auth/users.json 文件中定义。例如,以下示例中使用的 token1 对应于 user1

成功请求的示例如下所示

$ curl -v -H "Authorization: Bearer token1" localhost:8000/service
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /service HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.58.0
> Accept: */*
> Authorization: Bearer token1
>
< HTTP/1.1 200 OK
< content-type: text/html; charset=utf-8
< content-length: 24
< server: envoy
< date: Fri, 19 Jun 2020 15:04:29 GMT
< x-envoy-upstream-service-time: 2
<
* Connection #0 to host localhost left intact
Hello user1 from behind Envoy!

我们也可以使用 Open Policy Agent 服务器(启用了 envoy_ext_authz_grpc 插件)作为授权服务器。要运行此示例

$ pwd
envoy/examples/ext_authz
$ docker compose pull
$ # Tearing down the currently running setup
$ docker compose down
$ FRONT_ENVOY_YAML=config/opa-service/v3.yaml docker compose up --build -d

并将请求发送到上游服务(通过 Front Envoy),结果为

$ curl localhost:8000/service --verbose
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8000 (#0)
> GET /service HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 200 OK
< content-type: text/html; charset=utf-8
< content-length: 28
< server: envoy
< date: Thu, 02 Jul 2020 06:29:58 GMT
< x-envoy-upstream-service-time: 2
<
* Connection #0 to host localhost left intact
Hello OPA from behind Envoy!

从日志中,我们可以观察到 Open Policy Agent 服务器发出的策略决策消息(对于针对 config/opa-service/policy.rego 中定义的策略的上述请求)。

$ docker compose logs ext_authz-opa-service | grep decision_id -A 30
ext_authz-opa-service_1   |   "decision_id": "8143ca68-42d8-43e6-ade6-d1169bf69110",
ext_authz-opa-service_1   |   "input": {
ext_authz-opa-service_1   |     "attributes": {
ext_authz-opa-service_1   |       "destination": {
ext_authz-opa-service_1   |         "address": {
ext_authz-opa-service_1   |           "Address": {
ext_authz-opa-service_1   |             "SocketAddress": {
ext_authz-opa-service_1   |               "PortSpecifier": {
ext_authz-opa-service_1   |                 "PortValue": 8000
ext_authz-opa-service_1   |               },
ext_authz-opa-service_1   |               "address": "172.28.0.6"
ext_authz-opa-service_1   |             }
ext_authz-opa-service_1   |           }
ext_authz-opa-service_1   |         }
ext_authz-opa-service_1   |       },
ext_authz-opa-service_1   |       "metadata_context": {},
ext_authz-opa-service_1   |       "request": {
ext_authz-opa-service_1   |         "http": {
ext_authz-opa-service_1   |           "headers": {
ext_authz-opa-service_1   |             ":authority": "localhost:8000",
ext_authz-opa-service_1   |             ":method": "GET",
ext_authz-opa-service_1   |             ":path": "/service",
ext_authz-opa-service_1   |             "accept": "*/*",
ext_authz-opa-service_1   |             "user-agent": "curl/7.64.1",
ext_authz-opa-service_1   |             "x-forwarded-proto": "http",
ext_authz-opa-service_1   |             "x-request-id": "b77919c0-f1d4-4b06-b444-5a8b32d5daf4"
ext_authz-opa-service_1   |           },
ext_authz-opa-service_1   |           "host": "localhost:8000",
ext_authz-opa-service_1   |           "id": "16617514055874272263",
ext_authz-opa-service_1   |           "method": "GET",
ext_authz-opa-service_1   |           "path": "/service",

尝试发送与 GET 不同的方法的请求会遭到拒绝

$ curl -X POST localhost:8000/service --verbose
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8000 (#0)
> PUT /service HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 403 Forbidden
< date: Thu, 02 Jul 2020 06:46:13 GMT
< server: envoy
< content-length: 0

另请参见

ext_authz 过滤器

了解有关使用 Envoy 的 ext_authz 过滤器的更多信息。

Open Policy Agent

用于云原生环境的基于策略的控制。

envoy_ext_authz_grpc

Open Policy Agent Envoy 插件。

Compose 文档中的环境变量.

有关使用 Docker Compose 的 env 变量的更多信息。