Используйте bash, Azure CLI и REST API для доступа к CosmosDB - как получить токен и ха sh правильно? - PullRequest
1 голос
/ 25 апреля 2020

Моя конечная цель - загрузить документ в существующий экземпляр CosmosDB (SQL), используя bash и Azure CLI. Проблема в том, что Azure CLI не предлагает команду для изменения документов .

Чтобы обойти эту проблему, я посмотрел на команду az rest и надеялся вызвать REST API CosmosDB, чтобы завершить задачу, но после нескольких часов безуспешных попыток я всегда получаю сообщение об ошибке:

Unauthorized ({"code": "Unauthorized", "message": "Токен авторизации ввода может" t обслуживать запрос. Убедитесь, что ожидаемая полезная нагрузка построена в соответствии с протоколом, и проверьте используемый ключ. Сервер использовал следующую полезную нагрузку для подписи: 'get \ ndbs \ n \ nsat, 25 апреля 2020 13:50:22 +0000 \ n \ n '\ r \ nActivityId: ..., Microsoft. Azure .Documents.Common / 2.10.0 "})

Для простоты, я я пытаюсь составить список всех своих баз данных, используя REST API, , как описано в документации , и если это сработает, перейдите к фактической загрузке документов.

Я также пытаюсь следовать инструкциям представлен в документах о том, как сгенерировать заголовок авторизации.

* 10 19 * Запрос на получение списка БД использует формат: GET https://{databaseaccount}.documents.azure.com/dbs

Вот мой bash скрипт с выделенными проблемами / вопросами.

Часть 1: Получить токен доступа - вопрос : это правильный токен для начала?

masterKey=$(az cosmosdb keys list --name MYDBINSTANCENAME --query primaryMasterKey --output tsv)

Часть 2: Генерировать полезную нагрузку для ха sh - все содержимое должно быть в нижнем регистре

verb="get"
resourceType="dbs"
resourceLink="dbs"
now=$((date -uR) | tr '[A-Z]' '[a-z]')
payload="$verb\n$resourceType\n$resourceLink\n$now\n\\n"

Часть 3: Ха sh полезная нагрузка - выпуск : результат этого га sh отличается от того, что образец код в C# сборках . Таким образом, любой из них должен быть неправильным, но оба результата приводят к одному и тому же сообщению об ошибке.

hashedPayload=$(printf $payload | openssl dgst -sha256 -hmac $masterKey -binary)

Часть 4. Создание требуемой строки аутентификации и преобразование в базу 64 - вопрос: - база 64 кодировка, необходимая для использования с az rest?

authString="type=master&ver=1.0&sig=$hashedPayload" | base64

Часть 5: создайте строку заголовков. При этом используется нотация JSON, поскольку подход с разделением пробелами не работает, , хотя в документации указано, что он должен .

headers="{\"x-ms-date\": \"$now\", \"x-ms-version\": \"2018-12-31\", \"x-ms-documentdb-isquery\": \"true\", \"Content-Type\": \"application/query+json\", \"Authorization\": \"$authString\"}"

Часть 6: вызов API REST

az rest --verbose -m get -u "https://MYDBINSTANCENAME.documents.azure.com:443/dbs" --headers $headers

Выход:

Request URL: 'https://MYDBINSTANCENAME.documents.azure.com:443/dbs'
Request method: 'GET'
Request headers:
    'User-Agent': 'AZURECLI/2.4.0 (HOMEBREW)'
    'Accept-Encoding': 'gzip, deflate'
    'Accept': '*/*'
    'Connection': 'keep-alive'
    'x-ms-date': 'sat, 25 apr 2020 13:54:10 +0000'
    'x-ms-version': '2018-12-31'
    'x-ms-documentdb-isquery': 'true'
    'Content-Type': 'application/query+json'
    'Authorization': 'type%3dmaster%26ver%...'
    'x-ms-client-request-id': 'a55357fe-411c-4adf-9fd6-1a255e010cca'
    'CommandName': 'rest'
    'ParameterSetName': '--verbose -m -u --headers'
Request body:
None
Response status: 401
Response headers:
    'Transfer-Encoding': 'chunked'
    'Content-Type': 'application/json'
    'Content-Location': 'https://MYDBINSTANCENAME.documents.azure.com/dbs'
    'Server': 'Microsoft-HTTPAPI/2.0'
    'x-ms-activity-id': '9119f8bd-53d9-4a87-8aff-a887ec652fed'
    'Strict-Transport-Security': 'max-age=31536000'
    'x-ms-gatewayversion': 'version=2.10.0'
    'Date': 'Sat, 25 Apr 2020 13:54:11 GMT'
Response content:
{"code":"Unauthorized","message":"The input authorization token can't serve the request. Please check that the expected payload is built as per the protocol, and check the key being used. Server used the following payload to sign: 'get\ndbs\n\nsat, 25 apr 2020 13:54:10 +0000\n\n'\r\nActivityId: 9119f8bd-53d9-4a87-8aff-a887ec652fed, Microsoft.Azure.Documents.Common/2.10.0"}

1 Ответ

2 голосов
/ 27 апреля 2020

Спасибо за вашу поддержку @Gaurav Mantri и @Mark Brown. Ваши комментарии помогли избежать смерти из-за миллиона порезов: -)

Я запустил хранилище, где собираю Azure CLI bash сценарии. Найдите его в https://github.com/Krumelur/AzureScripts

Позвольте мне ответить на мой собственный вопрос (-ы) и предоставить скрипт, который читает существующие БД в экземпляре CosmosDB.

Это начинается интерактивный вход в систему в окне браузера.

az login

Укажите, к какому ресурсу мы хотим получить доступ. URI вместе с необходимыми значениями параметров можно найти по адресу: https://docs.microsoft.com/en-us/rest/api/cosmos-db/cosmosdb-resource-uri-syntax-for-rest

comsosDbInstanceName="YOUR INSTANCE NAME GOES HERE"
baseUrl="https://$comsosDbInstanceName.documents.azure.com/"
verb="get"
resourceType="dbs"
resourceLink="dbs"
resourceId=""

Получить мастер-ключ CosmosDB. Нам нужно это, чтобы получить доступ. Это тот же ключ, который можно найти на портале в разделе «Ключи» экземпляра CosmosDB. Первичный ключ - это то, что API REST называет «главным» ключом.

masterKey=$(az cosmosdb keys list --name $comsosDbInstanceName --query primaryMasterKey --output tsv)
echo "Masterkey: $masterKey"

API-интерфейсу REST CosmosDB требуется хешированный заголовок авторизации: https://docs.microsoft.com/de-de/rest/api/cosmos-db/access-control-on-cosmosdb-resources#authorization -header

Чтобы получить дату в формате HTTP, языковой стандарт должен быть установлен на США. В противном случае названия дней будут локализованы (например, на немецкий язык).

Формат HTTP напрямую не поддерживается bash. Чтобы это работало, установите текущий часовой пояс на GMT. Формат времени выглядит следующим образом: «понедельник, 27 апреля 2020 г., 09:46:58 гм».

now=$(env LANG=en_US TZ=GMT date '+%a, %d %b %Y %T %Z')
echo "Date: " $now

Глагол Concat, тип ресурса, идентификатор ресурса и дата в ожидаемом формате. REST API ожидает, что подпись будет в нижнем регистре.

«Маленькая» проблема, о которой я не знал: завершающие символы новой строки (\n) всегда усекаются при выводе строки. Это сломало бы ха sh, потому что CosmosDB ожидает, что они будут там. Вот почему два завершающих символа новой строки добавляются после операции в нижнем регистре.

signature="$(printf "%s" "$verb\n$resourceType\n$resourceId\n$now" | tr '[A-Z]' '[a-z]')\n\n"
echo "Signature: $signature"

Рассчитайте га sh подписи, используя первичный ключ экземпляра CosmosDB. См. https://superuser.com/questions/1546027/what-is-the-openssl-equivalent-of-this-given-c-hashing-code/1546036, чтобы узнать, почему это так сложно. TL; Dr; версия: OpenSSL и реализация сервера по-разному интерпретируют ключ хеширования.

hexKey=$(printf "$masterKey" | base64 --decode | hexdump -v -e '/1 "%02x"')
echo "Hex key: " $hexKey
hashedSignature=$(printf "$signature" | openssl dgst -sha256 -mac hmac -macopt hexkey:$hexKey -binary | base64)
echo "Hashed signature: $hashedSignature"```

Ожидается, что хешированная подпись будет закодирована в URL. Но, конечно, в bash нет встроенного способа сделать это. Geez. К счастью, мы имеем дело со строкой base64. Единственный символ, который нуждается в кодировании, это знак равенства, который становится "% 3d".

Создайте заголовок авторизации, используя формат "type = {typeoftoken} & ver = {tokenversion} & sig = {hashsignature}"

authString="type=master&ver=1.0&sig=$hashedSignature"
echo "Auth string: $authString"

Ожидается, что строка аутентификации будет закодирована в URL. Но, конечно, в bash нет встроенного способа сделать это. Geez. Это не полная кодировка base64, а только изменяет символы, которые мы можем видеть: = ->% 3d, & ->% 26, + =>% 2b, / =>% 2f

urlEncodedAuthString=$(printf "$authString" | sed 's/=/%3d/g' | sed 's/&/%26/g' | sed 's/+/%2b/g' | sed 's/\//%2f/g')
echo "URL encoded auth string: $urlEncodedAuthString"

Make вызов API путем объединения базового URL и ссылки на ресурс.

url="$baseUrl$resourceLink"
echo "URL: $url"

Можно использовать команду "az rest":

az rest --verbose -m $verb -u $url --headers x-ms-date="$now" x-ms-version=2018-12-31 x-ms-documentdb-isquery=true Content-Type=application/query+json Authorization=$urlEncodedAuthString --debug

Альтернатива: использовать cURL

curl --request $verb -H "x-ms-date: $now" -H "x-ms-version: 2018-12-31" -H "x-ms-documentdb-isquery: true" -H "Content-Type: application/query+json" -H "Authorization: $urlEncodedAuthString" $url
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...