HTTP流量授权
对使用HTTP流量的工作负载配置访问控制
使用Istio,您可以轻松地设置访问控制 工作量 在您的网格中。此任务显示如何使用Istio授权设置访问控制。首先,您配置一个简单的策略,该策略拒绝对工作负载的所有请求,然后逐渐并增量地授予对工作负载的更多访问权限。deny-all
运行以下命令deny-all在default名称空间中创建策略。该策略没有selector字段,该字段将策略应用于default名称空间中的每个工作负载 。该spec:政策的领域具有空值{}。该值表示不允许流量,实际上拒绝了所有请求。
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-all
namespace: default
spec:
{}
EOF
将浏览器指向Bookinfo productpage(http://$GATEWAY_URL/productpage)。您应该看到"RBAC: access denied"。该错误表明配置的deny-all策略按预期工作,并且Istio没有任何规则允许对网格中的工作负载进行任何访问。
运行以下命令以创建productpage-viewer策略,以允许通过GET方法访问productpage工作负载。该策略未在中设置from 字段,rules这意味着允许所有来源,从而有效地允许所有用户和工作负载:
kubectl apply -f - <<EOF
apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
name: "productpage-viewer"
namespace: default
spec:
selector:
matchLabels:
app: productpage
rules:
- to:
- operation:
methods: ["GET"]
EOF
将浏览器指向Bookinfo productpage(http://$GATEWAY_URL/productpage)。现在,您应该看到`Bookinfo示例`页面。但是,您可以在页面上看到以下错误:
Error fetching product details
Error fetching product reviews。
这些错误是预料之中的,因为我们尚未授予productpage 工作负载访问details和reviews工作负载的权限。接下来,您需要配置策略以授予对这些工作负载的访问权限。
运行以下命令以创建details-viewer策略,以允许productpage 使用cluster.local/ns/default/sa/bookinfo-productpage 服务帐户发出请求的details工作负载通过GET方法访问工作负载:
kubectl apply -f - <<EOF
apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
name: "details-viewer"
namespace: default
spec:
selector:
matchLabels:
app: details
rules:
- from:
- source:
principals: ["cluster.local/ns/default/sa/bookinfo-productpage"]
to:
- operation:
methods: ["GET"]
EOF
运行以下命令以创建策略,reviews-viewer以允许productpage使用cluster.local/ns/default/sa/bookinfo-productpage服务帐户发出请求的reviews工作负载通过GET方法访问工作负载:
kubectl apply -f - <<EOF
apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
name: "reviews-viewer"
namespace: default
spec:
selector:
matchLabels:
app: reviews
rules:
- from:
- source:
principals: ["cluster.local/ns/default/sa/bookinfo-productpage"]
to:
- operation:
methods: ["GET"]
EOF
将浏览器指向Bookinfo productpage(http://$GATEWAY_URL/productpage)。现在,您应该看到`Bookinfo Sample页面,其左下角为
Book Details,右下角为
Book Reviews。但是,在
Book Reviews`部分中存在错误Ratings service currently unavailable。
这是因为reviews工作负载无权访问该ratings工作负载。要解决此问题,您需要授予reviews工作负载访问工作负载的权限ratings。接下来,我们配置一个策略以授予reviews访问权限。
运行以下命令以创建ratings-viewer策略,以允许reviews使用cluster.local/ns/default/sa/bookinfo-reviews
服务帐户发出请求的ratings工作负载通过GET方法访问工作负载:
kubectl apply -f - <<EOF
apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
name: "ratings-viewer"
namespace: default
spec:
selector:
matchLabels:
app: ratings
rules:
- from:
- source:
principals: ["cluster.local/ns/default/sa/bookinfo-reviews"]
to:
- operation:
methods: ["GET"]
EOF
将浏览器指向Bookinfo productpage(http://$GATEWAY_URL/productpage)。您应该在`Book Reviews部分看到
黑色和
红色`ratings。
恭喜你!您已成功应用授权策略,以使用HTTP流量对工作负载实施访问控制。
清理
从您的配置中删除所有授权策略:
$ kubectl delete authorizationpolicy.security.istio.io/deny-all
$ kubectl delete authorizationpolicy.security.istio.io/productpage-viewer
$ kubectl delete authorizationpolicy.security.istio.io/details-viewer
$ kubectl delete authorizationpolicy.security.istio.io/reviews-viewer
$ kubectl delete authorizationpolicy.security.istio.io/ratings-viewer
TCP流量授权
先决条件
在foo命名空间中一起部署名为sleep和的两个工作负载。这两个工作负载都先于Envoy代理运行。在tcp-echo监听9000,9001和9002端口,回显任何带有hello前缀的流量。例如,如果您将world
发送给tcp-echo,它将以答复hello world
。tcp-echo Kubernetes服务对象只声明端口9000和9001,并且省略了9002端口,直通过滤器链将处理端口9002的流量。使用以下命令部署示例名称空间和工作负载:
kubectl create ns foo
kubectl apply -f <(istioctl kube-inject -f samples/tcp-echo/tcp-echo.yaml) -n foo
kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml) -n foo
使用以下命令验证tcp-echod的9000和9001端口上是否和sleep成功通信:
kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- sh -c 'echo "port 9000" | nc tcp-echo 9000' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
hello port 9000
connection succeeded
kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- sh -c 'echo "port 9001" | nc tcp-echo 9001' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
hello port 9001
connection succeeded
验证端口9002上是否sleep成功通信tcp-echo。tcp-echo由于端口9002在Kubernetes服务对象中未定义,因此您需要将流量直接发送到Pod IP tcp-echo。获取pod IP地址并使用以下命令发送请求:
TCP_ECHO_IP=$(kubectl get pod "$(kubectl get pod -l app=tcp-echo -n foo -o jsonpath={.items..metadata.name})" -n foo -o jsonpath="{.status.podIP}")
kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- sh -c "echo \"port 9002\" | nc $TCP_ECHO_IP 9002" | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
hello port 9002
connection succeeded
如果看不到预期的输出,请在几秒钟后重试。缓存和传播可能会导致延迟。
为TCP工作负载配置访问控制
在名称空间中tcp-policy为tcp-echo工作负载创建授权策略foo。运行以下命令以应用策略以允许请求到端口9000和9001:
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: tcp-policy
namespace: foo
spec:
selector:
matchLabels:
app: tcp-echo
action: ALLOW
rules:
- to:
- operation:
ports: ["9000", "9001"]
EOF
kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- sh -c 'echo "port 9000" | nc tcp-echo 9000' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
hello port 9000
connection succeeded
kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- sh -c 'echo "port 9001" | nc tcp-echo 9001' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
hello port 9001
connection succeeded
验证对端口9002的请求是否被拒绝。即使未在tcp-echoKubernetes服务对象中显式声明端口,授权策略也将执行此策略,该策略也适用于直通过滤器链。运行以下命令并验证输出:
$ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- sh -c "echo \"port 9002\" | nc $TCP_ECHO_IP 9002" | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
connection rejected
更新策略,以methods使用以下命令添加以端口9000命名的仅HTTP字段:
$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
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的请求是否被拒绝。发生这种情况是因为该规则在methods对TCP通信使用仅HTTP字段(methods)时变得无效。Istio会忽略无效的ALLOW规则。最终结果是该请求被拒绝,因为它与任何ALLOW规则都不匹配。运行以下命令并验证输出:
$ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- sh -c 'echo "port 9000" | nc tcp-echo 9000' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
connection rejected
验证对端口9001的请求是否被拒绝。发生这种情况是因为请求与任何ALLOW规则都不匹配。运行以下命令并验证输出:
$ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- sh -c 'echo "port 9001" | nc tcp-echo 9001' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
connection rejected
$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: tcp-policy
namespace: foo
spec:
selector:
matchLabels:
app: tcp-echo
action: DENY
rules:
- to:
- operation:
methods: ["GET"]
ports: ["9000"]
EOF
验证对端口9000的请求是否被拒绝。发生这种情况是因为Istio忽略了无效DENY规则中的仅HTTP字段。这与无效的ALLOW规则不同,ALLOW规则导致Istio忽略整个规则。最终结果是ports Istio仅使用该字段,并且由于它们与匹配而被拒绝ports:
$ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- sh -c 'echo "port 9000" | nc tcp-echo 9000' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
connection rejected
验证是否允许对端口9001的请求。发生这种情况是因为请求ports与DENY策略中的不匹配:
$ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- sh -c 'echo "port 9001" | nc tcp-echo 9001' | grep "hello" && echo 'connection succeeded' || echo 'connection rejected'
hello port 9001
connection succeeded
清理
删除名称空间foo:
$ kubectl delete namespace foo
JWT授权
此任务向您展示如何设置Istio授权策略以基于JSON Web令牌(JWT)强制执行访问。Istio授权策略支持字符串类型的和JWT字符串列表的声明。
先决条件
部署两个工作负载:httpbin和sleep。例如,将它们部署在一个名称空间中foo。这两个工作负载都在每个Envoy代理的前面运行。使用以下命令部署示例名称空间和工作负载:
$ kubectl create ns foo
$ kubectl apply -f <(istioctl kube-inject -f samples/httpbin/httpbin.yaml) -n foo
$ kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml) -n foo
使用以下命令验证是否可以sleep成功通信httpbin:
$ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl http://httpbin.foo:8000/ip -s -o /dev/null -w "%{http_code}\n"
200
如果看不到预期的输出,请在几秒钟后重试。缓存和传播可能会导致延迟。
允许具有有效JWT和列表类型声明的请求
以下命令jwt-example为名称空间中的httpbin工作负载创建请求身份验证策略foo。此httpbin工作负载政策接受以下机构发布的JWT testing@secure.istio.io:
$ kubectl apply -f - <<EOF
apiVersion: "security.istio.io/v1beta1"
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.8/security/tools/jwt/samples/jwks.json"
EOF
$ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "http://httpbin.foo:8000/headers" -s -o /dev/null -H "Authorization: Bearer invalidToken" -w "%{http_code}\n"
401
$ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "http://httpbin.foo:8000/headers" -s -o /dev/null -w "%{http_code}\n"
200
以下命令require-jwt为名称空间中的httpbin工作负载创建授权策略foo。该策略要求对httpbin工作负载的所有请求都必须具有有效的JWT, requestPrincipal并将其设置为testing@secure.istio.io/testing@secure.istio.io。Istio构建requestPrincipal通过组合iss和sub与令牌的JWT的/分离器,如下所示:
$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
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
获取将iss和sub键设置为相同值的JWT testing@secure.istio.io。这将导致Istio生成requestPrincipal具有以下值的属性testing@secure.istio.io/testing@secure.istio.io:
$ TOKEN=$(curl https://raw.githubusercontent.com/istio/istio/release-1.8/security/tools/jwt/samples/demo.jwt -s) && echo "$TOKEN" | cut -d '.' -f2 - | base64 --decode -
{"exp":4685989700,"foo":"bar","iat":1532389700,"iss":"testing@secure.istio.io","sub":"testing@secure.istio.io"}
$ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "http://httpbin.foo:8000/headers" -s -o /dev/null -H "Authorization: Bearer $TOKEN" -w "%{http_code}\n"
200
$ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "http://httpbin.foo:8000/headers" -s -o /dev/null -w "%{http_code}\n"
403
以下命令更新require-jwt授权策略,以要求JWT拥有一个groups包含值的声明group1:
$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
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"]
when:
- key: request.auth.claims[groups]
values: ["group1"]
EOF
request.auth.claims除非声明本身包含引号,否则请勿在该字段中包含引号。
获取将groups索赔声明设置为字符串列表的JWT :group1和group2:
$ TOKEN_GROUP=$(curl https://raw.githubusercontent.com/istio/istio/release-1.8/security/tools/jwt/samples/groups-scope.jwt -s) && echo "$TOKEN_GROUP" | cut -d '.' -f2 - | base64 --decode -
{"exp":3537391104,"groups":["group1","group2"],"iat":1537391104,"iss":"testing@secure.istio.io","scope":["scope1","scope2"],"sub":"testing@secure.istio.io"}
验证是否允许与JWT包含group1在groups索赔中的请求:
$ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "http://httpbin.foo:8000/headers" -s -o /dev/null -H "Authorization: Bearer $TOKEN_GROUP" -w "%{http_code}\n"
200
$ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "http://httpbin.foo:8000/headers" -s -o /dev/null -H "Authorization: Bearer $TOKEN" -w "%{http_code}\n"
403
清理
删除名称空间foo:
$ kubectl delete namespace foo
拒绝策略的授权策略
此任务说明如何设置拒绝Istio网格中HTTP流量的Istio授权策略。在我们的授权概念页面上了解更多信息。
先决条件
部署工作负载:
此任务使用部署在一个名称空间foo上的两个工作负载(httpbin和sleep)。这两个工作负载都在每个Envoy代理的前面运行。使用以下命令部署示例名称空间和工作负载:
kubectl create ns foo
kubectl apply -f <(istioctl kube-inject -f samples/httpbin/httpbin.yaml) -n foo
kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml) -n foo
使用以下命令验证与之sleep对话httpbin:
$ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl http://httpbin.foo:8000/ip -s -o /dev/null -w "%{http_code}\n"
200
如果在执行任务时未看到预期的输出,请在几秒钟后重试。缓存和传播开销可能会导致一些延迟。
明确拒绝请求
以下命令deny-method-get为名称空间中的httpbin工作负载创建授权策略foo。该策略将设置为action,DENY以拒绝满足本rules节中设置的条件的请求。这类策略被称为拒绝策略。在这种情况下,策略会拒绝请求,如果其方法为GET。
$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-method-get
namespace: foo
spec:
selector:
matchLabels:
app: httpbin
action: DENY
rules:
- to:
- operation:
methods: ["GET"]
EOF
$ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "http://httpbin.foo:8000/get" -X GET -s -o /dev/null -w "%{http_code}\n"
403
kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "http://httpbin.foo:8000/post" -X POST -s -o /dev/null -w "%{http_code}\n"
200
更新deny-method-get授权策略以GET仅在HTTP标头x-token值不是时才拒绝请求admin。以下示例策略将notValues字段的值设置为,["admin"]以拒绝标头值为的请求admin:
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
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
验证是否允许GET带有HTTP标头的请求x-token: admin:
kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "http://httpbin.foo:8000/get" -X GET -H "x-token: admin" -s -o /dev/null -w "%{http_code}\n"
200
验证带有HTTP标头的GET请求是否x-token: guest被拒绝:
$ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "http://httpbin.foo:8000/get" -X GET -H "x-token: guest" -s -o /dev/null -w "%{http_code}\n"
403
以下命令创建allow-path-ip授权策略,以允许在工作负载/ip路径上的请求httpbin。此授权策略将action字段设置为ALLOW。这种类型的策略被称为允许策略。
$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-path-ip
namespace: foo
spec:
selector:
matchLabels:
app: httpbin
action: ALLOW
rules:
- to:
- operation:
paths: ["/ip"]
EOF
验证该策略是否拒绝在路径中GET带有HTTP标头的请求。拒绝策略优先于允许策略:x-token: guest/ipdeny-method-get
$ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "http://httpbin.foo:8000/ip" -X GET -H "x-token: guest" -s -o /dev/null -w "%{http_code}\n"
403
9.确认策略允许路径中GET带有HTTP标头的请求:x-token: admin/ipallow-path-ip
$ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "http://httpbin.foo:8000/ip" -X GET -H "x-token: admin" -s -o /dev/null -w "%{http_code}\n"
200
验证路径为GETHTTP标头的请求是否被拒绝,因为它们与策略不匹配:x-token: admin/getallow-path-ip
kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "http://httpbin.foo:8000/get" -X GET -H "x-token: admin" -s -o /dev/null -w "%{http_code}\n"
403
清理
从配置中删除名称空间foo:
kubectl delete namespace foo