My ultimate goal is to upload a document to an existing CosmosDB (SQL) instance using bash and Azure CLI. Trouble is: Azure CLI does not offer a command to modify documents.
To work around this I looked into the az rest
command and was hoping to call into CosmosDB's REST API to complete the task, but after hours of unsuccessful trying, I'm always getting the error:
Unauthorized({"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:50:22 +0000\n\n'\r\nActivityId: ..., Microsoft.Azure.Documents.Common/2.10.0"})
To keep it simple for now, I'm trying to list all my databases using the REST API, as described in the docs and if that works, move on to actual document uploads.
I'm also trying to follow the instructions presented in the docs on how to generate the authorization header.
The request to get the list of DBs is using the format: GET https://{databaseaccount}.documents.azure.com/dbs
Here's my bash script with problems/questions highlighted.
Part 1: Get an access token - question: is this the right token to begin with?
masterKey=$(az cosmosdb keys list --name MYDBINSTANCENAME --query primaryMasterKey --output tsv)
Part 2: Generate payload to hash - all content must be lowercase
verb="get"
resourceType="dbs"
resourceLink="dbs"
now=$((date -uR) | tr '[A-Z]' '[a-z]')
payload="$verb\n$resourceType\n$resourceLink\n$now\n\\n"
Part 3: Hash the payload - issue: the result of this hash is different from what the sample code in C# builds. So either one must be wrong but both result in the same error message.
hashedPayload=$(printf $payload | openssl dgst -sha256 -hmac $masterKey -binary)
Part 4: Create the required authentication string and convert to base 64 - question: is the base 64 encoding required for use with az rest
?
authString="type=master&ver=1.0&sig=$hashedPayload" | base64
Part 5: create the headers string. This is using JSON notation because the blank separated approach does not work, although the docs state it should.
headers="{\"x-ms-date\": \"$now\", \"x-ms-version\": \"2018-12-31\", \"x-ms-documentdb-isquery\": \"true\", \"Content-Type\": \"application/query+json\", \"Authorization\": \"$authString\"}"
Part 6: call the REST API
az rest --verbose -m get -u "https://MYDBINSTANCENAME.documents.azure.com:443/dbs" --headers $headers
Output:
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"}