Skip to content

Instantly share code, notes, and snippets.

@cornfeedhobo
Created January 9, 2025 23:23
Show Gist options
  • Save cornfeedhobo/c15735331210c7923323372aa09aa5bd to your computer and use it in GitHub Desktop.
Save cornfeedhobo/c15735331210c7923323372aa09aa5bd to your computer and use it in GitHub Desktop.
quick and dirty cli to pull objects that were client side encrypted
package main
import (
"context"
"fmt"
"io"
"net/url"
"os"
"strings"
"github.com/aws/amazon-s3-encryption-client-go/v3/client"
"github.com/aws/amazon-s3-encryption-client-go/v3/materials"
"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"
"github.com/aws/aws-sdk-go/aws"
"github.com/urfave/cli/v3"
)
func main() {
ctx := context.Background()
if err := (&cli.Command{
Name: "s3-encryption-client-cli",
Usage: "quick and dirty cli to pull objects that were client side encrypted",
ArgsUsage: "<s3 uri> <kms alias name>",
Action: cmd,
}).Run(ctx, os.Args); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
}
}
func cmd(ctx context.Context, cmd *cli.Command) error {
uri := cmd.Args().Get(0)
kmsAlias := cmd.Args().Get(1)
url, err := url.Parse(uri)
if err != nil {
return fmt.Errorf("failed to parse provided url, %w", err)
}
bucket := url.Host
fmt.Printf("Bucket: %s\n", bucket)
key := strings.TrimPrefix(url.Path, "/")
fmt.Printf("Key: %s\n", key)
// Using the SDK's default configuration, loading additional config
// and credentials values from the environment variables, shared
// credentials, and shared configuration files
cfg, err := config.LoadDefaultConfig(ctx)
if err != nil {
return fmt.Errorf("unable to load SDK config, %w", err)
}
s3Client := s3.NewFromConfig(cfg)
// head (stat?) object
_, err = s3Client.HeadObject(ctx, &s3.HeadObjectInput{Bucket: &bucket, Key: &key})
if err != nil {
return fmt.Errorf("failed to list s3 object, %w", err)
}
kmsClient := kms.NewFromConfig(cfg)
kmsAliases, err := kmsClient.ListAliases(ctx, &kms.ListAliasesInput{})
if err != nil {
return fmt.Errorf("failed to list aliases, %w", err)
}
// Find the alias and print the Key ARN
var kmsKeyArn string
for _, alias := range kmsAliases.Aliases {
if strings.HasSuffix(*alias.AliasName, kmsAlias) {
kmsKeyArn = *alias.TargetKeyId
break
}
}
if kmsKeyArn == "" {
return fmt.Errorf("kms alias `%v` not found", kmsAlias)
}
fmt.Printf("KMS Key ARN: %s\n", kmsKeyArn)
// Create the keyring and &CMM-long; (&CMM-short;)
cmm, err := materials.NewCryptographicMaterialsManager(
materials.NewKmsKeyring(
kmsClient,
kmsKeyArn,
func(options *materials.KeyringOptions) {
options.EnableLegacyWrappingAlgorithms = true
},
),
)
if err != nil {
return fmt.Errorf("error while creating new CMM")
}
s3EncryptionClient, err := client.New(s3Client, cmm)
if err != nil {
return fmt.Errorf("error creating encryption client, %w", err)
}
out, err := s3EncryptionClient.GetObject(ctx, &s3.GetObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
})
if err != nil {
return fmt.Errorf("error calling getObject, %w", err)
}
content, err := io.ReadAll(out.Body)
if err != nil {
return fmt.Errorf("error reading object bytes, %w", err)
}
fmt.Printf("%s\n", content)
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment