外部授权
本任务将向您展示如何使用 action 字段 的新值 CUSTOM
设置 Istio 授权策略,以将访问控制委托给外部授权系统。这可用于与 OPA 授权、oauth2-proxy
、您自己的自定义外部授权服务器等集成。
开始之前
在开始本任务之前,请执行以下操作
阅读 Istio 授权概念。
按照 Istio 安装指南 安装 Istio。
部署测试工作负载
此任务使用两个工作负载
httpbin
和curl
,两者都部署在foo
命名空间中。这两个工作负载都运行带有 Envoy 代理 sidecar。使用以下命令部署foo
命名空间和工作负载$ kubectl create ns foo $ kubectl label ns foo istio-injection=enabled $ kubectl apply -f @samples/httpbin/httpbin.yaml@ -n foo $ kubectl apply -f @samples/curl/curl.yaml@ -n foo
使用以下命令验证
curl
是否可以访问httpbin
$ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" -c curl -n foo -- curl http://httpbin.foo:8000/ip -s -o /dev/null -w "%{http_code}\n" 200
部署外部授权器
首先,您需要部署外部授权器。为此,您只需在网格中的独立 Pod 中部署示例外部授权器。
运行以下命令以部署示例外部授权器
$ kubectl apply -n foo -f https://raw.githubusercontent.com/istio/istio/release-1.24/samples/extauthz/ext-authz.yaml service/ext-authz created deployment.apps/ext-authz created
验证示例外部授权器是否已启动并运行
$ kubectl logs "$(kubectl get pod -l app=ext-authz -n foo -o jsonpath={.items..metadata.name})" -n foo -c ext-authz 2021/01/07 22:55:47 Starting HTTP server at [::]:8000 2021/01/07 22:55:47 Starting gRPC server at [::]:9000
或者,您也可以将外部授权器作为单独的容器部署在需要外部授权的应用程序的同一 Pod 中,甚至将其部署在网格外部。在任何一种情况下,您都需要创建一个服务条目资源以将服务注册到网格并确保代理可以访问它。
以下是在需要外部授权的应用程序的同一 Pod 中部署的外部授权器的示例服务条目。
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: external-authz-grpc-local
spec:
hosts:
- "external-authz-grpc.local" # The service name to be used in the extension provider in the mesh config.
endpoints:
- address: "127.0.0.1"
ports:
- name: grpc
number: 9191 # The port number to be used in the extension provider in the mesh config.
protocol: GRPC
resolution: STATIC
定义外部授权器
为了在授权策略中使用 CUSTOM
操作,您必须定义允许在网格中使用的外部授权器。这目前在网格配置中的 扩展提供程序 中定义。
目前,唯一支持的扩展提供程序类型是 Envoy ext_authz
提供程序。外部授权器必须实现相应的 Envoy ext_authz
检查 API。
在本任务中,您将使用 示例外部授权器,它允许带有标头 x-ext-authz: allow
的请求。
使用以下命令编辑网格配置
$ kubectl edit configmap istio -n istio-system
在编辑器中,添加下面显示的扩展提供程序定义
以下内容定义了两个外部提供程序
sample-ext-authz-grpc
和sample-ext-authz-http
,它们使用相同的服务ext-authz.foo.svc.cluster.local
。该服务实现了 Envoyext_authz
过滤器定义的 HTTP 和 gRPC 检查 API。您将在后续步骤中部署该服务。data: mesh: |- # Add the following content to define the external authorizers. extensionProviders: - name: "sample-ext-authz-grpc" envoyExtAuthzGrpc: service: "ext-authz.foo.svc.cluster.local" port: "9000" - name: "sample-ext-authz-http" envoyExtAuthzHttp: service: "ext-authz.foo.svc.cluster.local" port: "8000" includeRequestHeadersInCheck: ["x-ext-authz"]
或者,您可以修改扩展提供程序以控制
ext_authz
过滤器的行为,例如向外部授权器发送哪些标头、向应用程序后端发送哪些标头、错误时返回的状态等等。例如,以下定义了一个扩展提供程序,可与oauth2-proxy
一起使用data: mesh: |- extensionProviders: - name: "oauth2-proxy" envoyExtAuthzHttp: service: "oauth2-proxy.foo.svc.cluster.local" port: "4180" # The default port used by oauth2-proxy. includeRequestHeadersInCheck: ["authorization", "cookie"] # headers sent to the oauth2-proxy in the check request. headersToUpstreamOnAllow: ["authorization", "path", "x-auth-request-user", "x-auth-request-email", "x-auth-request-access-token"] # headers sent to backend application when request is allowed. headersToDownstreamOnAllow: ["set-cookie"] # headers sent back to the client when request is allowed. headersToDownstreamOnDeny: ["content-type", "set-cookie"] # headers sent back to the client when request is denied.
使用外部授权启用
外部授权器现在已准备好在授权策略中使用。
使用以下命令启用外部授权
以下命令为
httpbin
工作负载应用带有CUSTOM
操作值的授权策略。该策略使用由sample-ext-authz-grpc
定义的外部授权器,为对路径/headers
的请求启用外部授权。$ kubectl apply -n foo -f - <<EOF apiVersion: security.istio.io/v1 kind: AuthorizationPolicy metadata: name: ext-authz spec: selector: matchLabels: app: httpbin action: CUSTOM provider: # The provider name must match the extension provider defined in the mesh config. # You can also replace this with sample-ext-authz-http to test the other external authorizer definition. name: sample-ext-authz-grpc rules: # The rules specify when to trigger the external authorizer. - to: - operation: paths: ["/headers"] EOF
在运行时,对
httpbin
工作负载的路径/headers
的请求将被ext_authz
过滤器暂停,并且将向外部授权器发送检查请求以决定是否允许或拒绝该请求。验证对带有标头
x-ext-authz: deny
的路径/headers
的请求是否被示例ext_authz
服务器拒绝$ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" -c curl -n foo -- curl "http://httpbin.foo:8000/headers" -H "x-ext-authz: deny" -s denied by ext_authz for not found header `x-ext-authz: allow` in the request
验证对带有标头
x-ext-authz: allow
的路径/headers
的请求是否被示例ext_authz
服务器允许$ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" -c curl -n foo -- curl "http://httpbin.foo:8000/headers" -H "x-ext-authz: allow" -s | jq '.headers' ... "X-Ext-Authz-Check-Result": [ "allowed" ], ...
验证对路径
/ip
的请求是否允许并且不会触发外部授权$ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" -c curl -n foo -- curl "http://httpbin.foo:8000/ip" -s -o /dev/null -w "%{http_code}\n" 200
检查示例
ext_authz
服务器的日志以确认它被调用了两次(对于这两个请求)。第一个被允许,第二个被拒绝$ kubectl logs "$(kubectl get pod -l app=ext-authz -n foo -o jsonpath={.items..metadata.name})" -n foo -c ext-authz 2021/01/07 22:55:47 Starting HTTP server at [::]:8000 2021/01/07 22:55:47 Starting gRPC server at [::]:9000 2021/01/08 03:25:00 [gRPCv3][denied]: httpbin.foo:8000/headers, attributes: source:{address:{socket_address:{address:"10.44.0.22" port_value:52088}} principal:"spiffe://cluster.local/ns/foo/sa/curl"} destination:{address:{socket_address:{address:"10.44.3.30" port_value:80}} principal:"spiffe://cluster.local/ns/foo/sa/httpbin"} request:{time:{seconds:1610076306 nanos:473835000} http:{id:"13869142855783664817" method:"GET" headers:{key:":authority" value:"httpbin.foo:8000"} headers:{key:":method" value:"GET"} headers:{key:":path" value:"/headers"} headers:{key:"accept" value:"*/*"} headers:{key:"content-length" value:"0"} headers:{key:"user-agent" value:"curl/7.74.0-DEV"} headers:{key:"x-b3-sampled" value:"1"} headers:{key:"x-b3-spanid" value:"377ba0cdc2334270"} headers:{key:"x-b3-traceid" value:"635187cb20d92f62377ba0cdc2334270"} headers:{key:"x-envoy-attempt-count" value:"1"} headers:{key:"x-ext-authz" value:"deny"} headers:{key:"x-forwarded-client-cert" value:"By=spiffe://cluster.local/ns/foo/sa/httpbin;Hash=dd14782fa2f439724d271dbed846ef843ff40d3932b615da650d028db655fc8d;Subject=\"\";URI=spiffe://cluster.local/ns/foo/sa/curl"} headers:{key:"x-forwarded-proto" value:"http"} headers:{key:"x-request-id" value:"9609691a-4e9b-9545-ac71-3889bc2dffb0"} path:"/headers" host:"httpbin.foo:8000" protocol:"HTTP/1.1"}} metadata_context:{} 2021/01/08 03:25:06 [gRPCv3][allowed]: httpbin.foo:8000/headers, attributes: source:{address:{socket_address:{address:"10.44.0.22" port_value:52184}} principal:"spiffe://cluster.local/ns/foo/sa/curl"} destination:{address:{socket_address:{address:"10.44.3.30" port_value:80}} principal:"spiffe://cluster.local/ns/foo/sa/httpbin"} request:{time:{seconds:1610076300 nanos:925912000} http:{id:"17995949296433813435" method:"GET" headers:{key:":authority" value:"httpbin.foo:8000"} headers:{key:":method" value:"GET"} headers:{key:":path" value:"/headers"} headers:{key:"accept" value:"*/*"} headers:{key:"content-length" value:"0"} headers:{key:"user-agent" value:"curl/7.74.0-DEV"} headers:{key:"x-b3-sampled" value:"1"} headers:{key:"x-b3-spanid" value:"a66b5470e922fa80"} headers:{key:"x-b3-traceid" value:"300c2f2b90a618c8a66b5470e922fa80"} headers:{key:"x-envoy-attempt-count" value:"1"} headers:{key:"x-ext-authz" value:"allow"} headers:{key:"x-forwarded-client-cert" value:"By=spiffe://cluster.local/ns/foo/sa/httpbin;Hash=dd14782fa2f439724d271dbed846ef843ff40d3932b615da650d028db655fc8d;Subject=\"\";URI=spiffe://cluster.local/ns/foo/sa/curl"} headers:{key:"x-forwarded-proto" value:"http"} headers:{key:"x-request-id" value:"2b62daf1-00b9-97d9-91b8-ba6194ef58a4"} path:"/headers" host:"httpbin.foo:8000" protocol:"HTTP/1.1"}} metadata_context:{}
您还可以从日志中看出,
ext-authz
过滤器和示例ext-authz
服务器之间的连接启用了 mTLS,因为源主体已填充了值spiffe://cluster.local/ns/foo/sa/curl
。您现在可以为示例
ext-authz
服务器应用另一个授权策略来控制谁被允许访问它。
清理
从您的配置中删除
foo
命名空间。$ kubectl delete namespace foo
从网格配置中删除扩展提供程序定义。
性能预期
请参阅 性能基准测试。