Istio安全设置笔记

2023年 7月 10日 61.5k 0

Istio 为网格中的微服务提供了较为完善的安全加固功能,在不影响代码的前提下,可以从多个角度提供安全支撑,官方文档做了较为详细的介绍,但是也比较破碎,这里尝试做个简介兼索引,实现过程还是要根据官方文档进行。

Istio 的安全功能主要分为三个部分的实现:

  • 双向 TLS 支持。
  • 基于黑白名单的访问控制。
  • 基于角色的访问控制。
  • JWT 认证支持。
  • 首先回顾一下 Istio 网格中的服务通信过程:

  • 利用自动或者手工注入,把 Envoy Proxy 注入到每个服务 Pod 中,用 Sidecar 的方式运行。
  • Pod 初始化过程里,使用 iptables 劫持所在 Pod 的出入流量。
  • 服务间的通信,从原来的直接通信,转换为现在的 Envoy 之间通信,Envoy 在这里同时作为客户端和服务端负载均衡组件。
  • Envoy 的工作过程中,可能会和 Mixer、Pilot 以及 Citadel 等组件发生互动。
  • 双向 TLS 支持

    双向 TLS 支持主要针对的是通信方面,把明文传输的服务通信,通过转换为 Envoy 之间的加密通信。这一安全设置较为基础,可以在全局、Namespace 或者单个服务的范围内生效。

    这一功能主要通过两个 Istio CRD 对象来完成:

    Policy

    例如 Basic Authentication Policy 中的一个样例,用于给单个服务设置 mtls:

    apiVersion: "authentication.istio.io/v1alpha1"
    kind: "Policy"
    metadata:
      name: "example-2"
    spec:
      targets:
      - name: httpbin
      peers:
      - mtls:
    

    其中 target 是可选项,如果去掉的话,作用域将扩展到整个 Namespace。

    DestinationRule

    同样的一个例子里面的目标规则如下:

    apiVersion: "networking.istio.io/v1alpha3"
    kind: "DestinationRule"
    metadata:
      name: "example-2"
    spec:
      host: httpbin.bar.svc.cluster.local
      trafficPolicy:
        tls:
          mode: DISABLE
        portLevelSettings:
        - port:
            number: 1234
          tls:
            mode: ISTIO_MUTUAL
    

    这个也很容易理解,这一规则用于指派对该地址的访问方式:

    • tls.mode = DISABLE,这个服务缺省是不开启 tls 支持的,如果取值 ISTIO_MUTUAL,则代表这个地址(服务)的所有端口都开启 TLS。
    • port...ISTIO_MUTUAL,只针对这一个端口启用 mTLS 支持。

    创建 Policy 之后,Citadel 会生成证书文件,并传递给 Envoy,我们可以在 Envoy 容器(kube-proxy)的 /etc/certs/ 目录中看到这几个 *.pem 文件。如果使用 openssl x509 -text -noout 查看 cert-chain.pem 的证书内容,会看到 spiffe 编码的 ServiceAccount 内容来作为 SAN:

     X509v3 Subject Alternative Name:
                URI:spiffe://cluster.local/ns/default/sa/default
    

    规则生效之后,原有的服务间调用是没有差异的,但是如果在网格之外,就必须 https,结合上面谈到的证书来访问目标服务才能完成访问。

    另外这里也提供了外部 CA 的支持,可以使用已有的证书体系来替换网格内的自签发体系。

    基于黑白名单的访问控制

    黑名单

    下面的例子来自官方,禁止 Reviews 的 v3 版本访问 Ratings 服务。

    首先使用 denier 适配器定义一个拒绝响应

    apiVersion: "config.istio.io/v1alpha2"
    kind: denier
    metadata:
      name: denyreviewsv3handler
    spec:
      status:
        code: 7
        message: Not allowed
    

    这里不需要额外属性输入,因此采用了 checknothing 模板:

    apiVersion: "config.istio.io/v1alpha2"
    kind: checknothing
    metadata:
      name: denyreviewsv3request
    spec:
    

    最后使用 rule 对象把这两者联系起来,并配合一个表达式来使之生效:

    apiVersion: "config.istio.io/v1alpha2"
    kind: rule
    metadata:
      name: denyreviewsv3
    spec:
      match: destination.labels["app"] == "ratings" && source.labels["app"]=="reviews" && source.labels["version"] == "v3"
      actions:
      - handler: denyreviewsv3handler.denier
        instances: [ denyreviewsv3request.checknothing ]
    

    白名单

    官方案例设置了一个允许 v2v3 版本访问 ratings 服务的白名单。

    白名单适配器要使用的是 listchecker,提供了一个允许访问的数组。

    apiVersion: config.istio.io/v1alpha2
    kind: listchecker
    metadata:
      name: whitelist
    spec:
      # providerUrl: 可以从外部 URL 获取列表内容
      overrides: ["v1", "v2"]  # 静态列表
      blacklist: false
    

    需要使用一个模板将 Pod 标签转换为 listchecker 的版本列表。

    apiVersion: config.istio.io/v1alpha2
    kind: listentry
    metadata:
      name: appversion
    spec:
      value: source.labels["version"]
    

    最后使用 Rule 进行连接:

    apiVersion: config.istio.io/v1alpha2
    kind: rule
    metadata:
      name: checkversion
    spec:
      match: destination.labels["app"] == "ratings"
      actions:
      - handler: whitelist.listchecker
        instances:
        - appversion.listentry
    

    注意:如果开启了 mTLS,可以使用 source.user == "cluster.local/ns/default/sa/bookinfo-productpage" 的形式来匹配 ServiceAccount。

    RBAC

    Helm 安装时,需要设置 global.rbacEnabled: true

    RBAC 提供较细粒度的访问控制。另外其中所使用的 ServiceRoleServiceRoleBinding 也更直观、更加易于管理。

    例如来自官方 Task 的 ServiceRole 定义,这个角色允许对指定服务进行只读访问:

    apiVersion: "config.istio.io/v1alpha2"
    kind: ServiceRole
    metadata:
      name: productpage-viewer
      namespace: default
    spec:
      rules:
      - services: ["productpage.default.svc.cluster.local"]
        methods: ["GET"]
    

    如果在 Namespace 级别进行设置,则可以这样:

    ...
      rules:
      - services: ["*"]
        methods: ["GET"]
        constraints:
        - key: "app"
          values: ["productpage"]
    ...
    

    和 Kubernetes 的 Rolebinding 类似,把用户和角色绑定起来,才能最后生效。

    例如:

      - user: [email protected]
    

    或者

      - properties:
          service: "reviews"
          namespace: "abc"
    

    subject 的内容,同样属于 Adapter 模型的实现范围,因此其可选项目仍然是由 Template 的输入产生的。具体样例可以参考 bookinfo 的 rbac 样板

    JWT 认证

    没有外部认证的需求,因此就先不理了 lol。

    参考链接

    • 安全任务:https://istio.io/docs/tasks/security
    • Istio RBAC 参考:https://istio.io/docs/reference/config/istio.rbac.v1alpha1/
    • Istio Adapters 参考:https://istio.io/docs/reference/config/policy-and-telemetry/adapters/
    • Bookinfo 示例:https://github.com/istio/istio/blob/release-0.8/samples/bookinfo/kube/

    相关文章

    KubeSphere 部署向量数据库 Milvus 实战指南
    探索 Kubernetes 持久化存储之 Longhorn 初窥门径
    征服 Docker 镜像访问限制!KubeSphere v3.4.1 成功部署全攻略
    那些年在 Terraform 上吃到的糖和踩过的坑
    无需 Kubernetes 测试 Kubernetes 网络实现
    Kubernetes v1.31 中的移除和主要变更

    发布评论