专栏首页CNCF使用OPA实现Envoy外部授权

使用OPA实现Envoy外部授权

作者:Ash Narkar

微服务通过将应用程序分解为更小的、独立的部分来提高单个开发团队的生产力。然而,仅使用微服务并不能解决诸如服务发现、身份验证和授权等古老的分布式系统问题。事实上,由于微服务环境的异构性和短暂性,这些问题往往更为严重。

随着越来越多的组织采用微服务体系结构,对分离的身份验证和授权的需求变得越来越明显。本文将深入探讨如何利用EnvoySPIFFE/SPIREOpen Policy Agent(OPA)在微服务环境中执行重要的安全政策。

背景

Envoy是为大型现代面向服务架构设计的L7代理和通信总线。Envoy(v1.7.0+)支持外部授权过滤器(External Authorization filter),它调用授权服务来检查传入的请求是否被授权。该特性使将授权决策委托给外部服务成为可能,并使请求上下文对服务可用。请求上下文包含诸如网络活动的源、网络活动的目标、网络请求(例如http请求)。所有这些信息都可以被外部事务处用来对Envoy收到的传入请求的命运作出知情的决定。

SPIFFE(Secure Production Identity Framework for Everyone)是一组开放源码标准,用于在动态和异构环境中安全地标识软件系统。采用SPIFFE的系统无论在何处运行,都可以轻松可靠地进行相互身份验证。SPIRE(SPIFFE Runtime Environment,SPIFFE运行时环境)是一个工具链,用于在各种平台上的工作负载之间建立信任。

OPA(Open Policy Agent,开放政策代理)是一个开放源码的通用政策引擎,支持跨整个堆栈的统一的、上下文感知的政策执行。OPA的高级声明性语言Rego允许创建细粒度的安全政策,用于对结构化文档中表示的信息进行推理。

OPA作为外部授权服务

我们将演练一个使用Envoy的外部授权过滤器和OPA作为授权服务的示例。

Envoy-OPA外部授权

该示例由三个服务(web、后端和db)组成,它们与正在运行的Envoy服务进行协作。每个服务使用外部授权过滤器调用各自的OPA实例,检查是否允许传入请求。

web服务接收来自部署在不同子网中的api-server-1和api-server-2的所有入站请求。请求被转发到后端服务,后端服务随后调用db服务。

web、后端和db服务之间的安全通信,通过在每个容器中配置Envoy代理来建立彼此之间的mTLS连接来实现的。Envoy从实现Envoy SDS的SPIRE代理,获得用于mTLS通信的客户机和服务器TLS证书和可信CA根。代理依次从SPIRE服务器获取此信息,并将其提供给已标识的工作负载。在下面的示例中,SPIRE以嵌入到TLS证书中的SPIFFE ID的形式,为每个工作负载提供一个身份,以方便mTLS通信。然后,OPA可以使用每个工作负载的SPIFFE ID来构建授权政策。更多关于塔尖的信息可以在这里找到。

https://spiffe.io/spire/overview/

  • Envoy监听每个容器8001端口的进入情况。
  • api-server-1和api-server-2是分别运行在端口5000和5001上的flask应用程序,它们将请求转发给web服务。
  • api-server-1在172.28.0.0/16子网中有一个静态IP,而api-server-2在192.28.0.0/16子网中有一个静态IP。
  • OPA通过GRPC服务器进行扩展,实现了Envoy外部授权API。
  • data.envoy.authz.allow是决定是否允许请求的默认OPA政策。
  • 查询的GRPC服务器端口和默认OPA政策都是可配置的。

运行这个例子

第一步:安装Docker

确保安装了docker和docker-compose的最新版本。

第二步:克隆repo并启动容器

克隆OPA-Envoy-SPIRE repo:

git clone git@github.com:ashutosh-narkar/opa-envoy-spire-ext-authz.git

$ cd opa-envoy-spire-ext-authz
$ docker-compose up --build -d
$ docker-compose ps

下列容器应正常运作:

                  Name                                 Command               State                 Ports
----------------------------------------------------------------------------------------------------------------------
opa-envoy-spiffe-ext-authz_api-server-1_1   flask run --host=0.0.0.0         Up      0.0.0.0:5000->5000/tcp
opa-envoy-spiffe-ext-authz_api-server-2_1   flask run --host=0.0.0.0         Up      0.0.0.0:5001->5000/tcp, 5001/tcp
opa-envoy-spiffe-ext-authz_backend_1        /bin/sh -c /usr/local/bin/ ...   Up      10000/tcp
opa-envoy-spiffe-ext-authz_db_1             /bin/sh -c /usr/local/bin/ ...   Up      10000/tcp
opa-envoy-spiffe-ext-authz_opa_be_1         ./opa_istio_linux_amd64 -- ...   Up      0.0.0.0:9192->9192/tcp
opa-envoy-spiffe-ext-authz_opa_db_1         ./opa_istio_linux_amd64 -- ...   Up      0.0.0.0:9193->9193/tcp
opa-envoy-spiffe-ext-authz_opa_web_1        ./opa_istio_linux_amd64 -- ...   Up      0.0.0.0:9191->9191/tcp
opa-envoy-spiffe-ext-authz_spire-server_1   /usr/bin/dumb-init /opt/sp ...   Up
opa-envoy-spiffe-ext-authz_web_1            /bin/sh -c /usr/local/bin/ ...   Up      10000/tcp, 0.0.0.0:8001->8001/tcp

第三步:启动SPIRE基础设施

启动SPIRE代理并在SPIRE服务器上注册web、后端和db服务器。更多关于注册过程的信息可以在这里找到。

$ ./configure-spire.sh

第四步:实行进入政策

进入政策声明web服务只能从子网172.28.0.0/16访问。

检查api-server-1是否可以访问web服务。

$ curl -i localhost:5000/hello
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 29
Server: Werkzeug/0.15.2 Python/2.7.15
Date: Thu, 02 May 2019 21:21:48 GMT

Hello from the web service !

检查api-server-2不能访问web服务。

$ curl -i localhost:5001/hello
HTTP/1.0 403 FORBIDDEN
Content-Type: text/html; charset=utf-8
Content-Length: 40
Server: Werkzeug/0.15.2 Python/2.7.15
Date: Thu, 02 May 2019 21:22:12 GMT

Access to the Web service is forbidden.

第五步:实施服务对服务政策

服务到服务政策声明请求可以从web流到后端到db服务。

检查这个流是否被接受。

$ curl -i localhost:5000/the/good/path
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 35
Server: Werkzeug/0.15.2 Python/2.7.15
Date: Thu, 02 May 2019 21:22:50 GMT

Allowed path: WEB -> BACKEND -> DB

检查web服务是否不允许直接调用db服务。

$ curl -i localhost:5000/the/bad/path
HTTP/1.0 403 FORBIDDEN
Content-Type: text/html; charset=utf-8
Content-Length: 26
Server: Werkzeug/0.15.2 Python/2.7.15
Date: Thu, 02 May 2019 21:23:22 GMT

Forbidden path: WEB -> DB

OPA政策例子

每个服务为一个决策调用其各自的OPA实例,并将其所需的政策加载到OPA中。要查看服务加载的OPA政策,请查看repo中的docker目录。

政策-1示例

上面示例中使用的以下OPA政策被加载到web服务调用的OPA中。

  • web服务只能从子网172.28.0.0/16访问
import input.attributes.request.http as http_request
import input.attributes.source.address as source_address

default allow = false

allowed_paths = {"/hello", "/the/good/path", "/the/bad/path"}

# allow access to the Web service from the subnet 172.28.0.0/16 for the allowed paths
allow {
    allowed_paths[http_request.path]
    http_request.method == "GET"
    net.cidr_contains("172.28.0.0/16", source_address.Address.SocketAddress.address)
}

OPA-Envoy进入政策

Rego游乐场尝试OPA-Envoy进入政策!

政策-2示例

本例中使用的另一项政策规定:

  • 请求可以从web流到后端到db服务

下面是一个政策片段,它被加载到db服务调用的OPA中。该政策只允许从后端服务请求db服务。

package envoy.authz

import input.attributes.request.http as http_request
import input.attributes.source.address as source_address

default allow = false

# allow Backend service to access DB service
allow {
    http_request.path == "/good/db"
    http_request.method == "GET"
    svc_spiffe_id == "spiffe://domain.test/backend-server"
}

svc_spiffe_id = client_id {
    [_, _, uri_type_san] := split(http_request.headers["x-forwarded-client-cert"], ";")
    [_, client_id] := split(uri_type_san, "=")
}

OPA-Envoy服务政策

Rego游乐场尝试OPA-Envoy服务对服务政策!

X-Forward-Client-Cert头由发起服务的Envoy代理注入,并由目标服务的Envoy代理验证。将Envoy配置为转发客户机证书中的URI字段。为了标识发出请求的服务,该政策使用X-Forward-Client-Cert头的URI字段,在本例中,该头是后端服务器的SPIFFE ID。

X-Forward-Client-Cert(XFCC)是一个代理标头,它指示请求在从客户机到服务器的过程中流经的部分,或全部客户机或代理的证书信息。有关标题及其支持的键的更多信息可以在这里找到。

https://www.envoyproxy.io/docs/envoy/latest/configuration/http_conn_man/headers#x-forwarded-client-cert

Envoy配置例子

下面是一个Envoy代理的示例配置,该代理侦听端口80上的HTTP客户机连接,然后调用OPA的gRPC服务器,该服务器实现了Envoy外部授权API。

https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/ext_authz_filter

static_resources:
  listeners:
  - address:
      socket_address:
        address: 0.0.0.0
        port_value: 80
    use_original_dst: true
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
          codec_type: auto
          stat_prefix: ingress_http
          access_log:
            - name: envoy.file_access_log
              config:
                path: "/dev/stdout"
          route_config:
            name: local_route
            virtual_hosts:
            - name: backend
              domains:
              - "*"
              routes:
              - match:
                  prefix: "/hello"
                route:
                  cluster: web-service
              - match:
                  prefix: "/the/good/path"
                route:
                  cluster: web-service
              - match:
                  prefix: "/the/bad/path"
                route:
                  cluster: web-service
          http_filters:
          - name: envoy.ext_authz
            config:
              failure_mode_allow: false
              grpc_service:
                google_grpc:
                  target_uri: opa:9191
                  stat_prefix: ext_authz
                timeout: 0.5s
          - name: envoy.router
            config: {}
  clusters:
  - name: web-service
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    http2_protocol_options: {}
    load_assignment:
      cluster_name: web-service
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: web-service
                port_value: 80
admin:
  access_log_path: "/dev/null"
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 8001

这就是了!

这就是如何使用OPA作为外部授权服务,使用Envoy的外部授权过滤器强制执行进入和服务到服务的安全政策。OPA利用SPIFFE/SPIRE提供的身份验证框架,通过将Envoy配置为转发客户端证书细节,OPA能够基于客户端X.509证书的URI SAN中包含的SPIFFE ID做出授权决策。

源代码

示例代码可以在这里找到:https://github.com/ashutosh-narkar/opa-envoy-spi-ext-authz。

本文分享自微信公众号 - CNCF(lf_cncf),作者:CNCF

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-05-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Rego Playground:新特性

    去年这个时候,我们推出了Rego游乐场(Rego Playground)。游乐场提供了一个在线交互环境,用户可以在这里试验和共享OPA策略。

    CNCF
  • 为什么使用OPA而不是原生的Pod安全策略?

    https://www.magalix.com/blog/enforce-pod-security-policies-in-kubernetes-using-o...

    CNCF
  • 波兰在线购物网站Allegro.pl迁移到服务网格经验分享

    Allegro.pl 平台工程师,领导的开发团队负责服务网格、服务发现和提高开发人员在 JVM 上的生产力的库。

    CNCF
  • 《云原生服务网格Istio》第3章 非侵入的流量治理

    yeedomliu
  • 部署模式 - 每个容器一个服务实例

    已经通过微服务架构的分解模式(参考按业务领域分解模式划分微服务),将整个应用程序划分为多个独立的微服务。

    羽客
  • 给机器学习面试者的十项建议 | 面试官角度

    在过去的一年里,我采访了一些在Expedia Group担任数据科学职位的人,职位从入门级到高级的都有。我想分享我的经验,这些经验适用于对申请数据科学职位的人。...

    磐创AI
  • 给机器学习面试者的十项建议 | 面试官角度

    在过去的一年里,我采访了一些在Expedia Group担任数据科学职位的人,职位从入门级到高级的都有。我想分享我的经验,这些经验适用于对申请数据科学职位的人。...

    AI研习社
  • 客户眼中的云计算长什么样?

    最近与接触政企一线的销售客户经理进行了一些交流,主要是面向中小企业的销售线条,提出的一些问题引起了我的深思。作为云服务商的销售团队,在接受了云知识的基础培训后,...

    希望的田野
  • 互联网募捐频频“剧情反转”,我们究竟需要什么样的慈善?

    今天早晨起来,看到《罗一笑,你给我站住》一篇文章在刷屏。 深圳某杂志社的主编罗尔的女儿得了白血病,公开募捐。名为“小铜人”的科技公司承诺,他们的公众账号“P2P...

    罗超频道
  • 【PMP】8.21早上题

    1.新项目经理在项目中途加入团队,项目有5位有影响力的相关方和30名项目团队成员,项目经理希望向团队更新项目状态。项目经理应该参考什么?A A.沟通管理计...

    心跳包

扫码关注云+社区

领取腾讯云代金券