diff --git a/.gitignore b/.gitignore index f1c181e..120976f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,6 @@ # Output of the go coverage tool, specifically when used with LiteIDE *.out + +# output binary +decrypt-and-start diff --git a/README.md b/README.md new file mode 100644 index 0000000..0285326 --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# decrypt-and-start + +This project began as a shell script to invoke the `kms-encryption decrypt` +on the variables in the environment, looking for anything with a prefix of +"decrypt:", decrypting it using AWS KMS using the instance's profile, and +exporting the decrypted value back to the environment before exec to the +next command. + +This is used as a Docker entrypoint for containers to be able to decrypt +encrypted environment variables passed into it. + +## Usage + +This project is a replacement for the ApplauseOSS/kms-encryption-toolbox +supplied shell script, `decrypt-and-start`. + + diff --git a/ci/build.sh b/ci/build.sh new file mode 100755 index 0000000..94c79d9 --- /dev/null +++ b/ci/build.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# Assumes go is installed + +go get ./... + +go build diff --git a/ci/test.sh b/ci/test.sh new file mode 100755 index 0000000..a3bacaa --- /dev/null +++ b/ci/test.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +ENC_VAR=$(go run test/encrypt-string.go) +./decrypt-and-start env | grep ENV_VAR diff --git a/decrypt-and-start.go b/decrypt-and-start.go new file mode 100644 index 0000000..34baf6d --- /dev/null +++ b/decrypt-and-start.go @@ -0,0 +1,66 @@ +package main + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/ec2metadata" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/kms" + + "encoding/base64" + "flag" + "fmt" + "log" + "os" + "os/exec" + "strings" + "syscall" +) + +// This function should work like an entrypoint: exec "${@}" +func Exec() { + flag.Parse() + if len(os.Args) == 1 { + return + } + cmd, err := exec.LookPath(os.Args[1]) + if err != nil { + log.Fatal(err) + } + if err := syscall.Exec(cmd, flag.Args(), os.Environ()); err != nil { + log.Fatal(err) + } +} + +func main() { + // Initialize a "fake" session to get our region + metaSession, _ := session.NewSession() + metaClient := ec2metadata.New(metaSession) + region, _ := metaClient.Region() + conf := aws.NewConfig().WithRegion(region) + // Initialize KMS session + sess := session.Must(session.NewSession(conf)) + // KMS service client + svc := kms.New(sess) + for _, e := range os.Environ() { + // e = each k=v pair/line, pair = split k = [0], v = [1] array + pair := strings.SplitN(e, "=", 2) + // See if value starts with 'decrypt:' + if strings.HasPrefix(pair[1], "decrypt:") { + fmt.Println("Decrypting " + pair[0] + " ...") + cyphertext, err := base64.URLEncoding.DecodeString(strings.TrimPrefix(pair[1], "decrypt:")) + if err != nil { + log.Fatal(err) + } + // blob := []byte(string(cyphertext)) + blob := cyphertext + // decrypt data + result, err := svc.Decrypt(&kms.DecryptInput{CiphertextBlob: blob}) + if err != nil { + log.Fatal(err) + } + decrypted_value := string(result.Plaintext) + os.Setenv(pair[0], decrypted_value) + } + } + Exec() +} diff --git a/test/encrypt-string.go b/test/encrypt-string.go new file mode 100644 index 0000000..62161d5 --- /dev/null +++ b/test/encrypt-string.go @@ -0,0 +1,55 @@ +package main + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/kms" + + "encoding/base64" + "flag" + "fmt" + "log" + "os" + "os/exec" + // "strings" + "syscall" +) + +// This function should work like an entrypoint: exec "${@}" +func Exec() { + flag.Parse() + if len(os.Args) == 1 { + return + } + cmd, err := exec.LookPath(os.Args[1]) + if err != nil { + log.Fatal(err) + } + if err := syscall.Exec(cmd, flag.Args(), os.Environ()); err != nil { + log.Fatal(err) + } +} + +func main() { + // Initialize KMS session + // sess := session.Must(session.NewSessionWithOptions(session.Options{ + // SharedConfigState: session.SharedConfigEnable, + // })) + sess := session.Must(session.NewSession(&aws.Config{ + Region: aws.String("us-east-1"), + })) + cmk_arn := "arn:aws:kms:us-east-1:873559269338:key/1b03c937-31f8-4fa5-a5cf-42e9f437bda2" + // KMS service client + svc := kms.New(sess) + + text := "some-encrypted-string" + + result, err := svc.Encrypt(&kms.EncryptInput{ + KeyId: aws.String(cmk_arn), + Plaintext: []byte(text), + }) + if err != nil { + log.Fatal(err) + } + fmt.Println(base64.URLEncoding.EncodeToString(result.CiphertextBlob)) +}