自定義授權服務
更新時間 2024-09-09 19:42:38
最近更新時間: 2024-09-09 19:42:38
分享文章
本章節介紹自定義授權服務
概述
應用服務網格支持接入第三方鑒權服務,用于網格內的服務鑒權,當前支持定義HTTP協議和gRPC協議的自定義鑒權服務。
添加自定義授權服務
- 從控制臺 選擇 網格安全中心 -> 自定義授權服務菜單,選擇創建。
- 填寫參數,提交即可。
參數說明如下:
| 配置 | 說明 |
|---|---|
| 協議 | 調用外部授權服務的協議,當前支持HTTP和gRPC。 |
| 名稱 | 唯一標識一個外部授權服務。 |
| 服務地址 | 外部授權服務的地址。 |
| 服務端口 | 外部授權服務的端口號。 |
| 超時時間 | 調用外部授權服務時的超時時間,單位秒。 |
針對HTTP協議的外部授權服務支持以下額外配置選項:
| 配置 | 說明 |
|---|---|
| 鑒權服務不可用時放行請求 | 打開此開關后,訪問鑒權服務出現異常時將放行請求。 |
| 在鑒權請求中攜帶header | 將請求中指定的頭部帶到鑒權服務。 |
| 在鑒權請求中新增header | 在發往鑒權服務的請求中新增頭部。 |
| 鑒權通過時覆蓋Header | 使用鑒權請求Response中Header覆蓋發往目標服務的請求中的Header。 |
| 鑒權失敗時覆蓋Header | 使用鑒權請求Response中Header覆蓋Response中的Header。 |
| 在鑒權請求中攜帶請求Body | 打開此開關后,將在訪問鑒權服務時攜帶請求Body。 |
| 鑒權請求攜帶Body的最大長度(Byte) | 限制發往鑒權服務的Body大小。 |
| 允許將不完整消息發送至鑒權服務 | 在請求Body超出最大長度限制時,若不啟用該選項則將拒絕請求并返回HTTP 413。 |
針對gRPC協議的外部授權服務支持以下額外配置選項:
| 配置 | 說明 |
|---|---|
| 鑒權服務不可用時放行請求 | 打開此開關后,訪問鑒權服務出現異常時將放行請求。 |
| 在鑒權請求中攜帶請求Body | 打開此開關后,將在訪問鑒權服務時攜帶請求Body。 |
| 鑒權請求攜帶Body的最大長度(Byte) | 限制發往鑒權服務的Body大小。 |
| 允許將不完整消息發送至鑒權服務 | 在請求Body超出最大長度限制時,若不啟用該選項則將拒絕請求并返回HTTP 413。 |
| 鑒權請求Body編碼方式及存放位置 | 當前支持兩種選項: 1,UTF8 String(Body):授權請求將編碼為UTF8字符串放到請求body字段。 2,RawBytes(RawBody):授權請求將編碼為原始字節串放到請求的raw_body字段。 |
修改自定義授權服務
- 從控制臺 選擇 網格安全中心 -> 自定義授權服務菜單,默認會展示當前定義的所有外部授權服務。
- 選擇要編輯的服務編輯即可。
刪除自定義授權服務
- 從控制臺 選擇 網格安全中心 -> 自定義授權服務菜單,默認會展示當前定義的所有外部授權服務。
- 選擇要編輯的服務刪除即可。
自定義授權服務使用示例
創建測試命名空間
kubectl create ns foo
打開sidecar自動注入:
kubectl label ns foo istio-injection=enabled
部署sleep和httpbin應用
apiVersion: v1
kind: ServiceAccount
metadata:
name: sleep
---
apiVersion: v1
kind: Service
metadata:
name: sleep
labels:
app: sleep
service: sleep
spec:
ports:
- port: 80
name: http
selector:
app: sleep
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: sleep
spec:
replicas: 1
selector:
matchLabels:
app: sleep
template:
metadata:
labels:
app: sleep
spec:
terminationGracePeriodSeconds: 0
serviceAccountName: sleep
containers:
- name: sleep
image: registry-vpc-crs-huadong1.cnsp-internal.daliqc.cn/library/curl
command: ["/bin/sleep", "infinity"]
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /etc/sleep/tls
name: secret-volume
volumes:
- name: secret-volume
secret:
secretName: sleep-secret
optional: true
---
部署外部授權服務
apiVersion: v1
kind: Service
metadata:
name: ext-authz
labels:
app: ext-authz
spec:
ports:
- name: http
port: 8000
targetPort: 8000
- name: grpc
port: 9000
targetPort: 9000
selector:
app: ext-authz
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ext-authz
spec:
replicas: 1
selector:
matchLabels:
app: ext-authz
template:
metadata:
labels:
app: ext-authz
spec:
containers:
- image: registry-vpc-crs-huadong1.cnsp-internal.daliqc.cn/library/ext-authz:1.16.2
imagePullPolicy: IfNotPresent
name: ext-authz
ports:
- containerPort: 8000
- containerPort: 9000
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: httpbin
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
labels:
app: httpbin
service: httpbin
spec:
ports:
- name: http
port: 8000
targetPort: 80
selector:
app: httpbin
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
version: v1
template:
metadata:
labels:
app: httpbin
version: v1
spec:
serviceAccountName: httpbin
containers:
- image: registry-vpc-crs-huadong1.cnsp-internal.daliqc.cn/library/httpbin
imagePullPolicy: IfNotPresent
name: httpbin
ports:
- containerPort: 80
部署完成后,在foo命名空間下看到3個服務。

不使用授權策略的情況下,驗證從sleep應用訪問httpbin用沒有被攔截(返回狀態碼200):
kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl //httpbin.foo:8000/ip -s -o /dev/null -w "%{http_code}\n"
200
查看外部授權服務已經啟動,HTTP和gRPC授權服務分別監聽8000和9000端口:
kubectl logs "$(kubectl get pod -l app=ext-authz -n foo -o jsonpath={.items..metadata.name})" -n foo -c ext-authz
2023/08/14 11:26:54 Starting HTTP server at [::]:8000
2023/08/14 11:26:54 Starting gRPC server at [::]:9000
添加外部授權服務
將上面的HTTP和gRPC服務添加到服務網格的外部授權服務內。
定義授權策略&驗證訪問
定義如下授權策略,對httpbin應用的/headers路徑的請求將被轉發到第三方授權服務進行驗證:
apiVersion: security.istio.io/v1beta1
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"]
從sleep應用請求httpbin的/headers路徑,由于請求頭帶了"x-ext-authz:deny",請求被攔截:
kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "//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"頭部,請求放行:
kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "//httpbin.foo:8000/headers" -H "x-ext-authz: allow" -s
{
"headers": {
"Accept": "*/*",
"Host": "httpbin.foo:8000",
"User-Agent": "curl/8.2.1",
"X-B3-Parentspanid": "eb42a8165099e7db",
"X-B3-Sampled": "1",
"X-B3-Spanid": "cd6540ba1cfd9e8c",
"X-B3-Traceid": "e7e15cc10dc66630eb42a8165099e7db",
"X-Envoy-Attempt-Count": "1",
"X-Ext-Authz": "allow",
"X-Ext-Authz-Additional-Header-Override": "grpc-additional-header-override-value",
"X-Ext-Authz-Check-Received": "source:{address:{socket_address:{address:\"10.1.0.25\" port_value:37654}} principal:\"spiffe://cluster.local/ns/foo/sa/sleep\"} destination:{address:{socket_address:{address:\"10.1.0.24\" port_value:80}} principal:\"spiffe://cluster.local/ns/foo/sa/httpbin\"} request:{time:{seconds:1692015383 nanos:990298000} http:{id:\"7462237371770661564\" method:\"GET\" headers:{key:\":authority\" value:\"httpbin.foo:8000\"} headers:{key:\":method\" value:\"GET\"} headers:{key:\":path\" value:\"/headers\"} headers:{key:\":scheme\" value:\"http\"} headers:{key:\"accept\" value:\"*/*\"} headers:{key:\"user-agent\" value:\"curl/8.2.1\"} headers:{key:\"x-b3-sampled\" value:\"1\"} headers:{key:\"x-b3-spanid\" value:\"eb42a8165099e7db\"} headers:{key:\"x-b3-traceid\" value:\"e7e15cc10dc66630eb42a8165099e7db\"} 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=c32db24acfa670a8bbe46f0897ebb70b9ccc0e630ee32afcd1ec037d6616e6c5;Subject=\\\"\\\";URI=spiffe://cluster.local/ns/foo/sa/sleep\"} headers:{key:\"x-forwarded-proto\" value:\"http\"} headers:{key:\"x-request-id\" value:\"aba7b68c-6bee-9d58-b163-7454075c6ece\"} path:\"/headers\" host:\"httpbin.foo:8000\" scheme:\"http\" protocol:\"HTTP/1.1\"}} metadata_context:{}",
"X-Ext-Authz-Check-Result": "allowed",
"X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/foo/sa/httpbin;Hash=c32db24acfa670a8bbe46f0897ebb70b9ccc0e630ee32afcd1ec037d6616e6c5;Subject=\"\";URI=spiffe://cluster.local/ns/foo/sa/sleep"
}
}