前言

在現代雲端原生架構中,微服務之間的通訊安全已成為企業最關注的議題之一。隨著服務數量的快速增長,傳統的邊界防護模式已無法滿足細粒度的安全需求,取而代之的是零信任架構的崛起。Istio 作為目前最成熟的 Service Mesh 解決方案,提供了完整的安全機制來保護服務間的通訊,包含身份驗證、授權控制以及加密傳輸等核心功能。

本文將深入探討 Istio 的安全架構設計理念,從 mTLS 雙向認證到 AuthorizationPolicy 授權策略,再到零信任架構的實踐方式,協助讀者建立完整的服務網格安全知識體系。透過豐富的程式碼範例與架構圖解,我們將一步步剖析如何在 Kubernetes 環境中實作企業級的微服務安全防護。

Istio 安全架構概觀

Istio 的安全架構建立在三個核心支柱之上,分別是身份識別、認證以及授權。這三個支柱相互配合,形成了一個完整的安全防護體系。在 Istio 的設計哲學中,每個工作負載都擁有唯一的身份識別,這個身份識別透過 SPIFFE 標準來實現,確保了跨叢集甚至跨雲環境的身份一致性。

身份識別是整個安全架構的基礎,Istio 為每個工作負載自動頒發 X.509 憑證,這些憑證包含了 SPIFFE ID,格式為 spiffe://cluster.local/ns/namespace/sa/service-account。透過這個標準化的身份識別機制,Istio 能夠在服務間建立可信賴的通訊管道。

認證機制則負責驗證通訊雙方的身份真實性。Istio 支援兩種認證模式,分別是 Peer Authentication 和 Request Authentication。前者用於服務間的雙向認證,後者則用於終端使用者的身份驗證,通常搭配 JWT Token 來實現。

授權機制是安全架構的最後一道防線,它決定了已認證的身份是否有權限存取特定資源。Istio 的 AuthorizationPolicy 提供了細粒度的存取控制能力,可以根據來源身份、目標服務、HTTP 方法、路徑等多種條件來制定存取策略。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

package "Istio 安全架構" {
    component "身份識別\n(SPIFFE/X.509)" as identity
    component "認證機制\n(mTLS/JWT)" as authn
    component "授權控制\n(AuthorizationPolicy)" as authz
}

identity --> authn : 提供身份憑證
authn --> authz : 驗證後的身份

note bottom of identity
  每個工作負載擁有
  唯一的 SPIFFE ID
end note

note bottom of authn
  支援 Peer Authentication
  與 Request Authentication
end note

note bottom of authz
  細粒度存取控制
  支援 RBAC 模式
end note

@enduml

這個架構圖清楚地展示了 Istio 安全機制的三個核心元件以及它們之間的關係。身份識別作為基礎,為認證機制提供必要的憑證資訊,而認證完成後的身份則被傳遞給授權控制模組進行存取決策。

mTLS 雙向認證機制

mutual TLS 是 Istio 安全架構中最重要的功能之一,它確保了服務間通訊的機密性、完整性以及身份真實性。與傳統的單向 TLS 不同,mTLS 要求通訊雙方都必須提供有效的憑證,這意味著客戶端和伺服器端都需要驗證對方的身份。

在 Istio 的實作中,mTLS 的運作完全透明於應用程式。當一個服務發起請求時,Envoy Sidecar 會自動將純文字流量加密成 TLS 流量,並在請求中附加客戶端憑證。接收端的 Envoy Sidecar 則會驗證客戶端憑證的有效性,確認通過後才將解密後的流量轉發給實際的應用程式。

Istio 的 mTLS 實作還包含了自動憑證管理功能。istiod 作為憑證授權中心,負責為所有工作負載簽發和輪換憑證。預設情況下,憑證的有效期限為 24 小時,並會在到期前自動更新,這大幅降低了憑證管理的複雜度。

要啟用 mTLS,我們需要設定 PeerAuthentication 資源。以下是一個在整個 mesh 範圍內啟用嚴格 mTLS 模式的範例:

# 這個設定檔定義了整個服務網格的 mTLS 策略
# 透過將此資源部署在 istio-system 命名空間,可以影響所有工作負載
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  # 名稱可以自訂,這裡使用 default 作為全域設定的慣例名稱
  name: default
  # 部署在 istio-system 命名空間表示這是全域設定
  namespace: istio-system
spec:
  mtls:
    # STRICT 模式要求所有流量必須使用 mTLS
    # 其他選項包括 PERMISSIVE(允許純文字)和 DISABLE(停用 mTLS)
    mode: STRICT

在實際的生產環境中,我們可能需要更細緻的 mTLS 設定。例如,某些遺留系統可能尚未整合 Istio,此時就需要使用 PERMISSIVE 模式來相容純文字流量。以下範例展示了如何針對特定命名空間設定不同的 mTLS 策略:

# 針對 legacy-services 命名空間設定寬鬆的 mTLS 模式
# 這允許該命名空間內的服務同時接受 mTLS 和純文字流量
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: legacy-permissive
  # 部署在特定命名空間,僅影響該命名空間內的工作負載
  namespace: legacy-services
spec:
  mtls:
    # PERMISSIVE 模式是遷移過程中的理想選擇
    # 它允許服務逐步遷移到 mTLS,而不會中斷現有通訊
    mode: PERMISSIVE

更進一步,我們還可以針對特定的連接埠設定不同的 mTLS 策略。這在某些特殊場景下非常有用,例如健康檢查端點可能需要允許純文字存取:

# 這個設定展示了如何為不同的連接埠設定不同的 mTLS 模式
# 適用於需要混合存取模式的複雜應用程式
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: mixed-mode-auth
  namespace: production
spec:
  # selector 用於指定此策略套用的工作負載
  # 透過標籤選擇器來匹配特定的 Pod
  selector:
    matchLabels:
      app: api-gateway
  mtls:
    # 預設模式為嚴格 mTLS
    mode: STRICT
  # portLevelMtls 允許針對特定連接埠覆寫預設設定
  portLevelMtls:
    # 8080 連接埠設定為寬鬆模式,允許健康檢查探針存取
    8080:
      mode: PERMISSIVE
    # 9090 連接埠完全停用 mTLS,用於 metrics 端點
    9090:
      mode: DISABLE

mTLS 的啟用不僅提供了傳輸層的安全保護,更重要的是它為後續的授權機制提供了可靠的身份資訊。只有在確認通訊雙方身份的前提下,授權決策才能準確執行。

AuthorizationPolicy 授權策略詳解

AuthorizationPolicy 是 Istio 授權機制的核心資源,它取代了早期版本中的 ServiceRole 和 ServiceRoleBinding,提供了更簡潔且強大的存取控制能力。AuthorizationPolicy 採用了類似 Kubernetes RBAC 的設計理念,但針對服務網格的特性進行了優化。

AuthorizationPolicy 的運作邏輯遵循「預設拒絕」的原則。當一個命名空間中存在任何 AuthorizationPolicy 資源時,所有未明確允許的請求都會被拒絕。這種設計確保了安全性優先,避免了因疏忽而導致的安全漏洞。

一個 AuthorizationPolicy 資源主要由三個部分組成:selector 用於指定策略套用的工作負載,action 定義了策略的行為(允許或拒絕),rules 則描述了觸發該行為的條件。這三個部分相互配合,形成了完整的授權決策邏輯。

以下是一個基本的 AuthorizationPolicy 範例,展示了如何允許特定服務存取 API:

# 這個授權策略定義了誰可以存取 product-service
# 只有來自 frontend 服務的請求才會被允許
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: product-service-policy
  # 此策略部署在 product-service 所在的命名空間
  namespace: production
spec:
  # selector 指定此策略套用於哪些工作負載
  # 這裡選擇標籤為 app: product-service 的所有 Pod
  selector:
    matchLabels:
      app: product-service
  # action 定義策略的行為,ALLOW 表示允許符合規則的請求
  action: ALLOW
  # rules 定義了允許存取的條件
  rules:
  - from:
    # principals 指定允許的來源身份
    # 這裡使用 Service Account 來識別 frontend 服務
    - source:
        principals: ["cluster.local/ns/production/sa/frontend"]
    to:
    # operations 定義允許的操作類型
    - operation:
        # 只允許 GET 和 POST 方法
        methods: ["GET", "POST"]
        # 只允許存取 /api/products 路徑下的資源
        paths: ["/api/products/*"]

在實際應用中,我們經常需要設定更複雜的授權規則。例如,一個訂單服務可能需要接受來自多個不同服務的請求,每個服務有不同的存取權限。以下範例展示了這種多規則授權策略的設定方式:

# 訂單服務的授權策略展示了如何處理多個來源的存取需求
# 不同的服務有不同的存取權限
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: order-service-policy
  namespace: production
spec:
  selector:
    matchLabels:
      app: order-service
  action: ALLOW
  rules:
  # 第一條規則:允許 frontend 服務讀取訂單
  - from:
    - source:
        principals: ["cluster.local/ns/production/sa/frontend"]
    to:
    - operation:
        methods: ["GET"]
        paths: ["/api/orders", "/api/orders/*"]
  # 第二條規則:允許 checkout 服務建立訂單
  - from:
    - source:
        principals: ["cluster.local/ns/production/sa/checkout"]
    to:
    - operation:
        methods: ["POST"]
        paths: ["/api/orders"]
  # 第三條規則:允許 admin-dashboard 服務完整存取
  - from:
    - source:
        principals: ["cluster.local/ns/admin/sa/admin-dashboard"]
    to:
    - operation:
        # 星號表示允許所有 HTTP 方法
        methods: ["*"]
        paths: ["/api/orders/*"]

AuthorizationPolicy 也支援基於 HTTP Header 的條件判斷,這在實作 API 版本控制或租戶隔離時特別有用:

# 這個策略展示了如何根據 HTTP Header 進行存取控制
# 適用於多租戶架構或 API 版本管理場景
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: tenant-isolation-policy
  namespace: multi-tenant
spec:
  selector:
    matchLabels:
      app: shared-service
  action: ALLOW
  rules:
  - from:
    - source:
        # 使用命名空間作為來源條件
        namespaces: ["tenant-a"]
    to:
    - operation:
        methods: ["GET", "POST", "PUT", "DELETE"]
    # when 條件允許更細緻的請求過濾
    when:
    # 要求請求必須包含正確的租戶 ID Header
    - key: request.headers[x-tenant-id]
      values: ["tenant-a"]
  - from:
    - source:
        namespaces: ["tenant-b"]
    to:
    - operation:
        methods: ["GET", "POST", "PUT", "DELETE"]
    when:
    - key: request.headers[x-tenant-id]
      values: ["tenant-b"]

除了 ALLOW 行為外,AuthorizationPolicy 還支援 DENY 和 CUSTOM 行為。DENY 行為用於明確拒絕特定請求,它的優先順序高於 ALLOW 規則。CUSTOM 行為則允許將授權決策委託給外部授權服務,適用於需要複雜業務邏輯的場景。

# DENY 規則用於明確拒絕特定模式的請求
# 這裡展示了如何阻擋來自特定命名空間的所有請求
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: deny-untrusted-namespace
  namespace: production
spec:
  # 不指定 selector 表示此策略套用於命名空間內所有工作負載
  action: DENY
  rules:
  - from:
    - source:
        # 拒絕來自 untrusted 命名空間的所有請求
        namespaces: ["untrusted"]
@startuml
!define DISABLE_LINK
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

start

:收到請求;

if (是否有 CUSTOM 策略?) then (是)
  :委託外部授權服務;
  if (外部服務允許?) then (是)
    :繼續處理;
  else (否)
    :拒絕請求;
    stop
  endif
endif

if (是否符合 DENY 規則?) then (是)
  :拒絕請求;
  stop
endif

if (是否有 ALLOW 規則?) then (是)
  if (是否符合 ALLOW 規則?) then (是)
    :允許請求;
  else (否)
    :拒絕請求;
    stop
  endif
else (否)
  :允許請求;
endif

:轉發至目標服務;

stop

@enduml

這個流程圖清楚地展示了 Istio AuthorizationPolicy 的決策邏輯。CUSTOM 規則具有最高優先順序,接著是 DENY 規則,最後才是 ALLOW 規則。這種優先順序設計確保了安全策略能夠有效執行。

零信任架構實踐

零信任架構是現代企業安全的核心理念,其核心原則是「永不信任,始終驗證」。在這種架構下,無論請求來自網路內部還是外部,都必須經過嚴格的身份驗證和授權檢查。Istio 的安全機制完美契合零信任架構的要求,為微服務環境提供了全面的零信任實踐基礎。

實踐零信任架構的第一步是建立強制的身份驗證機制。在 Istio 中,這意味著為所有服務啟用嚴格的 mTLS 模式,確保每個請求都經過身份驗證。同時,我們還需要為終端使用者請求設定 Request Authentication,驗證 JWT Token 的有效性。

以下範例展示了如何設定 Request Authentication 來驗證終端使用者的 JWT Token:

# RequestAuthentication 定義了如何驗證終端使用者的身份
# 這裡設定 JWT Token 的驗證規則
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
  name: jwt-auth
  namespace: production
spec:
  # selector 指定此驗證規則套用的工作負載
  selector:
    matchLabels:
      app: api-gateway
  # jwtRules 定義 JWT Token 的驗證參數
  jwtRules:
  # issuer 指定 Token 的發行者,必須與 Token 中的 iss 聲明相符
  - issuer: "https://auth.example.com"
    # jwksUri 指定公鑰的取得位置,用於驗證 Token 簽名
    jwksUri: "https://auth.example.com/.well-known/jwks.json"
    # audiences 指定允許的受眾,必須與 Token 中的 aud 聲明相符
    audiences:
    - "api.example.com"
    # forwardOriginalToken 設定是否將原始 Token 轉發給後端服務
    forwardOriginalToken: true
    # fromHeaders 指定從哪個 Header 中提取 Token
    fromHeaders:
    - name: Authorization
      # prefix 指定 Token 的前綴,這裡是 Bearer 格式
      prefix: "Bearer "

設定了 Request Authentication 後,我們需要搭配 AuthorizationPolicy 來執行基於 JWT 聲明的存取控制。這允許我們根據使用者的角色、部門或其他屬性來制定細粒度的存取策略:

# 這個授權策略展示了如何根據 JWT 聲明進行存取控制
# 只有具有特定角色的使用者才能存取管理功能
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: admin-only-policy
  namespace: production
spec:
  selector:
    matchLabels:
      app: admin-service
  action: ALLOW
  rules:
  - from:
    - source:
        # requestPrincipals 驗證 JWT Token 中的身份資訊
        # 格式為 issuer/subject
        requestPrincipals: ["https://auth.example.com/*"]
    to:
    - operation:
        methods: ["GET", "POST", "PUT", "DELETE"]
    when:
    # 檢查 JWT Token 中的 groups 聲明
    # 只有 admin 群組的使用者才能存取
    - key: request.auth.claims[groups]
      values: ["admin"]

零信任架構的另一個重要面向是最小權限原則。每個服務應該只被授予完成其工作所需的最小權限,不應該有任何多餘的存取能力。在 Istio 中,這意味著我們需要為每個服務精心設計 AuthorizationPolicy,確保只允許必要的通訊路徑。

以下是一個完整的微服務系統零信任授權設定範例:

# 前端服務只能存取 API Gateway
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: frontend-policy
  namespace: production
spec:
  selector:
    matchLabels:
      app: frontend
  action: ALLOW
  rules:
  - from:
    - source:
        # 允許來自 Ingress Gateway 的流量
        principals: ["cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"]
---
# API Gateway 可以存取後端各個微服務
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: api-gateway-policy
  namespace: production
spec:
  selector:
    matchLabels:
      app: api-gateway
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/production/sa/frontend"]
---
# 使用者服務只接受來自 API Gateway 的請求
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: user-service-policy
  namespace: production
spec:
  selector:
    matchLabels:
      app: user-service
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/production/sa/api-gateway"]
    to:
    - operation:
        methods: ["GET", "POST", "PUT"]
        paths: ["/api/users/*"]
---
# 訂單服務接受來自 API Gateway 和 Payment Service 的請求
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: order-service-policy
  namespace: production
spec:
  selector:
    matchLabels:
      app: order-service
  action: ALLOW
  rules:
  - from:
    - source:
        principals:
        - "cluster.local/ns/production/sa/api-gateway"
        - "cluster.local/ns/production/sa/payment-service"
    to:
    - operation:
        methods: ["GET", "POST", "PUT"]
        paths: ["/api/orders/*"]

這個範例展示了一個典型的微服務系統中的零信任授權配置。每個服務都有明確的授權策略,定義了誰可以存取它以及可以執行什麼操作。這種設計確保了即使某個服務被攻破,攻擊者也無法輕易橫向移動到其他服務。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

actor "終端使用者" as user
boundary "Ingress\nGateway" as ingress
control "Frontend" as frontend
control "API\nGateway" as gateway
entity "User\nService" as userservice
entity "Order\nService" as orderservice
entity "Payment\nService" as paymentservice

user --> ingress : HTTPS
ingress --> frontend : mTLS
frontend --> gateway : mTLS
gateway --> userservice : mTLS
gateway --> orderservice : mTLS
orderservice --> paymentservice : mTLS

note over ingress
  JWT 驗證
  TLS 終止
end note

note over gateway
  路由分發
  請求轉換
end note

note over userservice, paymentservice
  每個服務都有
  獨立的授權策略
end note

@enduml

這個架構圖展示了零信任架構下的服務通訊流程。所有服務間通訊都使用 mTLS 加密,並且每個服務都有獨立的授權策略控制存取權限。

RBAC 角色存取控制

Role-Based Access Control 是一種廣泛使用的存取控制模型,它根據使用者的角色來決定其存取權限。在 Istio 中,雖然 AuthorizationPolicy 已經取代了早期的 ServiceRole 和 ServiceRoleBinding 資源,但我們仍然可以透過設計良好的授權策略來實現 RBAC 模式。

實現 RBAC 的關鍵在於正確地將角色對應到授權規則。在 Kubernetes 和 Istio 的環境中,Service Account 通常作為工作負載的身份標識,我們可以將其視為角色的載體。透過為不同的服務設定不同的 Service Account,並在 AuthorizationPolicy 中引用這些 Service Account,就能實現基於角色的存取控制。

以下範例展示了如何設計一個三層角色的 RBAC 系統:

# 定義只讀角色的授權策略
# 這個角色只能執行 GET 請求
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: readonly-role
  namespace: production
spec:
  selector:
    matchLabels:
      app: data-service
  action: ALLOW
  rules:
  - from:
    - source:
        # 所有使用 readonly-sa Service Account 的服務都具有只讀權限
        principals: ["cluster.local/ns/production/sa/readonly-sa"]
    to:
    - operation:
        # 只允許 GET 方法
        methods: ["GET"]
        # 允許存取所有 API 路徑
        paths: ["/api/*"]
---
# 定義讀寫角色的授權策略
# 這個角色可以執行讀取和寫入操作
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: readwrite-role
  namespace: production
spec:
  selector:
    matchLabels:
      app: data-service
  action: ALLOW
  rules:
  - from:
    - source:
        # 使用 readwrite-sa Service Account 的服務具有讀寫權限
        principals: ["cluster.local/ns/production/sa/readwrite-sa"]
    to:
    - operation:
        # 允許 GET、POST 和 PUT 方法
        methods: ["GET", "POST", "PUT"]
        paths: ["/api/*"]
---
# 定義管理員角色的授權策略
# 這個角色擁有完整的存取權限
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: admin-role
  namespace: production
spec:
  selector:
    matchLabels:
      app: data-service
  action: ALLOW
  rules:
  - from:
    - source:
        # 使用 admin-sa Service Account 的服務具有完整權限
        principals: ["cluster.local/ns/production/sa/admin-sa"]
    to:
    - operation:
        # 允許所有 HTTP 方法
        methods: ["*"]
        paths: ["/api/*"]

在更複雜的場景中,我們可能需要結合 JWT Token 中的角色聲明來實現終端使用者的 RBAC。這種方式允許我們根據使用者在 Identity Provider 中的角色來控制其存取權限:

# 根據 JWT Token 中的角色聲明實現 RBAC
# 這允許對終端使用者進行細粒度的存取控制
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: user-rbac-policy
  namespace: production
spec:
  selector:
    matchLabels:
      app: resource-service
  action: ALLOW
  rules:
  # 訪客角色:只能讀取公開資源
  - from:
    - source:
        requestPrincipals: ["https://auth.example.com/*"]
    to:
    - operation:
        methods: ["GET"]
        paths: ["/api/public/*"]
    when:
    - key: request.auth.claims[role]
      values: ["guest"]
  # 會員角色:可以讀取所有資源並管理自己的資料
  - from:
    - source:
        requestPrincipals: ["https://auth.example.com/*"]
    to:
    - operation:
        methods: ["GET"]
        paths: ["/api/*"]
    when:
    - key: request.auth.claims[role]
      values: ["member"]
  - from:
    - source:
        requestPrincipals: ["https://auth.example.com/*"]
    to:
    - operation:
        methods: ["POST", "PUT", "DELETE"]
        paths: ["/api/users/me/*"]
    when:
    - key: request.auth.claims[role]
      values: ["member"]
  # 管理員角色:完整存取權限
  - from:
    - source:
        requestPrincipals: ["https://auth.example.com/*"]
    to:
    - operation:
        methods: ["*"]
        paths: ["/api/*"]
    when:
    - key: request.auth.claims[role]
      values: ["admin"]

實作 RBAC 時需要注意幾個重要的設計原則。首先,角色的定義應該基於業務需求,而不是技術實現。每個角色應該清楚地對應到一組業務功能,這樣才能確保授權策略的可維護性。其次,應該遵循最小權限原則,每個角色只應該被授予完成其職責所需的最小權限。最後,角色的繼承關係應該保持簡單,過度複雜的繼承結構會導致難以理解和維護的授權策略。

進階安全設定

除了基本的認證和授權功能外,Istio 還提供了許多進階安全設定,幫助我們建構更加安全的微服務環境。這些設定包括外部授權整合、安全稽核日誌以及安全態勢管理等。

外部授權是 Istio 的一個強大功能,它允許我們將授權決策委託給外部服務。這在需要複雜業務邏輯或需要整合現有授權系統時特別有用。以下範例展示了如何設定外部授權:

# 設定外部授權服務
# 這允許將複雜的授權邏輯委託給專門的授權服務
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: external-authz
  namespace: production
spec:
  selector:
    matchLabels:
      app: protected-service
  # CUSTOM action 表示使用外部授權
  action: CUSTOM
  provider:
    # 這裡指定外部授權提供者的名稱
    # 提供者需要在 mesh config 中預先設定
    name: "ext-authz-grpc"
  rules:
  - to:
    - operation:
        # 對所有路徑啟用外部授權
        paths: ["/*"]

要使用外部授權功能,還需要在 Istio 的 mesh config 中設定外部授權提供者:

# 這個設定需要添加到 istio ConfigMap 的 mesh 設定中
# 定義外部授權服務的連線資訊
extensionProviders:
- name: "ext-authz-grpc"
  # 使用 gRPC 協定與外部授權服務通訊
  envoyExtAuthzGrpc:
    # 外部授權服務的地址
    service: "ext-authz.auth-system.svc.cluster.local"
    # 外部授權服務的連接埠
    port: "9000"
    # 設定逾時時間
    timeout: 10s
    # 指定要傳遞給授權服務的 Header
    includeRequestHeadersInCheck:
    - authorization
    - x-tenant-id
    - x-request-id

安全稽核日誌對於安全事件的追蹤和分析至關重要。Istio 提供了詳細的存取日誌功能,可以記錄所有請求的安全相關資訊。以下範例展示了如何設定安全稽核日誌:

# Telemetry 資源用於設定存取日誌
# 這裡設定記錄詳細的安全相關資訊
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
  name: security-audit-log
  namespace: production
spec:
  accessLogging:
  - providers:
    - name: envoy
    # filter 允許只記錄特定條件的請求
    filter:
      # 只記錄授權失敗的請求
      expression: response.code >= 400 || connection.termination_details != ""

為了更好地監控和分析安全事件,我們還可以將 Istio 的存取日誌整合到集中式日誌系統中。透過設定 Envoy 的存取日誌格式,我們可以確保所有安全相關資訊都被正確記錄:

# 這個設定展示了如何自訂存取日誌格式
# 包含完整的安全相關欄位
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
  name: custom-access-log
  namespace: istio-system
spec:
  accessLogging:
  - providers:
    - name: envoy
  # 注意:實際的日誌格式設定需要在 EnvoyFilter 中進行
  # 這裡只是啟用存取日誌功能
@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

package "安全監控架構" {
    component "Envoy\nSidecar" as envoy
    database "存取日誌" as log
    component "日誌收集器\n(Fluentd)" as collector
    database "Elasticsearch" as es
    component "Kibana\n儀表板" as kibana
}

envoy --> log : 寫入日誌
log --> collector : 收集日誌
collector --> es : 索引儲存
es --> kibana : 查詢分析

note bottom of envoy
  記錄所有請求的
  安全相關資訊
end note

note bottom of kibana
  視覺化安全事件
  設定告警規則
end note

@enduml

這個架構圖展示了完整的安全監控流程,從 Envoy Sidecar 產生存取日誌,到最終在 Kibana 儀表板中進行視覺化分析。

最佳實踐與建議

在實際部署 Istio 安全機制時,遵循最佳實踐可以幫助我們避免常見的陷阱,並確保安全設定的有效性。以下是一些經過實踐驗證的建議。

首先,建議採用漸進式的安全部署策略。不要一次性為所有服務啟用嚴格模式,而是先從非關鍵服務開始,使用 PERMISSIVE 模式進行測試,確認沒有問題後再逐步切換到 STRICT 模式。這種方式可以降低部署風險,並讓團隊有時間熟悉 Istio 的安全機制。

其次,建議為每個命名空間建立預設的 DENY-ALL 授權策略。這確保了即使某個服務忘記設定授權策略,它也不會暴露在未經授權的存取風險中。以下是一個預設拒絕策略的範例:

# 預設拒絕所有請求的授權策略
# 這確保只有明確允許的請求才能通過
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: deny-all
  namespace: production
spec:
  # 空的 spec 加上 action: DENY 表示拒絕所有請求
  # 其他 AuthorizationPolicy 可以覆寫此設定,允許特定請求
  {}

第三,建議使用 GitOps 方式管理所有安全相關的 Kubernetes 資源。將 PeerAuthentication、RequestAuthentication 和 AuthorizationPolicy 等資源存放在 Git 儲存庫中,透過 CI/CD 流程進行部署。這不僅提供了版本控制和變更追蹤,還能確保安全設定的一致性和可重複性。

第四,建議定期審查和測試授權策略。授權策略可能會隨著業務需求的變化而過時,定期的審查可以確保策略仍然符合當前的安全需求。此外,建議使用自動化測試來驗證授權策略的正確性,確保預期的請求被允許而非預期的請求被拒絕。

最後,建議建立完整的安全監控和告警機制。監控 Istio 的安全指標,例如授權失敗次數、mTLS 握手失敗次數等,並設定適當的告警閾值。這可以幫助團隊及時發現和回應安全事件。

故障排除指南

在部署和維運 Istio 安全機制時,可能會遇到各種問題。以下是一些常見問題及其解決方案。

當服務間通訊失敗並出現「RBAC: access denied」錯誤時,首先應該檢查 AuthorizationPolicy 的設定是否正確。可以使用以下命令查看套用到特定工作負載的授權策略:

# 這個命令列出特定 Pod 套用的所有授權策略
# 可以幫助診斷授權失敗的問題
kubectl get authorizationpolicy -n production -o yaml

# 使用 istioctl 分析授權設定
# 這個命令會顯示詳細的授權決策邏輯
istioctl x authz check POD_NAME.production

# 查看 Envoy 的授權日誌
# 這可以顯示具體的授權失敗原因
kubectl logs POD_NAME -c istio-proxy -n production | grep "rbac"

當 mTLS 握手失敗時,可能是因為憑證問題或 PeerAuthentication 設定不一致。以下命令可以幫助診斷 mTLS 相關問題:

# 檢查工作負載的憑證狀態
# 確認憑證是否有效且未過期
istioctl proxy-config secret POD_NAME.production

# 檢查 mTLS 設定的一致性
# 確保來源和目標的 mTLS 模式相容
istioctl authn tls-check POD_NAME.production SERVICE_NAME.production.svc.cluster.local

# 查看詳細的 TLS 握手日誌
kubectl logs POD_NAME -c istio-proxy -n production | grep "tls"

當 JWT 驗證失敗時,常見原因包括 Token 過期、發行者不匹配或公鑰無法取得。可以使用以下方式進行診斷:

# 檢查 RequestAuthentication 設定
kubectl get requestauthentication -n production -o yaml

# 測試 JWKS 端點是否可存取
# 確保 Istio 能夠取得公鑰來驗證 Token
curl -v https://auth.example.com/.well-known/jwks.json

# 解碼 JWT Token 檢查其內容
# 確認 iss、aud、exp 等聲明是否正確
echo "YOUR_JWT_TOKEN" | cut -d. -f2 | base64 -d | jq .

結論

Istio 服務網格提供了一套完整且強大的安全機制,幫助我們在微服務環境中實現企業級的安全防護。透過 mTLS 雙向認證,我們確保了服務間通訊的機密性和完整性。透過 AuthorizationPolicy,我們實現了細粒度的存取控制,遵循零信任架構和最小權限原則。

在實際應用中,我們需要根據業務需求和安全要求,合理設計和部署這些安全機制。採用漸進式部署策略、建立預設拒絕策略、使用 GitOps 管理安全資源、定期審查授權策略,以及建立完整的監控告警機制,這些最佳實踐可以幫助我們有效地管理 Istio 的安全設定。

隨著雲端原生技術的不斷發展,服務網格安全的重要性將持續提升。掌握 Istio 的安全架構和授權機制,不僅能夠保護我們的微服務應用免受安全威脅,更能為企業的數位轉型提供堅實的安全基礎。期望本文的內容能夠幫助讀者深入理解 Istio 的安全機制,並在實際工作中有效地應用這些知識。