Kubernetes 監控:Service Mesh 實踐 -- Istio 安全管控
除了流量管理、可觀測性之外,Istio 服務網格中還可以對網格進行安全管控。Istio 的安全功能主要分為三個部分的實現:
- 雙向 TLS 支援
- 基於黑白名單的訪問控制
- 基於角色的訪問控制
- JWT 認證支援
安全閘道器
Istio 的身份和證書管理是通過 SDS(安全發現服務)來實現的,如下圖所示:
其執行的流程如下所示:
- 首先 Istio 提供一個 gRPC 服務來接受證書籤名請求(CSRs)
- Envoy 通過 SDS API 傳送證書和金鑰請求
- 在收到 SDS 請求後,istio-agent 建立私鑰和 CSR,然後將 CSR 及其憑據傳送到 Istiod 中的 CA 服務進行簽名
- CA 驗證 CSR 中攜帶的憑據並簽署 CSR 以生成證書
- istio-agent 通過 Envoy SDS API 將私鑰與從 Istio CA 收到的證書傳送給 Envoy
- 上述 CSR 過程會週期性地重複,以處理證書和金鑰輪換
這的 istio-agent 並不是指的單獨的一個容器,而是指 sidecar 容器中的 pilot-agent 程序。
接下來我們可以通過 SDS 來為 Istio Ingress Gateway 配置 TLS 安全認證,配置 TLS Ingress Gateway,讓它從 Ingress Gateway 代理通過 SDS 獲取憑據。Ingress Gateway 代理和 Ingress Gateway 在同一個 Pod 中執行,監聽 Ingress Gateway 所在名稱空間中新建的 Secret。在 Ingress Gateway 中啟用 SDS 具有如下好處:
- Ingress Gateway 無需重啟,就可以動態的新增、刪除或者更新金鑰/證書對以及根證書。
- 無需掛載 Secret 卷,建立了 kubernetes Secret 之後,這個 Secret 就會被 Gateway 代理捕獲,並以金鑰/證書對和根證書的形式傳送給 Ingress Gateway。
- Gateway 代理能夠監視多個金鑰/證書對,只需要為每個主機名建立 Secret 並更新 Gateway 定義就可以了
下面我們通過一個簡單的示例來說明如何啟用 Istio Ingress Gateway 的 TLS 認證。
單一主機
首先使用 OpenSSL 生成證書和金鑰,使用如下命令建立根證書和私鑰來為你的服務簽名證書:
$ openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example.com.key -out example.com.crt
然後使用上面的根證書和私鑰為 httpbin.example.com 域名進行簽名,首先生成證書籤名請求:
$ openssl req -out httpbin.example.com.csr -newkey rsa:2048 -nodes -keyout httpbin.example.com.key -subj "/CN=httpbin.example.com/O=some organization"
然後使用上面的證書籤名請求來請求籤發證書:
$ openssl x509 -req -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in httpbin.example.com.csr -out httpbin.example.com.crt
Signature ok
subject=CN = httpbin.example.com, O = some organization
Getting CA Private Key
簽名成功後會得到如下所示的幾個證書和金鑰:
$ ls -la
total 56
drwxr-xr-x 9 ych staff 288 Jul 25 15:51 .
drwxr-xr-x 7 ych staff 224 Jul 25 15:18 ..
-rw-r--r-- 1 ych staff 1180 Jul 25 15:50 example.com.crt
-rw------- 1 ych staff 1708 Jul 25 15:50 example.com.key
-rw-r--r-- 1 ych staff 1050 Jul 25 15:51 httpbin.example.com.crt
-rw-r--r-- 1 ych staff 944 Jul 25 15:50 httpbin.example.com.csr
-rw------- 1 ych staff 1704 Jul 25 15:50 httpbin.example.com.key
由於 Ingress Gateway 是通過監聽同一名稱空間下面的 Secret 物件來進行安全服務發現的,所以我們需要將上面生成的證書建立在 istio-system 名稱空間之下:
$ kubectl create secret tls httpbin-tls --cert=httpbin.example.com.crt --key=httpbin.example.com.key -n istio-system
secret/httpbin-tls created
然後建立 httpbin 示例應用,應用資源清單檔案如下所示:
# httpbin.yaml
apiVersion: v1
kind: Service
metadata:
name: httpbin
labels:
app: httpbin
spec:
ports:
- name: http
port: 8000
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:
containers:
- image: docker.io/citizenstig/httpbin
imagePullPolicy: IfNotPresent
name: httpbin
ports:
- containerPort: 8000
使用如下所示命令直接安裝即可:
$ kubectl apply -f <(istioctl kube-inject -f httpbin.yaml)
service/httpbin created
deployment.apps/httpbin created
$ kubectl get pods -l app=httpbin
NAME READY STATUS RESTARTS AGE
httpbin-56db79f4f5-b2vp9 2/2 Running 0 8m35s
$ kubectl get svc -l app=httpbin
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpbin ClusterIP 10.106.18.14 <none> 8000/TCP 8m47s
然後接下來建立一個 Gateway,其 servers 欄位的埠為 443,設定 credentialName 的值為上面建立的 Secret 物件 httpbin-tls,並將 TLS 模式設定為 SIMPLE。
$ cat <<EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: mygateway
spec:
selector:
istio: ingressgateway # 使用預設的 ingress gatewaygateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: "httpbin-tls" # 必須使用上面建立的同名的Secret物件
hosts:
- "httpbin.example.com"
EOF
這樣就成功建立了一個 TLS 的安全閘道器,接下來為 httpbin 應用配置路由規則,建立一個 VirtualService 物件,如下所示:
$ cat <<EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "httpbin.example.com"
gateways:
- mygateway
http:
- match:
- uri:
prefix: /status
- uri:
prefix: /delay
route:
- destination:
port:
number: 8000
host: httpbin
EOF
這樣我們就可以通過 HTTPS 協議安全的訪問 httpbin 應用了,由於我們這裡的 Istio Ingressgateway 是通過 NodePort 暴露的服務,所以我們在測試的時候應該使用 443 埠對應的 nodePort 埠:
$ kubectl get svc -n istio-system -l istio=ingressgateway
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway NodePort 10.102.120.128 <none> 15020:31093/TCP,80:32193/TCP,443:30951/TCP,31400:31871/TCP,15443:31367/TCP 46d
從上面可以看出我們的閘道器安全訪問埠是 30951,閘道器地址是任意的一個節點 IP,我們這裡使用 master 節點的地址 k8s.qikqiak.com,當然還要記得將域名 httpbin.example.com 也要解析到閘道器的節點上,我們可以執行如下所示的命令:
$ curl -v -HHost:httpbin.example.com --cacert example.com.crt https://httpbin.example.com:30951/status/418
* Trying 123.59.188.12...
* TCP_NODELAY set
* Connected to httpbin.example.com (123.59.188.12) port 30951 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: example.com.crt
CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=httpbin.example.com; O=some organization
* start date: Jul 25 07:51:14 2020 GMT
* expire date: Jul 25 07:51:14 2021 GMT
* common name: httpbin.example.com (matched)
* issuer: O=example Inc.; CN=example.com
* SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x7feb00008a00)
> GET /status/418 HTTP/2
> Host:httpbin.example.com
> User-Agent: curl/7.64.1
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 2147483647)!
< HTTP/2 418
< server: istio-envoy
< date: Sat, 25 Jul 2020 08:46:02 GMT
< access-control-allow-credentials: true
< access-control-allow-origin: *
< x-more-info: http://tools.ietf.org/html/rfc2324
< content-length: 135
< x-envoy-upstream-service-time: 10
<
-=[ teapot ]=-
_...._
.' _ _ `.
| ."` ^ `". _,
\_;`"---"`|//
| ;/
\_ _/
`"""`
* Connection #0 to host httpbin.example.com left intact
* Closing connection 0
通過上面的資訊可以看到輸出了正確的結果,通過 -v 引數還可以看到 TLS 握手建立連線的完整過程。
多個主機
上面是將單個主機配置到一個 Ingress Gateway 中,同樣我們還可以把多個主機名配置到同一個 Ingress Gateway 上,例如 httpbin.example.com 和 hello.example.com 兩個主機名配置到同一個閘道器上,Ingress Gateway 會為每個 credentialName 獲取一個唯一的憑據。
同樣先部署 helloworld 示例應用,對應的資源清單檔案如下所示:
# helloworld-v1.yaml
apiVersion: v1
kind: Service
metadata:
name: helloworld-v1
labels:
app: helloworld-v1
spec:
ports:
- name: http
port: 5000
selector:
app: helloworld-v1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: helloworld-v1
spec:
replicas: 1
selector:
matchLabels:
app: helloworld-v1
version: v1
template:
metadata:
labels:
app: helloworld-v1
version: v1
spec:
containers:
- name: helloworld
image: istio/examples-helloworld-v1
resources:
requests:
cpu: "100m"
imagePullPolicy: IfNotPresent #Always
ports:
- containerPort: 5000
使用如下所示命令直接安裝即可:
$ kubectl apply -f <(istioctl kube-inject -f helloworld-v1.yaml)
service/helloworld-v1 created
deployment.apps/helloworld-v1 created
$ kubectl get pods -l app=helloworld-v1
NAME READY STATUS RESTARTS AGE
httpbin-56db79f4f5-b2vp9 2/2 Running 0 8m35s
$ kubectl get svc -l app=helloworld-v1
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
helloworld-v1 ClusterIP 10.104.3.71 <none> 5000/TCP 30s
然後同樣使用上面我們建立的根證書來對域名 hello.example.com 進行簽名,首先生成證書籤名請求:
$ openssl req -out hello.example.com.csr -newkey rsa:2048 -nodes -keyout hello.example.com.key -subj "/CN=hello.example.com/O=some organization"
然後使用上面的證書籤名請求來請求籤發證書:
$ openssl x509 -req -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in hello.example.com.csr -out hello.example.com.crt
Signature ok
subject=CN = hello.example.com, O = some organization
Getting CA Private Key
同樣使用上面生成的證書和金鑰在 istio-system 名稱空間下面為 Ingress Gateway 新建一個 Secret 物件:
$ kubectl create secret tls hello-tls --cert=hello.example.com.crt --key=hello.example.com.key -n istio-system
secret/hello-tls created
然後重新定義上面的 Gateway 閘道器,其中包含了兩個 server,都開放了 443 埠。兩個 credentialName 欄位分別賦值為 httpbin-tls 和 hello-tls,設定 TLS 的 mode 為 SIMPLE 。
$ cat <<EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: mygateway
spec:
selector:
istio: ingressgateway # 使用 istio 預設的 ingress gateway
servers:
- port:
number: 443
name: https-httpbin
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: "httpbin-tls"
hosts:
- "httpbin.example.com"
- port:
number: 443
name: https-hello
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: "hello-tls"
hosts:
- "hello.example.com"
EOF
由於上面我們已經為 httpbin 應用配置了路由規則,所以接下來只需要為 helloworld 應用配置流量路由即可:
$ cat <<EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: hello
spec:
hosts:
- "hello.example.com"
gateways:
- mygateway
http:
- match:
- uri:
exact: /hello
route:
- destination:
host: helloworld-v1
port:
number: 5000
EOF
建立完成後將域名 hello.example.com 解析到閘道器的地址,然後對其傳送 HTTPS 請求:
$ curl -v -HHost:hello.example.com --cacert example.com.crt https://hello.example.com:30951/hello
......
< HTTP/2 200
< content-type: text/html; charset=utf-8
< content-length: 59
< server: istio-envoy
< date: Sat, 25 Jul 2020 08:49:42 GMT
< x-envoy-upstream-service-time: 313
<
......
同樣傳送 HTTPS 請求到 httpbin.example.com,還是會看到正確的結果:
$ curl -v -HHost:httpbin.example.com --cacert example.com.crt https://httpbin.example.com:30951/status/418
......
< HTTP/2 418
< server: istio-envoy
< date: Sat, 25 Jul 2020 08:50:53 GMT
< access-control-allow-credentials: true
< access-control-allow-origin: *
< x-more-info: http://tools.ietf.org/html/rfc2324
< content-length: 135
< x-envoy-upstream-service-time: 5
<
-=[ teapot ]=-
_...._
.' _ _ `.
| ."` ^ `". _,
\_;`"---"`|//
| ;/
\_ _/
`"""`
* Connection #0 to host httpbin.example.com left intact
* Closing connection 0
mTLS 認證
在 Istio 中主要有兩種型別的認證:
- 對等認證(PeerAuthentication):用於服務到服務的認證,以驗證進行連線的客戶端,Istio 提供雙向 TLS 作為傳輸認證的解決方案,無需更改服務程式碼就可以啟用它。
- 請求認證(RequestAuthentication):用於終端使用者認證,以驗證附加到請求的憑據,Istio 使用 JSON Web Token(JWT)驗證啟用請求級認證。
Istio 中的認證策略範圍主要包括如下三個方面:
- 網格
- 名稱空間
- 特定服務
此外,Istio 的認證機制支援相容模式(permissive mode),以幫助我們瞭解安全策略或者服務遷移。
接下來我們來為服務網格內部的服務開啟自動 mTLS(雙向TLS認證),實現客戶端、服務端都驗證雙方身份。前面我們已經在 default 名稱空間下面部署了 httpbin 應用:
$ kubectl get pods -l app=httpbin
NAME READY STATUS RESTARTS AGE
httpbin-68dbf6ccd9-npn6w 2/2 Running 0 11d
$ kubectl get svc -l app=httpbin
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpbin ClusterIP 10.106.18.14 <none> 8000/TCP 11d
現在我們來測試下名稱空間範圍內的認證,部署 sleep 應用到 mtls 名稱空間下面:
$ kubectl create ns mtls
namespace/mtls created
$ kubectl apply -f samples/sleep/sleep.yaml -n mtls
serviceaccount/sleep created
service/sleep created
deployment.apps/sleep created
$ kubectl get pods -n mtls
NAME READY STATUS RESTARTS AGE
sleep-f8cbf5b76-kfqzv 1/1 Running 0 95s
當應用部署完成後,以 sleep 應用為客戶端來訪問 default 名稱空間下面的 httpbin 應用,命令如下所示:
$ kubectl exec -it sleep-f8cbf5b76-kfqzv -n mtls -- curl http://httpbin.default:8000/ip
{
"origin": "127.0.0.1"
}
可以看到能夠正常訪問,這是因為通訊的雙方沒有任何的 TLS 認證方式,所以預設情況下是可以訪問的。然後我們建立一個對等認證的策略:
# mtls-demo.yaml
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: mtls-demo
namespace: default # 去掉namespace就是全域性的,加上就是名稱空間級別的
spec:
selector: # 如果配置了selector,則只會對下面匹配的服務生效(針對特定的服務),如果您沒有為 selector 欄位提供值,則 Istio 會將策略與策略儲存範圍內的所有工作負載進行匹配
matchLabels:
app: httpbin
mtls:
mode: PERMISSIVE # 相容模式:可以同時使用明文和加密的方式訪問
# mode: STRICT # 嚴格模式:雙方必須使用 mTLS 去訪問
# DISABLE:禁用雙向 TLS,從安全形度來看,除非您提供自己的安全解決方案,否則請勿使用此模式
裡我們建立了一個基於 default 這個名稱空間的對等認證策略,通過配置 mode: PERMISSIVE 指定使用相容模式進行認證,該模式下面可以同時使用明文和加密的方式訪問服務,此外還可以通過 labelSelector 去針對特定的服務生效。直接建立上面的資源物件即可:
$ kubectl apply -f mtls-demo.yaml
peerauthentication.security.istio.io/mtls-demo created
這個時候我們重新訪問 httpbin 應用可以看到仍然可以訪問,因為我們配置的是相容的寬鬆模式:
$ kubectl exec -it sleep-f8cbf5b76-kfqzv -n mtls -- curl http://httpbin.default:8000/ip
{
"origin": "127.0.0.1"
}
接下來我們將上面的 mode 改成嚴格模式 STRICT,重新更新後,再次訪問 httpbin 應用:
$ kubectl exec -it sleep-f8cbf5b76-kfqzv -n mtls -- curl http://httpbin.default:8000/ip
curl: (56) Recv failure: Connection reset by peer
command terminated with exit code 56
可以看到請求失敗了,證明我們配置的嚴格模式生效了。那麼正確訪問 httpbin 服務的方式是怎樣的呢?其實也非常簡單,只需要將我們的客戶端 sleep 應用加入到網格中來即可:
$ kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml) -n mtls
serviceaccount/sleep unchanged
service/sleep unchanged
deployment.apps/sleep configured
$ kubectl get pods -n mtls
NAME READY STATUS RESTARTS AGE
sleep-776fd7c979-jvpbt 2/2 Running 0 15s
$ kubectl exec -it sleep-776fd7c979-jvpbt -c sleep -n mtls -- curl http://httpbin.default:8000/ip
{
"origin": "127.0.0.1"
}
我們只是在網格中建立了一個對等認證策略的資源物件,就完成了 mTLS 認證,這是因為 Istio 已經實現了自動的 mTLS,會幫我們自動完成證書和金鑰的管理,直接注入即可。
基於 JWT 的認證和授權
JWT(JSON Web Token)是一種多方傳遞可信 JSON 資料的方案,一個 JWT token 由.分隔的三部分組成:{Header}.{Payload}.{Signature},其中 Header 是 Base64 編碼的 JSON 資料,包含令牌型別、簽名演算法以及祕鑰 ID 等資訊;Payload 是需要傳遞的 claims 資料,也是 Base64 編碼的 JSON 資料,其中有些欄位是 JWT 標準已有的欄位如:exp、iat、iss、sub 等,也可以根據需求新增自定義欄位;Signature 是對前兩部分的簽名,防止資料被篡改,以此確保 token 資訊是可信的。
Istio 中驗籤所需公鑰由 RequestAuthentication 請求認證資源的 jwks 配置提供。JWT 授權則是對終端使用者的訪問控制,比如某個內部服務需要管理員才能夠訪問,這時候就需要驗證終端使用者的角色是否為管理員,可以在 JWT claims 中帶有管理員角色資訊,然後在授權策略中對該角色進行授權。
要使用 JWT 授權的當然就需要有效的 JWT 終端身份認證,所以在使用 JWT 授權前首先要為服務新增終端身份認證即 RequestAuthentication。
Request 認證策略指定驗證 JWT 所需的值,這些值包括:
- token 在請求中的位置
- 請求的 issuer
- 公共 JSON Web Key Set(JWKS)
Istio 會根據 request 認證策略中的規則檢查提供的令牌(如果已提供),並拒絕令牌無效的請求。當請求不帶有令牌時,預設情況下將接受它們。要拒絕沒有令牌的請求,請提供授權規則。
現在我們來驗證基於 JWT 的認證功能,同樣使用 sleep 和 httpbin 應用為例,將 sleep 部署到名為 jwtest 的名稱空間:
$ kubectl create ns jwtest
namespace/jwtest created
$ kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml) -n jwtest
serviceaccount/sleep created
service/sleep created
deployment.apps/sleep created
$ kubectl get pods -n jwtest
NAME READY STATUS RESTARTS AGE
sleep-776fd7c979-7jrv2 2/2 Running 0 76s
現在預設情況下我們是可以正常訪問 httpbin 應用的:
$ kubectl exec -it sleep-776fd7c979-7jrv2 -c sleep -n jwtest -- curl http://httpbin.default:8000/ip
{
"origin": "127.0.0.1"
}
然後我們建立一個如下所示的請求認證物件:
# jwt-demo.yaml
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication # 請求認證
metadata:
name: jwt-demo
namespace: default
spec:
selector: # 針對特定的服務
matchLabels:
app: httpbin
jwtRules:
- issuer: "[email protected]"
jwksUri: "https://raw.githubusercontent.com/istio/istio/release-1.6/security/tools/jwt/samples/jwks.json"
# jwks
# fromHeaders
# fromParams
其中最重要的就是 jwtRules 屬性下面的配置,我們這裡通過 jwksUri 來指定所需的認證資訊,直接建立:
$ kubectl apply -f jwt-demo.yaml
requestauthentication.security.istio.io/jwt-demo created
這個請求認證策略使得 httpbin 應用接收 Issuer 為 [email protected] 的 JWT 令牌。比如我們通過一個無效的 Token 來訪問應用:
$ kubectl exec -it sleep-776fd7c979-7jrv2 -c sleep -n jwtest -- curl http://httpbin.default:8000/headers -s -o /dev/null -H "Authorization: Bearer invalidToken" -w "%{http_code}\n"
401
因為我們指定了 Token,所以就需要使用我們配置的 JWT Token 來進行認證。如果我們不帶上 Token,則可以正常訪問,這是因為我們並沒有配置任何授權策略:
$ kubectl exec -it sleep-776fd7c979-7jrv2 -c sleep -n jwtest -- curl http://httpbin.default:8000/headers -s -o /dev/null -w "%{http_code}\n"
200
接下來我們針對 httpbin 應用配置一個授權策略,要求所有發往 httpbin 應用的請求都要包含一個將 requestPrincipal 設定為 [email protected]/[email protected] 的有效 JWT。
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy # 授權策略
metadata:
name: auth-policy-demo
namespace: default
spec:
selector:
matchLabels:
app: httpbin
action: ALLOW # ALLOW、DENY
rules:
- from:
- source:
requestPrincipals: ["[email protected]/[email protected]"]
Istio 會使用 / 連線 JWT 的 iss 和 sub 來組成 requestPrincipal 欄位,比如我這裡的 iss 和 sub 都為 [email protected],這樣 Istio 生成的 requestPrincipal 屬性值為 [email protected]/[email protected],我們可以通過如下命令獲取測試的 Token 以及 JSON 資訊:
$ JWT_JSON=$(curl https://raw.githubusercontent.com/istio/istio/release-1.6/security/tools/jwt/samples/demo.jwt -s) && echo $JWT_JSON | cut -d '.' -f2 - | base64 --decode -
{"exp":4685989700,"foo":"bar","iat":1532389700,"iss":"[email protected]","sub":"[email protected]"}
$ TOKEN=$(curl https://raw.githubusercontent.com/istio/istio/release-1.6/security/tools/jwt/samples/demo.jwt -s)
直接建立上面的認證策略:
$ kubectl apply -f auth-policy-demo.yaml
authorizationpolicy.security.istio.io/auth-policy-demo created
建立完成後我們使用上面的有效的 TOKEN 來訪問 httpbin 應用:
$ kubectl exec -it sleep-776fd7c979-7jrv2 -c sleep -n jwtest -- curl "http://httpbin.default:8000/headers" -s -o /dev/null -H "Authorization: Bearer $TOKEN" -w "%{http_code}\n"
200
可以看到可以正常訪問,我們重新使用沒有 JWT Token 的 Header 來請求 httpbin 應用:
istio-1.6.1]# kubectl exec -it sleep-776fd7c979-7jrv2 -c sleep -n jwtest -- curl "http://httpbin.default:8000/headers" -s -o /dev/null -w "%{http_code}\n"
403
可以看到是 403 錯誤,這是因為當前的請求不符合上面我們配置的授權策略。關於安全相關的更多資訊或者資源物件屬性欄位可以檢視官方文件:https://istio.io/latest/zh/docs/concepts/security/。