|
| 1 | +#!/usr/bin/env ruby |
| 2 | + |
| 3 | +require 'aws-sdk-s3' |
| 4 | +require 'aws-sdk-kms' |
| 5 | +require 'json' |
| 6 | + |
| 7 | +def main |
| 8 | + # Check command line arguments |
| 9 | + if ARGV.length != 4 |
| 10 | + puts "Usage: #{$0} <bucket-name> <object-key> <kms-key-id> <region>" |
| 11 | + puts "Example: #{$0} avp-21638 s3ec-ruby-v2 arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 us-east-2" |
| 12 | + exit 1 |
| 13 | + end |
| 14 | + |
| 15 | + bucket_name = ARGV[0] |
| 16 | + object_key = ARGV[1] |
| 17 | + kms_key_id = ARGV[2] |
| 18 | + region = ARGV[3] |
| 19 | + |
| 20 | + puts "=== S3 Encryption Client v2 Example (Ruby) ===" |
| 21 | + puts "Bucket: #{bucket_name}" |
| 22 | + puts "Object Key: #{object_key}" |
| 23 | + puts "KMS Key ID: #{kms_key_id}" |
| 24 | + puts "Region: #{region}" |
| 25 | + puts |
| 26 | + |
| 27 | + begin |
| 28 | + # Test data for encryption |
| 29 | + test_data = "Hello, World! This is a test message for S3 encryption client v2 in Ruby." |
| 30 | + puts "Original data: #{test_data}" |
| 31 | + puts "Data length: #{test_data.length} bytes" |
| 32 | + puts |
| 33 | + |
| 34 | + puts "--- Initialize S3 Encryption Client v2 ---" |
| 35 | + |
| 36 | + # Create regular S3 client |
| 37 | + s3_client = Aws::S3::Client.new(region: region) |
| 38 | + |
| 39 | + # Create KMS client |
| 40 | + kms_client = Aws::KMS::Client.new(region: region) |
| 41 | + |
| 42 | + # Create S3 Encryption Client v2 |
| 43 | + encryption_client = Aws::S3::EncryptionV2::Client.new( |
| 44 | + client: s3_client, |
| 45 | + kms_key_id: kms_key_id, |
| 46 | + kms_client: kms_client, |
| 47 | + key_wrap_schema: :kms_context, |
| 48 | + content_encryption_schema: :aes_gcm_no_padding, |
| 49 | + security_profile: :v2 |
| 50 | + ) |
| 51 | + |
| 52 | + puts "Successfully initialized S3 Encryption Client v2" |
| 53 | + puts "--- Encrypt and Upload Object to S3 ---" |
| 54 | + |
| 55 | + # Add encryption context |
| 56 | + encryption_context = { |
| 57 | + 'purpose' => 'example', |
| 58 | + 'version' => 'v2', |
| 59 | + 'language' => 'ruby' |
| 60 | + } |
| 61 | + |
| 62 | + # Upload encrypted object using S3 Encryption Client |
| 63 | + put_response = encryption_client.put_object({ |
| 64 | + bucket: bucket_name, |
| 65 | + key: object_key, |
| 66 | + body: test_data, |
| 67 | + kms_encryption_context: encryption_context |
| 68 | + }) |
| 69 | + |
| 70 | + puts "Successfully uploaded encrypted object to S3!" |
| 71 | + puts " Bucket: #{bucket_name}" |
| 72 | + puts " Key: #{object_key}" |
| 73 | + puts " Encryption Context: #{encryption_context}" |
| 74 | + puts |
| 75 | + |
| 76 | + puts "--- Download and Decrypt Object from S3 ---" |
| 77 | + |
| 78 | + # Download and decrypt object using S3 Encryption Client |
| 79 | + get_response = encryption_client.get_object({ |
| 80 | + bucket: bucket_name, |
| 81 | + key: object_key, |
| 82 | + kms_encryption_context: encryption_context |
| 83 | + }) |
| 84 | + |
| 85 | + # Read the decrypted data |
| 86 | + decrypted_data = get_response.body.read |
| 87 | + |
| 88 | + puts "Successfully downloaded and decrypted object from S3!" |
| 89 | + puts " Object size: #{decrypted_data.length} bytes" |
| 90 | + puts " Decrypted data: #{decrypted_data}" |
| 91 | + puts |
| 92 | + |
| 93 | + puts "--- Verify Roundtrip Success ---" |
| 94 | + |
| 95 | + # Verify the roundtrip was successful |
| 96 | + if decrypted_data == test_data |
| 97 | + puts "SUCCESS: Roundtrip encryption/decryption completed successfully!" |
| 98 | + puts " Original data matches decrypted data" |
| 99 | + puts " Data integrity verified" |
| 100 | + else |
| 101 | + puts "ERROR: Roundtrip failed - data mismatch" |
| 102 | + puts " Original: #{test_data}" |
| 103 | + puts " Decrypted: #{decrypted_data}" |
| 104 | + exit 1 |
| 105 | + end |
| 106 | + |
| 107 | + # Optionally Delete the Object |
| 108 | + #puts "--- Cleanup ---" |
| 109 | + # Clean up the test object using regular S3 client |
| 110 | + # s3_client.delete_object({ |
| 111 | + # bucket: bucket_name, |
| 112 | + # key: object_key |
| 113 | + # }) |
| 114 | + # puts "Test object deleted from S3" |
| 115 | + |
| 116 | + puts |
| 117 | + puts "=== Example completed successfully! ===" |
| 118 | + |
| 119 | + rescue Aws::S3::Errors::NoSuchBucket => e |
| 120 | + puts "Error: S3 bucket '#{bucket_name}' does not exist or is not accessible" |
| 121 | + puts " #{e.message}" |
| 122 | + exit 1 |
| 123 | + rescue Aws::KMS::Errors::NotFoundException => e |
| 124 | + puts "Error: KMS key '#{kms_key_id}' not found or not accessible" |
| 125 | + puts " #{e.message}" |
| 126 | + exit 1 |
| 127 | + rescue Aws::S3::EncryptionV2::Errors::EncryptionError => e |
| 128 | + puts "S3 Encryption Error: #{e.message}" |
| 129 | + exit 1 |
| 130 | + rescue Aws::S3::EncryptionV2::Errors::DecryptionError => e |
| 131 | + puts "S3 Decryption Error: #{e.message}" |
| 132 | + exit 1 |
| 133 | + rescue Aws::Errors::ServiceError => e |
| 134 | + puts "AWS Service Error: #{e.message}" |
| 135 | + puts " Error Code: #{e.code}" if e.respond_to?(:code) |
| 136 | + exit 1 |
| 137 | + rescue StandardError => e |
| 138 | + puts "Unexpected error: #{e.message}" |
| 139 | + puts e.backtrace.first(5) |
| 140 | + exit 1 |
| 141 | + end |
| 142 | +end |
| 143 | + |
| 144 | +# Run the main function if this script is executed directly |
| 145 | +if __FILE__ == $0 |
| 146 | + main |
| 147 | +end |
0 commit comments