使用bash,curl访问Azure blob存储

时间:2013-11-20 17:51:11

标签: bash azure curl openssl

我正在尝试使用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

5 个答案:

答案 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中编写了一个简单的程序,它执行以下操作:

  1. 从命令行获取base64编码的密钥并将其解码为二进制。
  2. 从标准输入读取要签名的字符串。
  3. 使用libcrypto HMAC()例程生成签名。
  4. base64对签名进行编码并将结果打印到标准输出。
  5. 然后我通过调用我的程序替换了脚本中的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