授权

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工作负载配置访问控制

  1. 在名称空间中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
  1. 使用以下命令验证是否允许对端口9000的请求:

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
  1. 使用以下命令验证是否允许对端口9001的请求:

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
  1. 验证对端口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
  1. 更新策略,以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
  1. 验证对端口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
  1. 验证对端口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
  1. 使用以下命令将策略更新为DENY策略:

$ 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
  1. 验证对端口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
  1. 验证是否允许对端口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和列表类型声明的请求

  1. 以下命令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
  1. 验证带有无效JWT的请求是否被拒绝:

$ 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
  1. 验证是否允许没有JWT的请求,因为没有授权策略:

$ 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
  1. 以下命令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
  1. 获取将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"}
  1. 验证是否允许带有有效JWT的请求:

$ 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
  1. 验证没有JWT的请求是否被拒绝:

$ 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
  1. 以下命令更新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除非声明本身包含引号,否则请勿在该字段中包含引号。

  1. 获取将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"}
  1. 验证是否允许与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
  1. 验证没有请求的JWT请求是否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" -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

如果在执行任务时未看到预期的输出,请在几秒钟后重试。缓存和传播开销可能会导致一些延迟。

明确拒绝请求

  1. 以下命令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
  1. 验证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/get" -X GET -s -o /dev/null -w "%{http_code}\n"
403
  1. 验证是否POST允许请求:

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
  1. 更新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
  1. 验证是否允许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
  1. 验证带有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
  1. 以下命令创建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
  1. 验证该策略是否拒绝在路径中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
  1. 验证路径为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

Last updated