在 AWS SDK for .NET 中使用适用于 Amazon S3 加密的 AWS KMS 密钥 - AWS SDK for .NET

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

在 AWS SDK for .NET 中使用适用于 Amazon S3 加密的 AWS KMS 密钥

此示例说明如何使用 AWS Key Management Service 密钥对 Amazon S3 对象进行加密。该应用程序创建客户主密钥(CMK),并使用它来创建用于客户端加密的 AmazonS3EncryptionClientV2 对象。应用程序使用该客户端根据现有 Amazon S3 桶中的给定文本文件创建加密对象。然后,它会解密对象并显示其内容。

警告

名为AmazonS3EncryptionClient的类似类已被弃用,其安全性不如 AmazonS3EncryptionClientV2 类。要迁移使用 AmazonS3EncryptionClient 的现有代码,请参阅S3 加密客户端迁移

创建加密材料

以下代码片段创建了一个包含 KMS 密钥 ID 的 EncryptionMaterials 对象。

本主题末尾的示例显示了此片段的使用情况。

// Create a customer master key (CMK) and store the result CreateKeyResponse createKeyResponse = await new AmazonKeyManagementServiceClient().CreateKeyAsync(new CreateKeyRequest()); var kmsEncryptionContext = new Dictionary<string, string>(); var kmsEncryptionMaterials = new EncryptionMaterialsV2( createKeyResponse.KeyMetadata.KeyId, KmsType.KmsContext, kmsEncryptionContext);

创建并加密 Amazon S3 对象

以下代码片段创建了一个使用先前创建的加密材料的 AmazonS3EncryptionClientV2 对象。然后,它使用客户端来创建和加密一个新的 Amazon S3 对象。

本主题末尾的示例显示了此片段的使用情况。

// // Method to create and encrypt an object in an S3 bucket static async Task<GetObjectResponse> CreateAndRetrieveObjectAsync( EncryptionMaterialsV2 materials, string bucketName, string fileName, string itemName) { // CryptoStorageMode.ObjectMetadata is required for KMS EncryptionMaterials var config = new AmazonS3CryptoConfigurationV2(SecurityProfile.V2AndLegacy) { StorageMode = CryptoStorageMode.ObjectMetadata }; var s3EncClient = new AmazonS3EncryptionClientV2(config, materials); // Create, encrypt, and put the object await s3EncClient.PutObjectAsync(new PutObjectRequest { BucketName = bucketName, Key = itemName, ContentBody = File.ReadAllText(fileName) }); // Get, decrypt, and return the object return await s3EncClient.GetObjectAsync(new GetObjectRequest { BucketName = bucketName, Key = itemName }); }

完整代码

本部分显示了本示例的相关参考和完整代码。

using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using Amazon.Extensions.S3.Encryption; using Amazon.Extensions.S3.Encryption.Primitives; using Amazon.S3.Model; using Amazon.KeyManagementService; using Amazon.KeyManagementService.Model; namespace KmsS3Encryption { // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = // Class to store text in an encrypted S3 object. class Program { private const int MaxArgs = 3; public static async Task Main(string[] args) { // Parse the command line and show help if necessary var parsedArgs = CommandLine.Parse(args); if((parsedArgs.Count == 0) || (parsedArgs.Count > MaxArgs)) { PrintHelp(); return; } // Get the application arguments from the parsed list string bucketName = CommandLine.GetArgument(parsedArgs, null, "-b", "--bucket-name"); string fileName = CommandLine.GetArgument(parsedArgs, null, "-f", "--file-name"); string itemName = CommandLine.GetArgument(parsedArgs, null, "-i", "--item-name"); if(string.IsNullOrEmpty(bucketName) || (string.IsNullOrEmpty(fileName))) CommandLine.ErrorExit( "\nOne or more of the required arguments is missing or incorrect." + "\nRun the command with no arguments to see help."); if(!File.Exists(fileName)) CommandLine.ErrorExit($"\nThe given file {fileName} doesn't exist."); if(string.IsNullOrEmpty(itemName)) itemName = Path.GetFileName(fileName); // Create a customer master key (CMK) and store the result CreateKeyResponse createKeyResponse = await new AmazonKeyManagementServiceClient().CreateKeyAsync(new CreateKeyRequest()); var kmsEncryptionContext = new Dictionary<string, string>(); var kmsEncryptionMaterials = new EncryptionMaterialsV2( createKeyResponse.KeyMetadata.KeyId, KmsType.KmsContext, kmsEncryptionContext); // Create the object in the bucket, then display the content of the object var putObjectResponse = await CreateAndRetrieveObjectAsync(kmsEncryptionMaterials, bucketName, fileName, itemName); Stream stream = putObjectResponse.ResponseStream; StreamReader reader = new StreamReader(stream); Console.WriteLine(reader.ReadToEnd()); } // // Method to create and encrypt an object in an S3 bucket static async Task<GetObjectResponse> CreateAndRetrieveObjectAsync( EncryptionMaterialsV2 materials, string bucketName, string fileName, string itemName) { // CryptoStorageMode.ObjectMetadata is required for KMS EncryptionMaterials var config = new AmazonS3CryptoConfigurationV2(SecurityProfile.V2AndLegacy) { StorageMode = CryptoStorageMode.ObjectMetadata }; var s3EncClient = new AmazonS3EncryptionClientV2(config, materials); // Create, encrypt, and put the object await s3EncClient.PutObjectAsync(new PutObjectRequest { BucketName = bucketName, Key = itemName, ContentBody = File.ReadAllText(fileName) }); // Get, decrypt, and return the object return await s3EncClient.GetObjectAsync(new GetObjectRequest { BucketName = bucketName, Key = itemName }); } // // Command-line help private static void PrintHelp() { Console.WriteLine( "\nUsage: KmsS3Encryption -b <bucket-name> -f <file-name> [-i <item-name>]" + "\n -b, --bucket-name: The name of an existing S3 bucket." + "\n -f, --file-name: The name of a text file with content to encrypt and store in S3." + "\n -i, --item-name: The name you want to use for the item." + "\n If item-name isn't given, file-name will be used."); } } // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = // Class that represents a command line on the console or terminal. // (This is the same for all examples. When you have seen it once, you can ignore it.) static class CommandLine { // // Method to parse a command line of the form: "--key value" or "-k value". // // Parameters: // - args: The command-line arguments passed into the application by the system. // // Returns: // A Dictionary with string Keys and Values. // // If a key is found without a matching value, Dictionary.Value is set to the key // (including the dashes). // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN", // where "N" represents sequential numbers. public static Dictionary<string,string> Parse(string[] args) { var parsedArgs = new Dictionary<string,string>(); int i = 0, n = 0; while(i < args.Length) { // If the first argument in this iteration starts with a dash it's an option. if(args[i].StartsWith("-")) { var key = args[i++]; var value = key; // Check to see if there's a value that goes with this option? if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++]; parsedArgs.Add(key, value); } // If the first argument in this iteration doesn't start with a dash, it's a value else { parsedArgs.Add("--NoKey" + n.ToString(), args[i++]); n++; } } return parsedArgs; } // // Method to get an argument from the parsed command-line arguments // // Parameters: // - parsedArgs: The Dictionary object returned from the Parse() method (shown above). // - defaultValue: The default string to return if the specified key isn't in parsedArgs. // - keys: An array of keys to look for in parsedArgs. public static string GetArgument( Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys) { string retval = null; foreach(var key in keys) if(parsedArgs.TryGetValue(key, out retval)) break; return retval ?? defaultReturn; } // // Method to exit the application with an error. public static void ErrorExit(string msg, int code=1) { Console.WriteLine("\nError"); Console.WriteLine(msg); Environment.Exit(code); } } }

其他注意事项

  • 您可以查看此示例的结果。为此,请前往 Amazon S3 控制台并打开您提供给应用程序的桶。然后找到新对象,下载后在文本编辑器中打开该对象。

  • AmazonS3EncryptionClientV2 类实现与标准 AmazonS3Client 类相同的接口。这样可以更轻松地将代码移植到 AmazonS3EncryptionClientV2 类中,从而在客户端中自动透明地进行加密和解密。

  • 使用 AWS KMS 密钥作为主密钥的主要优势是无需存储和管理自己的主密钥,该工作由 AWS 来完成。第二个优势是 AWS SDK for .NET 的 AmazonS3EncryptionClientV2 类可与 AWS SDK for Java 的 AmazonS3EncryptionClientV2 类互操作。这意味着,您可以使用AWS SDK for Java加密,然后使用AWS SDK for .NET解密,反之亦然。

    注意

    只有在元数据模式中运行时,AWS SDK for .NET 的 AmazonS3EncryptionClientV2 类才支持 KMS 主密钥。AWS SDK for .NET 的 AmazonS3EncryptionClientV2 类的指令文件模式与 AWS SDK for Java 的 AmazonS3EncryptionClientV2 类不兼容。