static void Main(string[] args) { // This is standard code to interact with Blob Storage StorageCredentials creds = new StorageCredentials( ConfigurationManager.AppSettings["accountName"], ConfigurationManager.AppSettings["accountKey"]); CloudStorageAccount account = new CloudStorageAccount(creds, useHttps: true); CloudBlobClient client = account.CreateCloudBlobClient(); CloudBlobContainer contain = client.GetContainerReference(ConfigurationManager.AppSettings["container"]); contain.CreateIfNotExists(); // The Resolver object is used to interact with Key Vault for Azure Storage // This is where the GetToken method from above is used KeyVaultKeyResolver cloudResolver = new KeyVaultKeyResolver(GetToken); // Retrieve the key that you created previously // The IKey that is returned here is an RsaKey // Remember that we used the names contosokeyvault and testrsakey1 var rsa = cloudResolver.ResolveKeyAsync("https://contosokeyvault.vault.azure.net/keys/TestRSAKey1", CancellationToken.None).GetAwaiter().GetResult(); // Now you simply use the RSA key to encrypt by setting it in the BlobEncryptionPolicy. BlobEncryptionPolicy policy = new BlobEncryptionPolicy(rsa, null); BlobRequestOptions options = new BlobRequestOptions() { EncryptionPolicy = policy }; // Reference a block blob CloudBlockBlob blob = contain.GetBlockBlobReference("MyFile.txt"); // Upload using the UploadFromStream method using (var stream = System.IO.File.OpenRead(@"C:\data\MyFile.txt")) blob.UploadFromStream(stream, stream.Length, null, options, null); // In this case we will not pass a key and only pass the resolver because // this policy will only be used for downloading / decrypting policy = new BlobEncryptionPolicy(null, cloudResolver); options = new BlobRequestOptions() { EncryptionPolicy = policy }; using (var np = File.Open(@"C:\data\MyFileDecrypted.txt", FileMode.Create)) blob.DownloadToStream(np, null, options, null); }
static void Main(string[] args) { Console.WriteLine("Blob encryption with Key Vault integration demonstrating key rotation from Key 1 to Key 2"); Console.WriteLine(); // Create two secrets and obtain their IDs. This is normally a one-time setup step. // Although it is possible to use keys (rather than secrets) stored in Key Vault, this prevents caching. // Therefore it is recommended to use secrets along with a caching resolver (see below). string keyID1 = EncryptionShared.KeyVaultUtility.SetUpKeyVaultSecret("KeyRotationSampleSecret1"); string keyID2 = EncryptionShared.KeyVaultUtility.SetUpKeyVaultSecret("KeyRotationSampleSecret2"); // Retrieve storage account information from connection string // How to create a storage connection string - https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/ CloudStorageAccount storageAccount = EncryptionShared.Utility.CreateStorageAccountFromConnectionString(); CloudBlobClient client = storageAccount.CreateCloudBlobClient(); CloudBlobContainer container = client.GetContainerReference(DemoContainer + Guid.NewGuid().ToString("N")); // Construct a resolver capable of looking up keys and secrets stored in Key Vault. KeyVaultKeyResolver cloudResolver = new KeyVaultKeyResolver(EncryptionShared.KeyVaultUtility.GetAccessToken); // Set up a caching resolver so the secrets can be cached on the client. This is the recommended usage // pattern since the throttling targets for Storage and Key Vault services are orders of magnitude // different. CachingKeyResolver cachingResolver = new CachingKeyResolver(2, cloudResolver); // Create key instances corresponding to the key IDs. This will cache the secrets. IKey cloudKey1 = cachingResolver.ResolveKeyAsync(keyID1, CancellationToken.None).GetAwaiter().GetResult(); IKey cloudKey2 = cachingResolver.ResolveKeyAsync(keyID2, CancellationToken.None).GetAwaiter().GetResult(); // We begin with cloudKey1, and a resolver capable of resolving and caching Key Vault secrets. BlobEncryptionPolicy encryptionPolicy = new BlobEncryptionPolicy(cloudKey1, cachingResolver); client.DefaultRequestOptions.EncryptionPolicy = encryptionPolicy; client.DefaultRequestOptions.RequireEncryption = true; try { container.Create(); int size = 5 * 1024 * 1024; byte[] buffer1 = new byte[size]; byte[] buffer2 = new byte[size]; Random rand = new Random(); rand.NextBytes(buffer1); rand.NextBytes(buffer2); // Upload the first blob using the secret stored in Azure Key Vault. CloudBlockBlob blob = container.GetBlockBlobReference("blockblob1"); Console.WriteLine("Uploading Blob 1 using Key 1."); // Upload the encrypted contents to the first blob. using (MemoryStream stream = new MemoryStream(buffer1)) { blob.UploadFromStream(stream, size); } Console.WriteLine("Downloading and decrypting Blob 1."); // Download and decrypt the encrypted contents from the first blob. using (MemoryStream outputStream = new MemoryStream()) { blob.DownloadToStream(outputStream); } // At this point we will rotate our keys so new encrypted content will use the // second key. Note that the same resolver is used, as this resolver is capable // of decrypting blobs encrypted using either key. Console.WriteLine("Rotating the active encryption key to Key 2."); client.DefaultRequestOptions.EncryptionPolicy = new BlobEncryptionPolicy(cloudKey2, cachingResolver); // Upload the second blob using the key stored in Azure Key Vault. CloudBlockBlob blob2 = container.GetBlockBlobReference("blockblob2"); Console.WriteLine("Uploading Blob 2 using Key 2."); // Upload the encrypted contents to the second blob. using (MemoryStream stream = new MemoryStream(buffer2)) { blob2.UploadFromStream(stream, size); } Console.WriteLine("Downloading and decrypting Blob 2."); // Download and decrypt the encrypted contents from the second blob. using (MemoryStream outputStream = new MemoryStream()) { blob2.DownloadToStream(outputStream); } // Here we download and re-upload the first blob. This has the effect of updating // the blob to use the new key. using (MemoryStream memoryStream = new MemoryStream()) { Console.WriteLine("Downloading and decrypting Blob 1."); blob.DownloadToStream(memoryStream); memoryStream.Seek(0, SeekOrigin.Begin); Console.WriteLine("Re-uploading Blob 1 using Key 2."); blob.UploadFromStream(memoryStream); } // For the purposes of demonstration, we now override the encryption policy to only recognize key 2. BlobEncryptionPolicy key2OnlyPolicy = new BlobEncryptionPolicy(cloudKey2, null); BlobRequestOptions key2OnlyOptions = new BlobRequestOptions() { EncryptionPolicy = key2OnlyPolicy }; Console.WriteLine("Downloading and decrypting Blob 1."); // The first blob can still be decrypted because it is using the second key. using (MemoryStream outputStream = new MemoryStream()) { blob.DownloadToStream(outputStream, options: key2OnlyOptions); } Console.WriteLine("Press enter key to exit"); Console.ReadLine(); } finally { container.DeleteIfExists(); } }
static void Main(string[] args) { Console.WriteLine("Blob encryption with Key Vault integration"); Console.WriteLine(); // Get the key ID from App.config if it exists. string keyID = CloudConfigurationManager.GetSetting("KeyID"); // If no key ID was specified, we will create a new secret in Key Vault. // To create a new secret, this client needs full permission to Key Vault secrets. // Once the secret is created, its ID can be added to App.config. Once this is done, // this client only needs read access to secrets. if (string.IsNullOrEmpty(keyID)) { Console.WriteLine("No secret specified in App.config."); Console.WriteLine("Please enter the name of a new secret to create in Key Vault."); Console.WriteLine("WARNING: This will delete any existing secret with the same name."); Console.Write("Name of the new secret to create [{0}]: ", DefaultSecretName); string newSecretName = Console.ReadLine().Trim(); if (string.IsNullOrEmpty(newSecretName)) { newSecretName = DefaultSecretName; } // Although it is possible to use keys (rather than secrets) stored in Key Vault, this prevents caching. // Therefore it is recommended to use secrets along with a caching resolver (see below). keyID = EncryptionShared.KeyVaultUtility.SetUpKeyVaultSecret(newSecretName); Console.WriteLine(); Console.WriteLine("Created a secret with ID: {0}", keyID); Console.WriteLine("Copy the secret ID to App.config to reuse."); Console.WriteLine(); } // Retrieve storage account information from connection string // How to create a storage connection string - https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/ CloudStorageAccount storageAccount = EncryptionShared.Utility.CreateStorageAccountFromConnectionString(); CloudBlobClient client = storageAccount.CreateCloudBlobClient(); CloudBlobContainer container = client.GetContainerReference(DemoContainer + Guid.NewGuid().ToString("N")); // Construct a resolver capable of looking up keys and secrets stored in Key Vault. KeyVaultKeyResolver cloudResolver = new KeyVaultKeyResolver(EncryptionShared.KeyVaultUtility.GetAccessToken); // To demonstrate how multiple different types of key can be used, we also create a local key and resolver. // This key is temporary and won't be persisted. RsaKey rsaKey = new RsaKey("rsakey"); LocalResolver resolver = new LocalResolver(); resolver.Add(rsaKey); // If there are multiple key sources like Azure Key Vault and local KMS, set up an aggregate resolver as follows. // This helps users to define a plug-in model for all the different key providers they support. AggregateKeyResolver aggregateResolver = new AggregateKeyResolver() .Add(resolver) .Add(cloudResolver); // Set up a caching resolver so the secrets can be cached on the client. This is the recommended usage // pattern since the throttling targets for Storage and Key Vault services are orders of magnitude // different. CachingKeyResolver cachingResolver = new CachingKeyResolver(2, aggregateResolver); // Create a key instance corresponding to the key ID. This will cache the secret. IKey cloudKey = cachingResolver.ResolveKeyAsync(keyID, CancellationToken.None).GetAwaiter().GetResult(); try { container.Create(); int size = 5 * 1024 * 1024; byte[] buffer = new byte[size]; Random rand = new Random(); rand.NextBytes(buffer); // The first blob will use the key stored in Azure Key Vault. CloudBlockBlob blob = container.GetBlockBlobReference("blockblob1"); // Create the encryption policy using the secret stored in Azure Key Vault to be used for upload. BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy(cloudKey, null); // Set the encryption policy on the request options. BlobRequestOptions uploadOptions = new BlobRequestOptions() { EncryptionPolicy = uploadPolicy }; Console.WriteLine("Uploading the 1st encrypted blob."); // Upload the encrypted contents to the blob. using (MemoryStream stream = new MemoryStream(buffer)) { blob.UploadFromStream(stream, size, null, uploadOptions, null); } // Download the encrypted blob. BlobEncryptionPolicy downloadPolicy = new BlobEncryptionPolicy(null, cachingResolver); // Set the decryption policy on the request options. BlobRequestOptions downloadOptions = new BlobRequestOptions() { EncryptionPolicy = downloadPolicy }; Console.WriteLine("Downloading the 1st encrypted blob."); // Download and decrypt the encrypted contents from the blob. using (MemoryStream outputStream = new MemoryStream()) { blob.DownloadToStream(outputStream, null, downloadOptions, null); } // Upload second blob using the local key. blob = container.GetBlockBlobReference("blockblob2"); // Create the encryption policy using the local key. uploadPolicy = new BlobEncryptionPolicy(rsaKey, null); // Set the encryption policy on the request options. uploadOptions = new BlobRequestOptions() { EncryptionPolicy = uploadPolicy }; Console.WriteLine("Uploading the 2nd encrypted blob."); // Upload the encrypted contents to the blob. using (MemoryStream stream = new MemoryStream(buffer)) { blob.UploadFromStream(stream, size, null, uploadOptions, null); } // Download the encrypted blob. The same policy and options created before can be used because the aggregate resolver contains both // resolvers and will pick the right one based on the key ID stored in blob metadata on the service. Console.WriteLine("Downloading the 2nd encrypted blob."); // Download and decrypt the encrypted contents from the blob. using (MemoryStream outputStream = new MemoryStream()) { blob.DownloadToStream(outputStream, null, downloadOptions, null); } Console.WriteLine("Press enter key to exit"); Console.ReadLine(); } finally { container.DeleteIfExists(); } }