2013-11-20 39 views
12

我正在嘗試使用REST API從bash腳本使用Azure blob存儲服務。我知道有可能使用各種其他工具或語言完成此操作,但是我想將其作爲bash腳本來完成。使用bash訪問Azure blob存儲,捲曲

以下腳本嘗試列出Azure存儲容器中的斑點。

此腳本導致身份驗證錯誤。根據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 

回答

10

我能得到它的工作。 這段代碼有兩個錯誤,第一個,正如帕特里克帕克指出的那樣,用printf代替echo -n。第二個是用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編碼版本,而不是原始值。

+0

也許你可以幫我[this](https://stackoverflow.com/questions/41853666/storage-service-api-call)? – Munchkin

+0

我已經修改了這一點,並增加了對下載的支持。我粘貼在這裏:https://gist.github.com/jrwren/ff46f4ba177f042ccdc48c080c198f60 – jrwren

1

使用Fiddler(或您平臺上的同等設備)攔截對Windows Azure存儲的調用。如果失敗,這會顯示Storage Service用來驗證呼叫的字符串,您可以將其與您使用的字符串進行比較。

+0

感謝您的出色建議。由於我運行的環境,這樣做很困難。如果我的調試仍然沒有成果,我會堅持這個建議。 – yozhik

0

看看上面的REST API文檔和您的代碼,我認爲您構建canonicalized_resource字符串的方式存在問題。您錯過了該字符串中的查詢參數。你canonicalized_resource字符串應該是:

canonicalized_resource="/${storage_account}/${container_name}\ncomp:list\nrestype:container" 
+0

查詢參數在string_to_sign變量賦值期間被追加。運行腳本時從存儲服務返回的身份驗證錯誤包括Azure用於創建其授權簽名的字符串。當我打印'string_to_sign'變量時,它看起來就像Azure在錯誤中返回的字符串。 – yozhik

+0

對不起,我的壞!之前沒有看到該代碼。你能分享你創建的'string_to_sign'的輸出和Windows Azure返回的輸出嗎?我很確定那裏肯定有一些小問題。 –

+0

要尋找的另一件事是如何解碼您的帳戶密鑰。來自C#世界,我們通過'Convert.FromBase64String()'獲取以字節爲單位的賬戶密鑰。這可能是驗證失敗的另一個原因。 –

0

它看起來像OpenSSL的DGST不會爲你生成正確的HMAC。 我在C寫一個簡單的程序,執行以下操作:

  1. 從命令行注意到base64編碼密鑰和其解碼成二進制。
  2. 讀取字符串以從標準輸入中籤名。
  3. 使用libcrypto HMAC()例程來生成簽名。
  4. base64編碼簽名並將結果打印到標準輸出。

然後我用你的腳本中的openssl dgst管道替換掉了我的程序的調用,它實現了訣竅。

請注意,您從Azure獲得的輸出是XML包裝和base-64編碼,因此您需要爲其提供某種解析/轉換代碼。

+0

只是一個說明 - 我使用wazproxy作爲我的參考,你可能想看看它。當涉及分析任何流量/協議時,Wireshark也是您最好的朋友。 – KiteRunner

0

用printf取代echo(我的作品)

例如:

SIGNATURE = printf "$string_to_sign" | openssl dgst -sha256 -mac HMAC -macopt hexkey:$HEXKEY -binary | base64 -w0