mirror of https://github.com/istio/istio.io.git
[zh] Sync common-problems/security-issues/ (#15438)
This commit is contained in:
parent
a601124274
commit
e17e279356
|
|
@ -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。
|
||||
|
|
|
|||
Loading…
Reference in New Issue