diff --git a/all-examples/go/v3/Makefile b/all-examples/go/v3/Makefile new file mode 100644 index 00000000..d7285fe9 --- /dev/null +++ b/all-examples/go/v3/Makefile @@ -0,0 +1,69 @@ +# Makefile for S3 Encryption Client Go v3 Example + +# Default target +.PHONY: all install clean run help + +# Variables +SCRIPT = main.go + +# Default arguments for running the example +# Override these when calling make run +BUCKET_NAME ?= avp-21638 +OBJECT_KEY ?= s3ec-go-v3 +KMS_KEY_ID ?= arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 +AWS_REGION ?= us-east-2 + +all: install + +# Install dependencies using Go modules +install: + @echo "Installing Go dependencies..." + @go mod tidy + @echo "Dependencies installed successfully!" + +# Clean Go artifacts +clean: + @echo "Cleaning Go artifacts..." + @go clean + @echo "Clean completed!" + +# Run the example with default arguments +run: install + @echo "Running S3 Encryption Client v3 Go example..." + @echo "Bucket: $(BUCKET_NAME)" + @echo "Object Key: $(OBJECT_KEY)" + @echo "KMS Key ID: $(KMS_KEY_ID)" + @echo "Region: $(AWS_REGION)" + @echo "" + @go run $(SCRIPT) $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) + +# Run with custom arguments +# Usage: make run-custom BUCKET_NAME=my-bucket OBJECT_KEY=my-key KMS_KEY_ID=my-kms-key AWS_REGION=my-region +run-custom: install + @go run $(SCRIPT) $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) + +# Show help +help: + @echo "S3 Encryption Client Go v3 Example Makefile" + @echo "" + @echo "Available targets:" + @echo " install - Install Go dependencies using Go modules" + @echo " run - Install dependencies and run the example with default parameters" + @echo " run-custom - Install dependencies and run with custom parameters" + @echo " clean - Remove Go artifacts" + @echo " help - Show this help message" + @echo "" + @echo "Default parameters:" + @echo " BUCKET_NAME = $(BUCKET_NAME)" + @echo " OBJECT_KEY = $(OBJECT_KEY)" + @echo " KMS_KEY_ID = $(KMS_KEY_ID)" + @echo " AWS_REGION = $(AWS_REGION)" + @echo "" + @echo "To run with custom parameters:" + @echo " make run BUCKET_NAME=your-bucket OBJECT_KEY=your-key KMS_KEY_ID=your-kms-key AWS_REGION=your-region" + @echo "" + @echo "Prerequisites:" + @echo " - Go 1.24+ installed on the system" + @echo " - AWS credentials configured (AWS CLI, environment variables, or IAM role)" + @echo " - Valid S3 bucket and KMS key with appropriate permissions" + @echo " - S3 Encryption Client v3 Go SDK (included in local-go-s3ec)" diff --git a/all-examples/go/v3/README.md b/all-examples/go/v3/README.md new file mode 100644 index 00000000..519dfc36 --- /dev/null +++ b/all-examples/go/v3/README.md @@ -0,0 +1,55 @@ +# S3 Encryption Client Go v3 Example + +This example demonstrates how to use the Amazon S3 Encryption Client v3 for Go to perform client-side encryption and decryption of objects. + +## Prerequisites + +1. **Go**: Requires Go 1.24 or later +2. **AWS Credentials**: Configure your AWS credentials using one of the following methods: + - AWS CLI: `aws configure` + - Environment variables: `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` + - IAM roles (for EC2 instances) +3. **KMS Key**: You'll need a KMS key ID or ARN. You can use the default example key: `arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01` +4. **S3 Bucket**: An existing S3 bucket where you have read/write permissions + +## Setup + +1. Initialize submodules and download dependencies: + ```bash + make install + ``` + + Or manually: + ```bash + go mod tidy + ``` + + **Note**: This example uses a local submodule for the S3EC Go v3 library via the `replace` directive in `go.mod`. + +## Usage + +### Using Make (Recommended) + +Run the example with default parameters: +```bash +make run +``` + +Run with custom parameters: +```bash +make run BUCKET_NAME=my-bucket OBJECT_KEY=my-key KMS_KEY_ID=my-kms-key AWS_REGION=my-region +``` + +### Manual Usage + +Run the example with the following command: + +```bash +go run main.go +``` + +### Example: + +```bash +go run main.go my-test-bucket s3ec-go-v3-test arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 us-east-2 +``` diff --git a/all-examples/go/v3/go.mod b/all-examples/go/v3/go.mod new file mode 100644 index 00000000..1821569a --- /dev/null +++ b/all-examples/go/v3/go.mod @@ -0,0 +1,32 @@ +module github.com/aws/amazon-s3-encryption-client-python/all-examples/go/v3 + +go 1.24 + +require ( + github.com/aws/amazon-s3-encryption-client-go/v3 v3.1.0 + github.com/aws/aws-sdk-go-v2 v1.24.0 + github.com/aws/aws-sdk-go-v2/config v1.26.1 + github.com/aws/aws-sdk-go-v2/service/kms v1.27.4 + github.com/aws/aws-sdk-go-v2/service/s3 v1.47.5 +) + +require ( + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.16.12 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 // indirect + github.com/aws/smithy-go v1.19.0 // indirect +) + +// S3EC Go V3 uses a local submodule for development +replace github.com/aws/amazon-s3-encryption-client-go/v3 => ./local-go-s3ec/v3 diff --git a/all-examples/go/v3/go.sum b/all-examples/go/v3/go.sum new file mode 100644 index 00000000..244c8814 --- /dev/null +++ b/all-examples/go/v3/go.sum @@ -0,0 +1,40 @@ +github.com/aws/aws-sdk-go-v2 v1.24.0 h1:890+mqQ+hTpNuw0gGP6/4akolQkSToDJgHfQE7AwGuk= +github.com/aws/aws-sdk-go-v2 v1.24.0/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 h1:OCs21ST2LrepDfD3lwlQiOqIGp6JiEUqG84GzTDoyJs= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4/go.mod h1:usURWEKSNNAcAZuzRn/9ZYPT8aZQkR7xcCtunK/LkJo= +github.com/aws/aws-sdk-go-v2/config v1.26.1 h1:z6DqMxclFGL3Zfo+4Q0rLnAZ6yVkzCRxhRMsiRQnD1o= +github.com/aws/aws-sdk-go-v2/config v1.26.1/go.mod h1:ZB+CuKHRbb5v5F0oJtGdhFTelmrxd4iWO1lf0rQwSAg= +github.com/aws/aws-sdk-go-v2/credentials v1.16.12 h1:v/WgB8NxprNvr5inKIiVVrXPuuTegM+K8nncFkr1usU= +github.com/aws/aws-sdk-go-v2/credentials v1.16.12/go.mod h1:X21k0FjEJe+/pauud82HYiQbEr9jRKY3kXEIQ4hXeTQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 h1:w98BT5w+ao1/r5sUuiH6JkVzjowOKeOJRHERyy1vh58= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10/go.mod h1:K2WGI7vUvkIv1HoNbfBA1bvIZ+9kL3YVmWxeKuLQsiw= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 h1:v+HbZaCGmOwnTTVS86Fleq0vPzOd7tnJGbFhP0stNLs= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9/go.mod h1:Xjqy+Nyj7VDLBtCMkQYOw1QYfAEZCVLrfI0ezve8wd4= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 h1:N94sVhRACtXyVcjXxrwK1SKFIJrA9pOJ5yu2eSHnmls= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9/go.mod h1:hqamLz7g1/4EJP+GH5NBhcUMLjW+gKLQabgyz6/7WAU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9 h1:ugD6qzjYtB7zM5PN/ZIeaAIyefPaD82G8+SJopgvUpw= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9/go.mod h1:YD0aYBWCrPENpHolhKw2XDlTIWae2GKXT1T4o6N6hiM= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9 h1:/90OR2XbSYfXucBMJ4U14wrjlfleq/0SB6dZDPncgmo= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9/go.mod h1:dN/Of9/fNZet7UrQQ6kTDo/VSwKPIq94vjlU16bRARc= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 h1:Nf2sHxjMJR8CSImIVCONRi4g0Su3J+TSTbS7G0pUeMU= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9/go.mod h1:idky4TER38YIjr2cADF1/ugFMKvZV7p//pVeV5LZbF0= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9 h1:iEAeF6YC3l4FzlJPP9H3Ko1TXpdjdqWffxXjp8SY6uk= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9/go.mod h1:kjsXoK23q9Z/tLBrckZLLyvjhZoS+AGrzqzUfEClvMM= +github.com/aws/aws-sdk-go-v2/service/kms v1.27.4 h1:c75pHGBV3h6WOsIjbJhLyOnlCPXzap45nbiP2Z5jk5M= +github.com/aws/aws-sdk-go-v2/service/kms v1.27.4/go.mod h1:D9FVDkZjkZnnFHymJ3fPVz0zOUlNSd0xcIIVmmrAac8= +github.com/aws/aws-sdk-go-v2/service/s3 v1.47.5 h1:Keso8lIOS+IzI2MkPZyK6G0LYcK3My2LQ+T5bxghEAY= +github.com/aws/aws-sdk-go-v2/service/s3 v1.47.5/go.mod h1:vADO6Jn+Rq4nDtfwNjhgR84qkZwiC6FqCaXdw/kYwjA= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 h1:ldSFWz9tEHAwHNmjx2Cvy1MjP5/L9kNoR0skc6wyOOM= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.5/go.mod h1:CaFfXLYL376jgbP7VKC96uFcU8Rlavak0UlAwk1Dlhc= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 h1:2k9KmFawS63euAkY4/ixVNsYYwrwnd5fIvgEKkfZFNM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5/go.mod h1:W+nd4wWDVkSUIox9bacmkBP5NMFQeTJ/xqNabpzSR38= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 h1:5UYvv8JUvllZsRnfrcMQ+hJ9jNICmcgKPAO1CER25Wg= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.5/go.mod h1:XX5gh4CB7wAs4KhcF46G6C8a2i7eupU19dcAAE+EydU= +github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM= +github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= diff --git a/all-examples/go/v3/local-go-s3ec b/all-examples/go/v3/local-go-s3ec new file mode 120000 index 00000000..7e5e770c --- /dev/null +++ b/all-examples/go/v3/local-go-s3ec @@ -0,0 +1 @@ +../../../test-server/go-v3-transition-server/local-go-s3ec \ No newline at end of file diff --git a/all-examples/go/v3/main.go b/all-examples/go/v3/main.go new file mode 100644 index 00000000..22732bc8 --- /dev/null +++ b/all-examples/go/v3/main.go @@ -0,0 +1,171 @@ +package main + +import ( + "context" + "fmt" + "io" + "os" + "strings" + + "github.com/aws/amazon-s3-encryption-client-go/v3/client" + "github.com/aws/amazon-s3-encryption-client-go/v3/commitment" + "github.com/aws/amazon-s3-encryption-client-go/v3/materials" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/kms" + "github.com/aws/aws-sdk-go-v2/service/s3" +) + +func main() { + // Check command line arguments + if len(os.Args) != 5 { + fmt.Printf("Usage: %s \n", os.Args[0]) + fmt.Printf("Example: %s avp-21638 s3ec-go-v3 arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 us-east-2\n", os.Args[0]) + os.Exit(1) + } + + bucketName := os.Args[1] + objectKey := os.Args[2] + kmsKeyID := os.Args[3] + region := os.Args[4] + + fmt.Println("=== S3 Encryption Client v3 Example (Go) ===") + fmt.Printf("Bucket: %s\n", bucketName) + fmt.Printf("Object Key: %s\n", objectKey) + fmt.Printf("KMS Key ID: %s\n", kmsKeyID) + fmt.Printf("Region: %s\n", region) + fmt.Println() + + // Test data for encryption + testData := "Hello, World! This is a test message for S3 encryption client v3 in Go." + fmt.Printf("Original data: %s\n", testData) + fmt.Printf("Data length: %d bytes\n", len(testData)) + fmt.Println() + + fmt.Println("--- Initialize S3 Encryption Client v3 ---") + + // Create regular S3 client + cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion(region)) + if err != nil { + fmt.Printf("Error loading AWS config: %v\n", err) + os.Exit(1) + } + s3Client := s3.NewFromConfig(cfg) + + // Create KMS client + kmsClient := kms.NewFromConfig(cfg) + + // Create KMS keyring + keyring := materials.NewKmsKeyring(kmsClient, kmsKeyID) + + // Create Cryptographic Materials Manager + cmm, err := materials.NewCryptographicMaterialsManager(keyring) + if err != nil { + fmt.Printf("Error creating CMM: %v\n", err) + os.Exit(1) + } + + // Create S3 Encryption Client v3 + encryptionClient, err := client.New(s3Client, cmm, func(options *client.EncryptionClientOptions) { + options.CommitmentPolicy = commitment.FORBID_ENCRYPT_ALLOW_DECRYPT + }) + if err != nil { + fmt.Printf("Error creating S3 Encryption Client: %v\n", err) + os.Exit(1) + } + + fmt.Println("Successfully initialized S3 Encryption Client v3") + fmt.Println("--- Encrypt and Upload Object to S3 ---") + + // Add encryption context + encryptionContext := map[string]string{ + "purpose": "example", + "version": "v3", + "language": "go", + } + + // Create context with encryption context + ctx := context.WithValue(context.Background(), "EncryptionContext", encryptionContext) + + // Upload encrypted object using S3 Encryption Client + putInput := &s3.PutObjectInput{ + Bucket: aws.String(bucketName), + Key: aws.String(objectKey), + Body: strings.NewReader(testData), + } + + _, err = encryptionClient.PutObject(ctx, putInput) + if err != nil { + if strings.Contains(err.Error(), "NoSuchBucket") { + fmt.Printf("Error: S3 bucket '%s' does not exist or is not accessible\n", bucketName) + } else if strings.Contains(err.Error(), "NotFoundException") { + fmt.Printf("Error: KMS key '%s' not found or not accessible\n", kmsKeyID) + } else { + fmt.Printf("Error uploading encrypted object: %v\n", err) + } + os.Exit(1) + } + + fmt.Println("Successfully uploaded encrypted object to S3!") + fmt.Printf(" Bucket: %s\n", bucketName) + fmt.Printf(" Key: %s\n", objectKey) + fmt.Printf(" Encryption Context: %v\n", encryptionContext) + fmt.Println() + + fmt.Println("--- Download and Decrypt Object from S3 ---") + + // Download and decrypt object using S3 Encryption Client + getInput := &s3.GetObjectInput{ + Bucket: aws.String(bucketName), + Key: aws.String(objectKey), + } + + getResponse, err := encryptionClient.GetObject(ctx, getInput) + if err != nil { + fmt.Printf("Error downloading and decrypting object: %v\n", err) + os.Exit(1) + } + defer getResponse.Body.Close() + + // Read the decrypted data + decryptedData, err := io.ReadAll(getResponse.Body) + if err != nil { + fmt.Printf("Error reading decrypted data: %v\n", err) + os.Exit(1) + } + + fmt.Println("Successfully downloaded and decrypted object from S3!") + fmt.Printf(" Object size: %d bytes\n", len(decryptedData)) + fmt.Printf(" Decrypted data: %s\n", string(decryptedData)) + fmt.Println() + + fmt.Println("--- Verify Roundtrip Success ---") + + // Verify the roundtrip was successful + if string(decryptedData) == testData { + fmt.Println("SUCCESS: Roundtrip encryption/decryption completed successfully!") + fmt.Println(" Original data matches decrypted data") + fmt.Println(" Data integrity verified") + } else { + fmt.Println("ERROR: Roundtrip failed - data mismatch") + fmt.Printf(" Original: %s\n", testData) + fmt.Printf(" Decrypted: %s\n", string(decryptedData)) + os.Exit(1) + } + + // Optionally Delete the Object + //fmt.Println("--- Cleanup ---") + // Clean up the test object using regular S3 client + // _, err = s3Client.DeleteObject(context.TODO(), &s3.DeleteObjectInput{ + // Bucket: aws.String(bucketName), + // Key: aws.String(objectKey), + // }) + // if err != nil { + // fmt.Printf("Error deleting test object: %v\n", err) + // } else { + // fmt.Println("Test object deleted from S3") + // } + + fmt.Println() + fmt.Println("=== Example completed successfully! ===") +}