• Istio(九):istio安全之授权


    一.模块概览

    在Kubernetes集群中,可以对用户进行RBAC授权role,rolebinding,clusterrole,clusterrolebinding;对于istio来说,可以对资源定义AuthorizationPolicy授权策略,执行拒绝、允许或审计动作。

    在 Istio 中,有多个组件参与提供安全功能:

    • 用于管理钥匙和证书的证书颁发机构(CA)。
    • Sidecar 和周边代理:实现客户端和服务器之间的安全通信,它们作为政策执行点(Policy Enforcement Point,简称PEP)工作
    • Envoy 代理扩展:管理遥测和审计
    • 配置 API 服务器:分发认证、授权策略和安全命名信息

    istio授权是在认证通过之后进行的,关于istio认证,可以查看博客《Istio(八):istio安全之认证,启用mTLS》https://www.cnblogs.com/renshengdezheli/p/16840382.html

    使用istio授权的前提是已经安装好了istio,关于istio的安装部署,请查看博客《Istio(二):在Kubernetes(k8s)集群上安装部署istio1.14》https://www.cnblogs.com/renshengdezheli/p/16836404.html

    二.系统环境

    服务器版本 docker软件版本 Kubernetes(k8s)集群版本 Istio软件版本 CPU架构
    CentOS Linux release 7.4.1708 (Core) Docker version 20.10.12 v1.21.9 Istio1.14 x86_64

    Kubernetes集群架构:k8scloude1作为master节点,k8scloude2,k8scloude3作为worker节点

    服务器 操作系统版本 CPU架构 进程 功能描述
    k8scloude1/192.168.110.130 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kube-apiserver,etcd,kube-scheduler,kube-controller-manager,kubelet,kube-proxy,coredns,calico k8s master节点
    k8scloude2/192.168.110.129 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kubelet,kube-proxy,calico k8s worker节点
    k8scloude3/192.168.110.128 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kubelet,kube-proxy,calico k8s worker节点

    三.istio授权

    3.1 istio授权

    授权是对访问控制问题中访问控制部分的响应。某个(经过认证的)主体是否被允许操作某个对象?用户 A 能否向服务 B 的路径 /hello 发送一个 GET 请求?

    请注意,尽管主体可以被认证,但它可能不被允许执行某个动作。你的公司 ID 卡可能是有效的、真实的,但我不能用它来进入另一家公司的办公室。如果我们继续之前的海关官员的比喻,我们可以说授权类似于你护照上的签证章。

    这就引出了下一个问题 —— 有认证而无授权(反之亦然)对我们没有什么好处。对于适当的访问控制,我们需要两者。让我给你举个例子:如果我们只认证主体而不授权他们,他们就可以做任何他们想做的事,对任何对象执行任何操作。相反,如果我们授权了一个请求,但我们没有认证它,我们就可以假装成其他人,再次对任何对象执行任何操作

    Istio 允许我们使用 AuthorizationPolicy 资源在网格、命名空间和工作负载层面定义访问控制。AuthorizationPolicy 支持 DENY、ALLOW、AUDIT 和 CUSTOM 操作

    每个 Envoy 代理实例都运行一个授权引擎,在运行时对请求进行授权。当请求到达代理时,引擎会根据授权策略评估请求的上下文,并返回 ALLOW 或 DENY。AUDIT 动作决定是否记录符合规则的请求。注意,AUDIT 策略并不影响请求被允许或拒绝

    没有必要明确地启用授权功能。为了执行访问控制,我们可以创建一个授权策略来应用于我们的工作负载。

    AuthorizationPolicy 资源是我们可以利用 PeerAuthentication 策略和 RequestAuthentication 策略中的主体的地方。

    在定义 AuthorizationPolicy 的时候,我们需要考虑三个部分

    1. 选择要应用该策略的工作负载
    2. 要采取的行动(拒绝、允许或审计)
    3. 采取该行动的规则

    让我们看看下面这个例子如何与 AuthorizationPolicy 资源中的字段相对应。

     apiVersion: security.istio.io/v1beta1
     kind: AuthorizationPolicy
     metadata:
      name: customers-deny
      namespace: default
     spec:
      selector:
        matchLabels:
          app: customers
          version: v2
      action: DENY
      rules:
      - from:
        - source:
            notNamespaces: ["default"]
    

    使用 selectormatchLabels,我们可以选择策略所适用的工作负载。在我们的案例中,我们选择的是所有设置了 app: customersversion: v2 标签的工作负载。action 字段被设置为 DENY

    最后,我们在 rules 字段中定义所有规则。我们例子中的规则是说,当请求来自 default 命名空间之外时,拒绝对 customers v2 工作负载的请求(action)

    除了规则中的 from 字段外,我们还可以使用 towhen 字段进一步定制规则。让我们看一个使用这些字段的例子。

     apiVersion: security.istio.io/v1beta1
     kind: AuthorizationPolicy
     metadata:
      name: customers-deny
      namespace: default
     spec:
      selector:
        matchLabels:
          app: customers
          version: v2
      action: DENY
      rules:
      - from:
        - source:
            notNamespaces: ["default"]
      - to:
         - operation:
             methods: ["GET"]
      - when:
         - key: request.headers [User-Agent]
           values: ["Mozilla/*"]
    

    我们在规则部分添加了 towhen 字段。如果我们翻译一下上面的规则,我们可以说,当客户的 GET 请求来自 default 命名空间之外,并且 User Agent 头的值与正则表达式 Mozilla/* 相匹配时,我们会拒绝 customers v2 的工作负载

    总的来说,to 定义了策略所允许的行动,from 定义了谁可以采取这些行动,when 定义了每个请求必须具备的属性,以便被策略所允许,selector 定义了哪些工作负载将执行该策略

    如果一个工作负载有多个策略,则首先评估拒绝的策略。评估遵循这些规则:

    1. 如果有与请求相匹配的 DENY 策略,则拒绝该请求
    2. 如果没有适合该工作负载的 ALLOW 策略,则允许该请求。
    3. 如果有任何 ALLOW 策略与该请求相匹配,则允许该请求。
    4. 拒绝该请求

    3.2 来源

    我们在上述例子中使用的源是 notNamespaces。我们还可以使用以下任何一个字段来指定请求的来源,如表中所示。

    来源 示例 释义
    principals principals: ["my-service-account"] 任何是有 my-service-account 的工作负载
    notPrincipals notPrincipals: ["my-service-account"] 除了 my-service-account 的任何工作负载
    requestPrincipals requestPrincipals: ["my-issuer/hello"] 任何具有有效 JWT 和请求主体 my-issuer/hello 的工作负载
    notRequestPrincipals notRequestPrincipals: ["*"] 任何没有请求主体的工作负载(只有有效的 JWT 令牌)。
    namespaces namespaces: ["default"] 任何来自 default 命名空间的工作负载
    notNamespaces notNamespaces: ["prod"] 任何不在 prod 命名空间的工作负载
    ipBlocks ipBlocks: ["1.2.3.4","9.8.7.6/15"] 任何具有 1.2.3.4 的 IP 地址或来自 CIDR 块的 IP 地址的工作负载
    notIpBlock notIpBlocks: ["1.2.3.4/24"] Any IP address that's outside of the CIDR block

    3.3 操作

    操作被定义在 to 字段下,如果多于一个,则使用 AND 语义。就像来源一样,操作是成对的,有正反两面的匹配。设置在操作字段的值是字符串:

    • hostsnotHosts
    • portsnotPorts
    • methodsnotMethods
    • pathsnotPath

    所有这些操作都适用于请求属性。例如,要在一个特定的请求路径上进行匹配,我们可以使用路径。paths:["/api/*","/admin"] 或特定的端口 ports: ["8080"],以此类推。

    3.4 条件

    为了指定条件,我们必须提供一个 key 字段。key 字段是一个 Istio 属性的名称。例如,request.headerssource.ipdestination.port 等等。关于支持的属性的完整列表,请参考 授权政策条件

    条件的第二部分是 valuesnotValues 的字符串列表。下面是一个 when 条件的片段:

     ...
      - when:
         - key: source.ip
           notValues: ["10.0.1.1"]
    

    四.实战:授权(访问控制)

    4.1 访问控制

    在这个实验中,我们将学习如何使用授权策略来控制工作负载之间的访问。

    首先部署 Gateway:

     apiVersion: networking.istio.io/v1alpha3
     kind: Gateway
     metadata:
       name: gateway
     spec:
       selector:
         istio: ingressgateway
       servers:
         - port:
             number: 80
             name: http
             protocol: HTTP
           hosts:
             - '*'
    

    将上述 YAML 保存为 gateway.yaml,并使用 kubectl apply -f gateway.yaml 部署网关。

    接下来,我们将创建 Web 前端部署、服务账户、服务 和 VirtualService。

     apiVersion: v1
     kind: ServiceAccount
     metadata:
       name: web-frontend
     ---
     apiVersion: apps/v1
     kind: Deployment
     metadata:
       name: web-frontend
       labels:
         app: web-frontend
     spec:
       replicas: 1
       selector:
         matchLabels:
           app: web-frontend
       template:
         metadata:
           labels:
             app: web-frontend
             version: v1
         spec:
           serviceAccountName: web-frontend
           containers:
             - image: gcr.io/tetratelabs/web-frontend:1.0.0
               imagePullPolicy: Always
               name: web
               ports:
                 - containerPort: 8080
               env:
                 - name: CUSTOMER_SERVICE_URL
                   value: 'http://customers.default.svc.cluster.local'
     ---
     kind: Service
     apiVersion: v1
     metadata:
       name: web-frontend
       labels:
         app: web-frontend
     spec:
       selector:
         app: web-frontend
       ports:
         - port: 80
           name: http
           targetPort: 8080
     ---
     apiVersion: networking.istio.io/v1alpha3
     kind: VirtualService
     metadata:
       name: web-frontend
     spec:
       hosts:
         - '*'
       gateways:
         - gateway
       http:
         - route:
             - destination:
                 host: web-frontend.default.svc.cluster.local
                 port:
                   number: 80
    

    将上述 YAML 保存为 web-frontend.yaml,并使用 kubectl apply -f web-frontend.yaml 创建资源。

    最后,我们将部署 customers v1 服务。

     apiVersion: v1
     kind: ServiceAccount
     metadata:
       name: customers-v1
     ---
     apiVersion: apps/v1
     kind: Deployment
     metadata:
       name: customers-v1
       labels:
         app: customers
         version: v1
     spec:
       replicas: 1
       selector:
         matchLabels:
           app: customers
           version: v1
       template:
         metadata:
           labels:
             app: customers
             version: v1
         spec:
           serviceAccountName: customers-v1
           containers:
             - image: gcr.io/tetratelabs/customers:1.0.0
               imagePullPolicy: Always
               name: svc
               ports:
                 - containerPort: 3000
     ---
     kind: Service
     apiVersion: v1
     metadata:
       name: customers
       labels:
         app: customers
     spec:
       selector:
         app: customers
       ports:
         - port: 80
           name: http
           targetPort: 3000
     ---
     apiVersion: networking.istio.io/v1alpha3
     kind: VirtualService
     metadata:
       name: customers
     spec:
       hosts:
         - 'customers.default.svc.cluster.local'
       http:
         - route:
             - destination:
                 host: customers.default.svc.cluster.local
                 port:
                   number: 80
    

    将上述内容保存为 customers-v1.yaml,并使用 kubectl apply -f customers-v1.yaml 创建部署和服务。如果我们打开 GATEWAY_URL,应该会显示带有 customers v1 服务数据的 web 前端页面。

    让我们先创建一个授权策略,拒绝 default 命名空间的所有请求

     apiVersion: security.istio.io/v1beta1
     kind: AuthorizationPolicy
     metadata:
      name: deny-all
      namespace: default
     spec:
       {}
    

    将上述内容保存为 deny-all.yaml,并使用 kubectl apply -f deny-all.yaml 创建该策略。

    如果我们尝试访问 GATEWAY_URL,我们将得到以下响应。

     RBAC: access denied
    

    同样,如果我们试图在集群内运行一个 Pod,并从 default 命名空间内向 Web 前端或 customers 服务提出请求,我们会得到同样的错误。

    让我们试试吧。

     $ kubectl run curl --image=radial/busyboxplus:curl -i --tty
     If you don't see a command prompt, try pressing enter.
     [ root@curl:/ ]$ curl customers
     RBAC: access denied
     [ root@curl:/ ]$ curl web-frontend
     RBAC: access denied
     [ root@curl:/ ]$
    

    在这两种情况下,我们都得到了拒绝访问的错误。

    我们要做的第一件事是使用 ALLOW 动作,允许从入口网关向 web-frontend 应用程序发送请求。在规则中,我们指定了入口网关运行的源命名空间(istio-system)和入口网关的服务账户名称

     apiVersion: security.istio.io/v1beta1
     kind: AuthorizationPolicy
     metadata:
       name: allow-ingress-frontend
       namespace: default
     spec:
       selector:
         matchLabels:
           app: web-frontend
       action: ALLOW
       rules:
         - from:
             - source:
                 namespaces: ["istio-system"]
             - source:
                 principals: ["cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"]
    

    将上述内容保存为 allow-ingress-frontend.yaml,并使用 kubectl apply -f allow-ingress-frontend.yaml 创建策略。

    如果我们尝试从我们的主机向GATEWAY_URL 发出请求,这次我们会得到一个不同的错误。

     $ curl http://$GATEWAY_URL
     "Request failed with status code 403"
    

    请注意,策略需要几秒钟才能分发到所有代理,所以你可能仍然会看到 RBAC:access denied 的消息,时间为几秒钟。

    这个错误来自 customers 服务——记得我们允许调用 Web 前端。然而,web-frontend仍然不能调用 customers 服务。

    如果我们回到我们在集群内运行的 curl Pod,尝试请求 http://web-frontend,我们会得到一个 RBAC 错误。DENY 策略是有效的,我们只允许从入口网关进行调用。

    当我们部署 Web 前端时,我们也为 Pod 创建了一个服务账户(否则,命名空间中的所有 Pod 都被分配了默认的服务账户)。现在我们可以使用该服务账户来指定 customers 服务调用的来源

     apiVersion: security.istio.io/v1beta1
     kind: AuthorizationPolicy
     metadata:
       name: allow-web-frontend-customers
       namespace: default
     spec:
       selector:
         matchLabels:
             app: customers
             version: v1
       action: ALLOW
       rules:
       - from:
         - source:
             namespaces: ["default"]
           source:
             principals: ["cluster.local/ns/default/sa/web-frontend"]
    

    将上述 YAML 保存为 allow-web-frontend-customers.yaml,并使用 kubectl apply -f allow-web-frontend-customers.yaml 创建策略。

    一旦策略被创建,我们将看到 Web 前端再次工作——它将获得 customers 服务的回应。

    我们使用了多个授权策略,明确地允许从入口到前端以及从前端到 customers 服务的调用。使用 deny-all 策略是一个很好的开始,因为我们可以控制、管理,然后明确地允许我们希望在服务之间发生的通信。

    4.2 清理

    删除 Deployment、Service、VirtualService 和 Gateway:

     kubectl delete sa customers-v1 web-frontend
     kubectl delete deploy web-frontend customers-v1
     kubectl delete svc customers web-frontend
     kubectl delete vs customers web-frontend
     kubectl delete gateway gateway
     kubectl delete authorizationpolicy allow-ingress-frontend allow-web-frontend-customers deny-all
     kubectl delete pod curl
    
  • 相关阅读:
    vue3+ts实现Tab滚动居中
    【设计模式】设计模式
    【华为OD机试真题 python】 拼接url【2022 Q4 | 100分】
    mits6.081-lab2
    【mybatis2】MyBatis的执行流程分析
    C/C++面试题
    商单视频播放超2000万!农院改造为何屡被催更?
    【SSM框架】Spring笔记 --- 事务详解
    第三届国际品质节,群硕企业与OI产品共同获奖
    【English】十大词性之感叹词(感叹句)
  • 原文地址:https://www.cnblogs.com/renshengdezheli/p/16840393.html