【Azure Developer - 密鑰保管庫 】使用 Python Azure SDK 實現(xiàn)從 Azure Key Vault Certificate 中下載證書(PEM文件)

問題描述

Azure Key Vault中集歇,我們可以從Azure門戶中下載證書PEM文件到本地。 可以通過OpenSSLPFX文件轉換到PEM文件。然后用TXT方式查看內容,操作步驟如下圖:

image

OpenSSL轉換命令為:

openssl pkcs12 -in "C:\Users\Downloads\mykeyvault01-cscert01-20220316.pfx" -nokeys -out "C:\tool\xd12.pem"

當然前方,Azure也提供了通過PowerShell或CLI命令來下載PEM文件狈醉,操作為:

**az keyvault certificate download** --vault-name vault -n cert-name -f cert.pem

(Source : https://docs.microsoft.com/en-us/cli/azure/keyvault/certificate?view=azure-cli-latest#az-keyvault-certificate-download)
那么,如何可以通過Python SDK的代碼獲取到PEM文件呢惠险?

問題解答

查看 Python SDK Certificate中公布出來的接口舔糖,并沒有 Export, Download 的方法莺匠。** Python Azure Key Vault SDK 中并沒有可以直接下載PEM文件的方法金吗。**
Azure SDK For Python KeyVault -- CertificateClient Class : https://docs.microsoft.com/en-us/python/api/azure-keyvault-certificates/azure.keyvault.certificates.aio.certificateclient?view=azure-python#methods
所以使用原始的SDK Methods方法不可行。

尋找解決方案

通過對CLI (az keyvault certificate download)指令的研究趣竣,發(fā)現(xiàn)CLI使用的是python代碼執(zhí)行的Get Certificates 操作摇庙,實質上是調用的Key Vault的**REST API: **
**Get Certificate: **https://docs.microsoft.com/en-us/rest/api/keyvault/certificates/get-certificate/get-certificate#getcertificate

image

DEBUG az 指令:

az keyvault certificate download --vault-name mykeyvault01 -n cscert01 -f cert2.pem  --debug
C:\Users>az keyvault certificate download --vault-name mykeyvault01 -n cscert01 -f cert2.pem  --debug
cli.knack.cli: Command arguments: ['keyvault', 'certificate', 'download', '--vault-name', 'mykeyvault01', '-n', 'cscert01', '-f', 'cert2.pem', '--debug']
cli.knack.cli: __init__ debug log:
Enable color in terminal.
Init colorama.
cli.knack.cli: Event: Cli.PreExecute []
cli.knack.cli: Event: CommandParser.OnGlobalArgumentsCreate [<function CLILogging.on_global_arguments at 0x033452F8>, <function OutputProducer.on_global_arguments at 0x034F0190>, <function CLIQuery.on_global_arguments at 0x03607D60>]
cli.knack.cli: Event: CommandInvoker.OnPreCommandTableCreate []
cli.azure.cli.core: Modules found from index for 'keyvault': ['azure.cli.command_modules.keyvault']
cli.azure.cli.core: Loading command modules:
cli.azure.cli.core: Name                  Load Time    Groups  Commands
cli.azure.cli.core: keyvault 0.038        19       117 cli.azure.cli.core: Total (1)                 0.038        19       117 cli.azure.cli.core: These extensions are not installed and will be skipped: ['azext_ai_examples', 'azext_next']
cli.azure.cli.core: Loading extensions:
cli.azure.cli.core: Name                  Load Time    Groups  Commands  Directory
cli.azure.cli.core: Total (0)                 0.000         0         0 cli.azure.cli.core: Loaded 19 groups, 117 commands.
cli.azure.cli.core: Found a match in the command table.
cli.azure.cli.core: Raw command  : keyvault certificate download
cli.azure.cli.core: Command table: keyvault certificate download
cli.knack.cli: Event: CommandInvoker.OnPreCommandTableTruncate [<function AzCliLogging.init_command_file_logging at 0x039701D8>]
cli.azure.cli.core.azlogging: metadata file logging enabled - writing logs to 'C:\Users\.azure\commands\2022-03-16.14-46-58.keyvault_certificate_download.21860.log'.
az_command_data_logger: command args: keyvault certificate download --vault-name {} -n {} -f {} --debug
cli.knack.cli: Event: CommandInvoker.OnPreArgumentLoad [<function register_global_subscription_argument.<locals>.add_subscription_parameter at 0x039B6268>, <function register_global_query_examples_argument.<locals>.register_query_examples at 0x039D8928>]
cli.knack.cli: Event: CommandInvoker.OnPostArgumentLoad []
cli.knack.cli: Event: CommandInvoker.OnPostCommandTableCreate [<function register_ids_argument.<locals>.add_ids_arguments at 0x039D8970>, <function register_cache_arguments.<locals>.add_cache_arguments at 0x039D8A00>]
cli.knack.cli: Event: CommandInvoker.OnCommandTableLoaded []
cli.knack.cli: Event: CommandInvoker.OnPreParseArgs []
cli.knack.cli: Event: CommandInvoker.OnPostParseArgs [<function OutputProducer.handle_output_argument at 0x034F01D8>, <function CLIQuery.handle_query_parameter at 0x03607DA8>, <function register_global_query_examples_argument.<locals>.handle_example_parameter at 0x039D88E0>, <function register_ids_argument.<locals>.parse_ids_arguments at 0x039D89B8>]
msrest.universal_http.requests: Configuring retry: max_retries=4, backoff_factor=0.8, max_backoff=90 msrest.service_client: Accept header absent and forced to application/json
msrest.universal_http: Configuring redirects: allow=True, max=30 msrest.universal_http: Configuring request: timeout=100, verify=True, cert=None
msrest.universal_http: Configuring proxies: ''
msrest.universal_http: Evaluate proxies against ENV settings: True urllib3.connectionpool: Starting new HTTPS connection (1): mykeyvault01.vault.azure.cn:443 urllib3.connectionpool: https://mykeyvault01.vault.azure.cn:443 "GET /certificates/cscert01/?api-version=7.0 HTTP/1.1" 401 97 cli.azure.cli.core._profile: Profile.get_raw_token invoked with resource='https://vault.azure.cn', subscription=None, tenant=None
cli.azure.cli.core.util: attempting to read file C:\Users\.azure\accessTokens.json as utf-8-sig
adal-python: 3f4f9351-cdc1-4891-b125-1f02ac02741b - Authority:Performing instance discovery: ...
adal-python: 3f4f9351-cdc1-4891-b125-1f02ac02741b - Authority:Performing static instance discovery
adal-python: 3f4f9351-cdc1-4891-b125-1f02ac02741b - Authority:Authority validated via static instance discovery
adal-python: 3f4f9351-cdc1-4891-b125-1f02ac02741b - TokenRequest:Getting token from cache with refresh if necessary.
adal-python: 3f4f9351-cdc1-4891-b125-1f02ac02741b - CacheDriver:finding with query keys: {'_clientId': '...', 'userId': '...'}
adal-python: 3f4f9351-cdc1-4891-b125-1f02ac02741b - CacheDriver:Looking for potential cache entries: {'_clientId': '...', 'userId': '...'}
adal-python: 3f4f9351-cdc1-4891-b125-1f02ac02741b - CacheDriver:Found 9 potential entries.
adal-python: 3f4f9351-cdc1-4891-b125-1f02ac02741b - CacheDriver:Resource specific token found.
adal-python: 3f4f9351-cdc1-4891-b125-1f02ac02741b - CacheDriver:Returning token from cache lookup, AccessTokenId: b'wR5KoJYE=', RefreshTokenId: b'5VNpWgDCg4ydvuf2PeWxGaph/r7KMelGLXVY+jLV89s='
urllib3.connectionpool: https://mykeyvault01.vault.azure.cn:443 "GET /certificates/cscert01/?api-version=7.0 HTTP/1.1" 200 2114 cli.knack.cli: Event: CommandInvoker.OnTransformResult [<function _resource_group_transform at 0x039A5C88>, <function _x509_from_base64_to_hex_transform at 0x039A5CD0>]
cli.knack.cli: Event: CommandInvoker.OnFilterResult []
cli.knack.cli: Event: Cli.SuccessfulExecute []
cli.knack.cli: Event: Cli.PostExecute [<function AzCliLogging.deinit_cmd_metadata_logging at 0x039702F8>]
az_command_data_logger: exit code: 0 cli.__main__: Command ran in 3.206 seconds (init: 0.394, invoke: 2.812)
telemetry.save: Save telemetry record of length 3005 in cache
telemetry.check: Negative: The C:\Users\.azure\telemetry.txt was modified at 2022-03-16 14:43:00.945931, which in less than 600.000000 s

如以上黃色高亮內容, download指令調用了 "GET /certificates/cscert01/?api-version=7.0 HTTP/1.1" 200 2114遥缕,且返回的HTTP Code為200 成功卫袒。所以當我們單獨對get certificates接口請求時,在返回結果中单匣,發(fā)現(xiàn)cer屬性值就是證書PEM格式內容夕凝。通過Postman發(fā)送請求并驗證結果:

image

那么,通過Python Azure SDK的 certificate_client.get_certificate方法户秤,獲取到certificate對象后码秉,其中包含的cer值,是否也是PEM的內容呢鸡号?

我們通過下面的代碼來進行驗證:

from azure.identity import DefaultAzureCredential 
from azure.keyvault.certificates import CertificateClient 
import ssl

credential = DefaultAzureCredential()

certificate_client = CertificateClient(vault_url=https://yourkeyvaultname.vault.azure.cn/, credential=credential)

certificate = certificate_client.get_certificate("your certificate name") print(certificate.name) print(certificate.properties.version) print(certificate.policy.issuer_name) print(str(certificate.cer)) # Convert the certificate to PEM format 
cert_PEM = ssl.DER_cert_to_PEM_cert(certificate.cer); print("Certificate in PEM format:"); print(cert_PEM);

是的转砖,在certificate對象中,cer就是我們證書的內容鲸伴,但是由于格式為DER府蔗,所以使用了SSL包中的 DER_cert_to_PEM_cert 方法完成轉換,最終得到PEM文件內容。


image

在 python代碼中獲取到PEM內容后,剩下的部分就是把內容輸出到 .pem 文件即可礁遣。

##接上一段代碼
 filename = 'mypem1.pem'
# Open the file in append mode and append the new content in file_object
with open(filename, 'a') as file_object:
    file_object.write(cert_PEM) print("output the PEM file End!")

注意:在創(chuàng)建 certificate_client對象時,需要使用credential薛匪,而以上代碼使用的是默認的DefaultAzureCredential(),在執(zhí)行代碼的本機中,已經(jīng)配置了如下環(huán)境變量:

  • AZURE_TENANT_ID
  • AZURE_CLIENT_ID
  • AZURE_CLIENT_SECRET

使用 ClientSecretCredential 認證方式后,代碼修改如下:

import os 
from azure.keyvault.certificates import CertificateClient 
import ssl 
from azure.identity import ClientSecretCredential 
from msrestazure.azure_cloud import AZURE_CHINA_CLOUD 

print('AZURE_TENANT_ID:' +os.environ["AZURE_TENANT_ID"]) 
print('AZURE_CLIENT_ID:' +os.environ["AZURE_CLIENT_ID"]) 
print('AZURE_CLIENT_SECRET:' +os.environ["AZURE_CLIENT_SECRET"])

 credential = ClientSecretCredential (client_id=os.environ["AZURE_CLIENT_ID"],client_secret=os.environ["AZURE_CLIENT_SECRET"],tenant_id=os.environ["AZURE_TENANT_ID"],cloud_environment=AZURE_CHINA_CLOUD,china=True) 
certificate_client = CertificateClient(vault_url="https://yourkeyvault.vault.azure.cn/", credential=credential)

certificate = certificate_client.get_certificate("your certificate name") print(certificate.name) print(certificate.properties.version) print(certificate.policy.issuer_name) print(str(certificate.cer)) # Convert the certificate to PEM format 
cert_PEM = ssl.DER_cert_to_PEM_cert(certificate.cer); print("Certificate in PEM format:"); print(cert_PEM);

filename = 'mypem2.pem'
# Open the file in append mode and append the new content in file_object
with open(filename, 'a') as file_object:
    file_object.write(cert_PEM) print("output the PEM file End!")

參考文檔

Retrieve a Certificate:https://docs.microsoft.com/en-us/python/api/overview/azure/keyvault-certificates-readme?view=azure-python#retrieve-a-certificate
Der_cert_to_pem_cert Function Of Ssl Module In Python: https://pythontic.com/ssl/ssl-module/der_cert_to_pem_cert
A certificate bundle consists of a certificate (X509) plus its attributes: https://docs.microsoft.com/en-us/rest/api/keyvault/certificates/get-certificate/get-certificate#certificatebundle

當在復雜的環(huán)境中面臨問題狂男,格物之道需:濁而靜之徐清综看,安以動之徐生品腹。 云中,恰是如此!

分類: 【Azure Developer】

標簽: Azure Developer, Azure Key Vault, 下載證書PEM文件, az keyvault certificate download, certificate_client.get_certificate, ClientSecretCredential

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末红碑,一起剝皮案震驚了整個濱河市舞吭,隨后出現(xiàn)的幾起案子泡垃,更是在濱河造成了極大的恐慌,老刑警劉巖羡鸥,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蔑穴,死亡現(xiàn)場離奇詭異,居然都是意外死亡惧浴,警方通過查閱死者的電腦和手機存和,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來衷旅,“玉大人捐腿,你說我怎么就攤上這事∈炼ィ” “怎么了茄袖?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長嘁锯。 經(jīng)常有香客問我宪祥,道長,這世上最難降的妖魔是什么家乘? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任蝗羊,我火速辦了婚禮,結果婚禮上仁锯,老公的妹妹穿的比我還像新娘肘交。我一直安慰自己,他們只是感情好扑馁,可當我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布涯呻。 她就那樣靜靜地躺著,像睡著了一般腻要。 火紅的嫁衣襯著肌膚如雪复罐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天雄家,我揣著相機與錄音效诅,去河邊找鬼。 笑死趟济,一個胖子當著我的面吹牛乱投,可吹牛的內容都是我干的。 我是一名探鬼主播顷编,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼戚炫,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了媳纬?” 一聲冷哼從身側響起双肤,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤施掏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后茅糜,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體七芭,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年蔑赘,在試婚紗的時候發(fā)現(xiàn)自己被綠了狸驳。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡缩赛,死狀恐怖锌历,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情峦筒,我是刑警寧澤究西,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站物喷,受9級特大地震影響卤材,放射性物質發(fā)生泄漏。R本人自食惡果不足惜峦失,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一扇丛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧尉辑,春花似錦帆精、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至购啄,卻和暖如春襟企,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背狮含。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工顽悼, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人几迄。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓蔚龙,卻偏偏與公主長得像,于是被迫代替她去往敵國和親映胁。 傳聞我的和親對象是個殘疾皇子木羹,可洞房花燭夜當晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內容