keytool 是 JDK 自帶的密鑰與證書管理工具,操作 Keystore(密鑰庫)數據庫。它支撐著 HTTPS、JAR 簽名、代碼簽名、單點登錄、雙向 TLS 等核心安全場景。熟練掌握 keytool,是 Java 開發與運維人員的必修課。本文系統梳理核心概念、常用命令、進階操作及生產級最佳實踐。
| 概念 | 說明 | 關鍵點 |
|---|---|---|
| Keystore (密鑰庫) | 存儲私鑰、密鑰對、信任證書的容器 | 默認格式 JKS (Java KeyStore);推薦 PKCS12 (業界標準、跨語言);受密碼保護 |
| Entry 類型 | PrivateKeyEntry:私鑰+證書鏈(用於簽名/解密) TrustedCertEntry:公鑰證書(用於驗證/建立信任) |
每個 Entry 有唯一別名,不區分大小寫 |
| 證書鏈 | 從葉子證書到根 CA 的信任鏈 | 導入 CA 回覆時自動構建;驗證時遞歸校驗至信任錨點 |
| KeyPair (密鑰對) | 非對稱加密的公私鑰 | 算法:RSA (簽名/加密)、EC (高效簽名)、DSA (僅簽名,已淘汰) |
# 查看支持的類型
keytool -list -keystore NONE -storetype PKCS12 -providerpath -provider org.bouncycastle.jce.provider.BouncyCastleProvider
# 推薦:PKCS12 (默認 JDK 9+)
# 優勢:跨平台/語言、支持加密私鑰、標準化、無專有格式鎖定
keytool -genkeypair -alias mykey -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.p12
# 生成 RSA 2048 密鑰對,有效期 365 天,簽名算法 SHA256withRSA
keytool -genkeypair \
-alias server \
-keyalg RSA \
-keysize 2048 \
-sigalg SHA256withRSA \
-dname "CN=api.example.com, OU=IT, O=Example Inc, L=Shanghai, ST=Shanghai, C=CN" \
-validity 365 \
-keystore server.p12 \
-storetype PKCS12 \
-storepass changeit \
-keypass changeit
# 修改私鑰密碼
keytool -keypasswd -alias server -keystore server.p12 -storepass changeit -keypass oldpass -new newpass
# 導出公鑰證書 (供客戶端信任)
keytool -exportcert -alias server -keystore server.p12 -storepass changeit -file server.cer -rfc
# 1. 生成 CSR (Certificate Signing Request)
keytool -certreq \
-alias server \
-keystore server.p12 \
-storepass changeit \
-file server.csr \
-sigalg SHA256withRSA
# 2. 提交 server.csr 給 CA (Let's Encrypt, DigiCert, 內部 CA 等)
# 3. 導入 CA 根證書 (建立信任鏈基座)
keytool -importcert -alias rootca -file rootca.cer -keystore server.p12 -storepass changeit -noprompt
# 4. 導入中間 CA 證書 (如有)
keytool -importcert -alias interca -file interca.cer -keystore server.p12 -storepass changeit -noprompt
# 5. 導入 CA 簽發的服務器證書 (自動匹配私鑰構建鏈)
keytool -importcert -alias server -file server_signed.cer -keystore server.p12 -storepass changeit
# 創建專用信任庫 (分離信任與身份)
keytool -importcert -alias trusted_server -file server.cer -keystore truststore.p12 -storetype PKCS12 -storepass changeit -noprompt
# 批量導入系統 CA (如需信任公網 HTTPS)
keytool -importcert -alias system_ca -cacerts -file /path/to/ca.cer -storepass changeit -noprompt
# 注意:修改 cacerts 需管理員權限,且 JDK 升級會覆蓋,建議維護獨立 truststore
# 列出所有條目摘要
keytool -list -v -keystore server.p12 -storepass changeit
# 檢查證書詳情 (有效期、SAN、指紋)
keytool -printcert -file server.cer
keytool -printcert -jarfile app.jar # 查看 JAR 簽名證書
# 檢查私鑰與證書匹配 (模數一致性)
openssl x509 -noout -modulus -in server.cer | openssl md5
openssl rsa -noout -modulus -in <(keytool -importkeystore -srckeystore server.p12 -destkeystore - -deststoretype PEM -srcalias server -srcstorepass changeit) | openssl md5
# 兩個 MD5 一致則匹配
# PKCS12 轉 PEM (含私鑰+證書鏈)
openssl pkcs12 -in server.p12 -out server.pem -nodes -passin pass:changeit
# PEM 分離私鑰與證書
openssl pkcs12 -in server.p12 -out key.pem -nocerts -nodes -passin pass:changeit
openssl pkcs12 -in server.p12 -out cert.pem -nokeys -passin pass:changeit
# JKS 遷移至 PKCS12
keytool -importkeystore -srckeystore legacy.jks -destkeystore modern.p12 -deststoretype PKCS12
# 簽名
jarsigner -keystore server.p12 -storetype PKCS12 -storepass changeit -keypass changeit -signedjar app-signed.jar app.jar server
# 簽名驗證
jarsigner -verify -verbose -certs app-signed.jar
# 簽名時間戳 (證書過期後簽名仍有效)
jarsigner -tsa https://timestamp.digicert.com -keystore server.p12 ...
# 服務端 (雙向 TLS 需同時設置 trustStore)
-Djavax.net.ssl.keyStore=server.p12
-Djavax.net.ssl.keyStorePassword=changeit
-Djavax.net.ssl.keyStoreType=PKCS12
-Djavax.net.ssl.trustStore=truststore.p12
-Djavax.net.ssl.trustStorePassword=changeit
-Djavax.net.ssl.trustStoreType=PKCS12
# 客戶端 (單向 TLS 僅需 trustStore)
-Djavax.net.ssl.trustStore=truststore.p12
-Djavax.net.ssl.trustStorePassword=changeit
# 調試 SSL 握手
-Djavax.net.debug=ssl:handshake:verbose
keystore (私鑰) 和 truststore (公鑰),最小化攻擊面。-storepass:env (JDK 11+),絕不寫在腳本/配置文件中。-keypass 與 -storepass 設置不同值,增加提權難度。cert-manager (K8s) 或 acme.sh 對接 Let's Encrypt/內部 ACME CA,實現 90 天自動輪換。keytool -list -v 導出審計日誌;Keystore 文件納入加密備份策略。-Dcom.sun.net.ssl.checkRevocation=true)。| 現象 | 可能原因 | 排查命令/動作 |
|---|---|---|
| SSLHandshakeException: PKIX path building failed | 客戶端 truststore 缺少服務端證書鏈中的 CA | keytool -list -keystore truststore 核對 CA 別名;openssl s_client -connect host:443 -showcerts 獲取完整鏈 |
| Private key not found / UnrecoverableKeyException | 別名錯誤、keypass 錯誤、Entry 類型非 PrivateKeyEntry | keytool -list -v 確認別名與 Entry 類型;嘗試 -keypass 指定私鑰密碼 |
| Certificate expired / Not yet valid | 系統時間漂移、證書確實過期 | NTP 同步時間;keytool -printcert 核對有效期;自動化續期 |
| Alias name already exists | 導入證書時別名衝突 | 使用 -alias new_name 或先 -delete -alias old |
Keytool 雖是命令行小工具,却串聯起 Java 安全體系的「信任鏈」核心環節。從開發自簽測試、生產 CA 簽發流程、容器化密鑰注入、到合規審計與應急輪換,每一步都考驗著工程師對 PKI 體系的理解深度。建議將常用操作封裝為腳本/Ansible Playbook/Helm Chart,構建「基礎設施即代碼」的密鑰管理流水線,讓安全不再是部署前的臨時抱佛腳,而是可觀測、可審計、可自愈的系統內生能力。