外部授權
此任務將向您展示如何使用 action 欄位的新值 CUSTOM
來設定 Istio 授權政策,以將存取控制委派給外部授權系統。這可用於與 OPA 授權、oauth2-proxy
、您自己的自訂外部授權伺服器等整合。
開始之前
在開始此任務之前,請執行以下操作
閱讀 Istio 授權概念。
遵循 Istio 安裝指南 安裝 Istio。
部署測試工作負載
此任務使用兩個工作負載,
httpbin
和curl
,它們都部署在命名空間foo
中。兩個工作負載都使用 Envoy 代理邊車執行。使用以下命令部署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
動作值。該策略啟用路徑為/headers
的請求的外部授權,並使用sample-ext-authz-grpc
定義的外部授權器。$ 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
從網格配置中移除擴充功能供應商定義。
效能期望
請參閱 效能基準測試。