為什麼 Istio 要使用 SPIRE 做身份認證?

語言: CN / TW / HK

今年 6 月初, Istio 1.14 發佈 ,該版本中最值得關注的特性是新增對 SPIRE 的支持。 SPIFFE 和 SPIRE 都是 CNCF 孵化項目,其中 SPIRE 是 SPIFFE 的實現之一。本文將帶你瞭解 SPIRE 對於零信任架構的意義,以及 Istio 是為何使用 SPIRE 實現身份認證。

Kubernetes 中的身份認證

我們都知道 Istio 最初是基於 Kubernetes 建立起來的,在談在 Istio 中使用 SPIRE 做身份認證之前,我們先來看下 Kubernetes 中如何做身份認證。

我們來看一個 pod 的 token 的例子,下面是 default 命名空間下 sleep pod 的 Service Account 的 token。

apiVersion: v1
data:
  ca.crt: {CA_CRT}
  namespace: ZGVmYXVsdA==
  token: {TOKEN_STRING}
kind: Secret
metadata:
  annotations:
    kubernetes.io/service-account.name: sleep
    kubernetes.io/service-account.uid: 2c0d00e8-13a2-48d0-9ff8-f987f3325ecf
  creationTimestamp: "2022-06-14T03:01:35Z"
  name: sleep-token-gwhwd
  namespace: default
  resourceVersion: "244535398"
  uid: b8822ceb-9553-4a17-96dc-d525bbaed0e0
type: kubernetes.io/service-account-token

我們看到其中有 ca.crttoken 字段,如果這個 token 被竊取,會有什麼後果?Kubernetes 中使用 Service Account 來管理 Pod 的身份,然後利用 RBAC 指定具有某 Service Account 的 Pod 對 Kubernetes API 的權限。Service Account 的 token 存儲在 Secret 中,token 中並不包含工作負載所運行的節點、pod 的聲明,一旦 token 被竊取破壞者就獲得了該賬户的所有權限,偽裝成該用户竊取信息或破壞。

一個 token 只能在一個集羣中標記負載身份,Istio 同時支持 Kubernetes 環境和虛擬機,還有多集羣多網格,如何統一這些異構環境中的工作負載身份?這時,一個統一的工作負載身份標準就呼之欲出了。

SPIFFE 與 SPIRE 簡介

SPIFFE 的目的是基於零信任的理念,建立一個開放、統一的工作負載身份標準,這有助於建立一個零信任的全面身份化的數據中心網絡。SPIFFE 的核心是通過簡單 API 定義了一個短期的加密身份文件 SVID,用作工作負載認證時使用的身份文件,例如建立 TLS 連接或簽署和驗證 JWT 令牌等。SPIRE 可以根據管理員定義的策略自動輪換 X.509 SVID 證書和祕鑰。Istio 可以通過 SPIRE 動態的消費工作負載標識,SPIRE 可以動態的提供工作負載標識。

下面我將為你簡單介紹一下與 SPIFFE 相關的一些術語。

  • SPIFFE (Secure Production Identity Framework For Everyone)是一套身份認證標準。
  • SPIRE (SPIFFE Runtime Environment) 是 SPIFFE 標準的一套生產就緒實現。
  • SVID (SPIFFE Verifiable Identity Document)是工作負載向資源或調用者證明其身份的文件。SVID 包含一個 SPIFFE ID,代表了服務的身份。它將 SPIFFE ID 編碼在一個可加密驗證的文件中,目前支持兩種格式:X.509 證書或 JWT 令牌。
  • SPIFFE ID 是一個統一資源標識符(URI),其格式如下: spiffe://trust_domain/workload_identifier

SPIRE 包含 Server 和 Agent 兩個部分,它們的作用如下。

SPIRE Server

  • 身份映射
  • 節點認證
  • SVID 頒發

SPIRE Agent

  • 工作負載認證
  • 提供工作負載 API

SPIFFE 與零信任安全

零信任的本質是以身份為中心的動態訪問控制。動態證書輪換、動態證書下發、動態權限控制。SPIFFE 解決的是標識工作負載的問題。

在虛擬機時代我們可能根據一個 IP 地址和端口來標識一個工作負載,基於 IP 地址標識存在多個服務共享一個 IP 地址,IP 地址偽造和訪問控制列表過大等問題。到了 Kubernetes 時代,容器的生命週期是短暫的,我們無法再用 IP 地址來標識負載,而是通過 pod 或 service 名稱。但是,不同的雲、軟件平台對工作負載標識的方法不同,相互之間存在兼容性問題。尤其是在異構混合雲的中,同時存在虛擬機和容器的工作負載。這時,建立一個細粒度、具有互操作性的標識系統,將具有重要意義。

在 Istio 中使用 SPIRE 做身份認證

Istio 會利用 SPIRE 為每個工作負載提供一個唯一標識,服務網格中的工作負載在進行對等身份認證、請求身份認證和授權策略都會使用到服務標識,用於驗證訪問是否被允許。SPIRE 原生支持 Envoy SDS API,SPIRE Agent 中的通過與工作負載中共享的 UNIX Domain Socket 通信,為工作負載頒發 SVID。請參考 Istio 文檔 瞭解如何在 Istio 中使用 SPIRE 做身份認證。

SDS 最重要的好處就是簡化了證書管理。如果沒有這個特性,在 Kubernetes deployment 中,證書就必須以 secret 的方式被創建,然後掛載進代理容器。如果證書過期了,就需要更新 secret 且代理容器需要被重新部署。如果使用 SDS,Istio 可以使用 SDS 服務器會將證書推送給所有的 Envoy 實例。如果證書過期了,服務器僅需要將新證書推送至 Envoy 實例,Envoy 將會立即使用新證書且不需要重新部署代理容器。

下圖展示了 Istio 中使用 SPIRE 進行身份認證的架構。

Istio 中使用 SPIRE 進行身份認證的架構圖

在 Kubernetes 集羣中的 spire 命名空間中使用 StatefulSet 部署 SPIRE Server 和 Kubernetes Workload Registrar,使用 DaemonSet 資源為每個節點部署一個 SPIRE Agent。假設你在安裝 Kubernetes 時使用的是默認的 DNS 名稱 cluster.localKubernetes Workload Registar 會為 Istio Mesh 中的工作負載創建如下格式的身份:

spiffe://cluster.local/ns/spire/sa/server
spiffe://cluster.local/ns/spire/sa/spire-agent
spiffe://cluster.local/k8s-workload-registrar/demo-cluster/node/
spiffe://cluster.local/{namespace}/spire/sa/{service_acount}

這樣不論是節點還是每個工作負載都有它們全局唯一的身份,而且還可以根據集羣 (信任域)擴展。

Istio Mesh 中的工作負載身份驗證過程如下圖所示。

Istio 服務網格中的工作負載身份認證過程示意圖

詳細過程如下:

pilot-agent

關於工作負載的註冊和認證的詳細過程請參考SPIRE 文檔 。

總結

身份是零信任網絡的基礎,SPIFFE 統一了異構環境下的身份標準。在 Istio 中不論我們是否使用 SPIRE,身份驗證對於工作負載來説是不會有任何感知的。通過 SPIRE 來為工作負載提供身份驗證,可以有效的管理工作負載的身份,為實現零信任網絡打好基礎。