在 Azure Kubernetes Service (AKS) 中使用網路原則來保護 Pod 之間的流量
當您在 Kubernetes 中執行新式微服務架構的應用程式時,您通常想要控制哪些元件可以彼此通訊。 最低權限原則應該套用至流量可以在 Azure Kubernetes Service (AKS) 叢集中的 Pod 之間流動的方式。 假設您可能想要封鎖直接流向後端應用程式的流量。 Kubernetes 中的「網路原則」功能可讓您針對叢集中 Pod 之間的輸入和輸出流量定義規則。
本文示範如何安裝網路原則引擎,並建立 Kubernetes 網路原則來控制 AKS 中 Pod 之間的流量流程。 網路原則只應用於 AKS 中的 Linux 型節點和 Pod。
開始之前
您必須安裝並設定 Azure CLI 版本 2.0.61 或更新版本。 執行 az --version
以尋找版本。 如果您需要安裝或升級,請參閱安裝 Azure CLI。
提示
如果您已在預覽期間使用網路原則功能,我們建議您建立新的叢集。
如果您想要繼續使用在預覽期間使用網路原則的現有測試叢集,請將您的叢集升級至最新 GA 版本的新 Kubernetes 版本,然後部署下列 YAML 資訊清單,以修正損毀的計量伺服器和 Kubernetes 儀表板。 只有使用 Calico 網路原則引擎的叢集才需要此修正。
作為安全性最佳做法,檢閱此 YAML 資訊清單的內容,了解部署到 AKS 叢集的內容。
kubectl delete -f https://raw.githubusercontent.com/Azure/aks-engine/master/docs/topics/calico-3.3.1-cleanup-after-upgrade.yaml
網路原則概觀
根據預設,AKS 叢集中的所有 Pod 都可以無限制地傳送及接收流量。 為了提升安全性,您可以定義可控制流量流程的規則。 例如,後端應用程式通常只會對必要的前端服務公開。 或者,只有連線到資料庫元件的應用層才能存取它們。
網路原則是一種 Kubernetes 規格,其定義 Pod 之間通訊的存取原則。 使用網路原則時,您可以定義一組已排序的規則來傳送和接收流量,並將其套用至符合一或多個標籤選取器的 Pod 集合。
這些網路原則規則會定義為 YAML 資訊清單。 網路原則可納入更廣泛的資訊清單中,而該清單也會建立部署或服務。
AKS 中的網路原則選項
Azure 提供兩種方式來實作網路原則。 當您建立 AKS 叢集時,可以選擇網路原則選項。 建立叢集之後,就無法變更原則選項:
- Azure 本身的實作,稱為 Azure 網路原則。
- Calico 網路原則,這是 Tigera 創建的開放原始碼網路和網路安全性解決方案。
這兩個部署都會使用 Linux IPTables 來強制執行指定的原則。 這些原則會轉譯成一組允許和不允許的 IP 配對。 這些配對接著會透過程式設計為 IPTable 篩選規則。
Azure 與 Calico 原則之間的差異及其功能
功能 | Azure | Calico |
---|---|---|
支援的平台 | Linux | Linux、Windows Server 2019 (preview) |
支援的網路功能選項 | Azure CNI | Azure CNI (Windows Server 2019 和 Linux) 和 kubenet (Linux) |
符合 Kubernetes 規格 | 支援所有原則類型 | 支援所有原則類型 |
其他功能 | None | 由全域網路原則、全域網路集和主機端點組成的延伸原則模型。 如需使用 calicoctl CLI 管理這些擴充功能的詳細資訊,請參閱 calicoctl 使用者參考。 |
支援 | 受到 Azure 支援和工程團隊支援 | Azure 社群支援。 如需其他付費支援的詳細資訊,請參閱 Project Calico 支援選項。 |
記錄 | 在 IPTables 中新增/刪除的規則會記錄在每一部主機的 /var/log/azure-npm.log 下 | 如需詳細資訊,請參閱 Calico 元件記錄 |
建立 AKS 叢集並啟用網路原則
若要查看運作中的網路原則,讓我們建立而後展開可定義流量流程的原則:
- 拒絕流向 Pod 的所有流量。
- 允許以 Pod 標籤為基礎的流量。
- 允許以命名空間為基礎的流量。
首先,讓我們建立支援網路原則的 AKS 叢集。
重要
只有在建立叢集時,才可以啟用網路原則功能。 您無法在現有的 AKS 叢集上啟用網路原則。
若要使用 Azure 網路原則,您必須使用 Azure CNI 外掛程式並定義自己的虛擬網路和子網路。 如需有關如何規劃出必要子網路範圍的詳細資訊,請參閱設定進階網路。 Calico 網路原則可以與這個相同的 Azure CNI 外掛程式或與 Kubenet CNI 外掛程式搭配使用。
下列範例指令碼:
- 建立虛擬網路和子網路。
- 建立 Azure Active Directory (Azure AD) 服務主體,以便搭配 AKS 叢集使用。
- 針對虛擬網路上的 AKS 叢集服務主體指派「參與者」權限。
- 在定義的虛擬網路中建立 AKS 叢集,然後啟用網路原則。
- 即會使用 Azure 網路原則選項。 若要改用 Calico 做為網路原則選項,請使用
--network-policy calico
參數。 注意:Calico 可以搭配--network-plugin azure
或--network-plugin kubenet
使用。
- 即會使用 Azure 網路原則選項。 若要改用 Calico 做為網路原則選項,請使用
請注意,不是使用服務主體,而是您可以使用受控識別來取得權限。 如需詳細資訊,請參閱使用受控識別。
提供您自己的安全 SP_PASSWORD。 您可以取代 RESOURCE_GROUP_NAME 和 CLUSTER_NAME 變數:
RESOURCE_GROUP_NAME=myResourceGroup-NP
CLUSTER_NAME=myAKSCluster
LOCATION=canadaeast
# Create a resource group
az group create --name $RESOURCE_GROUP_NAME --location $LOCATION
# Create a virtual network and subnet
az network vnet create \
--resource-group $RESOURCE_GROUP_NAME \
--name myVnet \
--address-prefixes 10.0.0.0/8 \
--subnet-name myAKSSubnet \
--subnet-prefix 10.240.0.0/16
# Create a service principal and read in the application ID
SP=$(az ad sp create-for-rbac --role Contributor --output json)
SP_ID=$(echo $SP | jq -r .appId)
SP_PASSWORD=$(echo $SP | jq -r .password)
# Wait 15 seconds to make sure that service principal has propagated
echo "Waiting for service principal to propagate..."
sleep 15
# Get the virtual network resource ID
VNET_ID=$(az network vnet show --resource-group $RESOURCE_GROUP_NAME --name myVnet --query id -o tsv)
# Assign the service principal Contributor permissions to the virtual network resource
az role assignment create --assignee $SP_ID --scope $VNET_ID --role Contributor
# Get the virtual network subnet resource ID
SUBNET_ID=$(az network vnet subnet show --resource-group $RESOURCE_GROUP_NAME --vnet-name myVnet --name myAKSSubnet --query id -o tsv)
建立適用于 Azure 網路原則的 AKS 叢集
建立 AKS 叢集,並為網路外掛程式和網路原則指定虛擬網路、服務主體資訊和 azure 。
az aks create \
--resource-group $RESOURCE_GROUP_NAME \
--name $CLUSTER_NAME \
--node-count 1 \
--generate-ssh-keys \
--service-cidr 10.0.0.0/16 \
--dns-service-ip 10.0.0.10 \
--docker-bridge-address 172.17.0.1/16 \
--vnet-subnet-id $SUBNET_ID \
--service-principal $SP_ID \
--client-secret $SP_PASSWORD \
--network-plugin azure \
--network-policy azure
建立叢集需要幾分鐘的時間。 當叢集備妥時,請使用 az aks get-credentials 命令,設定 kubectl
以連線到 Kubernetes 叢集。 此命令會下載憑證並設定 Kubernetes CLI 以供使用:
az aks get-credentials --resource-group $RESOURCE_GROUP_NAME --name $CLUSTER_NAME
建立適用于 Calico 網路原則的 AKS 叢集
建立 AKS 叢集並指定虛擬網路、服務主體資訊、 azure 作為網路外掛程式,以及網路原則的 calico 。 使用calico作為網路原則可在 Linux 和Windows節點集區上啟用 Calico 網路功能。
如果您打算將Windows節點集區新增至叢集,請包含 windows-admin-username
符合Windows 伺服器密碼需求的和 windows-admin-password
參數。 若要搭配Windows節點集區使用 Calico,您也需要註冊 Microsoft.ContainerService/EnableAKSWindowsCalico
。
EnableAKSWindowsCalico
使用az feature register 命令註冊功能旗標,如下列範例所示:
az feature register --namespace "Microsoft.ContainerService" --name "EnableAKSWindowsCalico"
您可以使用 az feature list 命令檢查註冊狀態:
az feature list -o table --query "[?contains(name, 'Microsoft.ContainerService/EnableAKSWindowsCalico')].{Name:name,State:properties.state}"
準備就緒時,請使用az provider register命令重新整理Microsoft.ContainerService資源提供者的註冊:
az provider register --namespace Microsoft.ContainerService
重要
目前,使用 Calico 網路原則搭配 Windows 節點,可在新的叢集上使用 Kubernetes 1.20 版或更新版本搭配 Calico 3.17.2,而且需要使用 Azure CNI 網路。 Windows已啟用 Calico 之 AKS 叢集上的節點,預設也會啟用直接伺服器傳回 (DSR) 。
若叢集只有執行 Kubernetes 1.20 且舊版 Calico 的 Linux 節點集區,Calico 版本會自動升級為 3.17.2。
具有Windows節點的 Calico 網路原則目前為預覽狀態。
重要
AKS 預覽功能可依自助式、加入宣告提供。 預覽提供「原狀」和「可用」,而且會從服務等級協定和有限擔保中排除。 客戶支援會以最佳方式涵蓋 AKS 預覽。 因此,這些功能不適合用于生產環境。 如需詳細資訊,請參閱下列支援文章:
建立使用者名稱,以作為叢集上Windows伺服器容器的系統管理員認證。 下列命令會提示您輸入使用者名稱,並將它設定為WINDOWS_USERNAME在稍後的命令中使用, (請記住,本文中的命令會輸入 BASH 殼層) 。
echo "Please enter the username to use as administrator credentials for Windows Server containers on your cluster: " && read WINDOWS_USERNAME
az aks create \
--resource-group $RESOURCE_GROUP_NAME \
--name $CLUSTER_NAME \
--node-count 1 \
--generate-ssh-keys \
--service-cidr 10.0.0.0/16 \
--dns-service-ip 10.0.0.10 \
--docker-bridge-address 172.17.0.1/16 \
--vnet-subnet-id $SUBNET_ID \
--service-principal $SP_ID \
--client-secret $SP_PASSWORD \
--windows-admin-username $WINDOWS_USERNAME \
--vm-set-type VirtualMachineScaleSets \
--kubernetes-version 1.20.2 \
--network-plugin azure \
--network-policy calico
建立叢集需要幾分鐘的時間。 根據預設,您的叢集只會使用 Linux 節點集區來建立。 如果您想要使用Windows節點集區,您可以新增節點集區。 例如:
az aks nodepool add \
--resource-group $RESOURCE_GROUP_NAME \
--cluster-name $CLUSTER_NAME \
--os-type Windows \
--name npwin \
--node-count 1
當叢集備妥時,請使用 az aks get-credentials 命令,設定 kubectl
以連線到 Kubernetes 叢集。 此命令會下載憑證並設定 Kubernetes CLI 以供使用:
az aks get-credentials --resource-group $RESOURCE_GROUP_NAME --name $CLUSTER_NAME
拒絕流向 Pod 的所有輸入流量
在您定義規則以允許特定網路流量之前,先建立網路原則以拒絕所有流量。 此原則可讓您開始建立只允許流量的允許清單。 您可以也清楚地看到套用網路原則時會捨棄該流量。
針對範例應用程式環境和流量規則,讓我們先建立名為 development 的命名空間以執行範例 Pod:
kubectl create namespace development
kubectl label namespace/development purpose=development
建立可執行 NGINX 的範例後端 Pod。 這個後端 Pod 可用於模擬範例後端 Web 應用程式。 在 development 命名空間中建立這個 Pod,然後開啟連接埠 80 來處理 Web 流量。 替 Pod 加上 app=webapp,role=backend 標籤,以便我們在下一節中使用網路原則以其作為目標:
kubectl run backend --image=mcr.microsoft.com/oss/nginx/nginx:1.15.5-alpine --labels app=webapp,role=backend --namespace development --expose --port 80
建立另一個 Pod,然後連結終端機工作階段,來測試您是否可以成功觸達預設 NGINX 網頁:
kubectl run --rm -it --image=mcr.microsoft.com/aks/fundamental/base-ubuntu:v0.0.11 network-policy --namespace development
在殼層提示字元,使用 wget
來確認您可以存取預設 NGINX 網頁:
wget -qO- http://backend
下列範例輸出會顯示傳回的預設 NGINX 網頁:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
[...]
結束連結的終端機工作階段。 測試 Pod 會自動刪除。
exit
建立並套用網路原則
既然已確認您可以在範例後端 Pod 上使用基本 NGINX 網頁,請建立網路原則以拒絕所有流量。 建立名為 backend-policy.yaml
的檔案,並貼上下列 YAML 資訊清單。 此資訊清單會使用 podSelector 將原則連結至具有 app:webapp,role:backend 標籤的 Pod,例如您的範例 NGINX Pod。 ingress 之下未定義任何規則,因此會拒絕流向 Pod 的所有輸入流量:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: backend-policy
namespace: development
spec:
podSelector:
matchLabels:
app: webapp
role: backend
ingress: []
移至 https://shell.azure.com,以在瀏覽器中開啟 Azure Cloud Shell。
使用 kubectl apply 命令來套用網路原則,並指定 YAML 資訊清單的名稱:
kubectl apply -f backend-policy.yaml
測試網路原則
讓我們看看您是否可以在後端 Pod 上再次使用 NGINX 網頁。 建立另一個測試 Pod 並連結終端機工作階段:
kubectl run --rm -it --image=mcr.microsoft.com/aks/fundamental/base-ubuntu:v0.0.11 network-policy --namespace development
在殼層提示字元,使用 wget
來查看您是否可以存取預設 NGINX 網頁。 此時,將逾時值設定為 2 秒。 網路原則現在會封鎖所有輸入流量,因此無法載入此頁面,如下列範例所示:
wget -O- --timeout=2 --tries=1 http://backend
wget: download timed out
結束連結的終端機工作階段。 測試 Pod 會自動刪除。
exit
允許以 Pod 標籤為基礎的輸入流量
在上一節中,已排程後端 NGINX Pod,並建立了網路原則以拒絕所有流量。 讓我們建立前端 Pod 並更新網路原則,以允許來自前端 Pod 的流量。
更新網路原則,以允許來自任何命名空間中具有 app:webapp,role:frontend 標籤的 Pod 流量。 編輯先前的 backend-policy.yaml 檔案,然後新增 matchLabels 輸入規則,讓您的資訊清單看起來如下列範例所示:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: backend-policy
namespace: development
spec:
podSelector:
matchLabels:
app: webapp
role: backend
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: webapp
role: frontend
注意
此網路原則針對輸入規則使用 namespaceSelector 和 podSelector 元素。 YAML 語法對於附加輸入規則非常重要。 在此範例中,兩個元素都必須與要套用的輸入規則相符。 在 Kubernetes 1.12 之前的版本,可能無法如您所預期般正確地轉譯這些元素並限制網路流量。 如需此行為的詳細資訊,請參閱選取器的來回行為。
使用 kubectl apply 命令來套用已更新的網路原則,並指定 YAML 資訊清單的名稱:
kubectl apply -f backend-policy.yaml
排程標籤為 app=webapp,role=frontend 的 Pod 並連結終端機工作階段:
kubectl run --rm -it frontend --image=mcr.microsoft.com/aks/fundamental/base-ubuntu:v0.0.11 --labels app=webapp,role=frontend --namespace development
在殼層提示字元,使用 wget
來查看您是否可以存取預設 NGINX 網頁:
wget -qO- http://backend
因為輸入規則允許具有 app: webapp,role: frontend 標籤的 Pod 流量,所以允許來自前端 Pod 的流量。 下列範例輸出會顯示傳回的預設 NGINX 網頁:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
[...]
結束連結的終端機工作階段。 Pod 會自動刪除。
exit
測試沒有相符標籤的 Pod
網路原則允許來自標籤為 app: webapp,role: frontend 的 Pod 流量,但應該拒絕所有其他流量。 讓我們測試以查看另一個沒有這些標籤的 Pod 是否可以存取後端 NGINX Pod。 建立另一個測試 Pod 並連結終端機工作階段:
kubectl run --rm -it --image=mcr.microsoft.com/aks/fundamental/base-ubuntu:v0.0.11 network-policy --namespace development
在殼層提示字元,使用 wget
來查看您是否可以存取預設 NGINX 網頁。 網路原則會封鎖輸入流量,因此無法載入此頁面,如下列範例所示:
wget -O- --timeout=2 --tries=1 http://backend
wget: download timed out
結束連結的終端機工作階段。 測試 Pod 會自動刪除。
exit
只允許來自已定義命名空間的流量
在上述範例中,您建立了可拒絕所有流量的網路原則,然後更新了此原則,以允許來自具有特定標籤的 Pod 流量。 另一個常見需求是讓流量僅限於指定的命名空間內。 如果先前的範例是針對 development 命名空間中的流量,請建立網路原則,以防止來自另一個命名空間 (例如 production) 的流量觸達 Pod。
首先,建立新的命名空間,以模擬生產命名空間:
kubectl create namespace production
kubectl label namespace/production purpose=production
在標籤為 app=webapp,role=frontend 的 production 命名空間中排程測試 Pod。 連結終端機工作階段:
kubectl run --rm -it frontend --image=mcr.microsoft.com/aks/fundamental/base-ubuntu:v0.0.11 --labels app=webapp,role=frontend --namespace production
在殼層提示字元,使用 wget
來確認您可以存取預設 NGINX 網頁:
wget -qO- http://backend.development
因為 Pod 的標籤符合網路原則目前許可的內容,所以允許流量。 網路原則不會查看命名空間,只會查看 Pod 標籤。 下列範例輸出會顯示傳回的預設 NGINX 網頁:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
[...]
結束連結的終端機工作階段。 測試 Pod 會自動刪除。
exit
更新網路原則
讓我們更新輸入規則 namespaceSelector 區段,只允許來自 development 命名空間的流量。 編輯 backend-policy.yaml 資訊清單檔,如下列範例所示:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: backend-policy
namespace: development
spec:
podSelector:
matchLabels:
app: webapp
role: backend
ingress:
- from:
- namespaceSelector:
matchLabels:
purpose: development
podSelector:
matchLabels:
app: webapp
role: frontend
在更複雜的範例中,您可以定義多個輸入規則,例如依序使用 namespaceSelector 和 podSelector。
使用 kubectl apply 命令來套用已更新的網路原則,並指定 YAML 資訊清單的名稱:
kubectl apply -f backend-policy.yaml
測試已更新的網路原則
在 production 命名空間中排程另一個 Pod,然後連結終端機工作階段:
kubectl run --rm -it frontend --image=mcr.microsoft.com/aks/fundamental/base-ubuntu:v0.0.11 --labels app=webapp,role=frontend --namespace production
在殼層提示字元,使用 wget
來查看網路原則現在是否會拒絕流量:
wget -O- --timeout=2 --tries=1 http://backend.development
wget: download timed out
結束測試 Pod:
exit
拒絕了來自 production 命名空間的流量,回到 development 命名空間中排程測試 Pod,然後連結終端機工作階段:
kubectl run --rm -it frontend --image=mcr.microsoft.com/aks/fundamental/base-ubuntu:v0.0.11 --labels app=webapp,role=frontend --namespace development
在殼層提示字元,使用 wget
來查看網路原則是否允許流量:
wget -qO- http://backend
因為 Pod 已排定在符合網路原則許可內容的命名空間中,所以允許流量。 下列範例輸出會顯示傳回的預設 NGINX 網頁:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
[...]
結束連結的終端機工作階段。 測試 Pod 會自動刪除。
exit
清除資源
在本文中,我們已建立兩個命名空間並套用網路原則。 若要清除這些資源,請使用 kubectl delete 命令並指定資源名稱:
kubectl delete namespace production
kubectl delete namespace development
後續步驟
如需網路資源的詳細資訊,請參閱 Azure Kubernetes Service (AKS) 中應用程式的網路概念。
若要深入了解原則,請參閱 Kubernetes 網路原則。