回到 Istio 的微服務。 第3部分

回到 Istio 的微服務。 第3部分

筆記。 翻譯。: 第一部分 本系列致力於了解 Istio 的功能並在實踐中展示它們, 第二 — 精細調整的路由和網路流量管理。 現在我們來談談安全性:為了示範與之相關的基本功能,作者使用了Auth0身份服務,但其他提供者也可以以類似的方式進行設定。

我們設定了一個 Kubernetes 集群,在其中部署了 Istio 和一個範例微服務應用程式“情緒分析”,以演示 Istio 的功能。

借助 Istio,我們能夠保持服務規模較小,因為它們不需要實現重試、超時、斷路器、追蹤、監控等層。 此外,我們還使用了先進的測試和部署技術:A/B 測試、鏡像和金絲雀部署。

回到 Istio 的微服務。 第3部分

在新材料中,我們將處理商業價值之路上的最後幾層:身份驗證和授權 - 在 Istio 中這真是一種樂趣!

Istio 中的身份驗證和授權

我永遠不會相信我會受到身份驗證和授權的啟發。 從技術角度來看,Istio 可以提供什麼來使這些主題變得有趣,甚至更能啟發您?

答案很簡單:Istio 將這些功能的責任從您的服務轉移到 Envoy 代理程式。 當請求到達服務時,它們已經經過身份驗證和授權,因此您所要做的就是編寫業務有用的程式碼。

聽起來不錯? 讓我們看看裡面吧!

使用 Auth0 進行身份驗證

作為身份和存取管理的伺服器,我們將使用 Auth0,它有試用版,使用起來很直觀,我只是喜歡它。 然而,相同的原則可以應用於任何其他 OpenID 連線實施:KeyCloak、IdentityServer 等等。

要開始使用,請訪問 Auth0 入口網站 使用您的帳戶建立租戶 (租戶 - “租戶”,隔離的邏輯單元,更多詳細資訊請參見 文件 - 大約。 譯) 並前往 應用程式 > 預設應用程式選擇 ,如下圖所示:

回到 Istio 的微服務。 第3部分

在檔案中指定該網域 resource-manifests/istio/security/auth-policy.yaml (來源):

apiVersion: authentication.istio.io/v1alpha1
kind: Policy
metadata:
  name: auth-policy
spec:
  targets:
  - name: sa-web-app
  - name: sa-feedback
  origins:
  - jwt:
      issuer: "https://{YOUR_DOMAIN}/"
      jwksUri: "https://{YOUR_DOMAIN}/.well-known/jwks.json"
  principalBinding: USE_ORIGIN

有了這樣的資源,Pilot (Istio 中的三個基本控制平面組件之一 - 大約翻譯) 設定 Envoy 在將請求轉送至服務之前對請求進行身份驗證: sa-web-app и sa-feedback。 同時,此配置不適用於服務Envoys sa-frontend,允許我們離開前端未經身份驗證。 若要套用策略,請執行以下命令:

$ kubectl apply -f resource-manifests/istio/security/auth-policy.yaml
policy.authentication.istio.io “auth-policy” created

返回頁面並提出請求 - 您將看到它以狀態結束 401未經授權。 現在讓我們重新導向前端使用者以使用 Auth0 進行身份驗證。

使用 Auth0 驗證請求

要對最終使用者請求進行身份驗證,您需要在 Auth0 中建立一個 API,該 API 將代表經過身份驗證的服務(評論、詳細資訊和評級)。 若要建立 API,請前往 Auth0 入口網站 > API > 建立 API 並填寫表格:

回到 Istio 的微服務。 第3部分

這裡的重要訊息是 識別碼,我們稍後將在腳本中使用它。 讓我們這樣寫:

  • 課程對象::{YOUR_AUDIENCE}

我們需要的其餘詳細資訊位於 Auth0 入口網站的 部分 應用 - 選擇 測試申請 (與 API 一起自動建立)。

這裡我們會寫:

  • : {YOUR_DOMAIN}
  • 客戶編號:{YOUR_CLIENT_ID}

捲動到 測試申請 到文字字段 允許的回呼 URL (回呼的已解析 URL),其中我們指定身份驗證完成後應將呼叫傳送到的 URL。 在我們的例子中是:

http://{EXTERNAL_IP}/callback

並為 允許的登出 URL (允許登出的 URL)新增:

http://{EXTERNAL_IP}/logout

讓我們繼續討論前端。

前端更新

切換到分支 auth0 儲存庫 [istio-mastery]。 在此分支中,前端程式碼已變更為將使用者重新導向至 Auth0 進行身份驗證,並在對其他服務的請求中使用 JWT 令牌。 後者的實現如下(應用程序.js):

analyzeSentence() {
    fetch('/sentiment', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${auth.getAccessToken()}` // Access Token
        },
        body: JSON.stringify({ sentence: this.textField.getValue() })
    })
        .then(response => response.json())
        .then(data => this.setState(data));
}

若要變更前端以使用 Auth0 中的租戶數據,請開啟 sa-frontend/src/services/Auth.js 並替換我們上面寫的值(Auth.js):

const Config = {
    clientID: '{YOUR_CLIENT_ID}',
    domain:'{YOUR_DOMAIN}',
    audience: '{YOUR_AUDIENCE}',
    ingressIP: '{EXTERNAL_IP}' // Используется для редиректа после аутентификации
}

應用程式已準備就緒。 建置和部署所做的變更時,請在下列命令中指定您的 Docker ID:

$ docker build -f sa-frontend/Dockerfile 
 -t $DOCKER_USER_ID/sentiment-analysis-frontend:istio-auth0 
 sa-frontend

$ docker push $DOCKER_USER_ID/sentiment-analysis-frontend:istio-auth0

$ kubectl set image deployment/sa-frontend 
 sa-frontend=$DOCKER_USER_ID/sentiment-analysis-frontend:istio-auth0

嘗試該應用程式! 您將被重定向到 Auth0,您需要在其中登入(或註冊),之後您將被發送回已發出經過身份驗證的請求的頁面。 如果您使用curl嘗試本文第一部分中提到的命令,您將得到程式碼 401 狀態碼,表示該請求未經授權。

讓我們進行下一步 - 授權請求。

使用Auth0授權

身份驗證使我們能夠了解使用者是誰,但需要授權才能知道他們有權存取什麼。 Istio 也為此提供了工具。

例如,讓我們建立兩個使用者群組(見下圖):

  • 會員 (用戶) — 只能存取 SA-WebApp 和 SA-Frontend 服務;
  • 版主 (主持人) - 可以存取所有三項服務。

回到 Istio 的微服務。 第3部分
授權理念

為了建立這些群組,我們將使用 Auth0 授權擴充功能並使用 Istio 為它們提供不同層級的存取權限。

Auth0授權的安裝和配置

在 Auth0 入口網站中,前往擴充功能 (擴展)並安裝 Auth0 授權。 安裝完成後,進入 授權擴充,然後 - 透過點擊右上角並選擇適當的選單選項來查看租戶的配置 (配置)。 啟動群組 (組) 然後點選發布規則按鈕 (發布規則).

回到 Istio 的微服務。 第3部分

創建群組

在授權擴充功能中前往 並創建一個群組 版主。 由於我們將所有經過身份驗證的用戶視為普通用戶,因此無需為他們建立額外的群組。

選擇一個組 版主, 按 添加成員,新增您的主帳戶。 讓某些用戶不屬於任何群組,以確保他們被拒絕存取。 (可以透過手動建立新用戶 Auth0 入口網站 > 使用者 > 建立用戶.)

將群組聲明新增至存取令牌

使用者已新增至群組中,但此資訊也必須反映在存取權杖中。 為了遵守 OpenID Connect 並同時返回我們需要的群組,令牌需要添加自己的 客製化索賠。 透過Auth0規則實現。

若要建立規則,請前往 Auth0 Portal 規則, 按 創建規則 並從模板中選擇一個空規則。

回到 Istio 的微服務。 第3部分

複製下面的程式碼並將其另存為新規則 新增團體聲明 (命名空間組.js):

function (user, context, callback) {
    context.accessToken['https://sa.io/group'] = user.groups[0];
    return callback(null, user, context);
}

注意:此程式碼採用授權擴充功能中定義的第一個使用者群組,並將其作為自訂聲明新增至存取權杖(在其命名空間下,根據 Auth0 的要求)。

返回頁面 規則 並檢查您是否有兩個按以下順序編寫的規則:

  • auth0-授權-擴展
  • 新增團體聲明

順序很重要,因為群組欄位非同步接收規則 auth0-授權-擴展 然後根據第二條規則將其新增為聲明。 結果是一個像這樣的訪問令牌:

{
 "https://sa.io/group": "Moderators",
 "iss": "https://sentiment-analysis.eu.auth0.com/",
 "sub": "google-oauth2|196405271625531691872"
 // [сокращено для наглядности]
}

現在您需要設定 Envoy 代理程式來檢查使用者存取權限,為此將從聲明中提取群組(https://sa.io/group)在傳回的訪問令牌中。 這是本文下一節的主題。

Istio中的授權配置

為了使授權起作用,您必須為 Istio 啟用 RBAC。 為此,我們將使用以下配置:

apiVersion: "rbac.istio.io/v1alpha1"
kind: RbacConfig
metadata:
  name: default
spec:
  mode: 'ON_WITH_INCLUSION'                     # 1
  inclusion:
    services:                                   # 2
    - "sa-frontend.default.svc.cluster.local"
    - "sa-web-app.default.svc.cluster.local"
    - "sa-feedback.default.svc.cluster.local" 

說明:

  • 1 — 僅對欄位中列出的服務和命名空間啟用 RBAC Inclusion;
  • 2 — 我們列出了我們的服務清單。

讓我們使用以下命令應用配置:

$ kubectl apply -f resource-manifests/istio/security/enable-rbac.yaml
rbacconfig.rbac.istio.io/default created

所有服務現在都需要基於角色的存取控制。 換句話說,所有服務的存取都被禁止,並且會導致回應 RBAC: access denied。 現在讓我們允許授權使用者存取。

普通用戶的存取配置

所有使用者都必須有權存取 SA-Frontend 和 SA-WebApp 服務。 使用以下 Istio 資源實作:

  • 服務角色 ——確定使用者擁有的權利;
  • 服務角色綁定 — 確定此 ServiceRole 屬於誰。

對於普通用戶我們將允許存取某些服務(服務角色.yaml):

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRole
metadata:
  name: regular-user
  namespace: default
spec:
  rules:
  - services: 
    - "sa-frontend.default.svc.cluster.local" 
    - "sa-web-app.default.svc.cluster.local"
    paths: ["*"]
    methods: ["*"]

並通過 regular-user-binding 將 ServiceRole 套用至所有頁面訪客(常規使用者服務角色綁定.yaml):

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRoleBinding
metadata:
  name: regular-user-binding
  namespace: default
spec:
  subjects:
  - user: "*"
  roleRef:
    kind: ServiceRole
    name: "regular-user"

「所有使用者」是否意味著未經身份驗證的使用者也可以存取 SA WebApp? 否,策略將檢查 JWT 令牌的有效性。

讓我們套用這些配置:

$ kubectl apply -f resource-manifests/istio/security/user-role.yaml
servicerole.rbac.istio.io/regular-user created
servicerolebinding.rbac.istio.io/regular-user-binding created

主持人的訪問配置

對於版主,我們希望允許訪問所有服務(mod-service-role.yaml):

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRole
metadata:
  name: mod-user
  namespace: default
spec:
  rules:
  - services: ["*"]
    paths: ["*"]
    methods: ["*"]

但我們只希望那些訪問令牌包含聲明的用戶擁有這樣的權利 https://sa.io/group 有意義 Moderators (mod-服務-角色綁定.yaml):

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRoleBinding
metadata:
  name: mod-user-binding
  namespace: default
spec:
  subjects:
  - properties:
      request.auth.claims[https://sa.io/group]: "Moderators"
  roleRef:
    kind: ServiceRole
name: "mod-user" 

讓我們套用這些配置:

$ kubectl apply -f resource-manifests/istio/security/mod-role.yaml
servicerole.rbac.istio.io/mod-user created
servicerolebinding.rbac.istio.io/mod-user-binding created

由於 Envoy 中存在緩存,授權規則可能需要幾分鐘才能生效。 然後,您可以確保用戶和主持人具有不同的訪問等級。

這部分的結論

但說真的,您見過更簡單、輕鬆、可擴展且安全的身份驗證和授權方法嗎?

只需三個 Istio 資源(RbacConfig、ServiceRole 和 ServiceRoleBinding)即可實現對最終使用者存取服務的身份驗證和授權的細粒度控制。

此外,我們也透過特使服務解決了這些問題,實現了:

  • 減少可能包含安全問題和錯誤的通用程式碼的數量;
  • 減少愚蠢情況的數量,在這種情況下,一個端點可從外部存取但忘記報告;
  • 無需在每次新增角色或權限時更新所有服務;
  • 新服務仍然簡單、安全且快速。

產量

Istio 讓團隊將資源集中在關鍵業務任務上,而不增加服務開銷,將其恢復到微觀狀態。

本文(分三部分)提供了在實際專案中開始使用 Istio 的基礎知識和現成的實用說明。

譯者PS

另請閱讀我們的博客:

來源: www.habr.com

添加評論