零信任網路存取憑證策略

Zero Trust Network Access Certificate Strategy

零信任網路存取(Zero Trust Network Access, ZTNA)是現代企業安全架構的核心概念。在這個框架中,憑證扮演著至關重要的角色,負責驗證使用者、裝置和服務的身份。本文將深入探討零信任架構中的憑證策略,包括裝置憑證、短期憑證、mTLS 實作等關鍵主題。

零信任架構概念

什麼是零信任?

零信任(Zero Trust)是一種安全模型,其核心原則是「永不信任,始終驗證」(Never Trust, Always Verify)。這種架構假設網路內外都可能存在威脅,因此不再依賴傳統的網路邊界防禦,而是對每一次存取請求進行嚴格的身份驗證和授權。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
傳統安全模型 vs 零信任模型

+-----------------------------------+
|        傳統安全模型               |
+-----------------------------------+
|                                   |
|   +---------------------------+   |
|   |     企業內部網路          |   |
|   |   (信任區域)              |   |
|   |                           |   |
|   |   +---------+  +-------+  |   |
|   |   | 伺服器  |  | 使用者 |  |   |
|   |   +---------+  +-------+  |   |
|   +---------------------------+   |
|              |                    |
|         防火牆邊界                |
|              |                    |
|   +---------------------------+   |
|   |     外部網路              |   |
|   |   (不信任區域)            |   |
|   +---------------------------+   |
+-----------------------------------+

+-----------------------------------+
|        零信任模型                 |
+-----------------------------------+
|                                   |
|   每個存取請求都需要驗證:        |
|                                   |
|   +-------+    驗證    +-------+  |
|   | 使用者 | --------> | 資源  |  |
|   +-------+            +-------+  |
|       |                    |      |
|   +---------------------------+   |
|   |    身份驗證 + 授權        |   |
|   |    裝置健康檢查           |   |
|   |    存取政策評估           |   |
|   |    持續監控               |   |
|   +---------------------------+   |
+-----------------------------------+

零信任的核心原則

  1. 明確驗證:基於所有可用的資料點進行驗證,包括使用者身份、位置、裝置健康狀態、服務或工作負載、資料分類和異常檢測。

  2. 最小權限存取:使用即時和足夠的存取權限(JIT/JEA),風險型調適政策和資料保護來限制使用者存取。

  3. 假設已被入侵:最小化影響範圍,分段存取,驗證端對端加密,並使用分析來提高可見性、驅動威脅偵測和改善防禦。

ZTNA 與傳統 VPN 的差異

特性傳統 VPNZTNA
存取模式全網路存取單一應用程式存取
信任模型連接後信任持續驗證
可見性僅限連接狀態完整應用程式層可見性
擴展性需要複雜設定雲原生易擴展
安全性橫向移動風險高最小攻擊面

憑證在零信任中的角色

憑證的核心功能

在零信任架構中,憑證是實現身份驗證的關鍵技術。憑證提供以下核心功能:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
+-------------------------------------------+
|           憑證在零信任中的角色            |
+-------------------------------------------+
|                                           |
|  +-------------+    +-------------+       |
|  | 身份證明    |    | 加密通訊    |       |
|  | Identity    |    | Encryption  |       |
|  +------+------+    +------+------+       |
|         |                  |              |
|         v                  v              |
|  +-------------+    +-------------+       |
|  | 存取控制    |    | 完整性驗證  |       |
|  | Access Ctrl |    | Integrity   |       |
|  +------+------+    +------+------+       |
|         |                  |              |
|         +--------+---------+              |
|                  |                        |
|                  v                        |
|         +----------------+                |
|         | 零信任安全保障 |                |
|         +----------------+                |
+-------------------------------------------+

憑證類型與用途

憑證類型用途零信任應用場景
裝置憑證識別和驗證裝置裝置健康檢查、設備准入控制
使用者憑證識別和驗證使用者多因素認證、無密碼登入
服務憑證識別和驗證服務微服務通訊、API 認證
工作負載憑證識別和驗證容器/工作負載Kubernetes Pod 認證

憑證生命週期管理

1
2
3
4
5
6
7
8
9
+----------------------------------------------------------+
|                  憑證生命週期                            |
+----------------------------------------------------------+
|                                                          |
|   申請 --> 簽發 --> 分發 --> 使用 --> 監控 --> 更新/撤銷 |
|    ^                                              |      |
|    +----------------------------------------------+      |
|                     持續循環                             |
+----------------------------------------------------------+

裝置憑證與身份驗證

裝置身份的重要性

在零信任架構中,裝置身份與使用者身份同等重要。即使使用者身份正確,若裝置不受信任或未通過健康檢查,存取請求仍應被拒絕。

裝置憑證部署流程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 1. 為裝置產生私鑰
openssl genrsa -out device-001.key 2048

# 2. 建立裝置憑證簽署請求(CSR)
openssl req -new -key device-001.key -out device-001.csr \
    -subj "/C=TW/ST=Taiwan/O=Enterprise/OU=Devices/CN=device-001"

# 3. 建立裝置憑證擴展設定檔
cat > device-001.ext << EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = device-001.internal
URI.1 = urn:device:uuid:550e8400-e29b-41d4-a716-446655440000
EOF

# 4. 使用企業 CA 簽發裝置憑證
openssl x509 -req -in device-001.csr \
    -CA enterprise-ca.crt -CAkey enterprise-ca.key \
    -CAcreateserial -out device-001.crt -days 90 \
    -extfile device-001.ext -sha256

裝置憑證驗證腳本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/bash
# 裝置憑證驗證腳本

DEVICE_CERT="device-001.crt"
CA_CERT="enterprise-ca.crt"

# 驗證憑證有效性
echo "=== 驗證憑證鏈 ==="
openssl verify -CAfile $CA_CERT $DEVICE_CERT

# 檢查憑證到期時間
echo "=== 憑證有效期限 ==="
openssl x509 -in $DEVICE_CERT -noout -dates

# 提取裝置識別資訊
echo "=== 裝置識別資訊 ==="
openssl x509 -in $DEVICE_CERT -noout -subject

# 檢查憑證用途
echo "=== 憑證用途 ==="
openssl x509 -in $DEVICE_CERT -noout -purpose | grep "SSL client"

整合 MDM 的裝置憑證管理

現代企業通常透過行動裝置管理(MDM)或統一端點管理(UEM)系統來自動化裝置憑證的部署和管理:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# 範例:Intune/Jamf 裝置憑證設定檔
device_certificate_profile:
  name: "Zero Trust Device Certificate"
  platform:
    - Windows
    - macOS
    - iOS
    - Android
  certificate_type: "SCEP"
  scep_server_urls:
    - "https://scep.enterprise.com/certsrv/mscep/"
  key_size: 2048
  key_usage:
    - digital_signature
    - key_encipherment
  extended_key_usage:
    - client_authentication
  subject_name_format: "CN={{DeviceId}},OU=Devices,O=Enterprise"
  renewal_threshold_percentage: 20
  validity_period: 90
  validity_period_unit: "days"

裝置健康評估與憑證結合

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
裝置存取決策流程:

+----------------+     +------------------+     +----------------+
|   裝置連線     | --> |   憑證驗證       | --> |  健康檢查      |
+----------------+     +------------------+     +----------------+
                              |                        |
                              v                        v
                       憑證有效?              裝置合規?
                       /      \                /       \
                     是        否            是         否
                     |          |            |          |
                     v          v            v          v
               +----------+ +--------+ +---------+ +--------+
               | 繼續流程 | | 拒絕   | | 授權    | | 拒絕   |
               +----------+ +--------+ +---------+ +--------+

短期憑證與動態信任

為什麼需要短期憑證?

傳統的長期憑證(有效期 1-3 年)在零信任架構中存在以下問題:

  1. 憑證洩露風險:長期有效的憑證一旦洩露,攻擊者可長期利用
  2. 撤銷機制延遲:CRL/OCSP 可能存在快取和延遲問題
  3. 權限過時:使用者或裝置的權限可能已變更,但憑證仍有效
  4. 審計困難:難以追蹤長期憑證的使用情況

短期憑證的優勢

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
+-----------------------------------------------+
|           短期憑證優勢                        |
+-----------------------------------------------+
|                                               |
|  +------------------+  +------------------+   |
|  | 降低洩露風險     |  | 自動化輪換       |   |
|  | 憑證有效期短     |  | 無需手動介入     |   |
|  | 洩露影響有限     |  | 減少運維負擔     |   |
|  +------------------+  +------------------+   |
|                                               |
|  +------------------+  +------------------+   |
|  | 即時權限控制     |  | 簡化撤銷流程     |   |
|  | 每次簽發時評估   |  | 憑證自然過期     |   |
|  | 動態調整權限     |  | 無需維護 CRL     |   |
|  +------------------+  +------------------+   |
+-----------------------------------------------+

建議的憑證有效期

憑證類型建議有效期說明
服務網格憑證1-24 小時高頻輪換,最小攻擊面
API 存取憑證1-7 天平衡安全性與效能
工作負載憑證7-30 天容器和無伺服器環境
裝置憑證30-90 天配合 MDM 管理週期
使用者憑證8-24 小時每日重新認證

使用 Vault 實作短期憑證

HashiCorp Vault 是實作短期憑證的理想工具。以下是設定範例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 1. 啟用 PKI 密鑰引擎
vault secrets enable pki

# 2. 設定 PKI 最大租期
vault secrets tune -max-lease-ttl=87600h pki

# 3. 產生根憑證
vault write pki/root/generate/internal \
    common_name="Zero Trust Root CA" \
    ttl=87600h

# 4. 設定 CA 和 CRL URLs
vault write pki/config/urls \
    issuing_certificates="https://vault.enterprise.com:8200/v1/pki/ca" \
    crl_distribution_points="https://vault.enterprise.com:8200/v1/pki/crl"

# 5. 啟用中繼 CA
vault secrets enable -path=pki_int pki
vault secrets tune -max-lease-ttl=43800h pki_int

# 6. 產生中繼 CA CSR
vault write -format=json pki_int/intermediate/generate/internal \
    common_name="Zero Trust Intermediate CA" \
    | jq -r '.data.csr' > pki_intermediate.csr

# 7. 使用根 CA 簽發中繼 CA 憑證
vault write -format=json pki/root/sign-intermediate \
    csr=@pki_intermediate.csr \
    format=pem_bundle ttl="43800h" \
    | jq -r '.data.certificate' > intermediate.cert.pem

# 8. 設定中繼 CA 憑證
vault write pki_int/intermediate/set-signed \
    certificate=@intermediate.cert.pem

建立短期憑證角色

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 建立短期憑證角色(有效期 24 小時)
vault write pki_int/roles/short-lived-cert \
    allowed_domains="enterprise.com" \
    allow_subdomains=true \
    max_ttl="24h" \
    ttl="1h" \
    key_type="ec" \
    key_bits=256 \
    require_cn=true \
    allow_ip_sans=true \
    allow_localhost=true

# 簽發短期憑證
vault write pki_int/issue/short-lived-cert \
    common_name="service-api.enterprise.com" \
    ttl="1h"

自動化短期憑證輪換

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/bin/bash
# 短期憑證自動輪換腳本

VAULT_ADDR="https://vault.enterprise.com:8200"
CERT_PATH="/etc/ssl/certs/service.crt"
KEY_PATH="/etc/ssl/private/service.key"
SERVICE_NAME="api-service"
RENEWAL_THRESHOLD=600  # 秒

renew_certificate() {
    echo "[$(date)] 更新憑證..."

    # 從 Vault 取得新憑證
    response=$(vault write -format=json pki_int/issue/short-lived-cert \
        common_name="${SERVICE_NAME}.enterprise.com" \
        ttl="1h")

    # 提取憑證和私鑰
    echo "$response" | jq -r '.data.certificate' > $CERT_PATH
    echo "$response" | jq -r '.data.private_key' > $KEY_PATH

    # 設定權限
    chmod 644 $CERT_PATH
    chmod 600 $KEY_PATH

    # 重新載入服務
    systemctl reload nginx

    echo "[$(date)] 憑證更新完成"
}

check_and_renew() {
    # 取得憑證到期時間
    expiry=$(openssl x509 -in $CERT_PATH -noout -enddate | cut -d= -f2)
    expiry_epoch=$(date -d "$expiry" +%s)
    current_epoch=$(date +%s)
    remaining=$((expiry_epoch - current_epoch))

    echo "[$(date)] 憑證剩餘有效時間: ${remaining} 秒"

    if [ $remaining -lt $RENEWAL_THRESHOLD ]; then
        renew_certificate
    fi
}

# 持續監控
while true; do
    check_and_renew
    sleep 300  # 每 5 分鐘檢查一次
done

mTLS 實作

零信任架構中的 mTLS

mTLS(Mutual TLS)是零信任架構中實現服務間安全通訊的核心技術。在 mTLS 中,通訊雙方都需要提供憑證進行驗證。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
mTLS 握手流程

+----------------+                    +----------------+
|    客戶端      |                    |    伺服器      |
+----------------+                    +----------------+
        |                                    |
        | 1. ClientHello                     |
        |----------------------------------->|
        |                                    |
        | 2. ServerHello + ServerCertificate |
        |    + CertificateRequest            |
        |<-----------------------------------|
        |                                    |
        | 3. ClientCertificate               |
        |    + CertificateVerify             |
        |----------------------------------->|
        |                                    |
        | 4. 驗證客戶端憑證                  |
        |                                    |
        | 5. Finished (雙向驗證完成)         |
        |<---------------------------------->|
        |                                    |
        | 6. 加密應用資料傳輸                |
        |<=================================>|
        |                                    |

Nginx mTLS 進階設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# /etc/nginx/conf.d/mtls.conf

# 上游服務(也使用 mTLS)
upstream backend_api {
    server api-server-1:8443;
    server api-server-2:8443;
}

server {
    listen 443 ssl http2;
    server_name api.enterprise.com;

    # 伺服器憑證
    ssl_certificate /etc/nginx/ssl/server.crt;
    ssl_certificate_key /etc/nginx/ssl/server.key;

    # CA 憑證(用於驗證客戶端)
    ssl_client_certificate /etc/nginx/ssl/ca-chain.crt;

    # 強制要求客戶端憑證
    ssl_verify_client on;
    ssl_verify_depth 3;

    # TLS 設定
    ssl_protocols TLSv1.3;
    ssl_ciphers 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256';
    ssl_prefer_server_ciphers off;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;

    # 存取日誌(包含客戶端憑證資訊)
    log_format mtls_log '$remote_addr - $ssl_client_s_dn - '
                        '[$time_local] "$request" $status $body_bytes_sent '
                        '"$http_referer" "$http_user_agent" '
                        'ssl_client_verify=$ssl_client_verify';

    access_log /var/log/nginx/mtls_access.log mtls_log;

    location / {
        # 基於客戶端憑證 CN 的存取控制
        if ($ssl_client_s_dn_cn !~ "^(service-a|service-b|admin)$") {
            return 403 "Unauthorized client\n";
        }

        # 傳遞客戶端憑證資訊到後端
        proxy_set_header X-SSL-Client-CN $ssl_client_s_dn_cn;
        proxy_set_header X-SSL-Client-DN $ssl_client_s_dn;
        proxy_set_header X-SSL-Client-Serial $ssl_client_serial;
        proxy_set_header X-SSL-Client-Verify $ssl_client_verify;
        proxy_set_header X-SSL-Client-Fingerprint $ssl_client_fingerprint;

        # 後端 mTLS 連線
        proxy_pass https://backend_api;
        proxy_ssl_certificate /etc/nginx/ssl/client.crt;
        proxy_ssl_certificate_key /etc/nginx/ssl/client.key;
        proxy_ssl_trusted_certificate /etc/nginx/ssl/backend-ca.crt;
        proxy_ssl_verify on;
        proxy_ssl_verify_depth 2;
        proxy_ssl_protocols TLSv1.3;
    }
}

Kubernetes Ingress mTLS 設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# Kubernetes Secret 存放 CA 憑證
apiVersion: v1
kind: Secret
metadata:
  name: mtls-ca-secret
  namespace: production
type: Opaque
data:
  ca.crt: |
    LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t...    

---
# Nginx Ingress mTLS 設定
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: mtls-ingress
  namespace: production
  annotations:
    nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"
    nginx.ingress.kubernetes.io/auth-tls-secret: "production/mtls-ca-secret"
    nginx.ingress.kubernetes.io/auth-tls-verify-depth: "3"
    nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: "true"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - api.enterprise.com
      secretName: api-tls-secret
  rules:
    - host: api.enterprise.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 8080

使用 curl 測試 mTLS

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 完整的 mTLS 連線測試
curl -v \
    --cacert ca-chain.crt \
    --cert client.crt \
    --key client.key \
    https://api.enterprise.com/health

# 驗證憑證鏈
openssl s_client -connect api.enterprise.com:443 \
    -CAfile ca-chain.crt \
    -cert client.crt \
    -key client.key \
    -showcerts

服務身份認證

SPIFFE/SPIRE 架構

SPIFFE(Secure Production Identity Framework For Everyone)是一個開放標準,用於在動態和異質環境中安全地識別軟體服務。SPIRE 是 SPIFFE 的參考實作。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
SPIFFE/SPIRE 架構

+---------------------------------------------------+
|                   SPIRE Server                    |
|  +---------------------------------------------+  |
|  |  Registration API  |  Node/Workload API    |  |
|  +---------------------------------------------+  |
|  |              Data Store                     |  |
|  |    (Registration Entries, CA Keys)          |  |
|  +---------------------------------------------+  |
+------------------------+---------------------------+
                         |
          +--------------+--------------+
          |              |              |
          v              v              v
+----------------+ +----------------+ +----------------+
|  SPIRE Agent   | |  SPIRE Agent   | |  SPIRE Agent   |
|  (Node 1)      | |  (Node 2)      | |  (Node 3)      |
+----------------+ +----------------+ +----------------+
        |                  |                  |
        v                  v                  v
+----------------+ +----------------+ +----------------+
|  Workload API  | |  Workload API  | |  Workload API  |
|  (Unix Socket) | |  (Unix Socket) | |  (Unix Socket) |
+----------------+ +----------------+ +----------------+
        |                  |                  |
        v                  v                  v
+----------------+ +----------------+ +----------------+
|   Workload A   | |   Workload B   | |   Workload C   |
| SPIFFE ID:     | | SPIFFE ID:     | | SPIFFE ID:     |
| spiffe://...   | | spiffe://...   | | spiffe://...   |
+----------------+ +----------------+ +----------------+

SPIFFE ID 格式

1
2
3
4
5
6
SPIFFE ID 格式:
spiffe://trust-domain/path

範例:
spiffe://enterprise.com/ns/production/sa/api-service
spiffe://enterprise.com/region/us-west/workload/payment

SPIRE 部署範例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# SPIRE Server ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: spire-server-config
  namespace: spire
data:
  server.conf: |
    server {
        bind_address = "0.0.0.0"
        bind_port = "8081"
        trust_domain = "enterprise.com"
        data_dir = "/run/spire/data"
        log_level = "INFO"

        ca_ttl = "24h"
        default_svid_ttl = "1h"

        ca_subject {
            country = ["TW"]
            organization = ["Enterprise"]
            common_name = "SPIRE CA"
        }
    }

    plugins {
        DataStore "sql" {
            plugin_data {
                database_type = "postgres"
                connection_string = "host=postgres dbname=spire user=spire password=secret"
            }
        }

        NodeAttestor "k8s_psat" {
            plugin_data {
                clusters = {
                    "production" = {
                        service_account_allow_list = ["spire:spire-agent"]
                    }
                }
            }
        }

        KeyManager "disk" {
            plugin_data {
                keys_path = "/run/spire/data/keys.json"
            }
        }

        Notifier "k8sbundle" {
            plugin_data {
                namespace = "spire"
                config_map = "trust-bundle"
            }
        }
    }    

---
# SPIRE Server Deployment
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: spire-server
  namespace: spire
spec:
  replicas: 1
  selector:
    matchLabels:
      app: spire-server
  serviceName: spire-server
  template:
    metadata:
      labels:
        app: spire-server
    spec:
      serviceAccountName: spire-server
      containers:
        - name: spire-server
          image: ghcr.io/spiffe/spire-server:1.8.0
          args:
            - -config
            - /run/spire/config/server.conf
          ports:
            - containerPort: 8081
          volumeMounts:
            - name: spire-config
              mountPath: /run/spire/config
            - name: spire-data
              mountPath: /run/spire/data
      volumes:
        - name: spire-config
          configMap:
            name: spire-server-config
        - name: spire-data
          persistentVolumeClaim:
            claimName: spire-data

工作負載註冊

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# 註冊 API 服務工作負載
kubectl exec -n spire spire-server-0 -- \
    /opt/spire/bin/spire-server entry create \
    -spiffeID spiffe://enterprise.com/api-service \
    -parentID spiffe://enterprise.com/spire/agent/k8s_psat/production/node1 \
    -selector k8s:ns:production \
    -selector k8s:sa:api-service \
    -ttl 3600

# 註冊資料庫客戶端工作負載
kubectl exec -n spire spire-server-0 -- \
    /opt/spire/bin/spire-server entry create \
    -spiffeID spiffe://enterprise.com/db-client \
    -parentID spiffe://enterprise.com/spire/agent/k8s_psat/production/node1 \
    -selector k8s:ns:production \
    -selector k8s:sa:db-client \
    -ttl 3600

# 列出所有註冊條目
kubectl exec -n spire spire-server-0 -- \
    /opt/spire/bin/spire-server entry show

應用程式整合範例(Go)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// Go 應用程式整合 SPIFFE
package main

import (
    "context"
    "log"
    "net/http"

    "github.com/spiffe/go-spiffe/v2/spiffeid"
    "github.com/spiffe/go-spiffe/v2/spiffetls"
    "github.com/spiffe/go-spiffe/v2/spiffetls/tlsconfig"
    "github.com/spiffe/go-spiffe/v2/workloadapi"
)

func main() {
    ctx := context.Background()

    // 連接 SPIRE Agent Workload API
    source, err := workloadapi.NewX509Source(ctx)
    if err != nil {
        log.Fatalf("無法取得 X.509 來源: %v", err)
    }
    defer source.Close()

    // 定義授權的 SPIFFE ID
    authorizedID := spiffeid.RequireFromString("spiffe://enterprise.com/api-client")

    // 建立 mTLS 伺服器
    tlsConfig := tlsconfig.MTLSServerConfig(source, source, tlsconfig.AuthorizeID(authorizedID))

    server := &http.Server{
        Addr:      ":8443",
        TLSConfig: tlsConfig,
    }

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("已通過 SPIFFE mTLS 驗證!"))
    })

    log.Println("伺服器啟動於 :8443")
    log.Fatal(server.ListenAndServeTLS("", ""))
}

應用程式整合範例(Python)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/usr/bin/env python3
"""Python 應用程式整合 SPIFFE"""

from pyspiffe.spiffe_id.spiffe_id import SpiffeId
from pyspiffe.workloadapi.default_workload_api_client import DefaultWorkloadApiClient
from pyspiffe.bundle.x509_bundle.x509_bundle_set import X509BundleSet
import ssl

def create_mtls_context():
    """建立 mTLS SSL Context"""
    # 連接 SPIRE Agent
    client = DefaultWorkloadApiClient()

    # 取得 X.509 SVID
    x509_svid = client.fetch_x509_svid()

    # 取得信任 Bundle
    x509_bundles = client.fetch_x509_bundles()

    # 建立 SSL Context
    context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
    context.verify_mode = ssl.CERT_REQUIRED

    # 載入客戶端憑證
    context.load_cert_chain(
        certfile=x509_svid.cert_chain_path,
        keyfile=x509_svid.private_key_path
    )

    # 載入 CA 憑證
    for bundle in x509_bundles.bundles():
        context.load_verify_locations(cafile=bundle.path)

    return context

if __name__ == "__main__":
    ctx = create_mtls_context()
    print("mTLS Context 建立成功")

憑證自動化輪換

Cert-Manager 自動化管理

Cert-Manager 是 Kubernetes 中管理憑證生命週期的標準工具:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 安裝 Cert-Manager
# kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml

# 設定 Vault Issuer
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: vault-issuer
spec:
  vault:
    path: pki_int/sign/short-lived-cert
    server: https://vault.enterprise.com:8200
    auth:
      kubernetes:
        role: cert-manager
        mountPath: /v1/auth/kubernetes
        serviceAccountRef:
          name: cert-manager

---
# 建立短期憑證
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: api-service-cert
  namespace: production
spec:
  secretName: api-service-tls
  duration: 1h
  renewBefore: 15m
  issuerRef:
    name: vault-issuer
    kind: ClusterIssuer
  commonName: api-service.production.svc.cluster.local
  dnsNames:
    - api-service
    - api-service.production
    - api-service.production.svc
    - api-service.production.svc.cluster.local
  usages:
    - server auth
    - client auth

自動化輪換監控

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# Prometheus 監控規則
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: certificate-alerts
  namespace: monitoring
spec:
  groups:
    - name: certificate.rules
      rules:
        - alert: CertificateExpiringSoon
          expr: |
            certmanager_certificate_expiration_timestamp_seconds - time() < 86400            
          for: 1h
          labels:
            severity: warning
          annotations:
            summary: "憑證即將到期"
            description: "憑證 {{ $labels.name }} 將在 24 小時內到期"

        - alert: CertificateExpired
          expr: |
            certmanager_certificate_expiration_timestamp_seconds - time() < 0            
          for: 5m
          labels:
            severity: critical
          annotations:
            summary: "憑證已過期"
            description: "憑證 {{ $labels.name }} 已經過期"

        - alert: CertificateRenewalFailed
          expr: |
            increase(certmanager_certificate_renewal_timestamp_seconds[1h]) == 0
            and certmanager_certificate_expiration_timestamp_seconds - time() < 7200            
          for: 30m
          labels:
            severity: critical
          annotations:
            summary: "憑證更新失敗"
            description: "憑證 {{ $labels.name }} 更新失敗,需要人工介入"

憑證輪換通知腳本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#!/usr/bin/env python3
"""
憑證輪換監控與通知腳本
"""

import ssl
import socket
import datetime
from typing import Dict, List
import smtplib
from email.mime.text import MIMEText

def check_certificate(hostname: str, port: int = 443) -> Dict:
    """檢查憑證狀態"""
    context = ssl.create_default_context()

    with socket.create_connection((hostname, port), timeout=10) as sock:
        with context.wrap_socket(sock, server_hostname=hostname) as ssock:
            cert = ssock.getpeercert()

            # 解析到期時間
            not_after = datetime.datetime.strptime(
                cert['notAfter'], '%b %d %H:%M:%S %Y %Z'
            )

            # 計算剩餘天數
            remaining = (not_after - datetime.datetime.utcnow()).days

            return {
                'hostname': hostname,
                'subject': dict(x[0] for x in cert['subject']),
                'issuer': dict(x[0] for x in cert['issuer']),
                'not_after': not_after.isoformat(),
                'remaining_days': remaining,
                'serial_number': cert.get('serialNumber', 'N/A')
            }

def send_alert(cert_info: Dict, threshold: int = 7):
    """發送警報通知"""
    if cert_info['remaining_days'] <= threshold:
        msg = MIMEText(f"""
憑證即將到期警報

主機: {cert_info['hostname']}
主體: {cert_info['subject'].get('commonName', 'N/A')}
發行者: {cert_info['issuer'].get('commonName', 'N/A')}
到期時間: {cert_info['not_after']}
剩餘天數: {cert_info['remaining_days']}

請立即處理憑證更新!
        """)

        msg['Subject'] = f"[警報] 憑證即將到期: {cert_info['hostname']}"
        msg['From'] = 'security@enterprise.com'
        msg['To'] = 'ops-team@enterprise.com'

        with smtplib.SMTP('smtp.enterprise.com') as server:
            server.send_message(msg)

        print(f"警報已發送: {cert_info['hostname']}")

def main():
    """主程式"""
    hosts = [
        'api.enterprise.com',
        'auth.enterprise.com',
        'app.enterprise.com',
    ]

    for host in hosts:
        try:
            cert_info = check_certificate(host)
            print(f"檢查 {host}: 剩餘 {cert_info['remaining_days']} 天")
            send_alert(cert_info, threshold=7)
        except Exception as e:
            print(f"檢查 {host} 失敗: {e}")

if __name__ == '__main__':
    main()

Systemd Timer 排程自動輪換

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# /etc/systemd/system/cert-renewal.service
[Unit]
Description=Certificate Renewal Service
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/renew-certificates.sh
User=root
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# /etc/systemd/system/cert-renewal.timer
[Unit]
Description=Run certificate renewal every hour

[Timer]
OnBootSec=5min
OnUnitActiveSec=1h
Persistent=true

[Install]
WantedBy=timers.target
1
2
3
4
5
6
# 啟用排程
sudo systemctl enable cert-renewal.timer
sudo systemctl start cert-renewal.timer

# 檢查狀態
sudo systemctl status cert-renewal.timer

實施建議與案例

零信任憑證策略實施路線圖

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
+---------------------------------------------------------------+
|                    實施路線圖                                 |
+---------------------------------------------------------------+
|                                                               |
|  階段 1: 評估與規劃 (1-2 個月)                                |
|  +----------------------------------------------------------+ |
|  | - 盤點現有憑證和 PKI 基礎架構                            | |
|  | - 識別關鍵服務和敏感資料流                               | |
|  | - 定義安全需求和合規要求                                 | |
|  | - 制定遷移計劃和時間表                                   | |
|  +----------------------------------------------------------+ |
|                           |                                   |
|                           v                                   |
|  階段 2: 基礎架構建設 (2-3 個月)                              |
|  +----------------------------------------------------------+ |
|  | - 部署企業 PKI 或採用雲端 CA 服務                        | |
|  | - 設定 HashiCorp Vault 或類似的密鑰管理系統              | |
|  | - 部署 SPIRE 或其他服務身份管理系統                      | |
|  | - 建立憑證管理自動化流程                                 | |
|  +----------------------------------------------------------+ |
|                           |                                   |
|                           v                                   |
|  階段 3: 試點導入 (1-2 個月)                                  |
|  +----------------------------------------------------------+ |
|  | - 選擇非關鍵服務進行試點                                 | |
|  | - 部署裝置憑證管理                                       | |
|  | - 實施 mTLS 於試點服務                                   | |
|  | - 驗證短期憑證輪換機制                                   | |
|  +----------------------------------------------------------+ |
|                           |                                   |
|                           v                                   |
|  階段 4: 全面部署 (3-6 個月)                                  |
|  +----------------------------------------------------------+ |
|  | - 逐步推廣至所有服務                                     | |
|  | - 強制執行 mTLS 政策                                     | |
|  | - 淘汰長期憑證                                           | |
|  | - 完善監控和告警機制                                     | |
|  +----------------------------------------------------------+ |
|                           |                                   |
|                           v                                   |
|  階段 5: 持續優化 (持續進行)                                  |
|  +----------------------------------------------------------+ |
|  | - 定期審計和合規檢查                                     | |
|  | - 調整憑證策略和有效期                                   | |
|  | - 更新安全政策和程序                                     | |
|  | - 教育訓練和意識提升                                     | |
|  +----------------------------------------------------------+ |
+---------------------------------------------------------------+

企業案例:金融服務公司

以下是一個金融服務公司實施零信任憑證策略的完整案例:

架構設計

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# 零信任憑證架構設計
infrastructure:
  pki:
    root_ca:
      provider: "AWS Private CA"
      key_algorithm: "RSA_4096"
      validity: "10 years"
      storage: "HSM"

    intermediate_cas:
      - name: "Device CA"
        validity: "5 years"
        purpose: "裝置憑證簽發"

      - name: "Service CA"
        validity: "3 years"
        purpose: "服務憑證簽發"

      - name: "User CA"
        validity: "3 years"
        purpose: "使用者憑證簽發"

  certificate_policy:
    device_certificates:
      validity: "90 days"
      key_size: 2048
      renewal_threshold: "20%"
      distribution: "MDM/UEM"

    service_certificates:
      validity: "1 hour"
      key_type: "ECDSA P-256"
      renewal: "automatic"
      issuer: "Vault PKI"

    user_certificates:
      validity: "8 hours"
      key_type: "ECDSA P-256"
      renewal: "on login"
      issuer: "SPIRE"

  mtls_zones:
    - name: "External API Gateway"
      client_verification: "required"
      allowed_clients:
        - "partner-services"
        - "mobile-apps"

    - name: "Internal Service Mesh"
      client_verification: "required"
      allowed_clients:
        - "all-registered-services"

    - name: "Database Access"
      client_verification: "required"
      allowed_clients:
        - "authorized-services"

實施效果

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
+-----------------------------------------------+
|              實施成效報告                     |
+-----------------------------------------------+
|                                               |
|  安全改善:                                    |
|  +----------------------------------------+   |
|  | - 消除長期憑證洩露風險                 |   |
|  | - 實現完整的服務間 mTLS 加密           |   |
|  | - 達成 100% 裝置憑證覆蓋率             |   |
|  | - 憑證相關安全事件減少 95%             |   |
|  +----------------------------------------+   |
|                                               |
|  運維效率:                                    |
|  +----------------------------------------+   |
|  | - 憑證管理工時減少 80%                 |   |
|  | - 憑證過期事件降至零                   |   |
|  | - 自動化輪換覆蓋率 100%                |   |
|  | - 部署時間從數小時縮短至數分鐘         |   |
|  +----------------------------------------+   |
|                                               |
|  合規達成:                                    |
|  +----------------------------------------+   |
|  | - 符合 PCI DSS 加密要求                |   |
|  | - 滿足金管會資安規範                   |   |
|  | - 通過 SOC 2 Type II 審計              |   |
|  | - 達成 ISO 27001 憑證管理要求          |   |
|  +----------------------------------------+   |
+-----------------------------------------------+

最佳實踐清單

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
+-----------------------------------------------+
|           零信任憑證最佳實踐                  |
+-----------------------------------------------+

1. 憑證有效期
   [v] 裝置憑證: 90 天或更短
   [v] 服務憑證: 24 小時或更短
   [v] 使用者憑證: 工作時間內有效
   [v] 避免使用超過 1 年的憑證

2. 金鑰管理
   [v] 使用 HSM 保護根 CA 金鑰
   [v] 實施金鑰輪換策略
   [v] 採用 ECDSA P-256 或以上
   [v] 禁止導出私鑰

3. 自動化
   [v] 自動化憑證簽發和更新
   [v] 實施自動化健康檢查
   [v] 設定自動告警機制
   [v] 自動化撤銷流程

4. 監控與審計
   [v] 記錄所有憑證操作
   [v] 監控憑證到期時間
   [v] 追蹤憑證使用情況
   [v] 定期合規審計

5. 存取控制
   [v] 實施最小權限原則
   [v] 基於身份的存取控制
   [v] 強制 mTLS 於所有服務
   [v] 隔離敏感資料存取

6. 災難復原
   [v] 備份 CA 金鑰和設定
   [v] 文件化復原程序
   [v] 定期測試復原流程
   [v] 維護離線根 CA 備份

常見問題與解決方案

問題原因解決方案
憑證輪換失敗Vault 連線問題實施健康檢查和自動重試
mTLS 連線逾時憑證驗證延遲啟用 OCSP Stapling
服務啟動失敗憑證尚未就緒實施 Init Container 等待機制
裝置無法存取憑證過期設定更早的更新閾值
審計日誌遺失儲存空間不足實施日誌輪換和歸檔

總結

零信任網路存取憑證策略是現代企業安全架構的核心組成部分。透過實施短期憑證、mTLS、服務身份認證和自動化管理,組織可以顯著提升其安全態勢,同時降低運維負擔。

關鍵要點回顧:

  • 零信任原則:永不信任,始終驗證 - 憑證是實現這一原則的關鍵技術
  • 短期憑證:大幅降低憑證洩露風險,簡化撤銷流程
  • mTLS:確保服務間通訊的雙向驗證和加密
  • 服務身份:使用 SPIFFE/SPIRE 建立可靠的工作負載身份
  • 自動化管理:透過 Cert-Manager 和 Vault 實現憑證生命週期自動化

成功實施零信任憑證策略需要周詳的規劃、適當的工具選擇,以及持續的優化和監控。建議從試點專案開始,逐步擴展至整個組織,確保平穩過渡並最大化安全效益。

參考資料

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy