0

Reference1: https://learn.microsoft.com/en-us/rest/api/storageservices/copy-blob-from-url

Reference2: Authorization of Azure Storage service REST API

I implemented listing of containers according to the above reference2 as a backend server in Next.js (/pages/api/). I got the implementation in Reference2 to work with response status===OK. My goal is to copy a blob with tier===cool and paste it into a different container with tier===archive so I don't have to change the archived blob's access tier when downloading it.

I follow exactly reference2 with the following changes:

  1. set strToSign to (least sure about this part):

const strToSign= PUT\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:${strTime}\nx-ms-version:2020-10-02\n/${account}/\n${containerName}/${blobName}

  1. set header (following reference1) to:

     const putConfig = {
         method: 'PUT', 
         headers: {
             'Authorization': auth,
             'x-ms-date': strTime,
             'x-ms-version': "2020-10-02",
             'x-ms-copy-source': blobUrl,
             'x-ms-requires-sync':'true'
         }
    

    }

where (as in reference1),

   const blobUrl = `https://${account}.blob.core.windows.net/${containerName}/${blobName}`
  1. The fetch is set up like this:

    fetch(https://${account}.blob.core.windows.net/${containerName}/${blobName}, putConfig) .then( results => console.log(results), res.end())

  2. This is the console.log(results) output I get:

    Response { size: 0, timeout: 0, [Symbol(Body internals)]: { body: PassThrough { _readableState: [ReadableState], _events: [Object: null prototype], _eventsCount: 2, _maxListeners: undefined, _writableState: [WritableState], allowHalfOpen: true, [Symbol(kCapture)]: false, [Symbol(kCallback)]: null }, disturbed: false, error: null }, [Symbol(Response internals)]: { url: 'https://.blob.core.windows.net//', status: 403, statusText: 'Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.', headers: Headers { [Symbol(map)]: [Object: null prototype] }, counter: 0 } }

Not sure what the error is - can it be related to setting access on the specific blob (resource) on azure portal? How do you fix this issue?

P.S.

Reference3: Authentication Failed in REST api call to PUT Blob in Azure Storage [REST][Azure Blob]

I also tried to use the following:

const strToSign = `PUT\n\n\n\n\n\n\n\n\n\n\n\nx-ms-blob-type:BlockBlob\nx-ms-date:${strTime}\nx-ms-version:2020-10-02\n/${account}/\n${containerName}/\n${blobName}`;

The error remains the same.

ShrutiJoshi-MT
  • 1,622
  • 1
  • 4
  • 9
Andres R
  • 120
  • 1
  • 5
  • Is there a reason why you’re not using the SDK? – Gaurav Mantri Oct 22 '21 at 03:17
  • Yes. I want you download the archived blob without changing its access tier. You cannot use blob copy or blob copy from url with the sdk if a blob is in archive tier. To rehydrate archived blobs you need to change the tier with the sdk which means you lose the archived data. If you know a way to copy the blob without changing its tier using the sdk, let me know. Appreciate it! – Andres R Oct 22 '21 at 11:38
  • Simple answer is that you can't. In order to read an archived blob, it must be hydrated first by moving into either hot or cool tier. – Gaurav Mantri Oct 22 '21 at 11:40

2 Answers2

0

As Suggested By Gaurav Matri

blob is in the archive access tier, it's considered to be offline and can't be read or modified.

In order to read or modify data in an archived blob, you must first rehydrate the blob to an online tier, either the hot or cool tier.

There are two options for rehydrating a blob that is stored in the archive tier:

  1. Copy an archived blob to an online tier

You can rehydrate an archived blob by copying it to a new blob in the hot or cool tier with the Copy Blob or Copy Blob from URL operation. Microsoft recommends this option for most scenarios.

  1. Change a blob's access tier to an online tier

You can rehydrate an archived blob to hot or cool by changing its tier using the Set Blob Tier operation.

For more details refer this document

ShrutiJoshi-MT
  • 1,622
  • 1
  • 4
  • 9
  • First, I want to copy an archived blob to avoid extra cost when changing the tier - so that cancels option 2. Yes I am aware of this document and I read it. My understanding is that archived blobs can only be copied via the REST API. However, I gave 1) a shot: 1) I tried both "syncCopyFromUrl" and "startCopyFromURL" In both cases the answer is this: "message": "This operation is not permitted on an archived blob." The exact code I am using is this: const targetBlobClient = containerClient.getBlockBlobClient('targettest'); await targetBlobClient.syncCopyFromURL(url); – Andres R Oct 22 '21 at 17:33
  • So unless I am wrong about not being able to copy archived blobs with the SDK (btw if you click on the 'copy blob' and 'copy blob from url' links in your document you are forwarded to the REST API documentation) , we are back to the original question: what is wrong about my REST API code in the original email? – Andres R Oct 22 '21 at 17:39
0

SOLUTION:

const CryptoJS = require("crypto-js");

const key = "accesskey";
const version="2020-10-02"
const account = 'storagename'
const containerName = 'containername'
const strTime = (new Date()).toUTCString();

export default async (req, res) => {  
  if (req.method === 'POST') {

    const { blobName } = req.body
    const srcBlobName = blobName
    const srcBlobUrl = `https://${account}.blob.core.windows.net/${containerName}/${srcBlobName}`
    const destBlobName = srcBlobName + 'rHrH'
    const destBlobUrl = `https://${account}.blob.core.windows.net/${containerName}/${destBlobName}`;
    
    const destAccessTier = 'Cool'
    const canonicalizedHeaders = `x-ms-access-tier:${destAccessTier}\nx-ms-copy-source:${srcBlobUrl}\nx-ms-date:${strTime}\nx-ms-version:${version}\n`;
    const canonicalizedResource = `/${account}/${containerName}/${destBlobName}`;
    const strToSign = `PUT\n\n\n\n\n\n\n\n\n\n\n\n${canonicalizedHeaders}${canonicalizedResource}`;
    const secret = CryptoJS.enc.Base64.parse(key);
    const hash = CryptoJS.HmacSHA256(strToSign, secret);
    const hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
    const auth = `SharedKey ${account}:`+hashInBase64;
    
    const PUTconfig = {
    method: 'PUT',
    headers: {
        'x-ms-access-tier': destAccessTier,
        'x-ms-copy-source': srcBlobUrl,
        'x-ms-date': strTime,
        'x-ms-version': version,
        'Authorization': auth
        }
    };

    fetch(destBlobUrl, PUTconfig)
    .then( results => {
        if(results.status==200) {console.log('api works')} else {console.log(results)}},
        res.end()
    )    
  } 
}
Andres R
  • 120
  • 1
  • 5
  • Welcome to Stack Overflow! Please provide some description with your code to help readers understand your solution. For more info, see [How do I write a good answer?](https://stackoverflow.com/help/how-to-answer). – Shane Bishop Oct 27 '21 at 15:02
  • MSFT removed the 'copy from blob url' upon a prompt that it is not suitable for rehydration of blobs https://learn.microsoft.com/en-us/azure/storage/blobs/archive-rehydrate-overview reason: there was no ability to set the access tier of the target blob – Andres R Oct 27 '21 at 20:14