我正在尝试使用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
答案 0 :(得分:12)
我能够让它运转起来。
这段代码有两个问题,第一个,就像帕特里克帕克指出的那样,用echo -n
取代了printf
。第二个是用openssl上的sed
选项替换-binary
魔法。
比较原文:
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编码版本,而不是原始值。
答案 1 :(得分:1)
使用Fiddler(或您平台上的同等产品)拦截对Windows Azure存储的调用。如果失败,这将显示存储服务用于验证呼叫的字符串,您可以将其与您使用的字符串进行比较。
答案 2 :(得分:0)
查看REST API文档和上面的代码,我认为构建canonicalized_resource
字符串的方式存在问题。您错过了该字符串中的查询参数。您的canonicalized_resource
字符串应为:
canonicalized_resource="/${storage_account}/${container_name}\ncomp:list\nrestype:container"
答案 3 :(得分:0)
看起来openssl dgst不会为您生成适当的HMAC。 我在C中编写了一个简单的程序,它执行以下操作:
然后我通过调用我的程序替换了脚本中的openssl dgst管道,它就可以了。
请注意,您从Azure获得的输出是XML包装和base-64编码的,因此您需要为它提供某种解析/转换代码。
答案 4 :(得分:0)
使用printf而不是echo(它适用于我)
例如:
SIGNATURE = printf "$string_to_sign" | openssl dgst -sha256 -mac HMAC -macopt hexkey:$HEXKEY -binary | base64 -w0