0

我正在尝试通过 Python 向 Azure 发出请求以列出我拥有的存储服务。

我的基本代码是这样的:

import httplib
conn = httplib.HTTPSConnection('management.core.windows.net')
conn.request('GET', '/[subscription id]/services/storageservices/')
response = conn.getresponse()
print response.status response.reason

显然,因为我没有进行身份验证,所以打印出来403 Forbidden

所以,我按照http://msdn.microsoft.com/en-us/library/windowsazure/gg651127上的说明创建了一个证书,给了我cert.cer. 我将我上传.cer到我的 Azure 帐户并将其复制.cer到我正在使用 Python 的 Linux VM。我将我的代码修改为:

import httplib
cert_file = '/path/to/cert.cer'
conn = httplib.HTTPSConnection('management.core.windows.net', cert_file = cert_file)
conn.request('GET', '/[subscription id]/services/storageservices/')

并得到错误:

ssl.SSLError: [Errno 336265225] _ssl.c:351: error:140B0009:SSL routines:SSL_CTX_use_PrivateKey_file:PEM lib

给人的印象可能是因为我试图使用.cer证书而不是.pem 和 .cer 之间区别(它们是相同的东西,但扩展名不同).pem,我只是将我的 .cer 上的扩展名更改为 .pem 并再次尝试,得到相同的错误。

如何正确地向 Azure 验证自己以访问其 API?这是我如何上传证书的问题,还是我需要对证书做一些事情以使其适合呈现给服务器?在 Windows 上,我似乎可以将其安装.cer到某种证书存储中 - 在 Linux 中是否有一个等效项,我需要在使用它进行身份验证之前从中检索证书?感谢您的帮助 =)

4

2 回答 2

4

这是一些有效的 Python 代码,但正如您所指出的,诀窍是获取正确的 PEM 文件:

import httplib

conn = httplib.HTTPSConnection('management.core.windows.net', cert_file='cert.pem', key_file='key.pem')
conn.request('GET', '/%s/services/storageservices' % subscription_id, headers={'x-ms-version': '2011-02-25'})
print conn.getresponse().read()

我从https://github.com/smarx/waz-cmd获得了我的 PEM 文件,这是我编写的一个基于 Ruby 的命令行工具,用于与服务管理 API 交互。请注意,您需要两个部分( thecert_file和 the key_file)。

您已经拥有证书文件,但我认为您实际上可能需要通过类似opensslPEM 格式的方式将其转换。对于密钥文件,我认为您需要导出在 Windows 机器上创建的证书,然后用于openssl将私钥导出为 PEM 文件。

如今,您可以从 Windows Azure 门户下载文件,而不是创建自己的证书,.publishsettings该门户会生成并为您提供准备就绪的证书。请参阅http://blog.smarx.com/posts/calling-the-windows-azure-service-management-api-with-the-new-publishsettings-file。那里的证书是 PFX 格式的,但正确的openssl魔法应该会给你你需要的两件。我实际上曾经解决过这个问题(用于curl在 Mac 上使用),但我不再手头有确切的命令。:-(我可能会试一试,今晚写一篇关于它的博客文章。

编辑

这是一个完整的 Python 程序,它.publishsettings在命令行上获取一个文件,将密钥和证书转储到当前目录中的单个文件 (cert.pem) 中,然后使用它调用服务管理 API 并打印所有名称您的存储帐户。在运行之前,只需pip install lxml pyopenssl.

import httplib
import argparse
from StringIO import StringIO
from lxml import etree
import base64
from OpenSSL.crypto import *

parser = argparse.ArgumentParser()
parser.add_argument('file', metavar='file', type=str, help='Your .publishsettings file.')
args = parser.parse_args()

tree = etree.parse(args.file)
pp = tree.find('PublishProfile')
cert = load_pkcs12(base64.decodestring(pp.get('ManagementCertificate')))
with open('cert.pem', 'w') as f:
    f.write(dump_certificate(FILETYPE_PEM, cert.get_certificate()))
    f.write(dump_privatekey(FILETYPE_PEM, cert.get_privatekey()))
subscription_id = pp.find('Subscription').get('Id')

conn = httplib.HTTPSConnection('management.core.windows.net', cert_file='cert.pem')
conn.request('GET', '/%s/services/storageservices' % subscription_id, headers={'x-ms-version': '2011-02-25'})
for e in etree.parse(StringIO(conn.getresponse().read())).iterfind('//{http://schemas.microsoft.com/windowsazure}ServiceName'): print e.text
于 2012-08-15T22:31:01.623 回答
2

这就是我如何将在我的问题中创建的证书转换为我可以用来验证我对 Azure 服务管理 API 的请求的格式。Smarx 的答案也有效,实际上我使用了他的技术创建的证书,涉及.publishsettings文件来确定我转换后的证书的外观。

通过打开 Visual Studio 命令提示符并键入以下内容来创建您的证书:

makecert -r -pe -a sha1 -n "CN=My Azure Management Certificate" -ss My -len 2048 -sp   
"Microsoft Enhanced RSA and AES Cryptographic Provider" -sy 24 myazuremanagementcert.cer

按照http://msdn.microsoft.com/en-us/library/windowsazure/gg651127的指示。

certmgr.msc然后,通过在搜索框中键入来打开证书管理器。我在Certificates - Current User/Personal/Certificates.

右键单击证书,转到“所有任务”,然后单击“导出”。出现提示时,确保选择“是,导出私钥”并将文件导出为 .PFX (PKCS#12)。

在这里,我将我的 .PFX 移至 Linux VM。

从这里开始的所有内容都遵循http://blog.scottlowe.org/2005/12/02/certificate-conversion-using-openssl/中列出的步骤

打开终端,输入:

openssl pkcs12 -in pfxfilename.pfx -out tempfile.pem

这将提示您输入用于加密 .pfx 的密码和用于加密 .pem 的新密码。请勿将此密码留空!我做了并且很困惑,因为密钥不仅被解密,而且根本没有包含在新的 .pem 中

将新 .pem 中的密钥和证书分成两个不同的文件,删除除行之外的所有多余----begin/end cert/key----行。

通过键入以下内容来解密密钥:

openssl rsa -in encryptedkey -out decryptedkey

并且,重新组合密钥和证书:

cat decryptedkey certificatefile > finalfile.pem

现在,此证书应正确验证对 Azure 的服务管理请求:

import httplib
sub_id = [subid]
conn = httplib.HTTPSConnection('management.core.windows.net', cert_file = 'finalfile.pem')
conn.request('GET', '/%s/services/storageservices' % sub_id, headers = {'x-ms-versiojn':'2012-03-01'})

response = conn.getresponse()
print reponse.status response.reason
于 2012-08-21T23:31:21.580 回答