<p>I am uploading and downloading files to Azure storage from a React spa using SAS tokens.</p>
<p>When running on localhost, everything works, however when deployed to Kubernetes on Azure, I receive the following authentication error.</p>
<pre><code>onError RestError: &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;&lt;Error&gt;&lt;Code&gt;AuthenticationFailed&lt;/Code&gt;&lt;Message&gt;Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:e6bfca97-c01e-0030-2e29-4e7d7c000000
Time:2020-06-29T15:26:39.7164613Z&lt;/Message&gt;&lt;AuthenticationErrorDetail&gt;Signature did not match. String to sign used was w

2020-06-29T20:26:39Z
/blob/datalake/container/Natural_Language_Processing.pdf

</code></pre>
<p>The javascript code responsible for the upload is</p>
<pre class="lang-js prettyprint-override"><code>// upload to Azure
const blobName = file.name;
const accountSas = resp.data.SAS;
const account = resp.data.account;
const containerName = resp.data.container;
const anonymousCredential = new AnonymousCredential();
const blobServiceClient = new BlobServiceClient(
    `https://${account}.blob.core.windows.net?${accountSas}`,
    anonymousCredential
);
// Create a container
const containerClient = blobServiceClient.getContainerClient(
    containerName
);
// Create a blob
const content = file;
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
const uploadBlobResponse = await blockBlobClient.upload(
    content,
    Buffer.byteLength(content)
);
</code></pre>
<p>while the backend Python code for the SAS token generation is the following</p>
<pre class="lang-py prettyprint-override"><code>if content['up_down'] == 'download':
    permission = BlobSasPermissions(read=True)
else:
    permission = BlobSasPermissions(write=True)

account_name = os.getenv(&quot;STORAGE_ACCOUNT_NAME&quot;)
container_name = metadata.get_container_name()
blob_name = content['filePath']
expiry = datetime.utcnow() + timedelta(hours=5)

options = {
    'account_name': account_name,
    'container_name': container_name,
    'blob_name': blob_name,
    'account_key': os.getenv(&quot;STORAGE_ACCESS_KEY&quot;),
    'permission': permission,
    'expiry': expiry
}

SAS = generate_blob_sas(**options)
</code></pre>
<p>Where <a href="https://learn.microsoft.com/en-us/python/api/azure-storage-blob/azure.storage.blob?view=azure-python#generate-blob-sas-account-name--container-name--blob-name--snapshot-none--account-key-none--user-delegation-key-none--permission-none--expiry-none--start-none--policy-id-none--ip-none----kwargs-" rel="nofollow noreferrer"><code>generate_blob_sas</code></a> is imported from azure-storage-blob (version 12.3.1).</p>
<p>Any idea on how to resolve this?</p>

GZZ
<p>After a long time scratching my head to find a solution, I figured out where the problem was.</p>
<p>It had nothing to do with the Python library for accessing the blob, but rather with the environment variables in the Kubernetes pod.</p>
<p>The environment variables were passed to Kubernetes as secrets using a yaml file (as explained in this <a href="https://kubernetes.io/docs/concepts/configuration/secret/#creating-a-secret-manually" rel="nofollow noreferrer">link</a>).
Using this method, the secret needs to be base64 encoded. For this I was using the following</p>
<pre class="lang-sh prettyprint-override"><code>echo 'secret' | base64
&gt;&gt; c2VjcmV0Cg==
</code></pre>
<p>In this way however, the <code>echo</code> command appends by default a newline character to the output. What I should have used instead was</p>
<pre class="lang-sh prettyprint-override"><code>echo -n 'secret' | base64
&gt;&gt; c2VjcmV0
</code></pre>
<p>This bug was particularly difficult to find especially because when printed, the wrong solution would appear to lead to the correct result</p>
<pre class="lang-sh prettyprint-override"><code>echo 'secret' | base64 | base64 -d
&gt;&gt; secret
</code></pre>
<p>Anyway, I hope that my mistake will help someone in the future!</p>
