1
votes

I'm using this approach to encrypt files and store them in Azure block blobs. I would like to copy the encrypted blob to another blob storage account and decrypt it in the process. I know it's possible to do a "copy blob" operation which runs entirely inside Azure asynchronously and doesn't download the blob contents through my local computer in transit. I believe this is accomplished through the CloudBlockBlob.StartCopy method. But is it possible to do that with an encrypted file and decrypt it in transit to the other storage account?

Following that link above, my code looks like the following. blob.OpenRead works but blob2.StartCopy doesn't work.

BlobEncryptionPolicy policy = new BlobEncryptionPolicy(null, cloudResolver);
BlobRequestOptions options = new BlobRequestOptions() { EncryptionPolicy = policy };
CloudBlockBlob blob = container.GetBlockBlobReference("MyFile.txt");
//var blobStream = blob.OpenRead(null, options); //this works

CloudBlockBlob blob2 = container2.GetBlockBlobReference("MyFile2.txt");
blob2.StartCopy(blob, null, null, options, null); //this fails with: The remote server returned an error: (404) Not Found.
1
Which nuget package and version are you using for storage account management?juvchan
@juvchan 6.1 Microsoft.WindowsAzure.Storage DLLGregGalloway
just to be sure, your storage account is created in Class mode or Resource Manager mode? Seems like the earlier by the nuget you're using.juvchan
@juvchan Classic. Does it matter for this?GregGalloway
@juvchan - I don't think it would matter if the storage account is created in classic/ARM way in this particular scenario. That impacts how the storage account themselves are managed (from Service Management/ARM API perspective). Management of data inside the storage account remains the same. In both cases, it would make use of account name/key for data management.Gaurav Mantri

1 Answers

6
votes

The answer is that encryption is done in the storage client library so if you do a copy blob to a new storage account it will still be encrypted.

The reason your code is failing is because the source blob is in a Private container. For cross-account copy to work, the source blob should be publicly accessible. Within same storage account, you can copy a blob from a private container. AFAIK, the error has nothing to do with encryption.

What you could do is create a SAS URL on the source blob and then use the following override of StartCopy method:

public string StartCopy(
    Uri source,
    AccessCondition sourceAccessCondition = null,
    AccessCondition destAccessCondition = null,
    BlobRequestOptions options = null,
    OperationContext operationContext = null
)

Here's the sample code to do so:

    private static void StartCopyAcrossAccount()
    {
        var sourceAccount = new CloudStorageAccount(new StorageCredentials("source-account-name", "source-account-key"), true);
        var sourceContainer = sourceAccount.CreateCloudBlobClient().GetContainerReference("source-container");
        var sourceBlob = sourceContainer.GetBlockBlobReference("blob-name");
        var sourceBlobSas = sourceBlob.GetSharedAccessSignature(new Microsoft.WindowsAzure.Storage.Blob.SharedAccessBlobPolicy()
            {
                SharedAccessExpiryTime = DateTime.UtcNow.AddHours(1),
                Permissions = Microsoft.WindowsAzure.Storage.Blob.SharedAccessBlobPermissions.Read
            });
        var sourceBlobSasUrl = sourceBlob.Uri.AbsoluteUri + sourceBlobSas;

        var targetAccount = new CloudStorageAccount(new StorageCredentials("target-account-name", "target-account-key"), true);
        var targetContainer = targetAccount.CreateCloudBlobClient().GetContainerReference("target-container");
        var targetBlob = targetContainer.GetBlockBlobReference("blob-name");

        var copyId = targetBlob.StartCopy(new Uri(sourceBlobSasUrl), null, null);
    }