使用 bash、curl 访问 Azure blob 存储
Posted
技术标签:
【中文标题】使用 bash、curl 访问 Azure blob 存储【英文标题】:Accessing Azure blob storage using bash, curl 【发布时间】:2013-12-04 21:03:44 【问题描述】:我正在尝试使用 REST API 从 bash 脚本中使用 Azure blob 存储服务。我知道可以使用各种其他工具或语言来完成此操作,但我想将其作为 bash 脚本来完成。
以下脚本尝试列出 Azure 存储容器中的 blob。
此脚本会导致身份验证错误。根据 REST API (reference) 文档,签名字符串和标头看起来是正确的。我怀疑问题可能在于处理签名过程的各个部分。
是否有人成功使用 bash 和 curl 访问 Azure 或其他提供商等云存储资源?
#!/bin/bash
# List the blobs in an Azure storage container.
echo "usage: $0##*/ <storage-account-name> <container-name> <access-key>"
storage_account="$1"
container_name="$2"
access_key="$3"
blob_store_url="blob.core.windows.net"
authorization="SharedKey"
request_method="GET"
request_date=$(TZ=GMT date "+%a, %d %h %Y %H:%M:%S %Z")
storage_service_version="2011-08-18"
# HTTP Request headers
x_ms_date_h="x-ms-date:$request_date"
x_ms_version_h="x-ms-version:$storage_service_version"
# Build the signature string
canonicalized_headers="$x_ms_date_h\n$x_ms_version_h"
canonicalized_resource="/$storage_account/$container_name"
string_to_sign="$request_method\n\n\n\n\n\n\n\n\n\n\n\n$canonicalized_headers\n$canonicalized_resource\ncomp:list\nrestype:container"
# Decode the Base64 encoded access key, convert to Hex.
decoded_hex_key="$(echo -n $access_key | base64 -d -w0 | xxd -p -c256)"
# Create the HMAC signature for the Authorization header
signature=$(echo -n "$string_to_sign" | openssl dgst -sha256 -mac HMAC -macopt "hexkey:$decoded_hex_key" | sed 's/^.*= //' | base64 -w0)
authorization_header="Authorization: $authorization $storage_account:$signature"
curl \
-H "$x_ms_date_h" \
-H "$x_ms_version_h" \
-H "$authorization_header" \
"https://$storage_account.$blob_store_url/$container_name?restype=container&comp=list"
更新 - 存储服务错误和脚本生成的相应签名字符串。
以下是存储服务针对 AuthenticationFailed
错误返回的内容。
<?xml version="1.0" encoding="utf-8"?>
<Error>
<Code>AuthenticationFailed</Code>
<Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:27e6337e-52f3-4e85-98c7-2fabaacd9ebc
Time:2013-11-21T22:10:11.7029042Z</Message>
<AuthenticationErrorDetail>The MAC signature found in the HTTP request
'OGYxYjk1MTFkYmNkMCgzN2YzODQwNzcyNiIyYTQxZDg0OWFjNGJiZDlmNWY5YzM1ZWQzMWViMGFjYTAyZDY4NAo='
is not the same as any computed signature. Server used following string to sign:
'GET
x-ms-date:Thu, 21 Nov 2013 22:10:11 GMT
x-ms-version:2011-08-18
/storage_account_name/storage_container
comp:list
restype:container'
</AuthenticationErrorDetail>
</Error>
接下来是脚本生成的string_to_sign
。
GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Thu, 21 Nov 2013 22:10:11 GMT\nx-ms-version:2011-08-18\n/storage_account_name/storage_container\ncomp:list\nrestype:container
【问题讨论】:
【参考方案1】:使用Fiddler(或您平台上的等效项)拦截对 Windows Azure 存储的调用。失败时,这将向您显示存储服务用于验证调用的字符串,您可以将其与您使用的字符串进行比较。
【讨论】:
感谢您的出色建议。由于我正在运行的环境,这样做很困难。如果我的调试仍然没有结果,我会坚持这个建议。【参考方案2】:查看 REST API 文档和您上面的代码,我认为您构建 canonicalized_resource
字符串的方式存在问题。您缺少该字符串中的查询参数。你的canonicalized_resource
字符串应该是:
canonicalized_resource="/$storage_account/$container_name\ncomp:list\nrestype:container"
【讨论】:
在分配string_to_sign
变量期间正在附加查询参数。我运行脚本时从存储服务返回的身份验证错误包括 Azure 用于创建其授权签名的字符串。当我打印 string_to_sign
变量时,它看起来与 Azure 在错误中返回的字符串完全一样。
对不起,我的错!之前没有看到那个代码。您能否分享您创建的string_to_sign
的输出和Windows Azure 返回的输出。我很确定那里一定有一些小问题。
另一件事是你如何解码你的帐户密钥。来自 C# 世界,我们使用Convert.FromBase64String()
来获取以字节为单位的帐户密钥。这可能是身份验证失败的另一个原因。
我将string_to_sign
的输出添加到原始问题中。我还包含了存储服务作为响应生成的错误 XML。
我最怀疑解码帐户密钥、创建签名、然后重新编码的过程的各个部分。我想我可能会使用另一种语言(可能是 Java)编写一个简单的签名生成器,然后并排运行签名生成以进行比较。【参考方案3】:
看起来 openssl dgst 没有为您生成正确的 HMAC。 我用 C 编写了一个简单的程序,它执行以下操作:
-
从命令行获取 base64 编码的密钥并将其解码为二进制。
从标准输入读取字符串以进行签名。
使用 libcrypto HMAC() 例程生成签名。
base64 编码签名并将结果打印到标准输出。
然后,我将脚本中的 openssl dgst 管道替换为对我的程序的调用,它成功了。
请注意,您从 Azure 获得的输出是 XML 包装和 base-64 编码的,因此您需要为其提供某种解析/转换代码。
【讨论】:
请注意 - 我使用 wazproxy 作为参考,您可能想查看一下。在分析任何流量/协议时,Wireshark 也是您最好的朋友。【参考方案4】:使用 printf 代替 echo(它适用于我)
例如:
签名=printf "$string_to_sign" | openssl dgst -sha256 -mac HMAC -macopt hexkey:$HEXKEY -binary | base64 -w0
【讨论】:
【参考方案5】:我能够让它工作。
这段代码有两个问题,第一,正如 Patrick Park 所指出的,将echo -n
替换为printf
。第二个是用 openssl 上的 -binary
选项替换 sed
魔法。
对比原文:
signature=$(echo -n "$string_to_sign" | openssl dgst -sha256 -mac HMAC -macopt "hexkey:$decoded_hex_key" -binary | sed 's/^.*= //' | base64 -w0)
与固定:
signature=$(printf "$string_to_sign" | openssl dgst -sha256 -mac HMAC -macopt "hexkey:$decoded_hex_key" -binary | base64 -w0)
需要回显更改,因为echo -n
不会将\n
转换为实际的换行符。
-binary
更改是必要的,因为即使您剥离了坏部分,openssl 仍然以 ascii-encoded-hex 格式输出签名,而不是二进制格式。所以在传递给base64
之后,结果是十六进制表示的 b64 编码版本,而不是原始值。
【讨论】:
也许你可以在this 上帮助我? 我对此进行了一些修改并添加了对下载的支持。我贴在这里:gist.github.com/jrwren/ff46f4ba177f042ccdc48c080c198f60 decoded_hex_key="$(echo -n $access_key | base64 -d -w0 | xxd -p -c256)" 这个命令给了我 base64: invalid input。有没有办法解决这个问题?仍然遇到同样的错误以上是关于使用 bash、curl 访问 Azure blob 存储的主要内容,如果未能解决你的问题,请参考以下文章