From bc84cf4ff1b7ca876feb869e7d63bcb31fcc043c Mon Sep 17 00:00:00 2001 From: Adam Hamsik Date: Fri, 21 Sep 2018 17:21:08 +0200 Subject: [PATCH 1/6] Update deps, fix dockerfile and makefile Signed-off-by: Adam Hamsik --- Dockerfile | 17 +++- Gopkg.lock | 260 +++++++++++++++++++++++++++++++++++++++++++++++++---- Makefile | 34 +++---- 3 files changed, 271 insertions(+), 40 deletions(-) diff --git a/Dockerfile b/Dockerfile index 08a8d061..59251181 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,16 @@ -FROM alpine:3.6 +FROM golang:1.10.3 as builder -RUN apk add --update ca-certificates +ARG CI_COMMIT_TAG +ARG CI_COMMIT_SHA +ARG CI_DATE + +COPY . /go/src/github.com/jetstack/vault-unsealer +WORKDIR /go/src/github.com/jetstack/vault-unsealer -COPY vault-unsealer_linux_amd64 /usr/local/bin/vault-unsealer +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -tags netgo -ldflags "-w -X main.version=${CI_COMMIT_TAG} -X main.commit=${CI_COMMIT_SHA} -X main.date=${CI_DATE}" -o vault-unsealer + +FROM alpine:3.6 +RUN apk add --update ca-certificates +COPY --from=builder /go/src/github.com/jetstack/vault-unsealer/vault-unsealer /usr/local/bin/vault-unsealer -ENTRYPOINT ["/usr/local/bin/vault-unsealer"] +ENTRYPOINT ["/usr/local/bin/vault-unsealer"] \ No newline at end of file diff --git a/Gopkg.lock b/Gopkg.lock index cfbe30b2..baa8f24d 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -3,234 +3,464 @@ [[projects]] branch = "master" + digest = "1:44d2c03bc8126d8d5ed8bc7ef37efbf09d169ca2196fcc16a8dd66fb56878bce" name = "cloud.google.com/go" - packages = ["compute/metadata","iam","internal","internal/optional","internal/version","storage"] + packages = [ + "compute/metadata", + "iam", + "internal", + "internal/optional", + "internal/version", + "storage", + ] + pruneopts = "" revision = "ae792a8babd4ec16f4b1677026d838411d8b2c79" [[projects]] + digest = "1:99080c23669518951a484330eddad059c79962ea0f029f241e4437d7dd5c7e6f" name = "github.com/aws/aws-sdk-go" - packages = ["aws","aws/awserr","aws/awsutil","aws/client","aws/client/metadata","aws/corehandlers","aws/credentials","aws/credentials/ec2rolecreds","aws/credentials/endpointcreds","aws/credentials/stscreds","aws/defaults","aws/ec2metadata","aws/endpoints","aws/request","aws/session","aws/signer/v4","internal/shareddefaults","private/protocol","private/protocol/json/jsonutil","private/protocol/jsonrpc","private/protocol/query","private/protocol/query/queryutil","private/protocol/rest","private/protocol/xml/xmlutil","service/kms","service/ssm","service/sts"] + packages = [ + "aws", + "aws/awserr", + "aws/awsutil", + "aws/client", + "aws/client/metadata", + "aws/corehandlers", + "aws/credentials", + "aws/credentials/ec2rolecreds", + "aws/credentials/endpointcreds", + "aws/credentials/stscreds", + "aws/defaults", + "aws/ec2metadata", + "aws/endpoints", + "aws/request", + "aws/session", + "aws/signer/v4", + "internal/shareddefaults", + "private/protocol", + "private/protocol/json/jsonutil", + "private/protocol/jsonrpc", + "private/protocol/query", + "private/protocol/query/queryutil", + "private/protocol/rest", + "private/protocol/xml/xmlutil", + "service/kms", + "service/ssm", + "service/sts", + ] + pruneopts = "" revision = "1b176c5c6b57adb03bb982c21930e708ebca5a77" version = "v1.12.70" [[projects]] + digest = "1:55848e643a99a9dfceb19e090ce67111328fbb1780f34c62a0430994ff85fb90" name = "github.com/fatih/structs" packages = ["."] + pruneopts = "" revision = "a720dfa8df582c51dee1b36feabb906bde1588bd" version = "v1.0" [[projects]] + digest = "1:eb53021a8aa3f599d29c7102e65026242bdedce998a54837dc67f14b6a97c5fd" name = "github.com/fsnotify/fsnotify" packages = ["."] + pruneopts = "" revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" version = "v1.4.7" [[projects]] + digest = "1:a00483fe4106b86fb1187a92b5cf6915c85f294ed4c129ccbe7cb1f1a06abd46" name = "github.com/go-ini/ini" packages = ["."] + pruneopts = "" revision = "32e4c1e6bc4e7d0d8451aa6b75200d19e37a536a" version = "v1.32.0" [[projects]] + digest = "1:bcb38c8fc9b21bb8682ce2d605a7d4aeb618abc7f827e3ac0b27c0371fdb23fb" name = "github.com/golang/protobuf" - packages = ["proto","protoc-gen-go/descriptor","ptypes","ptypes/any","ptypes/duration","ptypes/timestamp"] + packages = [ + "proto", + "protoc-gen-go/descriptor", + "ptypes", + "ptypes/any", + "ptypes/duration", + "ptypes/timestamp", + ] + pruneopts = "" revision = "925541529c1fa6821df4e44ce2723319eb2be768" version = "v1.0.0" [[projects]] branch = "master" + digest = "1:09307dfb1aa3f49a2bf869dcfa4c6c06ecd3c207221bd1c1a1141f0e51f209eb" name = "github.com/golang/snappy" packages = ["."] + pruneopts = "" revision = "553a641470496b2327abcac10b36396bd98e45c9" [[projects]] + digest = "1:e097a364f4e8d8d91b9b9eeafb992d3796a41fde3eb548c1a87eb9d9f60725cf" name = "github.com/googleapis/gax-go" packages = ["."] + pruneopts = "" revision = "317e0006254c44a0ac427cc52a0e083ff0b9622f" version = "v2.0.0" [[projects]] branch = "master" + digest = "1:304c322b62533a48ac052ffee80f67087fce1bc07186cd4e610a1b0e77765836" name = "github.com/hashicorp/errwrap" packages = ["."] + pruneopts = "" revision = "7554cd9344cec97297fa6649b055a8c98c2a1e55" [[projects]] branch = "master" + digest = "1:f5d25fd7bdda08e39e01193ef94a1ebf7547b1b931bcdec785d08050598f306c" name = "github.com/hashicorp/go-cleanhttp" packages = ["."] + pruneopts = "" revision = "d5fe4b57a186c716b0e00b8c301cbd9b4182694d" [[projects]] branch = "master" + digest = "1:b46ef59de1f724e8a2b508ea2b329eaf6cac4d71cbd44ad5e3dbd4e8fd49de9b" name = "github.com/hashicorp/go-multierror" packages = ["."] + pruneopts = "" revision = "b7773ae218740a7be65057fc60b366a49b538a44" [[projects]] branch = "master" + digest = "1:ff65bf6fc4d1116f94ac305342725c21b55c16819c2606adc8f527755716937f" name = "github.com/hashicorp/go-rootcerts" packages = ["."] + pruneopts = "" revision = "6bb64b370b90e7ef1fa532be9e591a81c3493e00" [[projects]] branch = "master" + digest = "1:147d671753effde6d3bcd58fc74c1d67d740196c84c280c762a5417319499972" name = "github.com/hashicorp/hcl" - packages = [".","hcl/ast","hcl/parser","hcl/scanner","hcl/strconv","hcl/token","json/parser","json/scanner","json/token"] + packages = [ + ".", + "hcl/ast", + "hcl/parser", + "hcl/scanner", + "hcl/strconv", + "hcl/token", + "json/parser", + "json/scanner", + "json/token", + ] + pruneopts = "" revision = "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8" [[projects]] branch = "master" + digest = "1:d416038e340ad697bbf4d8c15e4acd077f851971ff940f006f227692243bc5a5" name = "github.com/hashicorp/vault" - packages = ["api","helper/compressutil","helper/jsonutil","helper/parseutil"] + packages = [ + "api", + "helper/compressutil", + "helper/jsonutil", + "helper/parseutil", + ] + pruneopts = "" revision = "8ca8b46c51847bd721a8b534925cc8f8f3ea68e4" [[projects]] + digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be" name = "github.com/inconshreveable/mousetrap" packages = ["."] + pruneopts = "" revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" version = "v1.0" [[projects]] + digest = "1:6f49eae0c1e5dab1dafafee34b207aeb7a42303105960944828c2079b92fc88e" name = "github.com/jmespath/go-jmespath" packages = ["."] + pruneopts = "" revision = "0b12d6b5" [[projects]] + digest = "1:739b2038a38cebb50e922d18f4b042c042256320fea2db094814aeef8891e0c1" name = "github.com/magiconair/properties" packages = ["."] + pruneopts = "" revision = "d419a98cdbed11a922bf76f257b7c4be79b50e73" version = "v1.7.4" [[projects]] branch = "master" + digest = "1:59d11e81d6fdd12a771321696bb22abdd9a94d26ac864787e98c9b419e428734" name = "github.com/mitchellh/go-homedir" packages = ["."] + pruneopts = "" revision = "b8bc1bf767474819792c23f32d8286a45736f1c6" [[projects]] branch = "master" + digest = "1:a31c8ff06bf8ccc1826e3a28a4132bf217a53f3b096e6a03dcac7b6a9eb796f9" name = "github.com/mitchellh/mapstructure" packages = ["."] + pruneopts = "" revision = "b4575eea38cca1123ec2dc90c26529b5c5acfcff" [[projects]] + digest = "1:d60cfeee185019d4fcd35e8c89c83aff576e4723b6100300bf67b05be961388f" name = "github.com/pelletier/go-toml" packages = ["."] + pruneopts = "" revision = "acdc4509485b587f5e675510c4f2c63e90ff68a8" version = "v1.1.0" [[projects]] branch = "master" + digest = "1:0bbb3483b2d9386cca8af0d101b636aec54d6f425b8bb1037c69c427c83c4b42" name = "github.com/sethgrid/pester" packages = ["."] + pruneopts = "" revision = "760f8913c0483b776294e1bee43f1d687527127b" [[projects]] + digest = "1:42a42c4bc67bed17f40fddf0f24d4403e25e7b96488456cf4248e6d16659d370" name = "github.com/sirupsen/logrus" packages = ["."] + pruneopts = "" revision = "d682213848ed68c0a260ca37d6dd5ace8423f5ba" version = "v1.0.4" [[projects]] + digest = "1:dae0d7dd55563fd389e7263a32d2030022ef29cceff941336e53f6520e0308c0" name = "github.com/spf13/afero" - packages = [".","mem"] + packages = [ + ".", + "mem", + ] + pruneopts = "" revision = "bb8f1927f2a9d3ab41c9340aa034f6b803f4359c" version = "v1.0.2" [[projects]] + digest = "1:6ff9b74bfea2625f805edec59395dc37e4a06458dd3c14e3372337e3d35a2ed6" name = "github.com/spf13/cast" packages = ["."] + pruneopts = "" revision = "acbeb36b902d72a7a4c18e8f3241075e7ab763e4" version = "v1.1.0" [[projects]] + digest = "1:2208a80fc3259291e43b30f42f844d18f4218036dff510f42c653ec9890d460a" name = "github.com/spf13/cobra" packages = ["."] + pruneopts = "" revision = "7b2c5ac9fc04fc5efafb60700713d4fa609b777b" version = "v0.0.1" [[projects]] branch = "master" + digest = "1:104517520aab91164020ab6524a5d6b7cafc641b2e42ac6236f6ac1deac4f66a" name = "github.com/spf13/jwalterweatherman" packages = ["."] + pruneopts = "" revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394" [[projects]] + digest = "1:261bc565833ef4f02121450d74eb88d5ae4bd74bfe5d0e862cddb8550ec35000" name = "github.com/spf13/pflag" packages = ["."] + pruneopts = "" revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66" version = "v1.0.0" [[projects]] + digest = "1:59354ad53dfe6ed1b941844cb029cd37c0377598eec3a0d49c03aee2375ef9c4" name = "github.com/spf13/viper" packages = ["."] + pruneopts = "" revision = "25b30aa063fc18e48662b86996252eabdcf2f0c7" version = "v1.0.0" [[projects]] branch = "master" + digest = "1:febc7d7c1a817016b83441742910a3eab682d5c64613fcd91fde7ca06107ea49" name = "golang.org/x/crypto" packages = ["ssh/terminal"] + pruneopts = "" revision = "1875d0a70c90e57f11972aefd42276df65e895b9" [[projects]] branch = "master" + digest = "1:57cdbf612d6928a01850051b5c09972262244ae131a40dfea4c37fd525742db5" name = "golang.org/x/net" - packages = ["context","context/ctxhttp","http2","http2/hpack","idna","internal/timeseries","lex/httplex","trace"] + packages = [ + "context", + "context/ctxhttp", + "http2", + "http2/hpack", + "idna", + "internal/timeseries", + "lex/httplex", + "trace", + ] + pruneopts = "" revision = "0ed95abb35c445290478a5348a7b38bb154135fd" [[projects]] branch = "master" + digest = "1:36417e4645d439fcd9cf732f42006b9bfce0d9dc6118d9616819a031a349bb5b" name = "golang.org/x/oauth2" - packages = [".","google","internal","jws","jwt"] + packages = [ + ".", + "google", + "internal", + "jws", + "jwt", + ] + pruneopts = "" revision = "a032972e28060ca4f5644acffae3dfc268cc09db" [[projects]] branch = "master" + digest = "1:e4853644a857f4dd587ac56235c24ab32fefa393a8955be2ff5a535b820d5e19" name = "golang.org/x/sys" - packages = ["unix","windows"] + packages = [ + "unix", + "windows", + ] + pruneopts = "" revision = "3dbebcf8efb6a5011a60c2b4591c1022a759af8a" [[projects]] branch = "master" + digest = "1:9f9562b058a594dae0c8e2388c1a802664111736845bc08885246f0e4bf99bdd" name = "golang.org/x/text" - packages = ["collate","collate/build","internal/colltab","internal/gen","internal/tag","internal/triegen","internal/ucd","language","secure/bidirule","transform","unicode/bidi","unicode/cldr","unicode/norm","unicode/rangetable"] + packages = [ + "collate", + "collate/build", + "internal/colltab", + "internal/gen", + "internal/tag", + "internal/triegen", + "internal/ucd", + "language", + "secure/bidirule", + "transform", + "unicode/bidi", + "unicode/cldr", + "unicode/norm", + "unicode/rangetable", + ] + pruneopts = "" revision = "e19ae1496984b1c655b8044a65c0300a3c878dd3" [[projects]] branch = "master" + digest = "1:4b288a37811ddbb5a3aa8aebadaf3e3845c9de1aeb90a4d22475411c524b37d4" name = "google.golang.org/api" - packages = ["cloudkms/v1","gensupport","googleapi","googleapi/internal/uritemplates","googleapi/transport","internal","iterator","option","storage/v1","transport/http"] + packages = [ + "cloudkms/v1", + "gensupport", + "googleapi", + "googleapi/internal/uritemplates", + "googleapi/transport", + "internal", + "iterator", + "option", + "storage/v1", + "transport/http", + ] + pruneopts = "" revision = "ffa5046912fde3e38fd41244f9593c99431ecfa2" [[projects]] + digest = "1:934fb8966f303ede63aa405e2c8d7f0a427a05ea8df335dfdc1833dd4d40756f" name = "google.golang.org/appengine" - packages = [".","internal","internal/app_identity","internal/base","internal/datastore","internal/log","internal/modules","internal/remote_api","internal/urlfetch","urlfetch"] + packages = [ + ".", + "internal", + "internal/app_identity", + "internal/base", + "internal/datastore", + "internal/log", + "internal/modules", + "internal/remote_api", + "internal/urlfetch", + "urlfetch", + ] + pruneopts = "" revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a" version = "v1.0.0" [[projects]] branch = "master" + digest = "1:93d113349a5f430d3af09a200ccbe6fea38a44e18a9b7dc032e6eadb75cd1cb2" name = "google.golang.org/genproto" - packages = ["googleapis/api/annotations","googleapis/iam/v1","googleapis/rpc/status"] + packages = [ + "googleapis/api/annotations", + "googleapis/iam/v1", + "googleapis/rpc/status", + ] + pruneopts = "" revision = "4eb30f4778eed4c258ba66527a0d4f9ec8a36c45" [[projects]] + digest = "1:1c1ce3d4783796c0922d16dec8b0e9be02d383888e9126718e5a5db8baa3fe6d" name = "google.golang.org/grpc" - packages = [".","balancer","balancer/base","balancer/roundrobin","codes","connectivity","credentials","encoding","grpclb/grpc_lb_v1/messages","grpclog","internal","keepalive","metadata","naming","peer","resolver","resolver/dns","resolver/passthrough","stats","status","tap","transport"] + packages = [ + ".", + "balancer", + "balancer/base", + "balancer/roundrobin", + "codes", + "connectivity", + "credentials", + "encoding", + "grpclb/grpc_lb_v1/messages", + "grpclog", + "internal", + "keepalive", + "metadata", + "naming", + "peer", + "resolver", + "resolver/dns", + "resolver/passthrough", + "stats", + "status", + "tap", + "transport", + ] + pruneopts = "" revision = "6b51017f791ae1cfbec89c52efdf444b13b550ef" version = "v1.9.2" [[projects]] branch = "v2" + digest = "1:4b4e5848dfe7f316f95f754df071bebfb40cf4482da62e17e7e1aebdf11f4918" name = "gopkg.in/yaml.v2" packages = ["."] + pruneopts = "" revision = "d670f9405373e636a5a2765eea47fac0c9bc91a4" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "1daea21c293f583ed8049d95e6731b7377b1c81010bff0772806002d7681889a" + input-imports = [ + "cloud.google.com/go/storage", + "github.com/aws/aws-sdk-go/aws", + "github.com/aws/aws-sdk-go/aws/session", + "github.com/aws/aws-sdk-go/service/kms", + "github.com/aws/aws-sdk-go/service/ssm", + "github.com/hashicorp/vault/api", + "github.com/sirupsen/logrus", + "github.com/spf13/cobra", + "github.com/spf13/viper", + "golang.org/x/oauth2/google", + "google.golang.org/api/cloudkms/v1", + ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/Makefile b/Makefile index 06425d63..03b53cad 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,8 @@ -GO_PKG = gitlab.jetstack.net/jetstack/vault-unsealer - REGISTRY := quay.io/jetstack IMAGE_NAME := vault-unsealer BUILD_TAG := build IMAGE_TAGS := canary -BUILD_IMAGE_NAME := golang:1.10.4 - -GOPATH ?= /tmp/go - CI_COMMIT_TAG ?= unknown CI_COMMIT_SHA ?= unknown @@ -16,6 +10,8 @@ help: # all - runs verify, build and docker_build targets # test - runs go_test target # build - runs go_build target + # docker - build local version of vault-unsealer + # release - build application release in container and push it to repo # verify - verifies generated files & scripts # Util targets @@ -24,28 +20,22 @@ help: all: verify build docker_build +test: go_test + build: go_build -verify: go_verify +docker: docker_build -.builder_image: - docker pull ${BUILD_IMAGE_NAME} +release: verify docker_build docker_push -# Builder image targets -####################### -docker_%: .builder_image - docker run -it \ - -v ${GOPATH}/src:/go/src \ - -v $(shell pwd):/go/src/${GO_PKG} \ - -w /go/src/${GO_PKG} \ - -e GOPATH=/go \ - ${BUILD_IMAGE_NAME} \ - /bin/sh -c "make $*" +verify: go_verify # Docker targets ################ docker_build: - docker build -t $(REGISTRY)/$(IMAGE_NAME):$(BUILD_TAG) . + docker build -t $(REGISTRY)/$(IMAGE_NAME):$(BUILD_TAG) --build-arg CI_COMMIT_TAG=${CI_COMMIT_TAG} \ + --build-arg CI_COMMIT_SHA=${CI_COMMIT_SHA} --build-arg CI_DATE=$(shell date -u +%Y-%m-%dT%H:%M:%SZ) \ + -f Dockerfile . docker_push: docker_build set -e; \ @@ -59,7 +49,9 @@ docker_push: docker_build go_verify: go_fmt go_vet go_test go_build: - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -tags netgo -ldflags '-w -X main.version=$(CI_COMMIT_TAG) -X main.commit=$(CI_COMMIT_SHA) -X main.date=$(shell date -u +%Y-%m-%dT%H:%M:%SZ)' -o vault-unsealer_linux_amd64 + CGO_ENABLED=0 go build -a -tags netgo -ldflags '-w -X main.version=$(CI_COMMIT_TAG) \ + -X main.commit=$(CI_COMMIT_SHA) -X main.date=$(shell date -u +%Y-%m-%dT%H:%M:%SZ)' \ + -o vault-unsealer go_test: go test $$(go list ./... | grep -v '/vendor/') From ac9de81b9a8f19090cdb0f356ce387235106557e Mon Sep 17 00:00:00 2001 From: Adam Hamsik Date: Fri, 28 Sep 2018 17:41:20 +0200 Subject: [PATCH 2/6] Add new mode aws-sec-ssm which is using ssm parameters type SEcureString which can be automatically decrypted by AWS KMS key. Add example terraform templates which can be used to create these from env variables. Signed-off-by: Adam Hamsik --- README.md | 4 +- cmd/root.go | 3 +- cmd/util.go | 10 ++++ docs/vault/.gitignore | 2 + docs/vault/variables.tf | 21 +++++++ docs/vault/vault.tf | 75 +++++++++++++++++++++++ pkg/kv/aws_sec_ssm/aws_sec_ssm.go | 83 ++++++++++++++++++++++++++ pkg/kv/aws_sec_ssm/aws_sec_ssm_test.go | 62 +++++++++++++++++++ 8 files changed, 257 insertions(+), 3 deletions(-) create mode 100644 docs/vault/.gitignore create mode 100644 docs/vault/variables.tf create mode 100644 docs/vault/vault.tf create mode 100644 pkg/kv/aws_sec_ssm/aws_sec_ssm.go create mode 100644 pkg/kv/aws_sec_ssm/aws_sec_ssm_test.go diff --git a/README.md b/README.md index 5ad92581..a05a462c 100755 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ This is a CLI tool to help automate the setup and management of Hashicorp Vault. It will continuously attempt to unseal the target Vault instance, by retrieving -unseal keys from a Google Cloud KMS keyring. +unseal keys from a Google/AWS Cloud KMS keyring. Usage: vault-unsealer [command] @@ -30,7 +30,7 @@ Flags: --google-cloud-storage-bucket string The name of the Google Cloud Storage bucket to store values in --google-cloud-storage-prefix string The prefix to use for values store in Google Cloud Storage -h, --help help for vault-unsealer - --mode string Select the mode to use 'google-cloud-kms-gcs' => Google Cloud Storage with encryption using Google KMS; 'aws-kms-ssm' => AWS SSM parameter store using AWS KMS encryption (default "google-cloud-kms-gcs") + --mode string Select the mode to use 'google-cloud-kms-gcs' => Google Cloud Storage with encryption using Google KMS; 'aws-kms-ssm' => AWS SSM parameter store using AWS KMS encryption; 'aws-sec-ssm' => AWS SSM parameter mode using Secure strings and KMS key for encryption (default "google-cloud-kms-gcs") --secret-shares int Total count of secret shares that exist (default 1) --secret-threshold int Minimum required secret shares to unseal (default 1) diff --git a/cmd/root.go b/cmd/root.go index aa6fde1a..85836138 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -17,6 +17,7 @@ const cfgSecretThreshold = "secret-threshold" const cfgMode = "mode" const cfgModeValueAWSKMSSSM = "aws-kms-ssm" +const cfgModeValueAWSSECSSM = "aws-sec-ssm" const cfgModeValueGoogleCloudKMSGCS = "google-cloud-kms-gcs" const cfgModeValueLocal = "local" @@ -78,7 +79,7 @@ func init() { configStringVar( cfgMode, cfgModeValueGoogleCloudKMSGCS, - fmt.Sprintf("Select the mode to use '%s' => Google Cloud Storage with encryption using Google KMS; '%s' => AWS SSM parameter store using AWS KMS encryption; %s => Use local keys in path", cfgModeValueGoogleCloudKMSGCS, cfgModeValueAWSKMSSSM, cfgModeValueLocal), + fmt.Sprintf("Select the mode to use '%s' => Google Cloud Storage with encryption using Google KMS; '%s' => AWS SSM parameter store using AWS KMS encryption; '%s' => AWS SSM parameter mode using Secure strings and KMS key for encryption; %s => Use local keys in path", cfgModeValueGoogleCloudKMSGCS, cfgModeValueAWSKMSSSM, cfgModeValueAWSSECSSM, cfgModeValueLocal), ) // Secret config diff --git a/cmd/util.go b/cmd/util.go index 85e9c7a9..2f5ad0ee 100644 --- a/cmd/util.go +++ b/cmd/util.go @@ -7,6 +7,7 @@ import ( "github.com/jetstack/vault-unsealer/pkg/kv" "github.com/jetstack/vault-unsealer/pkg/kv/aws_kms" + "github.com/jetstack/vault-unsealer/pkg/kv/aws_sec_ssm" "github.com/jetstack/vault-unsealer/pkg/kv/aws_ssm" "github.com/jetstack/vault-unsealer/pkg/kv/cloudkms" "github.com/jetstack/vault-unsealer/pkg/kv/gcs" @@ -69,6 +70,13 @@ func kvStoreForConfig(cfg *viper.Viper) (kv.Service, error) { } return kms, nil + case cfgModeValueAWSSECSSM: + ssm, err := aws_sec_ssm.New(cfg.GetString(cfgAWSSSMKeyPrefix), cfg.GetString(cfgAWSKMSKeyID)) + if err != nil { + return nil, fmt.Errorf("error creating AWS SSM using Secure parameters kv store: %s", err.Error()) + } + + return ssm, nil case cfgModeValueLocal: return local.New(cfg.GetString(cfgLocalKeyDir)) @@ -76,4 +84,6 @@ func kvStoreForConfig(cfg *viper.Viper) (kv.Service, error) { default: return nil, fmt.Errorf("Unsupported backend mode: '%s'", cfg.GetString(cfgMode)) } + + return nil, fmt.Errorf("Unsupported backend mode: '%s'", cfg.GetString(cfgMode)) } diff --git a/docs/vault/.gitignore b/docs/vault/.gitignore new file mode 100644 index 00000000..c475f0a7 --- /dev/null +++ b/docs/vault/.gitignore @@ -0,0 +1,2 @@ +.env +.terraform \ No newline at end of file diff --git a/docs/vault/variables.tf b/docs/vault/variables.tf new file mode 100644 index 00000000..9c09c39f --- /dev/null +++ b/docs/vault/variables.tf @@ -0,0 +1,21 @@ +variable "environment" { + description = "Environment tag description" + default = "dev" +} + +variable "vault_unseal_key0" { + type = "string" + description = "" +} +variable "vault_unseal_key1" { + type = "string" + description = "" +} +variable "vault_unseal_key2" { + type = "string" + description = "" +} +variable "vault_unseal_key3" { + type = "string" + description = "" +} \ No newline at end of file diff --git a/docs/vault/vault.tf b/docs/vault/vault.tf new file mode 100644 index 00000000..65aa7960 --- /dev/null +++ b/docs/vault/vault.tf @@ -0,0 +1,75 @@ +terraform { + backend "s3" { + bucket = "vault-store" + key = "terraform.vault.state" + region = "us-east-1" + } +} + +provider "aws" { + region = "eu-west-1" +} + +resource "aws_kms_key" "vault_kms_key" { + description = "Vault dev kms key" + tags { + Environment = "${var.environment}" + Terraform = "true" + } +} + +resource "aws_kms_alias" "vault_kms_key_alias" { + name = "alias/${var.environment}-vault" + target_key_id = "${aws_kms_key.vault_kms_key.key_id}" +} + +resource "aws_ssm_parameter" "vault-unseal-0" { + name = "${var.environment}-vault-unseal-0" + description = "Vault Unseal key number 0" + type = "SecureString" + value = "${var.vault_unseal_key0}" + key_id = "${aws_kms_key.vault_kms_key.key_id}" + + tags { + Environment = "${var.environment}" + Terraform = "true" + } +} +resource "aws_ssm_parameter" "vault-unseal-1" { + name = "${var.environment}-vault-unseal-1" + description = "Vault Unseal key number 1" + type = "SecureString" + value = "${var.vault_unseal_key1}" + key_id = "${aws_kms_key.vault_kms_key.key_id}" + + tags { + Environment = "${var.environment}" + Terraform = "true" + } +} + +resource "aws_ssm_parameter" "vault-unseal-2" { + name = "${var.environment}-vault-unseal-2" + description = "Vault Unseal key number 2" + type = "SecureString" + value = "${var.vault_unseal_key2}" + key_id = "${aws_kms_key.vault_kms_key.key_id}" + + tags { + Environment = "${var.environment}" + Terraform = "true" + } +} + +resource "aws_ssm_parameter" "vault-unseal-3" { + name = "${var.environment}-vault-unseal-3" + description = "Vault Unseal key number 3" + type = "SecureString" + value = "${var.vault_unseal_key3}" + key_id = "${aws_kms_key.vault_kms_key.key_id}" + + tags { + Environment = "${var.environment}" + Terraform = "true" + } +} \ No newline at end of file diff --git a/pkg/kv/aws_sec_ssm/aws_sec_ssm.go b/pkg/kv/aws_sec_ssm/aws_sec_ssm.go new file mode 100644 index 00000000..10cfcee2 --- /dev/null +++ b/pkg/kv/aws_sec_ssm/aws_sec_ssm.go @@ -0,0 +1,83 @@ +package aws_sec_ssm + +import ( + "fmt" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/ssm" + + "github.com/jetstack/vault-unsealer/pkg/kv" +) + +type awsSSM struct { + ssmService *ssm.SSM + + keyPrefix string + kmsID string +} + +var _ kv.Service = &awsSSM{} + +func NewWithSession(sess *session.Session, keyPrefix string, kmsID string) (*awsSSM, error) { + return &awsSSM{ + ssmService: ssm.New(sess), + keyPrefix: keyPrefix, + kmsID: kmsID, + }, nil +} + +func New(keyPrefix string, kmsID string) (*awsSSM, error) { + sess, err := session.NewSession() + if err != nil { + return nil, err + } + + return NewWithSession(sess, keyPrefix, kmsID) +} + +func (a *awsSSM) Get(key string) ([]byte, error) { + out, err := a.ssmService.GetParameters(&ssm.GetParametersInput{ + Names: []*string{ + aws.String(a.name(key)), + }, + WithDecryption: aws.Bool(true), + }) + if err != nil { + return []byte{}, err + } + + if len(out.Parameters) < 1 { + return []byte{}, kv.NewNotFoundError("key '%s' not found", key) + } + + return []byte(*out.Parameters[0].Value), nil +} + +func (a *awsSSM) name(key string) string { + return fmt.Sprintf("%s%s", a.keyPrefix, key) +} + +func (a *awsSSM) Set(key string, val []byte) error { + _, err := a.ssmService.PutParameter(&ssm.PutParameterInput{ + Description: aws.String("vault-unsealer"), + Name: aws.String(a.name(key)), + Overwrite: aws.Bool(true), + Value: aws.String(string(val)), + Type: aws.String("SecureString"), + KeyId: aws.String(a.kmsID), + }) + return err +} + +func (a *awsSSM) Delete(key string) error { + _, err := a.ssmService.DeleteParameter(&ssm.DeleteParameterInput{ + Name: aws.String(a.name(key)), + }) + return err +} + +func (g *awsSSM) Test(key string) error { + // TODO: Implement a test if a Set is likely to work, AWS doesn't seemt to provide a dry-run on the parameter store + return nil +} diff --git a/pkg/kv/aws_sec_ssm/aws_sec_ssm_test.go b/pkg/kv/aws_sec_ssm/aws_sec_ssm_test.go new file mode 100644 index 00000000..886ebd49 --- /dev/null +++ b/pkg/kv/aws_sec_ssm/aws_sec_ssm_test.go @@ -0,0 +1,62 @@ +package aws_sec_ssm + +import ( + "os" + "testing" + + "github.com/jetstack/vault-unsealer/pkg/kv" +) + +func TestAWSIntegration(t *testing.T) { + region := os.Getenv("AWS_REGION") + + if region == "" { + t.Skip("Skip AWS integration tests: not environment variable 'AWS_REGION' specified") + } + + payloadKey := "test123" + payloadValue := "payload123" + + a, err := New("test-integration-") + if err != nil { + t.Errorf("Unexpected error creating SSM kv: %s", err) + } + + // graceful set (in case it's already existing) + err = a.Set(payloadKey, []byte(payloadValue)) + if err != nil { + t.Errorf("Unexpected error storing value in SSM kv: %s", err) + } + + // this should also work and overwrite a key + err = a.Set(payloadKey, []byte(payloadValue)) + if err != nil { + t.Errorf("Unexpected error storing value in SSM kv: %s", err) + } + + // this deletes the key + err = a.Delete(payloadKey) + if err != nil { + t.Errorf("Unexpected error storing value in SSM kv: %s", err) + } + + _, err = a.Get(payloadKey) + if _, ok := err.(*kv.NotFoundError); !ok { + t.Errorf("Expected an kv.NotFoundError for a non existing key") + } + + err = a.Set(payloadKey, []byte(payloadValue)) + if err != nil { + t.Errorf("Unexpected error storing value in SSM kv: %s", err) + } + + out, err := a.Get("test123") + if err != nil { + t.Errorf("Unexpected error storing value in SSM kv: %s", err) + } + + if exp, act := payloadValue, string(out); exp != act { + t.Errorf("Unexpected decrypt output: exp=%s act=%s", exp, act) + } + +} From dbccd3feadfa5513c941bfd506faa258f270300a Mon Sep 17 00:00:00 2001 From: Adam Hamsik Date: Thu, 11 Oct 2018 11:06:31 +0200 Subject: [PATCH 3/6] Add some todo. Signed-off-by: Adam Hamsik --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index a05a462c..08937c02 100755 --- a/README.md +++ b/README.md @@ -53,3 +53,9 @@ make -C $(go env GOPATH)/src/github.com/jetstack/vault-unsealer build ```bash docker build -t vault-unsealer: . ``` + +## TODO + +1) Add support for kubernetes leader election + + https://github.com/kubernetes/contrib/tree/master/election \ No newline at end of file From 21521297746180fbb70e19b644cbe39b2fc664e1 Mon Sep 17 00:00:00 2001 From: Adam Hamsik Date: Thu, 25 Oct 2018 17:41:43 +0200 Subject: [PATCH 4/6] Add release notes Signed-off-by: Adam Hamsik --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0531014b..acb2901d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. +## [0.3.4] - 2018-10-11 + +### Added + +* Adds new mode aws-sec-ssm which is using ssm parameters type SEcureString which can be automatically decrypted by AWS KMS key +* Update Dockerfile to multistage build format + ## [0.3.0] - 2017-09-03 ### Added From d5d2b36e5d91259e4e141f4bca0511740809bd59 Mon Sep 17 00:00:00 2001 From: Adam Hamsik Date: Fri, 26 Oct 2018 11:10:11 +0200 Subject: [PATCH 5/6] Fix go_vet check. Signed-off-by: Adam Hamsik --- pkg/kv/aws_sec_ssm/aws_sec_ssm_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kv/aws_sec_ssm/aws_sec_ssm_test.go b/pkg/kv/aws_sec_ssm/aws_sec_ssm_test.go index 886ebd49..1057002c 100644 --- a/pkg/kv/aws_sec_ssm/aws_sec_ssm_test.go +++ b/pkg/kv/aws_sec_ssm/aws_sec_ssm_test.go @@ -17,7 +17,7 @@ func TestAWSIntegration(t *testing.T) { payloadKey := "test123" payloadValue := "payload123" - a, err := New("test-integration-") + a, err := New("test-integration-", "TestKMSIDkey") if err != nil { t.Errorf("Unexpected error creating SSM kv: %s", err) } From c23a40f0a5623a9f9f477422eae108c6eb916d19 Mon Sep 17 00:00:00 2001 From: Adam Hamsik Date: Fri, 26 Oct 2018 11:11:25 +0200 Subject: [PATCH 6/6] Remove unreachable return. Signed-off-by: Adam Hamsik --- cmd/util.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmd/util.go b/cmd/util.go index 2f5ad0ee..338f7ff8 100644 --- a/cmd/util.go +++ b/cmd/util.go @@ -84,6 +84,4 @@ func kvStoreForConfig(cfg *viper.Viper) (kv.Service, error) { default: return nil, fmt.Errorf("Unsupported backend mode: '%s'", cfg.GetString(cfgMode)) } - - return nil, fmt.Errorf("Unsupported backend mode: '%s'", cfg.GetString(cfgMode)) }