安全问题
最终用户身份验证失败
使用 Istio,您可以通过 请求身份验证策略 为最终用户启用身份验证。按照以下步骤排查策略规范。
如果未设置
jwksUri
,请确保 JWT 发行者采用 url 格式,并且可以在浏览器中打开url + /.well-known/openid-configuration
;例如,如果 JWT 发行者为https://#
,请确保https://#/.well-known/openid-configuration
是一个有效的 url,并且可以在浏览器中打开。apiVersion: security.istio.io/v1 kind: RequestAuthentication metadata: name: "example-3" spec: selector: matchLabels: app: httpbin jwtRules: - issuer: "testing@secure.istio.io" jwksUri: "https://raw.githubusercontent.com/istio/istio/release-1.24/security/tools/jwt/samples/jwks.json"
如果 JWT 令牌放置在 HTTP 请求的 Authorization 标头中,请确保 JWT 令牌有效(未过期等)。JWT 令牌中的字段可以通过使用在线 JWT 解析工具进行解码,例如 jwt.io。
使用
istioctl proxy-config
命令验证目标工作负载的 Envoy 代理配置。应用上述示例策略后,使用以下命令检查入站端口
80
上的listener
配置。您应该看到envoy.filters.http.jwt_authn
过滤器,其设置与策略中指定的颁发者和 JWKS 相匹配。$ POD=$(kubectl get pod -l app=httpbin -n foo -o jsonpath={.items..metadata.name}) $ istioctl proxy-config listener ${POD} -n foo --port 80 --type HTTP -o json <redacted> { "name": "envoy.filters.http.jwt_authn", "typedConfig": { "@type": "type.googleapis.com/envoy.config.filter.http.jwt_authn.v2alpha.JwtAuthentication", "providers": { "origins-0": { "issuer": "testing@secure.istio.io", "localJwks": { "inlineString": "*redacted*" }, "payloadInMetadata": "testing@secure.istio.io" } }, "rules": [ { "match": { "prefix": "/" }, "requires": { "requiresAny": { "requirements": [ { "providerName": "origins-0" }, { "allowMissing": {} } ] } } } ] } }, <redacted>
授权过于严格或宽松
确保策略 YAML 文件中没有错别字
一个常见的错误是在 YAML 中无意中指定多个项目。以以下策略为例
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: example
namespace: foo
spec:
action: ALLOW
rules:
- to:
- operation:
paths:
- /foo
- from:
- source:
namespaces:
- foo
您可能希望策略允许请求,如果路径为 /foo
并且 源命名空间为 foo
。但是,策略实际上允许请求,如果路径为 /foo
或者 源命名空间为 foo
,这更加宽松。
在 YAML 语法中,from:
前面的 -
表示它是列表中的一个新元素。这在策略中创建了 2 个规则,而不是 1 个。在授权策略中,多个规则具有 OR
的语义。
要解决此问题,只需删除多余的 -
,使策略只有一个规则,该规则允许请求,如果路径为 /foo
并且 源命名空间为 foo
,这更加严格。
确保您没有在 TCP 端口上使用 HTTP 专用字段
授权策略将更加严格,因为 HTTP 专用字段(例如 host
、path
、headers
、JWT 等)在原始 TCP 连接中不存在。
在 ALLOW
策略的情况下,这些字段永远不会匹配。在 DENY
和 CUSTOM
操作的情况下,这些字段被认为始终匹配。最终效果是更严格的策略,可能会导致意外拒绝。
检查 Kubernetes 服务定义,以验证端口是否 以正确协议命名。如果您在端口上使用 HTTP 专用字段,请确保端口名称带有 http-
前缀。
确保策略应用于正确的目标
检查工作负载选择器和命名空间,以确认它应用于正确的目标。您可以通过运行 istioctl x authz check POD-NAME.POD-NAMESPACE
来确定生效的授权策略。
注意策略中指定的动作
如果没有指定,策略默认使用操作
ALLOW
。当工作负载同时应用多个操作(
CUSTOM
、ALLOW
和DENY
)时,必须满足所有操作才能允许请求。换句话说,如果任何操作拒绝,则拒绝请求;只有在所有操作都允许的情况下才能允许请求。AUDIT
操作不会执行访问控制,在任何情况下都不会拒绝请求。
阅读 授权隐式启用,了解评估顺序的更多详细信息。
确保 Istiod 接受策略
Istiod 将您的授权策略转换为代理并分发给代理。以下步骤将帮助您确保 Istiod 按预期工作
运行以下命令以启用 Istiod 中的调试日志记录
$ istioctl admin log --level authorization:debug
使用以下命令获取 Istiod 日志
$ kubectl logs $(kubectl -n istio-system get pods -l app=istiod -o jsonpath='{.items[0].metadata.name}') -c discovery -n istio-system
检查输出并验证是否存在错误。例如,您可能会看到类似以下内容
2021-04-23T20:53:29.507314Z info ads Push debounce stable[31] 1: 100.981865ms since last change, 100.981653ms since last push, full=true 2021-04-23T20:53:29.507641Z info ads XDS: Pushing:2021-04-23T20:53:29Z/23 Services:15 ConnectedEndpoints:2 Version:2021-04-23T20:53:29Z/23 2021-04-23T20:53:29.507911Z debug authorization Processed authorization policy for httpbin-74fb669cc6-lpscm.foo with details: * found 0 CUSTOM actions 2021-04-23T20:53:29.508077Z debug authorization Processed authorization policy for curl-557747455f-6dxbl.foo with details: * found 0 CUSTOM actions 2021-04-23T20:53:29.508128Z debug authorization Processed authorization policy for httpbin-74fb669cc6-lpscm.foo with details: * found 1 DENY actions, 0 ALLOW actions, 0 AUDIT actions * generated config from rule ns[foo]-policy[deny-path-headers]-rule[0] on HTTP filter chain successfully * built 1 HTTP filters for DENY action * added 1 HTTP filters to filter chain 0 * added 1 HTTP filters to filter chain 1 2021-04-23T20:53:29.508158Z debug authorization Processed authorization policy for curl-557747455f-6dxbl.foo with details: * found 0 DENY actions, 0 ALLOW actions, 0 AUDIT actions 2021-04-23T20:53:29.509097Z debug authorization Processed authorization policy for curl-557747455f-6dxbl.foo with details: * found 0 CUSTOM actions 2021-04-23T20:53:29.509167Z debug authorization Processed authorization policy for curl-557747455f-6dxbl.foo with details: * found 0 DENY actions, 0 ALLOW actions, 0 AUDIT actions 2021-04-23T20:53:29.509501Z debug authorization Processed authorization policy for httpbin-74fb669cc6-lpscm.foo with details: * found 0 CUSTOM actions 2021-04-23T20:53:29.509652Z debug authorization Processed authorization policy for httpbin-74fb669cc6-lpscm.foo with details: * found 1 DENY actions, 0 ALLOW actions, 0 AUDIT actions * generated config from rule ns[foo]-policy[deny-path-headers]-rule[0] on HTTP filter chain successfully * built 1 HTTP filters for DENY action * added 1 HTTP filters to filter chain 0 * added 1 HTTP filters to filter chain 1 * generated config from rule ns[foo]-policy[deny-path-headers]-rule[0] on TCP filter chain successfully * built 1 TCP filters for DENY action * added 1 TCP filters to filter chain 2 * added 1 TCP filters to filter chain 3 * added 1 TCP filters to filter chain 4 2021-04-23T20:53:29.510903Z info ads LDS: PUSH for node:curl-557747455f-6dxbl.foo resources:18 size:85.0kB 2021-04-23T20:53:29.511487Z info ads LDS: PUSH for node:httpbin-74fb669cc6-lpscm.foo resources:18 size:86.4kB
这表明 Istiod 生成了
具有策略
ns[foo]-policy[deny-path-headers]-rule[0]
的 HTTP 过滤器配置,用于工作负载httpbin-74fb669cc6-lpscm.foo
。具有策略
ns[foo]-policy[deny-path-headers]-rule[0]
的 TCP 过滤器配置,用于工作负载httpbin-74fb669cc6-lpscm.foo
。
确保 Istiod 正确地将策略分发到代理
Istiod 将授权策略分发给代理。以下步骤将帮助您确保 Istiod 按预期工作
运行以下命令以获取
httpbin
工作负载的代理配置转储$ kubectl exec $(kubectl get pods -l app=httpbin -o jsonpath='{.items[0].metadata.name}') -c istio-proxy -- pilot-agent request GET config_dump
检查日志并验证
- 日志包含一个
envoy.filters.http.rbac
过滤器,用于在每个传入请求上强制执行授权策略。 - 更新授权策略后,Istio 会相应地更新过滤器。
- 日志包含一个
以下输出表示
httpbin
的代理已启用envoy.filters.http.rbac
过滤器,该过滤器具有拒绝任何人访问路径/headers
的规则。{ "name": "envoy.filters.http.rbac", "typed_config": { "@type": "type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC", "rules": { "action": "DENY", "policies": { "ns[foo]-policy[deny-path-headers]-rule[0]": { "permissions": [ { "and_rules": { "rules": [ { "or_rules": { "rules": [ { "url_path": { "path": { "exact": "/headers" } } } ] } } ] } } ], "principals": [ { "and_ids": { "ids": [ { "any": true } ] } } ] } } }, "shadow_rules_stat_prefix": "istio_dry_run_allow_" } },
确保代理正确地执行策略
代理最终会强制执行授权策略。以下步骤将帮助您确保代理按预期工作
使用以下命令打开代理中的授权调试日志记录
$ istioctl proxy-config log deploy/httpbin --level "rbac:debug"
验证您是否看到以下输出
active loggers: ... ... rbac: debug ... ...
向
httpbin
工作负载发送一些请求以生成一些日志。使用以下命令打印代理日志
$ kubectl logs $(kubectl get pods -l app=httpbin -o jsonpath='{.items[0].metadata.name}') -c istio-proxy
检查输出并验证
输出日志显示
enforced allowed
或enforced denied
,具体取决于请求是否被允许或被拒绝。您的授权策略期望从请求中提取的数据。
以下是路径
/httpbin
的请求的示例输出... 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/curl, 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', '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/curl' , dynamicMetadata: filter_metadata { key: "istio_authn" value { fields { key: "request.auth.principal" value { string_value: "cluster.local/ns/foo/sa/curl" } } fields { key: "source.namespace" value { string_value: "foo" } } fields { key: "source.principal" value { string_value: "cluster.local/ns/foo/sa/curl" } } fields { key: "source.user" value { string_value: "cluster.local/ns/foo/sa/curl" } } } } 2021-04-23T20:43:18.552910Z debug envoy rbac enforced denied, matched policy ns[foo]-policy[deny-path-headers]-rule[0] ...
日志
enforced denied, matched policy ns[foo]-policy[deny-path-headers]-rule[0]
表示请求被策略ns[foo]-policy[deny-path-headers]-rule[0]
拒绝。以下是 干运行模式 中的授权策略的示例输出
... 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/curl, 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/curl' , dynamicMetadata: filter_metadata { key: "istio_authn" value { fields { key: "request.auth.principal" value { string_value: "cluster.local/ns/foo/sa/curl" } } fields { key: "source.namespace" value { string_value: "foo" } } fields { key: "source.principal" value { string_value: "cluster.local/ns/foo/sa/curl" } } fields { key: "source.user" value { string_value: "cluster.local/ns/foo/sa/curl" } } } } 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 ...
日志
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
表示请求实际上被允许,因为干运行策略是工作负载上唯一的策略。
密钥和证书错误
如果您怀疑 Istio 使用的一些密钥或证书不正确,您可以从任何 pod 检查其内容
$ istioctl proxy-config secret curl-8f795f47d-4s4t7
RESOURCE NAME TYPE STATUS VALID CERT SERIAL NUMBER NOT AFTER NOT BEFORE
default Cert Chain ACTIVE true 138092480869518152837211547060273851586 2020-11-11T16:39:48Z 2020-11-10T16:39:48Z
ROOTCA CA ACTIVE true 288553090258624301170355571152070165215 2030-11-08T16:34:52Z 2020-11-10T16:34:52Z
通过传递 -o json
标志,您可以将完整证书内容传递给 openssl
以分析其内容
$ istioctl proxy-config secret curl-8f795f47d-4s4t7 -o json | jq '[.dynamicActiveSecrets[] | select(.name == "default")][0].secret.tlsCertificate.certificateChain.inlineBytes' -r | base64 -d | openssl x509 -noout -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
99:59:6b:a2:5a:f4:20:f4:03:d7:f0:bc:59:f5:d8:40
Signature Algorithm: sha256WithRSAEncryption
Issuer: O = k8s.cluster.local
Validity
Not Before: Jun 4 20:38:20 2018 GMT
Not After : Sep 2 20:38:20 2018 GMT
...
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Subject Alternative Name:
URI:spiffe://cluster.local/ns/my-ns/sa/my-sa
...
确保显示的证书包含有效信息。特别是,Subject Alternative Name
字段应该是 URI:spiffe://cluster.local/ns/my-ns/sa/my-sa
。
双向 TLS 错误
如果您怀疑双向 TLS 存在问题,首先确保 Istiod 正常运行,其次确保 密钥和证书被正确传递 给 sidecar。
如果到目前为止一切正常,下一步是验证是否应用了正确的 身份验证策略 以及是否到位正确的目标规则。
如果您怀疑客户端 sidecar 可能错误地发送双向 TLS 或明文流量,请检查 Grafana 工作负载仪表板。出站请求将标注是否使用了 mTLS。检查完此内容后,如果您认为客户端 sidecar 存在故障,请在 GitHub 上报告问题。