Skip to content

milosgajdos/vaultops

Repository files navigation

vaultops: automate vault setup

Build Status go.dev reference Go Report Card License

vaultops is a command line utility which aims to simplify vault server setup. At the moment it supports automatic initialization and unsealing.

Motivation

Typical vault setup usually requires taking several steps before the server can be used:

  • initializing vault server
  • unsealing vault server(s)
  • mounting vault backends
  • creating vault backend roles
  • configuring vault policies

The above listed tasks are usually performed using the vault command line client which interacts with vault servers. Using the vault command line client requires writing a lot of shell scripts which often grow into unmanageable full fledged monsters which are often hard to debug and maintain.

vaultops attempts to address this problem by providing a simple manifest file which can be used to specify all the tasks required to perform vault setup once the vault server/cluster is running. vaultops reads the manifest file and performs all the actions requsted by user.

Quick start

Get the project:

$ go get -u github.com/milosgajdos/vaultops

Run the tests

$ cd $GOPATH/src/github.com/milosgajdos/vaultops
$ make test
for pkg in github.com/milosgajdos/vaultops github.com/milosgajdos/vaultops/cipher github.com/milosgajdos/vaultops/cloud/aws github.com/milosgajdos/vaultops/cloud/gcp github.com/milosgajdos/vaultops/command github.com/milosgajdos/vaultops/manifest github.com/milosgajdos/vaultops/store github.com/milosgajdos/vaultops/store/local; do \
		go test -coverprofile="../../../$pkg/coverage.txt" -covermode=atomic $pkg || exit; \
	done
?   	github.com/milosgajdos/vaultops	[no test files]
?   	github.com/milosgajdos/vaultops/cipher	[no test files]
ok  	github.com/milosgajdos/vaultops/cloud/aws	0.022s	coverage: 93.5% of statements
ok  	github.com/milosgajdos/vaultops/cloud/gcp	0.024s	coverage: 28.1% of statements
ok  	github.com/milosgajdos/vaultops/command	1.478s	coverage: 15.4% of statements
ok  	github.com/milosgajdos/vaultops/manifest	0.022s	coverage: 100.0% of statements
ok  	github.com/milosgajdos/vaultops/store	0.020s	coverage: 100.0% of statements
ok  	github.com/milosgajdos/vaultops/store/local	0.020s	coverage: 88.9% of statements

Build the binary:

$ make build
mkdir -p ./_build
go build -ldflags="-s -w" -o "./_build/vaultops"

Once you have pulled in all the project dependencies you can also build the binary running the familiar command:

$ go build -ldflags="-s -w"

Usage

vaultops provides various commands following the same UX as vault command line utility. You can see the currently available commands below:

Usage: vaultops [--version] [--help] <command> [<args>]

Available commands are:
    init      Initialize Vault cluster or server
    unseal    Unseal a Vault server

vaultops reads the same environment variables as vault utility, so you can rely on the familiar $VAULT_ environment variables when specifying the vault server URLs and tokens.

At the moment only init and unseal commands are implemented. The plan is to add a few more.

vaultops init

vaultops init initializes the vault server. Besides providing the familiar vault command line utility options to connect to the vault server, it adds a few flags which allow to encrypt the vault master keys and root token and store them either on the workstation filesystem or encrypted in a remote storage:

./vaultops init -help
Usage: vaultops init [options]

    Initialize a new Vault server or cluster.

    This command connects to a Vault server and initializes it for the first time.
    It sets up initial set of master keys and secret store.
    Unless overridden init stores vault root token and keys on the local filesystem.

    When init is called on already initialized server it will return error.
...
...
...

  -redact=true 		  Redacts sensitive information when printing into stdout
  -kms-provider 	  KMS provider (aws, gcp)
  -aws-kms-id		  AWS KMS ID. KMS keys with given ID will be used to encrypt vault keys
  -gcp-kms-crypto-key	  GCP KMS crypto key ID
  -gcp-kms-key-ring       GCP KMS keyring
  -gcp-kms-region     	  GCP region (eg. 'global', 'europe-west1')
  -gcp-kms-project  	  GCP project name
  -storage-bucket         Cloud storage bucket
  -storage-key            Cloud storage key
  -key-store=local	  Type of store where to loook up vault keys (default: local)
    			  Local store is ./.local/vault.json
  -key-local-path         Path to locally stored keys

init Options:

  -status 			Don't initialize the server, only check the init status
  -key-shares=5 		Number of key shares to split the master key into
  -key-threshold=3		Number of key shares required to reconstruct the master key
  -config			Path to a config file which contains a list of vault servers

When run with the default options, init command will store the vault keys UNENCRYPTED on your local filesystem in .local directory of your current working directory in a predefied json format which looks as follows:

{
  "root_token": "your-root-token",
  "master_keys": [
    "master-key-1",
    "master-key-2",
    "master-key-3",
    "master-key-4",
    "master-key-5"
  ]
}

This is not what you should do when initialising your vault servers! This option is provided as convenience for local development!

For real life setup, vaultops allows to encrypt the vault keys using the encryption keys provided by publc cloud providers such as AWS KMS or CGP Cloud KMS. These options are available via -kms-provider flag. Here is an example how to use the GCP Cloud KMS to encrypt the vault keys when initialising a new vault server:

$ # export VAULT_ADDR environment variable
$ export VAULT_ADDR="http://10.100.21.161:8200"
$ # initialize vault server and encrypt the vault keys
$ ./vaultops init -kms-provider="gcp" \
 		  -gcp-kms-project="kube-blog" \
		  -gcp-kms-region="europe-west1" \
		  -gcp-kms-key-ring="vaultops" \
		  -gcp-kms-crypto-key="vaultops"

[INFO] Attempting to initialize vault:
[INFO] 	http://10.100.21.161:8200
[INFO] Host: http://10.100.21.161:8200 initialized. Master keys:
[INFO] Key 1: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[INFO] Key 2: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[INFO] Key 3: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[INFO] Key 4: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[INFO] Key 5: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[INFO] Initial Root Token: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Running the above init command will store the vault master keys and initial root token locally in ./.local/vault.json file but now they're encrypted using the GCP Cloud KMS keys so if you try to inspect the local file you'll get a "garbage" pile of randomly generated bytes. If you want to see the actual unencrypted keys you need to decrypt the file using the same KMS keys you used when encrypting them.

At the moment only AWS KMS and GCP KMS are supported

Vault Keys redacting

By default vaultops tries to "redact" all sensitive information printed to stdout. You can disable this behavior via -redact command line switch by setting it to false. This will print the master keys and initial root token into stdout in plaintext.

Vault Key storage

vaultops allows you to store vault keys remotely either in AWS S3, Google Cloud Storage or kubernetes secrets. You can choose the appropriate remote storage option via -key-store flag. Here is an example how to initialize vault using AWS KMS and store the keys in AWS S3 bucket of your choice:

$ export VAULT_ADDR="http://${HostIP}:8200"
$ ./vaultops init -key-store="s3" \
		  -storage-bucket="vaultops-kms" \
		  -storage-key="vault.json" \
		  -kms-provider="aws" \
		  -aws-kms-id="your-kms-id"

NOTE: when using kubernetes secrets storage, you can also specify a namespace for the secret; the default value is set to default namespace

vaultops unseal

vaultops unseal unseals the vault cluster using the keys generated by vault during its initalisation. These keys can be stored encrypted or in plaintext either locally or remotely based on the command line switches you used when you initialized the server. unseal command allows you to read these keys from whatever location you stored them in during initialization and use them to unseal the vault server. See the available command line options listed below:

$ ./vaultops unseal -help
Usage: vaultops unseal [options]

    Unseal the vault serve by entering master keys.

    This command connects to a Vault server and attempts to unseal it.
    first time. It sets up initial set of master keys and backend store.

    When init is called on already initialized server it will error

...
...
...

  -redact=true 		  Redacts sensitive information when printing into stdout
  -kms-provider 	  KMS provider (aws, gcp)
  -aws-kms-id		  AWS KMS ID. KMS keys with given ID will be used to encrypt vault keys
  -gcp-kms-crypto-key	  GCP KMS crypto key id
  -gcp-kms-key-ring       GCP KMS key ring
  -gcp-kms-region     	  GCP region (eg. 'global', 'europe-west1')
  -gcp-kms-project  	  GCP project name
  -storage-bucket         Cloud storage bucket
  -storage-key            Cloud storage key
  -key-store=local	  Type of store where to loook up vault keys (default: local)
    			  Local store is ./.local/vault.json
  -key-local-path         Path to locally stored keys

unseal Options:

    -status 		  Don't unseal the server, only check the seal status
    -config		  Path to a config file which contains a list of vault servers

Here is an example of how to unseal the vault server using the keys stored in AWS S3 which were encrypted using AWS KMS:

$ export AWS_REGION="us-east-1"
$ export VAULT_ADDR="http://${HostIP}:8200"
$ # unseal the vault server
$ ./vaultops unseal -key-store="s3" \
		    -storage-bucket="vaultops-kms" \
		    -storage-key="vault.json" \
		    -kms-provider="aws" \
		    -aws-kms-id="your-kms-id"

Obviously, you can create all kinds of crazy combination of storages and encryption keys i.e. store the keys in AWS S3, but encrypt them using GCP Cloud KMS

Manifest

vaultops allows you to create a manifest file which can be used when running vaultops commands. The manifest is a simple YAML (woo, hoo! more YAML ᕕ( ᐛ )ᕗ) file which specifies a list of vault hosts for initialization and unsealing.

Let's look at a simple example:

hosts:
  # URL of vault server to use for initialization
  init:
    - "http://10.100.21.161:8200"
  # URLs of all vault servers that should be unsealed
  unseal:
    - "http://10.100.21.161:8200"
    - "http://10.100.21.162:8200"
    - "http://10.100.21.163:8200"

Hopefully the YAML snippet above is straightforward to understand: we've got a server to initialize and a cluster of servers to unseal.

You don't have to have a full manifest at hand if you want to run just one command. Say, you just want to initialize the server -- you can supply the following YAML snippet to init command via -config command line switch:

hosts:
  # URL of vault server to use for initialization
  init:
    - "http://10.100.21.161:8200"

Run the init command using the manifest above stored in some file on the local filesystem:

$ VAULT_ADDR="http://10.100.21.161:8200" ./vaultops init -config init.yaml
[INFO] Attempting to initialize vault:
[INFO] 	http://10.100.21.161:8200
[INFO] Host: http://10.100.21.161:8200 initialized. Master keys:
[INFO] Key 1: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[INFO] Key 2: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[INFO] Key 3: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[INFO] Key 4: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[INFO] Key 5: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[INFO] Initial Root Token: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Same rules apply when running the unseal command.

TODO

  • bigger test coverage
  • plenty of room for refactoring
  • setting up vault secret backends
  • setting up vault secret backend roles
  • setting up vault policies

About

Setup your vault servers and store the keys in an encrypted store of your choice

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published