安全问题

    1. 如果 未设置,确保 JWT 发行者是 url 格式并且 url + /.well-known/openid-configuration 可以在浏览器中打开;例如,如果 JWT 发行者是 https://accounts.google.com,确保 https://accounts.google.com/.well-known/openid-configuration 是有效的 url,并且可以在浏览器中打开。

    2. 如果 JWT Token 放在 HTTP 请求头 Authorization 字段值中,需要确认 JWT Token 的有效性(未过期等)。JWT 令牌中的字段可以使用在线 JWT 解析工具进行解码,例如:。

    3. 通过 istioctl proxy-config 命令来验证目标负载的 Envoy 代理配置是否正确。

      当配置完成上面提到的策略实例后,可以使用以下的指令来检查 listener 在入站端口 80 上的配置。您应该可以看到 envoy.filters.http.jwt_authn 过滤器包含我们在策略中已经声明的发行者和 JWKS 信息。

      1. $ POD=$(kubectl get pod -l app=httpbin -n foo -o jsonpath={.items..metadata.name})
      2. $ istioctl proxy-config listener ${POD} -n foo --port 80 --type HTTP -o json
      3. <redacted>
      4. {
      5. "name": "envoy.filters.http.jwt_authn",
      6. "typedConfig": {
      7. "@type": "type.googleapis.com/envoy.config.filter.http.jwt_authn.v2alpha.JwtAuthentication",
      8. "providers": {
      9. "origins-0": {
      10. "issuer": "testing@secure.istio.io",
      11. "localJwks": {
      12. "inlineString": "*redacted*"
      13. },
      14. "payloadInMetadata": "testing@secure.istio.io"
      15. }
      16. },
      17. "rules": [
      18. {
      19. "match": {
      20. "prefix": "/"
      21. },
      22. "requires": {
      23. "requiresAny": {
      24. "requirements": [
      25. {
      26. "providerName": "origins-0"
      27. },
      28. {
      29. "allowMissing": {}
      30. }
      31. ]
      32. }
      33. }
      34. }
      35. ]
      36. }
      37. },
      38. <redacted>

    授权过于严格或者宽松

    一个常见的错误是无意中在 YAML 文件中定义了多个项,例如下面的策略:

    1. apiVersion: security.istio.io/v1beta1
    2. kind: AuthorizationPolicy
    3. metadata:
    4. name: example
    5. namespace: foo
    6. spec:
    7. action: ALLOW
    8. rules:
    9. - to:
    10. - operation:
    11. paths:
    12. - /foo
    13. - from:
    14. - source:
    15. namespaces:
    16. - foo

    您期望的策略所允许的请求是符合路径为 /foo and 源命名空间为 foo。但是,策略实际上允许的请求是符合路径为 /foo or 源命名空间为 foo,这显然会更加宽松。

    在 YAML 的语义中,from: 前面的 - 意味着这是列表中的一个新元素。这会在策略中创建两条规则,而不是所希望的一条。在认证策略中,多条规则之间是 OR 的关系。

    为了解决这个问题,只需要将多余的 - 移除,这样策略就只有一条规则来允许符合路径为 /foo and 源命名空间为 foo 的请求,这样就更加严格了。

    授权策略会变得更加严格因为定义了仅适用于 HTTP 的字段 (比如 hostpathheaders,JWT, 等等) 在纯 TCP 连接上是不存在的。

    对于 ALLOW 类的策略来说,这些字段不会被匹配。但对于 DENY 以及 CUSTOM 类策略来说,这类字段会被认为是始终匹配的。最终结果会是一个更加严格的策略从而可能导致意外的连接拒绝。

    检查 Kubernetes 服务定义来确定端口是。如果您在端口上使用了仅适用于 HTTP 的字段,要确保端口名有 http- 前缀。

    检查工作负载的选择器和命名空间来确认策略配置在了正确的目标上。您可以通过指令 istioctl x authz check POD-NAME.POD-NAMESPACE 来检查认证策略。

    • 如果没有声明,策略中默认动作是 ALLOW

    • 当一个工作负载上同时配置了多个动作时 (, ALLOWDENY), 所有的动作必须都满足。换句话说,如果有任何一个动作拒绝该请求,那么该请求会被拒绝,并且只有所有的动作都允许了该请求,该请求才会被允许。

    • 在任何情况下,AUDIT 动作不会实施控制访问权并且不会拒绝请求。

    1. 运行下列命令,导出 Istiod 的 ControlZ

      1. $ istioctl dashboard controlz $(kubectl -n istio-system get pods -l app=istiod -o jsonpath='{.items[0].metadata.name}').istio-system
    2. 等待浏览器打开后,点击左侧菜单 Logging Scopes

    3. 在步骤 1 中打开的终端窗口中输入 Ctrl+C,终止端口转发进程。

    4. 执行以下命令,输出 Pilot 日志并搜索 authorization

      你可能需要先删除并重建授权策略,以保证调试日志能够根据这些策略正常生成。

    5. 检查输出并验证:

      • 没有出现错误。
      • 出现 building v1beta1 policy 内容,意味着为目标服务生成了过滤器。
    6. 例如你可能会看到类似这样的内容:

      1. 2020-03-05T23:43:21.621339Z debug authorization found authorization allow policies for workload [app=ext-authz-server,pod-template-hash=5fd587cc9d,security.istio.io/tlsMode=istio,service.istio.io/canonical-name=ext-authz-server,service.istio.io/canonical-revision=latest] in foo
      2. 2020-03-05T23:43:21.621348Z debug authorization building filter for HTTP listener protocol
      3. 2020-03-05T23:43:21.621351Z debug authorization building v1beta1 policy
      4. 2020-03-05T23:43:21.621399Z debug authorization constructed internal model: &{Permissions:[{Services:[] Hosts:[] NotHosts:[] Paths:[] NotPaths:[] Methods:[] NotMethods:[] Ports:[] NotPorts:[] Constraints:[] AllowAll:true v1beta1:true}] Principals:[{Users:[] Names:[cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account] NotNames:[] Group: Groups:[] NotGroups:[] Namespaces:[] NotNamespaces:[] IPs:[] NotIPs:[] RequestPrincipals:[] NotRequestPrincipals:[] Properties:[] AllowAll:false v1beta1:true}]}
      5. 2020-03-05T23:43:21.621528Z info ads LDS: PUSH for node:sleep-6bdb595bcb-vmchz.foo listeners:38
      6. 2020-03-05T23:43:21.621997Z debug authorization generated policy ns[foo]-policy[ext-authz-server]-rule[0]: permissions:<and_rules:<rules:<any:true > > > principals:<and_ids:<ids:<or_ids:<ids:<metadata:<filter:"istio_authn" path:<key:"source.principal" > value:<string_match:<exact:"cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account" > > > > > > > >
      7. 2020-03-05T23:43:21.622052Z debug authorization added HTTP filter to filter chain 0
      8. 2020-03-05T23:43:21.623532Z debug authorization found authorization allow policies for workload [app=ext-authz-server,pod-template-hash=5fd587cc9d,security.istio.io/tlsMode=istio,service.istio.io/canonical-name=ext-authz-server,service.istio.io/canonical-revision=latest] in foo
      9. 2020-03-05T23:43:21.623543Z debug authorization building filter for TCP listener protocol
      10. 2020-03-05T23:43:21.623546Z debug authorization building v1beta1 policy
      11. 2020-03-05T23:43:21.623572Z debug authorization constructed internal model: &{Permissions:[{Services:[] Hosts:[] NotHosts:[] Paths:[] NotPaths:[] Methods:[] NotMethods:[] Ports:[] NotPorts:[] Constraints:[] AllowAll:true v1beta1:true}] Principals:[{Users:[] Names:[cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account] NotNames:[] Group: Groups:[] NotGroups:[] Namespaces:[] NotNamespaces:[] IPs:[] NotIPs:[] RequestPrincipals:[] NotRequestPrincipals:[] Properties:[] AllowAll:false v1beta1:true}]}
      12. 2020-03-05T23:43:21.623625Z debug authorization generated policy ns[foo]-policy[ext-authz-server]-rule[0]: permissions:<and_rules:<rules:<any:true > > > principals:<and_ids:<ids:<or_ids:<ids:<authenticated:<principal_name:<exact:"spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account" > > > > > > >
      13. 2020-03-05T23:43:21.623645Z debug authorization added TCP filter to filter chain 0
      14. 2020-03-05T23:43:21.623648Z debug authorization added TCP filter to filter chain 1

      说明 Istiod 生成了:

      • 对于带 app=ext-authz-server,... 标签的负载生成了带有 ns[foo]-policy[ext-authz-server]-rule[0] 策略的 HTTP 过滤器配置。

      • 对于带 app=ext-authz-server,... 标签的负载生成了带有 ns[foo]-policy[ext-authz-server]-rule[0] 策略的 TCP 过滤器配置。

    确认 Istiod 正确的将策略分发给了代理服务器

    Pilot 负责向代理服务器分发授权策略。下面的步骤用来确认 Pilot 按照预期工作:

    这一章节的命令假设用户已经部署了 Bookinfo,否则的话应该将 "-l app=productpage" 部分根据实际情况进行替换。

    1. 运行下面的命令,获取 productpage 服务的代理配置信息:

      1. $ kubectl exec $(kubectl get pods -l app=productpage -o jsonpath='{.items[0].metadata.name}') -c istio-proxy -- pilot-agent request GET config_dump
    2. 校验日志内容:

      • 日志中包含了一个 envoy.filters.http.rbac 过滤器,会对每一个进入的请求执行授权策略。
      • 授权策略更新之后,Istio 会据此更新过滤器。
      1. {
      2. "name": "envoy.filters.http.rbac",
      3. "config": {
      4. "rules": {
      5. "policies": {
      6. "productpage-viewer": {
      7. "permissions": [
      8. {
      9. "and_rules": {
      10. "rules": [
      11. {
      12. "or_rules": {
      13. "rules": [
      14. {
      15. "header": {
      16. "exact_match": "GET",
      17. "name": ":method"
      18. }
      19. }
      20. ]
      21. }
      22. }
      23. ]
      24. }
      25. }
      26. ],
      27. "principals": [
      28. {
      29. "and_ids": {
      30. "ids": [
      31. {
      32. "any": true
      33. }
      34. ]
      35. }
      36. }
      37. ]
      38. }
      39. }
      40. },
      41. "shadow_rules": {
      42. "policies": {}
      43. }
      44. },

    代理是授权策略的最终实施者。下面的步骤帮助用户确认代理的工作情况:

    这里的命令假设用户已经部署了 Bookinfo,否则的话应该将 "-l app=productpage" 部分根据实际情况进行替换。

    1. 使用以下命令,在代理中打开授权调试日志:

    2. 在浏览器中打开 productpage,以便生成日志。

    3. 使用以下命令打印代理日志:

      1. $ kubectl logs $(kubectl get pods -l app=productpage -o jsonpath='{.items[0].metadata.name}') -c istio-proxy
    4. 检查输出,并验证:

      • 根据请求被允许或者被拒绝,分别输出日志包含 enforced allowed 或这 enforced denied

      • 授权策略需要从请求中获取数据。

    5. 下面的输出表示,对 productpageGET 请求被策略放行。shadow denied 没有什么影响,你可以放心的忽略它。

      1. ...
      2. [2018-07-26 20:39:18.060][152][debug][rbac] external/envoy/source/extensions/filters/http/rbac/rbac_filter.cc:79] checking request: remoteAddress: 10.60.0.139:51158, localAddress: 10.60.0.93:9080, ssl: uriSanPeerCertificate: spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account, subjectPeerCertificate: O=, headers: ':authority', '35.238.0.62'
      3. ':path', '/productpage'
      4. ':method', 'GET'
      5. 'upgrade-insecure-requests', '1'
      6. 'user-agent', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
      7. 'dnt', '1'
      8. 'accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8'
      9. 'accept-encoding', 'gzip, deflate'
      10. 'accept-language', 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7'
      11. 'x-forwarded-for', '10.60.0.1'
      12. 'x-forwarded-proto', 'http'
      13. 'x-request-id', 'e23ea62d-b25d-91be-857c-80a058d746d4'
      14. 'x-b3-traceid', '5983108bf6d05603'
      15. 'x-b3-spanid', '5983108bf6d05603'
      16. 'x-b3-sampled', '1'
      17. 'x-istio-attributes', 'CikKGGRlc3RpbmF0aW9uLnNlcnZpY2UubmFtZRINEgtwcm9kdWN0cGFnZQoqCh1kZXN0aW5hdGlvbi5zZXJ2aWNlLm5hbWVzcGFjZRIJEgdkZWZhdWx0Ck8KCnNvdXJjZS51aWQSQRI/a3ViZXJuZXRlczovL2lzdGlvLWluZ3Jlc3NnYXRld2F5LTc2NjY0Y2NmY2Ytd3hjcjQuaXN0aW8tc3lzdGVtCj4KE2Rlc3RpbmF0aW9uLnNlcnZpY2USJxIlcHJvZHVjdHBhZ2UuZGVmYXVsdC5zdmMuY2x1c3Rlci5sb2NhbApDChhkZXN0aW5hdGlvbi5zZXJ2aWNlLmhvc3QSJxIlcHJvZHVjdHBhZ2UuZGVmYXVsdC5zdmMuY2x1c3Rlci5sb2NhbApBChdkZXN0aW5hdGlvbi5zZXJ2aWNlLnVpZBImEiRpc3RpbzovL2RlZmF1bHQvc2VydmljZXMvcHJvZHVjdHBhZ2U='
      18. 'content-length', '0'
      19. 'x-envoy-internal', 'true'
      20. 'sec-istio-authn-payload', 'CkVjbHVzdGVyLmxvY2FsL25zL2lzdGlvLXN5c3RlbS9zYS9pc3Rpby1pbmdyZXNzZ2F0ZXdheS1zZXJ2aWNlLWFjY291bnQSRWNsdXN0ZXIubG9jYWwvbnMvaXN0aW8tc3lzdGVtL3NhL2lzdGlvLWluZ3Jlc3NnYXRld2F5LXNlcnZpY2UtYWNjb3VudA=='
      21. , dynamicMetadata: filter_metadata {
      22. key: "istio_authn"
      23. value {
      24. fields {
      25. key: "request.auth.principal"
      26. value {
      27. string_value: "cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"
      28. }
      29. }
      30. fields {
      31. key: "source.principal"
      32. value {
      33. string_value: "cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"
      34. }
      35. }
      36. }
      37. }
      38. [2018-07-26 20:39:18.060][152][debug][rbac] external/envoy/source/extensions/filters/http/rbac/rbac_filter.cc:88] shadow denied
      39. [2018-07-26 20:39:18.060][152][debug][rbac] external/envoy/source/extensions/filters/http/rbac/rbac_filter.cc:98] enforced allowed
      40. ...

    密钥和证书错误

    如果您怀疑 Istio 使用的某些密钥或证书不正确,您可以检查任何 Pod 的内容信息。

    通过 -o json 标记,您可以将证书的全部内容传递给 openssl 来分析其内容:

    1. $ istioctl proxy-config secret sleep-8f795f47d-4s4t7 -o json | jq '[.dynamicActiveSecrets[] | select(.name == "default")][0].secret.tlsCertificate.certificateChain.inlineBytes' -r | base64 -d | openssl x509 -noout -text
    2. Certificate:
    3. Data:
    4. Version: 3 (0x2)
    5. Serial Number:
    6. 99:59:6b:a2:5a:f4:20:f4:03:d7:f0:bc:59:f5:d8:40
    7. Signature Algorithm: sha256WithRSAEncryption
    8. Issuer: O = k8s.cluster.local
    9. Validity
    10. Not Before: Jun 4 20:38:20 2018 GMT
    11. Not After : Sep 2 20:38:20 2018 GMT
    12. ...
    13. X509v3 extensions:
    14. X509v3 Key Usage: critical
    15. Digital Signature, Key Encipherment
    16. X509v3 Extended Key Usage:
    17. TLS Web Server Authentication, TLS Web Client Authentication
    18. X509v3 Basic Constraints: critical
    19. CA:FALSE
    20. X509v3 Subject Alternative Name:
    21. URI:spiffe://cluster.local/ns/my-ns/sa/my-sa
    22. ...

    确保显示的证书包含有效信息。特别是,Subject Alternative Name 字段应为 URI:spiffe://cluster.local/ns/my-ns/sa/my-sa

    如果怀疑双向 TLS 出现了问题,首先要确认 ,接下来要查看的是密钥和证书正确下发 Sidecar.

    如果上述检查都正确无误,下一步就应该验证已经创建,并且对应的目标规则是否正确应用。