[zh] Sync common-problems/security-issues/ (#15438)

This commit is contained in:
Michael 2024-07-18 15:31:17 +08:00 committed by GitHub
parent a601124274
commit e17e279356
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 131 additions and 66 deletions

View File

@ -1,6 +1,6 @@
---
title: 安全问题
description: 定位常见 Istio 认证、授权、安全相关问题的技巧。
description: 定位 Istio 认证、授权、安全相关等常见问题的技巧。
force_inline_toc: true
weight: 20
keywords: [security,citadel]
@ -14,7 +14,7 @@ test: n/a
## 终端用户认证失败 {#end-user-authentication-fails}
使用 Istio可以通过[请求认证策略](/zh/docs/tasks/security/authentication/authn-policy/#end-user-authentication)启用终端用户认证。
使用 Istio可以通过[请求认证策略](/zh/docs/tasks/security/authentication/authn-policy/#end-user-authentication)启用终端用户认证。
目前Istio 认证策略提供的终端用户凭证是 JWT。以下是排查终端用户 JWT
身份认证问题的指南。
@ -25,8 +25,8 @@ test: n/a
是有效的 url并且可以在浏览器中打开。
{{< text yaml >}}
apiVersion: "security.istio.io/v1beta1"
kind: "RequestAuthentication"
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
name: "example-3"
spec:
@ -38,13 +38,13 @@ test: n/a
jwksUri: "{{< github_file >}}/security/tools/jwt/samples/jwks.json"
{{< /text >}}
1. 如果 JWT Token 放在 HTTP 请求头 Authorization 字段值中,需要确认
JWT Token 的有效性未过期等。JWT 令牌中的字段可以使用在线 JWT 解析工具进行解码,
例如:[jwt.io](https://jwt.io/)。
1. 如果 JWT 令牌放在 HTTP 请求头 Authorization 字段值中,需要确认
JWT 令牌的有效性未过期等。JWT 令牌中的字段可以使用
[jwt.io](https://jwt.io/) 这类在线 JWT 解析工具进行解码
1. 通过 `istioctl proxy-config` 命令来验证目标负载的 Envoy 代理配置是否正确。
当配置完成上面提到的策略例后,可以使用以下的指令来检查 `listener` 在入站端口
当配置完成上面提到的策略例后,可以使用以下的指令来检查 `listener` 在入站端口
`80` 上的配置。您应该可以看到 `envoy.filters.http.jwt_authn` 过滤器包含我们在策略中已经声明的发行者和
JWKS 信息。
@ -127,8 +127,8 @@ spec:
### 确保您没有在 TCP 端口上使用仅适用于 HTTP 的字段 {#make-sure-you-are-not-using-http-only-fields-on-tcp-ports}
授权策略会变得更加严格因为定义了仅适用于 HTTP 的字段 (比如 `host``path`
`headers`JWT等等) 在纯 TCP 连接上是不存在的。
授权策略会变得更加严格因为定义了仅适用于 HTTP 的字段
(比如 `host`、`path`、`headers`、JWT 等等) 在纯 TCP 连接上是不存在的。
对于 `ALLOW` 类的策略来说,这些字段不会被匹配。但对于 `DENY` 以及 `CUSTOM`
类策略来说,这类字段会被认为是始终匹配的。最终结果会是一个更加严格的策略从而可能导致意外的连接拒绝。
@ -145,7 +145,7 @@ spec:
- 如果没有声明,策略中默认动作是 `ALLOW`
- 当一个工作负载上同时配置了多个动作时(`CUSTOM``ALLOW` 和 `DENY`
- 当一个工作负载上同时配置了多个动作时(`CUSTOM``ALLOW` 和 `DENY`
所有的动作必须都满足。换句话说,如果有任何一个动作拒绝该请求,那么该请求会被拒绝,
并且只有所有的动作都允许了该请求,该请求才会被允许。
@ -155,7 +155,7 @@ spec:
## 确保 Istiod 接受策略 {#ensure-istiod-accepts-the-policies}
Istiod 负责对授权策略进行转换,并将其分发给 Sidecar。下面的步骤可以用于确认
Istiod 负责对授权策略进行转换,并将其分发给 Sidecar。下面的步骤可以用于确认
Istiod 是否按预期在工作:
1. 运行以下命令启用 Istiod 的调试日志记录:
@ -220,37 +220,38 @@ Istiod 是否按预期在工作:
- 适用于工作负载 `httpbin-74fb669cc6-lpscm.foo` 且带有策略
`ns[foo]-policy[deny-path-headers]-rule[0]` 的 TCP 过滤器配置。
## 确认 Istiod 正确的将策略分发给了代理服务器 {#ensure-istiod-distributes-policies-to-proxies-correctly}
## 确认 Istiod 正确地将策略分发给了代理 {#ensure-istiod-distributes-policies-to-proxies-correctly}
Pilot 负责向代理服务器分发授权策略。下面的步骤用来确认 Pilot 按照预期工作:
Pilot 负责向代理分发授权策略。下面的步骤用来确认 Pilot 按照预期工作:
{{< tip >}}
这一章节的命令假设用户已经部署了 [Bookinfo](/zh/docs/examples/bookinfo/)
否则的话应该将 `"-l app=productpage"` 部分根据实际情况进行替换
以下命令假设您已经部署了 [Bookinfo](/zh/docs/examples/bookinfo/)
如果您未使用 `httpbin`,则应该根据实际情况来替换 `"-l app=httpbin"`
{{< /tip >}}
1. 运行下面的命令,获取 `productpage` 服务的代理配置信息:
1. 运行下面的命令,获取 `httpbin` 工作负载的代理配置信息:
{{< text bash >}}
$ kubectl exec $(kubectl get pods -l app=productpage -o jsonpath='{.items[0].metadata.name}') -c istio-proxy -- pilot-agent request GET config_dump
$ kubectl exec $(kubectl get pods -l app=httpbin -o jsonpath='{.items[0].metadata.name}') -c istio-proxy -- pilot-agent request GET config_dump
{{< /text >}}
1. 校验日志内容:
- 日志中包含了一个 `envoy.filters.http.rbac` 过滤器,会对每一个进入的请求执行授权策略。
- 授权策略更新之后Istio 会据此更新过滤器。
- 日志中包含了一个 `envoy.filters.http.rbac` 过滤器,会对每一个进入的请求强制执行授权策略。
- 您更新授权策略之后Istio 会据此更新过滤器。
1. 下面的输出表明,`productpage` 的代理启用了 `envoy.filters.http.rbac` 过滤器,
配置的规则为允许任何人通过 `GET` 方法进行访问 `productpage` 服务。`shadow_rules`
没有生效,可以放心的忽略它。
1. 下面的输出表明,`httpbin` 的代理启用了 `envoy.filters.http.rbac` 过滤器,
配置的规则为拒绝所有人访问 `/headers` 路径。
{{< text plain >}}
{
"name": "envoy.filters.http.rbac",
"config": {
"typed_config": {
"@type": "type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC",
"rules": {
"action": "DENY",
"policies": {
"productpage-viewer": {
"ns[foo]-policy[deny-path-headers]-rule[0]": {
"permissions": [
{
"and_rules": {
@ -259,9 +260,10 @@ Pilot 负责向代理服务器分发授权策略。下面的步骤用来确认 P
"or_rules": {
"rules": [
{
"header": {
"exact_match": "GET",
"name": ":method"
"url_path": {
"path": {
"exact": "/headers"
}
}
}
]
@ -285,26 +287,24 @@ Pilot 负责向代理服务器分发授权策略。下面的步骤用来确认 P
}
}
},
"shadow_rules": {
"policies": {}
}
"shadow_rules_stat_prefix": "istio_dry_run_allow_"
}
},
{{< /text >}}
## 确认策略在代理服务器中正确执行 {#ensure-proxies-enforce-policies-correctly}
## 确认策略在代理中正确执行 {#ensure-proxies-enforce-policies-correctly}
代理是授权策略的最终实施者。下面的步骤帮助用户确认代理的工作情况
代理是授权策略的最终实施者。下面的步骤帮助用户确认代理是否按预期工作
{{< tip >}}
这里的命令假设用户已经部署了 [Bookinfo](/zh/docs/examples/bookinfo/)
否则的话应该将 `"-l app=productpage"` 部分根据实际情况进行替换
以下命令假设您已经部署了 `httpbin`,如果您没有使用 `httpbin`
则应将 `"-l app=httpbin"` 替换为实际的 Pod
{{< /tip >}}
1. 使用以下命令,在代理中打开授权调试日志:
{{< text bash >}}
$ kubectl exec $(kubectl get pods -l app=productpage -o jsonpath='{.items[0].metadata.name}') -c istio-proxy -- pilot-agent request POST 'logging?rbac=debug'
$ istioctl proxy-config log deploy/httpbin --level "rbac:debug"
{{< /text >}}
1. 确认可以看到以下输出:
@ -316,12 +316,12 @@ Pilot 负责向代理服务器分发授权策略。下面的步骤用来确认 P
... ...
{{< /text >}}
1. 在浏览器中打开 `productpage`,以便生成日志。
1. 发送一些请求到 `httpbin` 工作负载以生成一些日志。
1. 使用以下命令打印代理日志:
{{< text bash >}}
$ kubectl logs $(kubectl get pods -l app=productpage -o jsonpath='{.items[0].metadata.name}') -c istio-proxy
$ kubectl logs $(kubectl get pods -l app=httpbin -o jsonpath='{.items[0].metadata.name}') -c istio-proxy
{{< /text >}}
1. 检查输出,并验证:
@ -330,53 +330,118 @@ Pilot 负责向代理服务器分发授权策略。下面的步骤用来确认 P
- 授权策略需要从请求中获取数据。
1. 下面的输出表示,对 `productpage``GET` 请求被策略放行。`shadow denied` 没有什么影响,
您可以放心的忽略它。
1. 以下是在 `/httpbin` 路径处请求的输出示例:
{{< text plain >}}
...
[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'
':path', '/productpage'
2021-04-23T20:43:18.552857Z debug envoy rbac checking request: requestedServerName: outbound_.8000_._.httpbin.foo.svc.cluster.local, sourceIP: 10.44.3.13:46180, directRemoteIP: 10.44.3.13:46180, remoteIP: 10.44.3.13:46180,localAddress: 10.44.1.18:80, ssl: uriSanPeerCertificate: spiffe://cluster.local/ns/foo/sa/sleep, dnsSanPeerCertificate: , subjectPeerCertificate: , headers: ':authority', 'httpbin:8000'
':path', '/headers'
':method', 'GET'
'upgrade-insecure-requests', '1'
'user-agent', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
'dnt', '1'
'accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8'
'accept-encoding', 'gzip, deflate'
'accept-language', 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7'
'x-forwarded-for', '10.60.0.1'
':scheme', 'http'
'user-agent', 'curl/7.76.1-DEV'
'accept', '*/*'
'x-forwarded-proto', 'http'
'x-request-id', 'e23ea62d-b25d-91be-857c-80a058d746d4'
'x-b3-traceid', '5983108bf6d05603'
'x-b3-spanid', '5983108bf6d05603'
'x-b3-sampled', '1'
'x-istio-attributes', 'CikKGGRlc3RpbmF0aW9uLnNlcnZpY2UubmFtZRINEgtwcm9kdWN0cGFnZQoqCh1kZXN0aW5hdGlvbi5zZXJ2aWNlLm5hbWVzcGFjZRIJEgdkZWZhdWx0Ck8KCnNvdXJjZS51aWQSQRI/a3ViZXJuZXRlczovL2lzdGlvLWluZ3Jlc3NnYXRld2F5LTc2NjY0Y2NmY2Ytd3hjcjQuaXN0aW8tc3lzdGVtCj4KE2Rlc3RpbmF0aW9uLnNlcnZpY2USJxIlcHJvZHVjdHBhZ2UuZGVmYXVsdC5zdmMuY2x1c3Rlci5sb2NhbApDChhkZXN0aW5hdGlvbi5zZXJ2aWNlLmhvc3QSJxIlcHJvZHVjdHBhZ2UuZGVmYXVsdC5zdmMuY2x1c3Rlci5sb2NhbApBChdkZXN0aW5hdGlvbi5zZXJ2aWNlLnVpZBImEiRpc3RpbzovL2RlZmF1bHQvc2VydmljZXMvcHJvZHVjdHBhZ2U='
'content-length', '0'
'x-envoy-internal', 'true'
'sec-istio-authn-payload', 'CkVjbHVzdGVyLmxvY2FsL25zL2lzdGlvLXN5c3RlbS9zYS9pc3Rpby1pbmdyZXNzZ2F0ZXdheS1zZXJ2aWNlLWFjY291bnQSRWNsdXN0ZXIubG9jYWwvbnMvaXN0aW8tc3lzdGVtL3NhL2lzdGlvLWluZ3Jlc3NnYXRld2F5LXNlcnZpY2UtYWNjb3VudA=='
'x-request-id', '672c9166-738c-4865-b541-128259cc65e5'
'x-envoy-attempt-count', '1'
'x-b3-traceid', '8a124905edf4291a21df326729b264e9'
'x-b3-spanid', '21df326729b264e9'
'x-b3-sampled', '0'
'x-forwarded-client-cert', 'By=spiffe://cluster.local/ns/foo/sa/httpbin;Hash=d64cd6750a3af8685defbbe4dd8c467ebe80f6be4bfe9ca718e81cd94129fc1d;Subject="";URI=spiffe://cluster.local/ns/foo/sa/sleep'
, dynamicMetadata: filter_metadata {
key: "istio_authn"
value {
fields {
key: "request.auth.principal"
value {
string_value: "cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"
string_value: "cluster.local/ns/foo/sa/sleep"
}
}
fields {
key: "source.namespace"
value {
string_value: "foo"
}
}
fields {
key: "source.principal"
value {
string_value: "cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"
string_value: "cluster.local/ns/foo/sa/sleep"
}
}
fields {
key: "source.user"
value {
string_value: "cluster.local/ns/foo/sa/sleep"
}
}
}
}
[2018-07-26 20:39:18.060][152][debug][rbac] external/envoy/source/extensions/filters/http/rbac/rbac_filter.cc:88] shadow denied
[2018-07-26 20:39:18.060][152][debug][rbac] external/envoy/source/extensions/filters/http/rbac/rbac_filter.cc:98] enforced allowed
2021-04-23T20:43:18.552910Z debug envoy rbac enforced denied, matched policy ns[foo]-policy[deny-path-headers]-rule[0]
...
{{< /text >}}
日志 `enforced denied, matched policy ns[foo]-policy[deny-path-headers]-rule[0]`
意味着请求被策略 `ns[foo]-policy[deny-path-headers]-rule[0]` 拒绝。
1. 以下是[模拟运行模式](/zh/docs/tasks/security/authorization/authz-dry-run)下授权策略的输出示例:
{{< text plain >}}
...
2021-04-23T20:59:11.838468Z debug envoy rbac checking request: requestedServerName: outbound_.8000_._.httpbin.foo.svc.cluster.local, sourceIP: 10.44.3.13:49826, directRemoteIP: 10.44.3.13:49826, remoteIP: 10.44.3.13:49826,localAddress: 10.44.1.18:80, ssl: uriSanPeerCertificate: spiffe://cluster.local/ns/foo/sa/sleep, dnsSanPeerCertificate: , subjectPeerCertificate: , headers: ':authority', 'httpbin:8000'
':path', '/headers'
':method', 'GET'
':scheme', 'http'
'user-agent', 'curl/7.76.1-DEV'
'accept', '*/*'
'x-forwarded-proto', 'http'
'x-request-id', 'e7b2fdb0-d2ea-4782-987c-7845939e6313'
'x-envoy-attempt-count', '1'
'x-b3-traceid', '696607fc4382b50017c1f7017054c751'
'x-b3-spanid', '17c1f7017054c751'
'x-b3-sampled', '0'
'x-forwarded-client-cert', 'By=spiffe://cluster.local/ns/foo/sa/httpbin;Hash=d64cd6750a3af8685defbbe4dd8c467ebe80f6be4bfe9ca718e81cd94129fc1d;Subject="";URI=spiffe://cluster.local/ns/foo/sa/sleep'
, dynamicMetadata: filter_metadata {
key: "istio_authn"
value {
fields {
key: "request.auth.principal"
value {
string_value: "cluster.local/ns/foo/sa/sleep"
}
}
fields {
key: "source.namespace"
value {
string_value: "foo"
}
}
fields {
key: "source.principal"
value {
string_value: "cluster.local/ns/foo/sa/sleep"
}
}
fields {
key: "source.user"
value {
string_value: "cluster.local/ns/foo/sa/sleep"
}
}
}
}
2021-04-23T20:59:11.838529Z debug envoy rbac shadow denied, matched policy ns[foo]-policy[deny-path-headers]-rule[0]
2021-04-23T20:59:11.838538Z debug envoy rbac no engine, allowed by default
...
{{< /text >}}
日志 `shadow denied, matched policy ns[foo]-policy[deny-path-headers]-rule[0]`
意味着请求将会被**模拟运行**策略 `ns[foo]-policy[deny-path-headers]-rule[0]` 拒绝。
日志 `no engine, allowed by default` 意味着请求实际上是被允许的,
因为模拟运行策略是工作负载上唯一的策略。
## 密钥和证书错误 {#keys-and-certificates-errors}
如果您怀疑 Istio 使用的某些密钥或证书不正确,您可以检查任何 Pod 的内容信息。
@ -415,18 +480,18 @@ Certificate:
...
{{< /text >}}
确保显示的证书包含有效信息。特别是Subject Alternative Name 字段应为
确保显示的证书包含有效信息。特别是,`Subject Alternative Name` 字段应为
`URI:spiffe://cluster.local/ns/my-ns/sa/my-sa`
## 双向 TLS 错误 {#mutual-TLS-errors}
如果怀疑双向 TLS 出现了问题,首先要确认 istiod 的健康状态,
接下来要查看的是[密钥和证书正确下发](#keys-and-certificates-errors) Sidecar。
接下来要查看的是[密钥和证书正确下发到了](#keys-and-certificates-errors) Sidecar。
如果上述检查都正确无误,下一步就应该验证[认证策略](/zh/docs/tasks/security/authentication/authn-policy/)已经创建,
并且对应的目标规则是否正确应用。
如果您怀疑客户端 Sidecar 可能不正确地发送双向 TLS 或明文流量,
请检查 [Grafana Workload dashboard](/zh/docs/ops/integrations/grafana/)。
无论是否使用 mTLS都对出站请求进行注释。检查后,如果您认为客户端 Sidecar 是错误的,
报一个 issue 在 GitHub
请检查 [Grafana 工作负载仪表盘](/zh/docs/ops/integrations/grafana/)。
无论是否使用 mTLS都对出站请求添加注解。检查后,如果您认为客户端 Sidecar 是错误的,
请在 GitHub 上提交一个 Issue