<矩形寬度=“1200”高度=“340”rx=“12”填滿=“url(#bg-6430)”/>
<矩形x =“60”y =“50”寬度=“4”高度=“60”rx =“2”填滿=“#fbbf24”/>
<矩形x =“80”y =“50”寬度=“121”高度=“28”rx =“14”填滿=“#fbbf24”不透明度=“0.15”/>
1.有 Vault 的 Spring Boot
Spring Cloud Vault
Spring Cloud Vault 將 Vault 作為 Spring Boot 中的 PropertySource 整合 - Vault 中的機密會自動綁定到應用程式屬性。
<依賴關係>
org.springframework.cloud
spring-cloud-starter-vault-config
<依賴關係>
org.springframework.vault
spring-vault-core
配置
# application.yml
春天:
雲:
vault:
uri:https://vault.company.com:8200
身份驗證:KUBERNETES
庫伯內特:
角色:網頁應用程式
kubernetes 路徑:auth/kubernetes
服務帳戶令牌檔案:/var/run/secrets/kubernetes.io/serviceaccount/token
千伏:
啟用:真
後端:秘密
預設上下文:生產/webapp
設定檔分隔符號:/
資料庫:
啟用:真
角色:webapp-db
後端:資料庫
配置:
生命週期:
啟用:真
最短更新時間:10秒
過期閾值:1m
AppRole 驗證
彈簧:
雲:
vault:
uri:https://vault.company.com:8200
認證:APPROLE
應用程式角色:
角色 ID:${VAULT_ROLE_ID}
秘密 ID:${VAULT_SECRET_ID}
應用程式角色路徑:auth/approle
在程式碼中使用 Secret
// Vault 和 @Value 綁定的秘密
@服務
公共類別資料庫服務{
@Value("${db.用戶名}")
私有字串 dbUsername;
@Value("${db.password}")
私有字串 dbPassword;@Value("${api.key}")
私有字串 apiKey;
}
// Hoặc dùng @ConfigurationProperties
@配置
@ConfigurationProperties(前綴=“db”)
公共類別資料庫配置{
私有字符串主機;
私有 int 連接埠;
私有字串使用者名稱;
私有字符串密碼;
// 取得器、設定器
}
動態資料庫憑證
@Configuration
公共類別 VaultDatabaseConfig {
@豆子
公共資料來源資料來源(
SecretLeaseContainer 租借貨櫃,
@Value("${spring.datasource.url}") 字串 url) {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(url);
// Lắng nghe 秘密輪換
LeaseContainer.addLeaseListener(事件 -> {
if (event.getSource().getPath().equals("database/creds/webapp-db")) {
if (SecretLeaseExpiredEvent 的事件實例 ||
SecretLeaseCreatedEvent 事件實例) {
Map Secrets = event.getSource().getSecrets();
dataSource.setUsername((String)secrets.get("使用者名稱"));
dataSource.setPassword((String) Secrets.get("密碼"));
// 軟驅逐連接
dataSource.getHikariPoolMXBean()
.softEvictConnections();
}
}
});
返回資料來源;
}
}
Java 傳輸加密
@Service
公共類加密服務{
私有最終 VaultTransitOperations 傳輸;
公共 EncryptionService(VaultTemplateVaultTemplate) {
this.transit =VaultTemplate.opsForTransit();
}
公共字串加密(字串明文){
返回transit.encrypt(“my-app-key”, plaintext);
}
公共字串解密(字串密文){
return transit.decrypt("my-app-key", ciphertext);
}
// 批次加密
public List encryptBatch(List plaintexts) {
List batch = plaintexts.stream()
.map(明文::of)
.collect(Collectors.toList());
返回transit.encrypt(“my-app-key”,batch);
}
}
</code></pre>
<h2 id="2-nodejs-vault"><strong>2. Node.js 與 Vault</strong></h2>
<h3 id="node-vault-client"><strong>node-vault 用戶端</strong></h3>
<pre><code class="language-javascript">// npm install node-vault
constVault = require('node-vault')({
api版本: 'v1',
端點:process.env.VAULT_ADDR || 'https://vault.company.com:8200',
});
// 透過 AppRole 登入
非同步函數登入() {
const 結果 = 等待Vault.approleLogin({
role_id:process.env.VAULT_ROLE_ID,
Secret_id:process.env.VAULT_SECRET_ID,
});
vault.token = result.auth.client_token;
返回結果;
}
// Đọc KV 秘密
非同步函數 getSecret(path) {
const 結果 = 等待Vault.read(`secret/data/${path}`);
返回結果.數據.數據;
}// Sinh 資料庫憑證
非同步函數 getDatabaseCreds(角色) {
const 結果 = 等待Vault.read(`database/creds/${role}`);
返回{
使用者名稱:結果.資料.使用者名,
密碼:結果.資料.密碼,
租賃Id:結果.lease_id,
租賃持續時間:結果.lease_duration,
};
}
// 加密傳輸
非同步函數加密(明文){
const 結果=等待vault.write('transit/encrypt/my-key', {
明文: Buffer.from(plaintext).toString('base64'),
});
返回結果.數據.密文;
}
// 主要
(異步()=> {
等待登入();
const dbConfig =等待 getSecret('生產/db');
console.log(`Connecting to ${dbConfig.host}:${dbConfig.port}`);
})();
</code></pre>
<h3 id="kubernetes-auth-nodejs"><strong>來自 Node.js 的 Kubernetes 驗證</strong></h3>
<pre><code class="language-javascript">const fs = require('fs');
非同步函數 k8sLogin() {
const jwt = fs.readFileSync(
'/var/run/secrets/kubernetes.io/serviceaccount/token',
'utf8'
);
const 結果 = 等待Vault.kubernetesLogin({
角色:'網頁應用程式',
傑威特:傑威特,
});
vault.token = result.auth.client_token;
返回結果;
}
</code></pre>
<h2 id="3-python-hvac"><strong>3. Python 與暖通空調</strong></h2>
<pre><code class="language-python"># pip install hvac
進口暖通空調
客戶端 = hvac.Client(url='https://vault.company.com:8200')
# 應用程式角色登入
client.auth.approle.login(
role_id=os.environ['VAULT_ROLE_ID'],
Secret_id=os.environ['VAULT_SECRET_ID'],
)
# KV v2
秘密 = client.secrets.kv.v2.read_secret_version(
路徑='生產/資料庫',
mount_point='秘密',
)
db_password = 秘密['資料']['資料']['密碼']
# 資料庫動態憑證
信用 = client.secrets.database.generate_credentials(
name='應用程式角色',
mount_point='資料庫',
)
print(f"使用者名稱: {creds['data']['使用者名稱']}")
print(f"密碼: {creds['data']['password']}")
# 傳輸加密
結果 = client.secrets.transit.encrypt_data(
name='我的密鑰',
plaintext=base64.b64encode(b'敏感資料').decode(),
)
密文 = 結果['數據']['密文']
</code></pre>
<h2 id="4-application-patterns"><strong>4.應用模式</strong></h2>
<表>
<標題>
<tr><th>模式</th><th>運作方式</th><th>優點</th><th>缺點</th></tr>
</標題>
<正文>
<tr><td><strong>直接API</strong></td><td>應用直接呼叫Vault API</td><td>完全控制</td><td>應用程式必須了解Vault,處理續訂</td></tr>
<tr><td><strong>Agent Sidecar</strong></td><td>Vault Agent 渲染文件</td><td>應用讀取文件,未知 Vault</td><td>Sidecar 開銷</td></tr>
<tr><td><strong>環境注入</strong></td><td>秘密注入環境變數</td><td>簡單,通用</td><td>靜態,無自動旋轉</td></tr>
<tr><td><strong>CSI 卷</strong></td><td>秘密掛載到卷</td><td>原生 K8s,無 sidecar</td><td>限制動態秘密</td></tr>
<tr><td><strong>VSO</strong></td><td>Operator 同步到 K8s Secret</td><td>推薦,自動刷新</td><td>K8s etcd 中的 Secret</td></tr>
</tbody>
</表>
<h2 id="5-secret-zero-problem"><strong>5。秘密零問題</strong></h2>
<p>「秘密零」是個悖論:要從保險庫取得秘密,需要第一個秘密進行身分驗證。解決方案:</p><ul>
<li><p><strong>平台身分</strong>:Kubernetes SA、AWS IAM 角色、Azure 託管身分 → 無密碼</p></li>
<li><p><strong>回應包裝</strong>:Orchestrator 產生包裝的 SecretID,分配給應用程式。應用程式解開一次</p></li>
<li><p><strong>CI/CD OIDC</strong>:GitHub Actions/GitLab CI OIDC 令牌 → JWT 驗證,無靜態機密</p></li>
</ul>
<h2 id="6-tong-ket"><strong>6。摘要</strong></h2>
<ul>
<li><p><strong>Spring Cloud Vault</strong> — 最深度整合、自動 PropertySource 綁定、動態憑證輪替</p></li>
<li><p><strong>Node.js (node-vault)</strong> — 靈活的客戶端程式庫、非同步/等待 API</p></li>
<li><p><strong>Python (hvac)</strong> — 用於腳本編寫和應用程式的綜合客戶端</p></li>
<li><p><strong>平台身分</strong>-最有效地解決零秘密問題</p></li>
</ul>
<p>下一篇文章將了解如何將 Vault 與 Terraform、Ansible 和 CI/CD 管道整合 - 基礎設施即程式碼與秘密管理結合。 </p>