diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml new file mode 100644 index 00000000..30e47a06 --- /dev/null +++ b/.github/workflows/examples.yml @@ -0,0 +1,115 @@ +name: Run Examples + +on: + workflow_call: + +jobs: + run-examples: + runs-on: macos-14-large + permissions: + id-token: write + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@v5 + with: + submodules: true + token: ${{ secrets.PAT_FOR_PRIVATE_RUBY }} + + - name: Checkout CPP code for cpp-v2-transition + uses: actions/checkout@v5 + with: + submodules: recursive + token: ${{ secrets.PAT_FOR_CPP }} + repository: awslabs/aws-sdk-cpp-staging + ref: fire-egg-dev + path: test-server/cpp-v2-transition-server/aws-sdk-cpp/ + + - name: Checkout CPP code cpp-v3 + uses: actions/checkout@v5 + with: + submodules: recursive + token: ${{ secrets.PAT_FOR_CPP }} + repository: awslabs/aws-sdk-cpp-staging + ref: fire-egg-dev + path: test-server/cpp-v3-server/aws-sdk-cpp/ + + - name: Checkout .NET V2 code + uses: actions/checkout@v5 + with: + token: ${{ secrets.PAT_FOR_DOTNET }} + repository: aws/private-amazon-s3-encryption-client-dotnet-staging + ref: v3sdk-development + path: test-server/net-v2-v3-server/s3ec-net-v2/ + + - name: Checkout .NET V3 code + uses: actions/checkout@v5 + with: + token: ${{ secrets.PAT_FOR_DOTNET }} + repository: aws/private-amazon-s3-encryption-client-dotnet-staging + ref: s3ec-v3 + path: test-server/net-v2-v3-server/s3ec-net-v3 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.4" + + - name: Set up PHP with Composer + uses: shivammathur/setup-php@verbose + with: + php-version: "8.1" + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: 1.24 + + # Cache uv dependencies + - name: Cache uv dependencies + uses: actions/cache@v3 + with: + path: ~/.cache/uv + key: ${{ runner.os }}-uv-${{ hashFiles('./test-server/python-v3-server/**/pyproject.toml') }} + restore-keys: | + ${{ runner.os }}-uv- + + - name: Install Uv + run: pip install uv + + # Cache Gradle dependencies and build outputs + - name: Cache Gradle packages + uses: actions/cache@v4 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + test-server/java-v3-server/.gradle + test-server/java-tests/.gradle + key: ${{ runner.os }}-gradle-${{ hashFiles('test-server/java-v3-server/**/*.gradle*', 'test-server/java-tests/**/gradle-wrapper.properties', 'test-server/java-tests/**/*.gradle*', 'test-server/java-v3-server/**/gradle-wrapper.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: arn:aws:iam::370957321024:role/S3EC-Python-Github-test-role + aws-region: us-west-2 + + - name: Install dependencies for all examples + working-directory: ./all-examples + run: make install + + - name: Run all examples + working-directory: ./all-examples + run: make run + env: + AWS_REGION: us-west-2 + BUCKET_NAME: ${{ vars.TEST_SERVER_S3_BUCKET }} + KMS_KEY_ID: ${{ vars.TEST_SERVER_KMS_KEY_ARN }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 52c3e465..d53b9dca 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -35,3 +35,11 @@ jobs: name: Run Duvet uses: ./.github/workflows/duvet.yml secrets: inherit + + run-examples: + permissions: + id-token: write + contents: read + name: Run Examples + uses: ./.github/workflows/examples.yml + secrets: inherit diff --git a/all-examples/Makefile b/all-examples/Makefile new file mode 100644 index 00000000..7dac8ce6 --- /dev/null +++ b/all-examples/Makefile @@ -0,0 +1,110 @@ +# Makefile for S3 Encryption Client Examples +# Runs make commands across all language/version directories + +# Default target +.PHONY: all install clean run help list-examples + +# Find all directories with Makefiles +EXAMPLE_DIRS := $(shell find . -name Makefile -not -path "./Makefile" | xargs dirname | sed 's|^\./||' | $(if $(FILTER),grep -E "$$(echo '$(FILTER)' | sed 's/,/|/g')",cat) | sort) + +all: install + +# Install dependencies for all examples +install: + @echo "Installing dependencies for all examples..." + @failed=0; \ + for dir in $(EXAMPLE_DIRS); do \ + echo ""; \ + echo "=== Installing dependencies in $$dir ==="; \ + if (cd $$dir && $(MAKE) install); then \ + echo "✓ Successfully installed dependencies in $$dir"; \ + else \ + echo "✗ Failed to install dependencies in $$dir"; \ + failed=$$((failed + 1)); \ + fi; \ + done; \ + echo ""; \ + if [ $$failed -eq 0 ]; then \ + echo "All dependencies installed successfully!"; \ + else \ + echo "$$failed example(s) failed to install dependencies"; \ + exit 1; \ + fi + +# Clean all examples +clean: + @echo "Cleaning all examples..." + @failed=0; \ + for dir in $(EXAMPLE_DIRS); do \ + echo ""; \ + echo "=== Cleaning $$dir ==="; \ + if (cd $$dir && $(MAKE) clean); then \ + echo "✓ Successfully cleaned $$dir"; \ + else \ + echo "✗ Failed to clean $$dir"; \ + failed=$$((failed + 1)); \ + fi; \ + done; \ + echo ""; \ + if [ $$failed -eq 0 ]; then \ + echo "All examples cleaned successfully!"; \ + else \ + echo "$$failed example(s) failed to clean"; \ + exit 1; \ + fi + +# Run all examples with default parameters +run: + @echo "Running all examples with default parameters..." + @failed=0; \ + for dir in $(EXAMPLE_DIRS); do \ + echo ""; \ + echo "=== Running example in $$dir ==="; \ + if (cd $$dir && $(MAKE) run); then \ + echo "✓ Successfully ran example in $$dir"; \ + else \ + echo "✗ Failed to run example in $$dir"; \ + failed=$$((failed + 1)); \ + fi; \ + done; \ + echo ""; \ + if [ $$failed -eq 0 ]; then \ + echo "All examples completed successfully!"; \ + else \ + echo "$$failed example(s) failed to run"; \ + exit 1; \ + fi + +# List all available examples +list-examples: + @echo "Available S3 Encryption Client examples:" + @for dir in $(EXAMPLE_DIRS); do \ + echo " $$dir"; \ + done + +# Show help +help: + @echo "S3 Encryption Client Examples Makefile" + @echo "" + @echo "Available targets:" + @echo " install - Install dependencies for all examples" + @echo " run - Run all examples with default parameters" + @echo " clean - Clean all examples" + @echo " list-examples - List all available example directories" + @echo " help - Show this help message" + @echo "" + @echo "Filtering examples:" + @echo " Use FILTER to run commands on specific examples:" + @echo " make install FILTER=go # Only Go examples" + @echo " make run FILTER=v4 # Only v4 examples" + @echo " make clean FILTER=go/v3,ruby # Go v3 and Ruby examples" + @echo "" + @echo "Individual example usage:" + @echo " To work with a specific example, cd into its directory and use its Makefile:" + @echo " cd go/v4 && make run" + @echo " cd ruby/v2 && make install" + @echo "" + @echo "Available examples:" + @for dir in $(EXAMPLE_DIRS); do \ + echo " $$dir"; \ + done diff --git a/all-examples/go/v4/Makefile b/all-examples/go/v4/Makefile new file mode 100644 index 00000000..1e8307e7 --- /dev/null +++ b/all-examples/go/v4/Makefile @@ -0,0 +1,69 @@ +# Makefile for S3 Encryption Client Go v4 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-v4 +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 v4 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 v4 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 v4 Go SDK (included in local-go-s3ec)" diff --git a/all-examples/go/v4/README.md b/all-examples/go/v4/README.md new file mode 100644 index 00000000..b6972f26 --- /dev/null +++ b/all-examples/go/v4/README.md @@ -0,0 +1,55 @@ +# S3 Encryption Client Go v4 Example + +This example demonstrates how to use the Amazon S3 Encryption Client v4 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 v4 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-v4-test arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 us-east-2 +``` diff --git a/all-examples/go/v4/go.mod b/all-examples/go/v4/go.mod new file mode 100644 index 00000000..48bea56e --- /dev/null +++ b/all-examples/go/v4/go.mod @@ -0,0 +1,32 @@ +module github.com/aws/amazon-s3-encryption-client-python/all-examples/go/v4 + +go 1.24 + +require ( + github.com/aws/amazon-s3-encryption-client-go/v4 v4.0.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 V4 uses a local submodule for development +replace github.com/aws/amazon-s3-encryption-client-go/v4 => ./local-go-s3ec/v4 diff --git a/all-examples/go/v4/go.sum b/all-examples/go/v4/go.sum new file mode 100644 index 00000000..244c8814 --- /dev/null +++ b/all-examples/go/v4/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/v4/local-go-s3ec b/all-examples/go/v4/local-go-s3ec new file mode 120000 index 00000000..d06737d9 --- /dev/null +++ b/all-examples/go/v4/local-go-s3ec @@ -0,0 +1 @@ +../../../test-server/go-v4-server/local-go-s3ec \ No newline at end of file diff --git a/all-examples/go/v4/main.go b/all-examples/go/v4/main.go new file mode 100644 index 00000000..a1227790 --- /dev/null +++ b/all-examples/go/v4/main.go @@ -0,0 +1,171 @@ +package main + +import ( + "context" + "fmt" + "io" + "os" + "strings" + + "github.com/aws/amazon-s3-encryption-client-go/v4/client" + "github.com/aws/amazon-s3-encryption-client-go/v4/commitment" + "github.com/aws/amazon-s3-encryption-client-go/v4/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-v4 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 v4 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 v4 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 v4 ---") + + // 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 v4 + encryptionClient, err := client.New(s3Client, cmm, func(options *client.EncryptionClientOptions) { + options.CommitmentPolicy = commitment.REQUIRE_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 v4") + fmt.Println("--- Encrypt and Upload Object to S3 ---") + + // Add encryption context + encryptionContext := map[string]string{ + "purpose": "example", + "version": "v4", + "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! ===") +} diff --git a/all-examples/ruby/v2/main.rb b/all-examples/ruby/v2/main.rb index 51d85cc9..3fc86f7c 100644 --- a/all-examples/ruby/v2/main.rb +++ b/all-examples/ruby/v2/main.rb @@ -4,6 +4,9 @@ require 'aws-sdk-kms' require 'json' +# See: https://github.com/ruby/openssl/issues/949 +Aws.use_bundled_cert! + def main # Check command line arguments if ARGV.length != 4 diff --git a/all-examples/ruby/v3/main.rb b/all-examples/ruby/v3/main.rb index fb15f317..59743515 100644 --- a/all-examples/ruby/v3/main.rb +++ b/all-examples/ruby/v3/main.rb @@ -4,6 +4,9 @@ require 'aws-sdk-kms' require 'json' +# See: https://github.com/ruby/openssl/issues/949 +Aws.use_bundled_cert! + def main # Check command line arguments if ARGV.length != 4 diff --git a/test-server/go-v4-server/local-go-s3ec b/test-server/go-v4-server/local-go-s3ec index 6a2a7fe0..9946186d 160000 --- a/test-server/go-v4-server/local-go-s3ec +++ b/test-server/go-v4-server/local-go-s3ec @@ -1 +1 @@ -Subproject commit 6a2a7fe0418ceebc1b555c0f79b6328896e81939 +Subproject commit 9946186d6b760074750a535b663d6c84c5815308