istio 安全 授权
Istio 的授权功能为网格中的工作负载提供网格范围、命名空间范围和工作负载范围的访问控制。
1、授权架构
授权策略对服务器端Envoy代理中的入站流量实施访问控制。每个Envoy代理都运行一个授权引擎,在运行时对请求进行授权。当请求到达代理时,授权引擎根据当前授权策略评估请求上下文,并返回授权结果ALLOW或DENY。
2、隐式启用
您无需明确启用 Istio 的授权功能;安装后即可使用。
对于未应用授权策略的工作负载,Istio 允许所有请求。
Istio按层检查匹配策略,顺序是:CUSTOM, DENY,然后ALLOW。对于每种类型的操作,Istio首先检查是否存在应用了该操作的策略,然后检查请求是否与策略规范匹配。如果请求与其中一层中的策略不匹配,则继续检查下一层。
3、授权策略
授权策略包括选择器、操作和规则列表:
-
selector字段指定策略的目标
-
action字段指定是否允许或拒绝请求
-
rules指定何时触发操作
-
from中的字段指定rules请求的来源
-
to中的字段指定rules请求的操作
-
when字段指定应用规则所需的条件
拒绝策略优先于允许策略 。如果请求与拒绝策略匹配,则匹配允许策略的请求会被拒绝。Istio 首先评估拒绝策略,以确保允许策略无法绕过拒绝策略。
3.1、策略目标
您可以使用metadata/namespace字段和可选的selector字段指定策略的范围或目标。策略应用于metadata/namespace字段中的命名空间。如果将其值设置为 根命名空间,则该策略应用于网格中的 所有命名空间 。根命名空间的值是可配置的,默认值为 istio-system 。如果设置为任何其他命名空间,则该策略仅适用于指定的命名空间。
您可以使用selector字段来进一步限制策略应用于特定工作负载。选择器使用标签来选择目标工作负载。选择器包含{key:Value}对的列表,其中键是标签的名称。 如果未设置,授权策略将应用于与授权策略相同命名空间中的所有工作负载。
3.2、值匹配
授权策略中的大多数字段都支持以下所有匹配模式:
-
精确匹配:字符串精确匹配。
-
前缀匹配:以"*"结尾的字符串。例如,"test.abc.*" 匹配"test.abc.com"、"test.abc.com.cn"、"test.abc.org"等。
-
后缀匹配:以"*"开头的字符串。例如,"*.abc.com" 匹配"eng.abc.com"、"test.eng.abc.com"等。
-
存在匹配:*用于指定任何内容但不能为空。要指定字段必须存在,请使用fieldname: ["*"]格式。这与不指定字段不同,后者表示匹配任何内容,包括空。
有些字段仅支持精确匹配。
3.3、排除匹配
为了匹配负条件,例如when字段中的notValues、source字段中的notIpBlocks、to字段中的notPorts,Istio支持排除匹配。如果请求路径不是/healthz,以下示例需要有效的请求主体,该主体从JWT身份验证派生。因此,该策略将对/healthz路径的请求排除在JWT身份验证之外:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: disable-jwt-for-healthz
namespace: default
spec:
selector:
matchLabels:
app: products
action: ALLOW
rules:
- to:
- operation:
notPaths: ["/healthz"]
from:
- source:
requestPrincipals: ["*"]
以下示例拒绝/api/没有请求主体的请求路径的请求:
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: enable-jwt-for-admin
namespace: default
spec:
selector:
matchLabels:
app: service-a
action: DENY
rules:
- to:
- operation:
paths: ["/api/*"]
from:
- source:
notRequestPrincipals: ["*"]
EOF
标签匹配是根据pod的标签进行匹配的。
3.4、默认策略
下面的示例显示了一个不匹配任何内容的ALLOW策略。如果没有其他ALLOW策略,则由于“默认拒绝”行为,请求将始终被拒绝。
注意,“默认拒绝”行为仅在工作负载至少有一个带有ALLOW操作的授权策略时才适用。
警告
从“不允许”策略开始,然后逐渐添加更多的“允许”策略,以打开对工作负载的更多访问,这是一个很好的安全实践。
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: allow-nothing
spec:
action: ALLOW
# the rules field is not specified, and the policy will never match.
实测也是非常有生产环境价值的功能,默认拒绝所有请求,在配置了上述策略之后,进行以下测试
服务间访问
curl http://service-c:9000/api/v1/testC/
RBAC: access denied
外部请求
curl "service-a.localserver.com/api/v1/testA/get_headers/" -s -o /dev/null -w "%{http_code}\n"\n
403
当我执行以下策略时,服务a可以正常访问,别的不可以。
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: enable-jwt-for-admin-a
namespace: default
spec:
selector:
matchLabels:
app: service-a
action: ALLOW
rules:
- to:
- operation:
paths: ["/api/*"]
EOF
下面的示例显示了显式拒绝所有访问的DENY策略。它将始终拒绝请求,即使存在另一个允许请求的ALLOW策略,因为deny策略优先于ALLOW策略。 如果您想暂时禁用对工作负载的所有访问 ,这很有用。
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: deny-all
spec:
action: DENY
# the rules field has an empty rule, and the policy will always match.
rules:
- {}
下面的示例展示了允许对工作负载进行完全访问的ALLOW策略。它将使其他ALLOW策略无效,因为它总是允许请求。 如果您想暂时公开对工作负载的完全访问权限 ,这可能会很有用。注意,由于CUSTOM和DENY策略,请求仍然可能被拒绝。
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: allow-all
spec:
action: ALLOW
# This matches everything.
rules:
- {}
4、http流量授权
4.1、默认策略
运行以下命令在命名空间default中创建策略allow-nothing。该策略没有selector字段,该字段将策略应用于 default命名空间中的每个工作负载。spec:策略的字段具有空值{}。该值表示不允许任何流量,从而有效地拒绝所有请求。
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: allow-nothing
namespace: default
spec:
{}
EOF
4.2、访问productpage
运行以下命令创建productpage-viewer策略以允许使用GET方法访问productpage工作负载。该策略未设置from 字段,这rules意味着允许所有来源,从而有效地允许所有用户和工作负载。
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: "productpage-viewer"
namespace: default
spec:
selector:
matchLabels:
app: productpage
action: ALLOW
rules:
- to:
- operation:
methods: ["GET"]
EOF
4.3、productpage访问details
使用 cluster.local/ns/default/sa/bookinfo-productpage 服务账户通过get方法访问details工作负载。在productpage的deployment中引用了bookinfo-productpage的服务账户。
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: "details-viewer"
namespace: default
spec:
selector:
matchLabels:
app: details
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/default/sa/bookinfo-productpage"]
to:
- operation:
methods: ["GET"]
EOF
4.4、productpage访问reviews
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: "reviews-viewer"
namespace: default
spec:
selector:
matchLabels:
app: reviews
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/default/sa/bookinfo-productpage"]
to:
- operation:
methods: ["GET"]
EOF
4.5、reviews访问ratings
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: "ratings-viewer"
namespace: default
spec:
selector:
matchLabels:
app: ratings
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/default/sa/bookinfo-reviews"]
to:
- operation:
methods: ["GET"]
EOF
最终页面就跟没有任何授权控制一样。
5、tcp流量授权
5.1、allow
5.1.1、允许端口请求
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: tcp-policy
namespace: foo
spec:
selector:
matchLabels:
app: tcp-echo
action: ALLOW
rules:
- to:
- operation:
ports: ["9000", "9001"]
EOF
5.1.2、增加仅http生效的字段
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: tcp-policy
namespace: foo
spec:
selector:
matchLabels:
app: tcp-echo
action: ALLOW
rules:
- to:
- operation:
methods: ["GET"]
ports: ["9000"]
EOF
验证对端口9000的请求被拒绝。 这是因为当规则对TCP通信使用仅限http的字段(方法)时 ,该规则将失效。Istio忽略无效的ALLOW规则。最终的结果是请求被拒绝,因为它不匹配任何ALLOW规则。
5.2、deny
5.2.1、配置包含http字段的策略
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: tcp-policy
namespace: foo
spec:
selector:
matchLabels:
app: tcp-echo
action: DENY
rules:
- to:
- operation:
methods: ["GET"]
EOF
验证对端口 9000 的请求是否被拒绝。发生这种情况的原因是 Istio 在为 tcp 端口创建 DENY 规则时不理解 HTTP-only 字段,并且由于其限制性,它拒绝了到 tcp 端口的所有流量。
5.2.2、添加包含 TCP 和 HTTP 字段的 DENY 策略
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: tcp-policy
namespace: foo
spec:
selector:
matchLabels:
app: tcp-echo
action: DENY
rules:
- to:
- operation:
methods: ["GET"]
ports: ["9000"]
EOF
tcp和http的规则最好不要同时配置。
6、jwt令牌
6.1、最终用户身份验证
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: RequestAuthentication
metadata:
name: "jwt-example"
namespace: foo
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"
EOF
-
验证带有无效 JWT 的请求返回401。
-
没有带有token的请求被正常放行。
单独如上的配置加上token和没有token都可以正常访问。
6.2、加上授权策略
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: require-jwt
namespace: foo
spec:
selector:
matchLabels:
app: httpbin
action: ALLOW
rules:
- from:
- source:
requestPrincipals: ["testing@secure.istio.io/testing@secure.istio.io"]
EOF
此时包含jwt的请求才能正常被通过。
7、明确拒绝
DENY操作具有更高的优先级,并且不会被任何ALLOW操作绕过。
7.1、拒绝get请求
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: deny-method-get
namespace: foo
spec:
selector:
matchLabels:
app: httpbin
action: DENY
rules:
- to:
- operation:
methods: ["GET"]
EOF
访问 app=httpbin的标签时,get请求被拒绝,post请求会被通过。
7.2、header中某个值不匹配
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: deny-method-get
namespace: foo
spec:
selector:
matchLabels:
app: httpbin
action: DENY
rules:
- to:
- operation:
methods: ["GET"]
when:
- key: request.headers[x-token]
notValues: ["admin"]
EOF
7.3、path匹配
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: allow-path-ip
namespace: foo
spec:
selector:
matchLabels:
app: httpbin
action: ALLOW
rules:
- to:
- operation:
paths: ["/ip"]
EOF
8、入口网关授权
8.1、基于ip的允许列表和拒绝列表
svc中如果配置了externalTrafficPolicy: Local