【问题标题】:Accessing Azure blob storage using bash, curl使用 bash、curl 访问 Azure blob 存储
【发布时间】: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

【问题讨论】:

    标签: bash azure curl openssl


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

    1. 从命令行获取 base64 编码的密钥并将其解码为二进制。
    2. 从标准输入读取字符串以进行签名。
    3. 使用 libcrypto HMAC() 例程生成签名。
    4. 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。有没有办法解决这个问题?仍然遇到同样的错误
      猜你喜欢
      • 2013-01-28
      • 1970-01-01
      • 2012-03-01
      • 2020-06-03
      • 2021-12-18
      • 2021-11-19
      • 1970-01-01
      • 2019-10-13
      • 2012-09-30
      相关资源
      最近更新 更多