前提条件
- 已开通云容器引擎,至少有一个云容器引擎集群实例。产品入口:云容器引擎。
- 开通天翼云服务网格实例。
操作步骤
创建测试命名空间
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.ctyun.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.ctyun.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.ctyun.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 http://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 "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"头部,请求放行:
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" -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"
}
}