Secrets Management(機密管理)

是什麼?

Secrets Management 是管理應用程式中敏感資訊(API Key、資料庫密碼、加密金鑰、Certificate)的完整生命週期:產生、儲存、存取、輪替、撤銷。

ℹ️什麼算是 Secret?

任何洩漏後會造成安全風險的資訊:API Key、Database Connection String、JWT Signing Key、OAuth Client Secret、TLS Certificate Private Key、Encryption Key。

核心觀念

儲存方式比較

| 方式 | 安全性 | 適用場景 | |------|--------|----------| | 硬編碼在程式碼中 | 極危險 | 永遠不要這樣做 | | .env 檔案(不 commit) | 低 | 本地開發 | | 環境變數 | 中 | 容器化部署 | | Cloud Secret Manager | 高 | AWS/GCP/Azure 雲端服務 | | HashiCorp Vault | 最高 | 企業級集中管理 |

Key Rotation 策略

零信任原則

常見誤區

⚠️常犯錯誤

  • .env 檔案 commit 到 Git(即使之後刪除,Git history 中仍然存在)
  • 在 log 中印出 secret(即使是 debug 模式)
  • 所有服務共用同一個 API Key(一個洩漏全部完蛋)
  • Secret 從不輪替(洩漏時影響範圍無限擴大)

執行流程

1

產生 Secret

用密碼學安全的隨機數產生器建立 secret

2

安全儲存

存入 Vault 或 Cloud Secret Manager,加密靜態儲存

3

存取控制

透過 IAM Policy 或 ACL 控制誰能讀取

4

注入應用

啟動時從 Vault 取得,注入環境變數或記憶體

5

輪替與撤銷

定期自動輪替,緊急時立即撤銷

流程解讀:Secret 的生命週期從安全產生開始,絕對不能使用可預測的值。儲存時必須加密(encryption at rest),存取時透過嚴格的權限控制。應用程式啟動時從 Vault 動態取得 secret,避免寫死在設定檔中。定期輪替確保即使 secret 洩漏,攻擊視窗也是有限的。

程式碼範例

C# 版本

csharp
// ASP.NET Core — 使用 Azure Key Vault
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
 
var builder = WebApplication.CreateBuilder(args);
 
// 從 Azure Key Vault 載入 secrets
builder.Configuration.AddAzureKeyVault(
    new Uri("https://my-vault.vault.azure.net/"),
    new DefaultAzureCredential()
);
 
// 使用時直接從 Configuration 取得
var dbConnection = builder.Configuration["DatabaseConnection"];
 
// 絕對不要這樣做
// var apiKey = "sk-hardcoded-key-12345"; // 硬編碼
 
// HashiCorp Vault 整合
using VaultSharp;
 
var vaultClient = new VaultClient(new VaultClientSettings(
    "https://vault.mycompany.com",
    new TokenAuthMethodInfo("hvs.token")
));
 
var secret = await vaultClient.V1.Secrets.KeyValue.V2
    .ReadSecretAsync("myapp/database");
var password = secret.Data.Data["password"].ToString();

TypeScript 版本

typescript
import { SecretManagerServiceClient } from "@google-cloud/secret-manager";
 
// Google Cloud Secret Manager
const client = new SecretManagerServiceClient();
 
async function getSecret(secretName: string): Promise<string> {
  const [version] = await client.accessSecretVersion({
    name: `projects/my-project/secrets/${secretName}/versions/latest`,
  });
  return version.payload?.data?.toString() ?? "";
}
 
// 應用啟動時載入所有需要的 secrets
async function loadSecrets() {
  const dbPassword = await getSecret("db-password");
  const apiKey = await getSecret("external-api-key");
 
  return {
    database: { password: dbPassword },
    externalApi: { key: apiKey },
  };
}
 
// .env 只用於本地開發,搭配 .gitignore
// .env 檔案內容:
// DB_PASSWORD=local-dev-password
// API_KEY=test-key-not-real

Python 版本

python
import boto3
import json
from functools import lru_cache
 
# AWS Secrets Manager
def get_secret(secret_name: str) -> dict:
    client = boto3.client("secretsmanager", region_name="ap-northeast-1")
    response = client.get_secret_value(SecretId=secret_name)
    return json.loads(response["SecretString"])
 
# 快取 secret,避免每次請求都呼叫 API
@lru_cache(maxsize=32)
def get_db_credentials() -> dict:
    return get_secret("myapp/database")
 
# HashiCorp Vault
import hvac
 
client = hvac.Client(url="https://vault.mycompany.com",
                     token="hvs.token")
 
# 讀取 KV secret
secret = client.secrets.kv.v2.read_secret_version(
    path="myapp/database"
)
db_password = secret["data"]["data"]["password"]
 
# 動態 Secret — 用完即棄的資料庫憑證
creds = client.secrets.database.generate_credentials(
    name="myapp-readonly"
)
temp_username = creds["data"]["username"]
temp_password = creds["data"]["password"]
# 這組憑證會在 TTL 到期後自動失效

結構圖

Application
request secret
Vault / Secret Manager
check permission
IAM / Access Policy
Audit Log
Key Rotation
periodic update
Encrypted Storage

圖中 Application 向 Vault 請求 secret,Vault 先透過 IAM 檢查權限,通過後從 Encrypted Storage 取出 secret 並回傳,同時在 Audit Log 記錄存取行為。Key Rotation 定期觸發更新 secret,確保即使洩漏也只在有限時間內有效。

面試常見問題

Q: 如果發現 secret 被 commit 到 Git 了,該怎麼處理?

A: 第一步立即撤銷該 secret(不是刪除 commit,因為可能已經被 clone)。第二步產生新的 secret 並部署。第三步用 git filter-branchBFG Repo-Cleaner 從 Git history 中移除。第四步檢查審計日誌確認是否已被未授權存取。

Q: 環境變數比硬編碼好,但仍有什麼風險?

A: 環境變數可能出現在 process listing(/proc/PID/environ)、crash dump、子程序繼承、container inspection(docker inspect)中。更安全的做法是使用 Vault SDK 在記憶體中管理 secret,用完立即清除。

Q: 什麼是 Dynamic Secret?為什麼比 Static Secret 更安全?

A: Dynamic Secret 是 Vault 根據請求動態產生的短期憑證(例如 15 分鐘有效的資料庫帳密)。好處是:每個 client 拿到的憑證不同(可追溯來源)、自動過期(不需手動撤銷)、洩漏影響範圍極小。

理解測驗

🤔 以下哪種 secret 儲存方式最安全?

🤔 Key Rotation 的主要目的是什麼?

🤔 發現 secret 被 commit 到 Git 後,第一步該做什麼?

重點整理

💡一句話記住

Secrets Management = 不硬編碼 + 集中管理 + 定期輪替。 口訣:「密鑰放 Vault,存取要審計,定期要換鎖」

| 概念 | 說明 | |------|------| | Secret | API Key、密碼、金鑰等敏感資訊 | | Vault | 集中管理 secret 的安全儲存服務 | | Key Rotation | 定期自動更換 secret,限制洩漏風險 | | Dynamic Secret | 用完即棄的短期憑證 | | 核心原則 | 最小權限、加密儲存、完整審計 |

你可能也想看

CSRF and CORSDependency Security

按 ← → 鍵切換課程