Получите блоб в Azure Blob Storage с общим ключом API - PullRequest
0 голосов
/ 02 июня 2019

У меня есть (частный) большой двоичный объект в хранилище больших двоичных объектов Azure, который был записан через учетную запись, у которой есть доступ для записи и чтения (он был записан через эту учетную запись terraform). Я пытаюсь получить его через Python (без Azure SDK), но мне не удалось.

Мой запрос выглядит следующим образом:

import datetime
import requests


key = ...
secret = ...
now = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
# the required settings, as per https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob
headers = {'Authorization': 'SharedKey {}:{}'.format(key, secret),
           'Date': now,
           'x-ms-version': '2018-03-28'
           }

storage_account = ...
container = ...
url = 'https://{}.blob.core.windows.net/{}/terraform.tfstate'.format(storage_account, container)

response = requests.get(url, headers=headers)

print(response.status_code)
print(response.text)

Это дает

400
<?xml version="1.0" encoding="utf-8"?><Error>
<Code>OutOfRangeInput</Code><Message>One of the request inputs is out of range. 
RequestId:...
Time:...</Message></Error>

Я подтвердил, что этот файл существует (проводник хранилища) и что, когда я обращаюсь к нему через консоль, я получаю тот же URL-адрес, что и выше, но с дополнительными параметрами GET.


Для тех, кто интересуется: причина, по которой я решил не использовать Azure SDK для Python: мне нужно только получить большой двоичный объект, и pip install azure[blob] добавит 88 зависимостей в проект (IMO недопустимо большое число для таких простая задача).

1 Ответ

0 голосов
/ 02 июня 2019

Итак, причина в том, что signature, упомянутый в документации, составлен из запроса и подробно описан здесь .

Python 3-эквивалент всего этого:

import base64
import hmac
import hashlib
import datetime

import requests


def _sign_string(key, string_to_sign):
    key = base64.b64decode(key.encode('utf-8'))
    string_to_sign = string_to_sign.encode('utf-8')
    signed_hmac_sha256 = hmac.HMAC(key, string_to_sign, hashlib.sha256)
    digest = signed_hmac_sha256.digest()
    encoded_digest = base64.b64encode(digest).decode('utf-8')
    return encoded_digest


def get_blob(storage_account, token, file_path):
    now = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
    url = 'https://{account}.blob.core.windows.net/{path}'.format(account=storage_account, path=file_path)
    version = '2018-03-28'
    headers = {'x-ms-version': version,
               'x-ms-date': now}

    content = 'GET{spaces}x-ms-date:{now}\nx-ms-version:{version}\n/{account}/{path}'.format(
        spaces='\n'*12,
        now=now,
        version=version,
        account=storage_account,
        path=file_path
    )

    headers['Authorization'] = 'SharedKey ' + storage_account + ':' + _sign_string(token, content)

    response = requests.get(url, headers=headers)

    assert response.status_code == 200
    return response.text

, где file_path имеет форму {container}/{path-in-container}.

Использование этого фрагмента было еще лучше, если добавить 88 зависимостей в проект.

...