外部授权过滤器

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

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

此沙箱的设置与 front-proxy 部署非常相似,但是对代理后面上游服务的调用会被外部 HTTP 或 gRPC 服务检查。在此沙箱中,对于每个授权的调用,外部授权服务都会在原始请求头部添加 x-current-user,然后该调用会被转发到上游服务。

运行沙箱

以下文档说明了上述对于 Envoy 容器编译环境进行设置的过程。

步骤 1:安装 Docker

确保你已安装较新版本的 dockerdocker-compose

一个最简单的方法来完成此事就是使用 Docker Desktop

步骤 2:克隆 Envoy 仓库

如果你还没有克隆 Envoy 仓库,用如下方式进行克隆:

git clone [email protected]:envoyproxy/envoy
git clone https://github.com/envoyproxy/envoy.git

步骤 3: 启动所有容器

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

$ 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, 0.0.0.0:8001->8001/tcp
ext_authz_upstream-service_1         python3 /app/service/server.py   Up

Note

此沙箱具有受 FRONT_ENVOY_YAML 环境变量控制的多个设置,这些设置指向要使用的有效 Envoy 配置。FRONT_ENVOY_YAML 可以在 .env 文件中定义默认值,也可以在运行 docker-compose up 命令时内联提供。更多有关信息,请参阅 Compose 文档中的环境变量

默认情况下,FRONT_ENVOY_YAML 指向 config/grpc-service/v3.yaml 文件,该文件使用 ext_authz HTTP 过滤器引导 front-envoy,此 ext_authz HTTP 过滤器使用 gRPC v3 服务(这是在 transport_api_version 字段 中指定的)。

FRONT_ENVOY_YAML 的可选值可以在 envoy/examples/ext_authz/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 后面的上游服务

现在,你可以尝试通过 front-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 令牌。

Note

envoy/examples/ext_authz/auth/users.json 文件中定义了完整的用户列表。例如,以下示例中使用的 token1user1 相对应。

下面是一个成功请求的示例:

$ 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/v2.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