基于角色的访问控制

在服务网格中为服务进行授权控制(基于角色的访问控制)时,会涉及到本例中包含的一系列操作。在授权一节中讲述了更多这方面的内容,并且还有一个基本的 Istio 安全方面的教程。

准备任务

本文活动开始之前,我们有如下假设:

  • 具有对授权概念的了解。

  • 在 Istio 中遵循快速入门的步骤 启用了认证功能,这个教程对双向 TLS 有依赖,因此要在安装步骤中启用双向 TLS 认证。

  • 部署 Bookinfo 示例应用。

  • Istio 1.0 中的 RBAC 有较大更新。请确认在继续之前,已经清理了所有现存 RBAC 规则。

    • 运行下面的命令,禁用旧的 RBAC 功能,在 1.0 中就无需这一步骤了:
    $ kubectl delete authorization requestcontext -n istio-system
    $ kubectl delete rbac handler -n istio-system
    $ kubectl delete rule rbaccheck -n istio-system
    
    • 用这个命令移除所有现存 RBAC 策略:
    $ kubectl delete servicerole --all
    $ kubectl delete servicerolebinding --all
    
  • 用浏览器打开 Bookinfo 的 productpage 页面,会看到:

    • 页面左下角是 “Book Details”,其中包含了类型、页数、出版商等信息。
    • 页面右下角是 “Book Reviews” 部分。

    如果刷新几次,会发现 productpage 在切换使用不同的 reviews 版本(红星、黑星、无)。

授权许可模式

本节介绍如何在以下两种情况下使用授权许可模式:

* 在未经授权的环境中,测试是否可以安全地启用授权。
* 在已启用授权的环境中,测试添加新授权策略是否安全。

测试启用全局授权是否安全

此任务说明如何使用授权许可模式来测试是否可以安全地启用全局授权。

在开始之前,请确保您已完成准备任务

  1. 将全局授权配置设置为许可模式。

    运行以下命令:

    $ kubectl apply -f - <<EOF
    apiVersion: "rbac.istio.io/v1alpha1"
    kind: RbacConfig
    metadata:
      name: default
    spec:
      mode: 'ON_WITH_INCLUSION'
      inclusion:
        namespaces: ["default"]
      enforcement_mode: PERMISSIVE
    EOF
    

    将浏览器指向 Bookinfo productpagehttp://$GATEWAY_URL/productpage),您应该看到一切正常,与准备任务相同。

  2. 将 YAML 文件应用于许可模式度量标准集合。

    运行以下命令:

    Zip
    $ kubectl apply -f @samples/bookinfo/platform/kube/rbac/rbac-permissive-telemetry.yaml@
    logentry.config.istio.io/rbacsamplelog created
    stdio.config.istio.io/rbacsamplehandler created
    rule.config.istio.io/rabcsamplestdio created
    
  3. 将流量发送到示例应用程序。

    对于 Bookinfo 示例,请在 Web 浏览器中访问 http://$GATEWAY_URL/productpage 或发出以下命令:

    $ curl http://$GATEWAY_URL/productpage
    

    将您的浏览器指向 Bookinfo productpagehttp://$GATEWAY_URL/productpage),您应该看到一切正常。

  4. 验证已创建日志流并检查 permissiveResponseCode

    在 Kubernetes 环境中,搜索日志以查找 istio-telemetry pods,如下所示:

    $ kubectl -n istio-system logs -l istio-mixer-type=telemetry -c mixer | grep \"instance\":\"rbacsamplelog.logentry.istio-system\"
    {"level":"warn","time":"2018-08-30T21:53:42.059444Z","instance":"rbacsamplelog.logentry.istio-system","destination":"ratings","latency":"9.158879ms","permissiveResponseCode":"403","permissiveResponsePolicyID":"","responseCode":200,"responseSize":48,"source":"reviews","user":"cluster.local/ns/default/sa/bookinfo-reviews"}
    {"level":"warn","time":"2018-08-30T21:53:41.037824Z","instance":"rbacsamplelog.logentry.istio-system","destination":"reviews","latency":"1.091670916s","permissiveResponseCode":"403","permissiveResponsePolicyID":"","responseCode":200,"responseSize":379,"source":"productpage","user":"cluster.local/ns/default/sa/bookinfo-productpage"}
    {"level":"warn","time":"2018-08-30T21:53:41.019851Z","instance":"rbacsamplelog.logentry.istio-system","destination":"productpage","latency":"1.112521495s","permissiveResponseCode":"403","permissiveResponsePolicyID":"","responseCode":200,"responseSize":5723,"source":"istio-ingressgateway","user":"cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"}
    

    在上面的遥测日志中,用户现在看到的 responseCode 是 200。 用户在将全局授权配置从 PERMISSIVE 模式切换到 ENFORCED 模式后将看到 permissiveResponseCode 是 403, 这表示全局授权配置在滚动到生产后将按预期工作。

  5. 在生产中推出新的授权策略之前,请以许可模式应用它。 注意,当全局授权配置处于许可模式时,默认情况下所有策略都将处于许可模式。

    运行以下命令:

    Zip
    $ kubectl apply -f @samples/bookinfo/platform/kube/rbac/productpage-policy.yaml@
    
  6. 再次向示例应用程序发送流量。

    对于 Bookinfo 示例,请在 Web 浏览器中访问 http://$GATEWAY_URL/productpage 或发出以下命令:

    $ curl http://$GATEWAY_URL/productpage
    

    将您的浏览器指向 Bookinfo productpagehttp://$GATEWAY_URL/productpage),您应该看到一切正常。

  7. 验证已创建日志流并检查 permissiveResponseCode

    在 Kubernetes 环境中,搜索日志以查找 istio-telemetry pods,如下所示:

    $ kubectl -n istio-system logs -l istio-mixer-type=telemetry -c mixer | grep \"instance\":\"rbacsamplelog.logentry.istio-system\"
    {"level":"warn","time":"2018-08-30T21:55:53.590430Z","instance":"rbacsamplelog.logentry.istio-system","destination":"ratings","latency":"4.415633ms","permissiveResponseCode":"403","permissiveResponsePolicyID":"","responseCode":200,"responseSize":48,"source":"reviews","user":"cluster.local/ns/default/sa/bookinfo-reviews"}
    {"level":"warn","time":"2018-08-30T21:55:53.565914Z","instance":"rbacsamplelog.logentry.istio-system","destination":"reviews","latency":"32.97524ms","permissiveResponseCode":"403","permissiveResponsePolicyID":"","responseCode":200,"responseSize":379,"source":"productpage","user":"cluster.local/ns/default/sa/bookinfo-productpage"}
    {"level":"warn","time":"2018-08-30T21:55:53.544441Z","instance":"rbacsamplelog.logentry.istio-system","destination":"productpage","latency":"57.800056ms","permissiveResponseCode":"200","permissiveResponsePolicyID":"productpage-viewer","responseCode":200,"responseSize":5723,"source":"istio-ingressgateway","user":"cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"}
    

    在上面的遥测日志中,用户现在看到的 responseCode 是 200。 对于 productpage 页面服务,permissiveResponseCode 为 200,对于 ratingsreviews 服务为 403, 这是用户在将策略模式从 PERMISSIVE 模式切换到 ENFORCED 模式后将看到的内容; 结果与步骤1一致。

  8. 删除与许可模式相关的 yaml 文件:

    ZipZipZip
    $ kubectl delete -f @samples/bookinfo/platform/kube/rbac/productpage-policy.yaml@
    $ kubectl delete -f @samples/bookinfo/platform/kube/rbac/rbac-config-on-permissive.yaml@
    $ kubectl delete -f @samples/bookinfo/platform/kube/rbac/rbac-permissive-telemetry.yaml@
    
  9. 现在我们已经验证了授权在打开时按预期工作,在启用 Istio 授权下面打开授权是安全的。

在滚动到生产之前,测试新的授权策略按预期工作

此任务说明如何使用授权许可模式来测试新授权策略在已启用授权的环境中按预期工作。

在开始之前,请确保您已完成步骤1

  1. 在应用新策略之前,通过将其模式设置为permissive来测试它:

    运行以下命令:

    Zip
    $ kubectl apply -f @samples/bookinfo/platform/kube/rbac/details-reviews-policy-permissive.yaml@
    

    该策略与允许访问详细信息和评论服务中定义的策略相同, 除了在 ServiceRoleBinding 中设置了 PERMISSIVE 模式。

    apiVersion: "rbac.istio.io/v1alpha1"
    kind: ServiceRoleBinding
    metadata:
      name: bind-details-reviews
      namespace: default
    spec:
      subjects:
      - user: "cluster.local/ns/default/sa/bookinfo-productpage"
      roleRef:
        kind: ServiceRole
        name: "details-reviews-viewer"
      mode: PERMISSIVE
    

    将您的浏览器指向 Bookinfo productpagehttp://$GATEWAY_URL/productpage), 您仍然会在页面上看到错误 Error fetching product detailsError fetching product reviews。由于策略处于 PERMISSIVE 模式,因此预期会出现这些错误。

  2. 将 YAML 文件应用于许可模式度量标准集合。

    运行以下命令:

    Zip
    $ kubectl apply -f @samples/bookinfo/platform/kube/rbac/rbac-permissive-telemetry.yaml@
    
  3. 将流量发送到示例应用程序。

    对于 Bookinfo 示例,请在 Web 浏览器中访问 http://$GATEWAY_URL/productpage 或发出以下命令:

    $ curl http://$GATEWAY_URL/productpage
    
  4. 验证日志并再次检查 permissiveResponseCode

    在 Kubernetes 环境中,搜索日志以查找 istio-telemetry pods,如下所示:

    $ kubectl -n istio-system logs -l istio-mixer-type=telemetry -c mixer | grep \"instance\":\"rbacsamplelog.logentry.istio-system\"
    {"level":"warn","time":"2018-08-30T22:59:42.707093Z","instance":"rbacsamplelog.logentry.istio-system","destination":"details","latency":"423.381µs","permissiveResponseCode":"200","permissiveResponsePolicyID":"details-reviews-viewer","responseCode":403,"responseSize":19,"source":"productpage","user":"cluster.local/ns/default/sa/bookinfo-productpage"}
    {"level":"warn","time":"2018-08-30T22:59:42.763423Z","instance":"rbacsamplelog.logentry.istio-system","destination":"reviews","latency":"237.333µs","permissiveResponseCode":"200","permissiveResponsePolicyID":"details-reviews-viewer","responseCode":403,"responseSize":19,"source":"productpage","user":"cluster.local/ns/default/sa/bookinfo-productpage"}
    

    在上面的遥测日志中,用户现在看到的 ratingsreviews 服务的 responseCode 为 403。 对于 ratingsreviews 服务,permissiveResponseCode 为 200, 这是用户在将策略模式从 PERMISSIVE 模式切换到 ENFORCED 模式后将看到的内容; 它表示新的授权策略在滚动到生产后将按预期工作。

  5. 删除与许可模式相关的 yaml 文件:

    ZipZip
    $ kubectl delete -f @samples/bookinfo/platform/kube/rbac/details-reviews-policy-permissive.yaml@
    $ kubectl delete -f @samples/bookinfo/platform/kube/rbac/rbac-permissive-telemetry.yaml@
    
  6. 现在我们已经验证了新策略将按预期工作,在步骤 2 应用策略之后是安全的。

启用 Istio 授权

运行下面的命令,为 default 命名空间启用 Istio 授权:

Zip
$ kubectl apply -f @samples/bookinfo/platform/kube/rbac/rbac-config-ON.yaml@

用浏览器再次打开 productpage (http://$GATEWAY_URL/productpage),这次会看到 RBAC: access denied。Istio 的鉴权行为是“缺省拒绝”的,也就是说必须要显式的进行授权,才能对服务进行访问。

命名空间级的访问控制

Istio 的授权能力可以轻松的设置命名空间级的访问控制,只要指定命名空间内的所有(或者部分)服务可以被另一命名空间的服务访问即可。

Bookinfo 示例中,productpagereviewsdetails 以及 ratings 服务被部署在 default 命名空间中,而 istio-ingressgateway 等 Istio 组件是部署在 istio-system 命名空间中的。我们可以定义一个策略,default 命名空间中所有服务,如果其 app 标签取值在 productpagereviewsdetails 以及 ratings 范围之内,就可以被本命名空间内以及 istio-system 命名空间内的服务进行访问。

运行这一命令,创建一个命名空间级别的访问控制策略:

Zip
$ kubectl apply -f @samples/bookinfo/platform/kube/rbac/namespace-policy.yaml@

这一策略完成如下任务:

  • 创建名为 service-viewerServiceRole,允许访问 default 命名空间中所有 app 标签值在 productpagereviewsdetails 以及 ratings 范围之内的服务。注意其中的 constraint 字段,确定了服务的 app 标签取值必须在指定范围以内:

    apiVersion: "rbac.istio.io/v1alpha1"
    kind: ServiceRole
    metadata:
      name: service-viewer
      namespace: default
    spec:
      rules:
      - services: ["*"]
        methods: ["GET"]
        constraints:
        - key: "destination.labels[app]"
          values: ["productpage", "details", "reviews", "ratings"]
    
  • 创建 ServiceRoleBinding 对象,用来把 service-viewer 角色指派给所有 istio-systemdefault 命名空间的服务:

    apiVersion: "rbac.istio.io/v1alpha1"
    kind: ServiceRoleBinding
    metadata:
      name: bind-service-viewer
      namespace: default
    spec:
      subjects:
      - properties:
          source.namespace: "istio-system"
      - properties:
          source.namespace: "default"
      roleRef:
        kind: ServiceRole
        name: "service-viewer"
    

命令执行结果大致如下:

servicerole "service-viewer" created
servicerolebinding "bind-service-viewer" created

如果这时用浏览器浏览 Bookinfo 的 productpage 页面 (http://$GATEWAY_URL/productpage),会再次看到完整的页面,包含了左下角的 “Book Details” 以及右下角的 “Book Reviews”。

清除命名空间级的访问控制

在进行后续任务之前,首先移除下面的配置:

Zip
$ kubectl delete -f @samples/bookinfo/platform/kube/rbac/namespace-policy.yaml@

服务级的访问控制

这个任务展示了使用 Istio 授权功能配置服务级访问控制的方法。开始之前,请进行下面的确认:

  • 已经启用 Istio 授权
  • 已经[清除命名空间级的访问控制](清除命名空间级的访问控制:

浏览器打开 Bookinfo 的 productpage (http://$GATEWAY_URL/productpage)。会看到:RBAC: access denied。我们会在 Bookinfo 中逐步为服务加入访问许可。

第一步,允许到 productpage 服务的访问

这里我们要创建一条策略,允许外部请求通过 Ingress 浏览 productpage

执行命令:

Zip
$ kubectl apply -f @samples/bookinfo/platform/kube/rbac/productpage-policy.yaml@

这条策略完成以下工作:

  • 创建 ServiceRole,命名为 productpage-viewer,允许到 productpage 服务的读取访问:

    apiVersion: "rbac.istio.io/v1alpha1"
    kind: ServiceRole
    metadata:
      name: productpage-viewer
      namespace: default
    spec:
      rules:
      - services: ["productpage.default.svc.cluster.local"]
        methods: ["GET"]
    
  • 创建 ServiceRole,并命名为 productpage-viewer,将 productpage-viewer 角色赋予给所有用户和服务:

    apiVersion: "rbac.istio.io/v1alpha1"
    kind: ServiceRoleBinding
    metadata:
      name: bind-productpager-viewer
      namespace: default
    spec:
      subjects:
      - user: "*"
      roleRef:
        kind: ServiceRole
        name: "productpage-viewer"
    

再次浏览 Bookinfo 的 productpage (http://$GATEWAY_URL/productpage)。应该能看到 “Bookinfo Sample” 页面了。但是还会显示 Error fetching product detailsError fetching product reviews 的错误信息。这是因为我们还没有给 productpage 访问 detailsreviews 服务的授权。我们接下来就修复这个问题。

第二步,允许对 detailsreviews 服务的访问

创建一条策略,让 productpage 服务能够读取 detailsreviews 服务。注意在准备任务中,我们给 productpage 服务创建了一个命名为 bookinfo-productpage 的 Service account,它就是 productpage 服务的认证 ID。

运行下面的命令:

Zip
$ kubectl apply -f @samples/bookinfo/platform/kube/rbac/details-reviews-policy.yaml@

这一策略完成以下任务:

  • 创建一个 ServiceRole,命名为 details-reviews-viewer,允许对 detailsreviews 服务进行只读访问。

    apiVersion: "rbac.istio.io/v1alpha1"
    kind: ServiceRole
    metadata:
      name: details-reviews-viewer
      namespace: default
    spec:
      rules:
      - services: ["details.default.svc.cluster.local", "reviews.default.svc.cluster.local"]
        methods: ["GET"]
    
  • 创建一个 ServiceRoleBinding 并命名为 bind-details-review,用来把 details-reviews-viewer 角色授予给 cluster.local/ns/default/sa/bookinfo-productpage(也就是 productpage 服务的 Service account)。

    apiVersion: "rbac.istio.io/v1alpha1"
    kind: ServiceRoleBinding
    metadata:
      name: bind-details-reviews
      namespace: default
    spec:
      subjects:
      - user: "cluster.local/ns/default/sa/bookinfo-productpage"
      roleRef:
        kind: ServiceRole
        name: "details-reviews-viewer"
    

浏览 Bookinfo 页面 productpage (http://$GATEWAY_URL/productpage)。现在看到的 “Bookinfo Sample” 中包含了左下角的 “Book Details” 以及右下角的 “Book Reviews”。然而 “Book Reviews” 中有一条错误信息: Ratings service currently unavailable,这是因为 reviews 服务无权访问 ratings 服务,要更正这一问题,就应该给 ratings 服务授权,使其能够访问 reviews 服务。下面的步骤就会完成这一需要。

第三步,允许对 ratings 服务的访问

接下来新建一条策略,允许 reviews 服务对 ratings 发起读取访问。注意,我们在准备任务步骤里为 reviews 服务创建了 Service account bookinfo-reviews,这个账号就是 reviews 服务的认证凭据。

下面的命令会创建一条允许 reviews 服务读取 ratings 服务的策略。

Zip
$ kubectl apply -f @samples/bookinfo/platform/kube/rbac/ratings-policy.yaml@

这条策略完成以下工作:

  • 创建 ServiceRole 命名为 ratings-viewer,这一角色允许对 ratings 服务的访问。

    apiVersion: "rbac.istio.io/v1alpha1"
    kind: ServiceRole
    metadata:
      name: ratings-viewer
      namespace: default
    spec:
      rules:
      - services: ["ratings.default.svc.cluster.local"]
        methods: ["GET"]
    
  • 创建 ServiceRoleBinding,命名为 bind-ratings,将 ratings-viewer 角色指派给 cluster.local/ns/default/sa/bookinfo-reviews,给这个 Service account 授权,也就就代表了给 reviews 服务授权。

    apiVersion: "rbac.istio.io/v1alpha1"
    kind: ServiceRoleBinding
    metadata:
      name: bind-ratings
      namespace: default
    spec:
      subjects:
      - user: "cluster.local/ns/default/sa/bookinfo-reviews"
      roleRef:
        kind: ServiceRole
        name: "ratings-viewer"
    

用浏览器浏览 Bookinfo 应用的 productpage (http://$GATEWAY_URL/productpage),应该就会看到 “Book Reviews” 区域中显示红色或者黑色的评级信息。

清理

  • 清理 Istio 授权策略的相关配置:

    ZipZipZip
    $ kubectl delete -f @samples/bookinfo/platform/kube/rbac/ratings-policy.yaml@
    $ kubectl delete -f @samples/bookinfo/platform/kube/rbac/details-reviews-policy.yaml@
    $ kubectl delete -f @samples/bookinfo/platform/kube/rbac/productpage-policy.yaml@
    

    或者也可以运行命令删除所有的 ServiceRole 以及 ServiceRoleBinding 资源:

    $ kubectl delete servicerole --all
    $ kubectl delete servicerolebinding --all
    
  • 禁用 Istio 的授权功能:

    Zip
    $ kubectl delete -f @samples/bookinfo/platform/kube/rbac/rbac-config-ON.yaml@