Hashicorp Vault Keystore
This tutorial shows how to setup a KES server that uses Vault’s K/V engine as a persistent and secure key store:
Prerequisites
To start a development server or interact with Vault using the Vault CLI, download the Vault binary.
Vault Server
KES requires Vault K/V engine v1 or v2 and credentials for either the AppRole or Kubernetes authentication method.
If you do not have an existing Vault cluster available, do one of the following:
- Follow Hashicorp Vault install guide to create a new cluster
- Create a single node dev instance
The docs below discuss setting up a single node dev instance for development purposes using the AppRole
authentication method.
Single Node Dev Vault Instance
The following command starts a Vault server in dev mode:
127.0.0.1:8200
.
A dev server is ephemeral and is not meant to be run in production.
Connect Vault to the Vault CLI
-
Set
VAULT_ADDR
endpointThe Vault CLI needs to know the Vault endpoint:
export VAULT_ADDR='https://127.0.0.1:8200'
-
Set
VAULT_TOKEN
The Vault CLI needs an authentication token to perform operations.
export VAULT_TOKEN=hvs.O6QNQB33ksXtMxtlRKlRZL0R
Replace the token value to your own Vault access token, such as the
Root token
provided in the output of thevault server -dev
command. -
Enable
K/V
BackendKES stores the secret keys at the Vault K/V backend. Vault provides two K/V engines,
v1
andv2
.MinIO recommends the K/V
v1
engine.The Vault policy for KES depends on the chosen K/V engine version. A policy designed for K/V
v1
will not work with a K/Vv2
engine. Likewise, a policy designed for K/Vv2
will not work with a K/Vv1
engine.For more information about migrating from
v1
tov2
refer to the Hashicorp docs on upgrading from v1.
Setup KES Access to Vault
-
Create Vault Policy
The Vault policy defines the API paths the KES server can access. Create a text file named
kes-policy.hcl
.The contents of the policy vary depending on the K/V engine used.
-
Write the policy to the Vault
The following command creates the policy at Vault:
vault policy write kes-policy kes-policy.hcl
-
Enable Authentication
This step allows the KES server to authenticate to Vault. For this tutorial, we use the
AppRole
authentication method.vault auth enable approle
-
Create KES Role
The following command adds a new role called
kes-server
at Vault:vault write auth/approle/role/kes-server token_num_uses=0 secret_id_num_uses=0 period=5m
-
Bind Policy to Role
The following command binds the
kes-server
role to thekes-policy
:vault write auth/approle/role/kes-server policies=kes-policy
-
Generate AppRole ID
Request an AppRole ID for the KES server:
vault read auth/approle/role/kes-server/role-id
-
Generate AppRole Secret
Request an AppRole secret for the KES server:
vault write -f auth/approle/role/kes-server/secret-id
The AppRole secret prints as
secret_id
. You can ignore thesecret_id_accessor
.
KES Server Setup
-
Generate KES Server Private Key & Certificate
The following command generates a new TLS private key
server.key
and a self-signed X.509 certificateserver.cert
for the IP127.0.0.1
and DNS namelocalhost
(as SAN). If you want to refer to your KES server using another IP or DNS name, such as10.1.2.3
orhttps://kes.example.net
, adjust the--ip
and/or--dns
parameters accordingly.kes identity new --key server.key --cert server.cert --ip "127.0.0.1" --dns localhost
The above command generates self-signed certificates. If you already have a way to issue certificates for your servers, you can use those.
Other tooling for X.509 certificate generation also works. For example, you could use
openssl
:openssl ecparam -genkey -name prime256v1 | openssl ec -out server.key openssl req -new -x509 -days 30 -key server.key -out server.cert \ -subj "/C=/ST=/L=/O=/CN=localhost" -addext "subjectAltName = IP:127.0.0.1"
-
Generate an API key
The following command generates a new KES API key.
kes identity new
The output resembles the following:
Your API key: kes:v1:ABfa1xsnIV0lltXQC8tHXic8lte7J6hT7EoGv6+s5QCW This is the only time it is shown. Keep it secret and secure! Your Identity: cf6c535e738c1dd47a1d746366fde7f0309d1e0a8471b9f6e909833906afbbfa The identity is not a secret. It can be shared. Any peer needs this identity in order to verify your API key. The identity can be computed again via: kes identity of kes:v1:ABfa1xsnIV0lltXQC8tHXic8lte7J6hT7EoGv6+s5QCW
The generated
identity
is NOT a secret and can be shared publicly. It will be used later on in the KES config file as admin identity or assigned to a policy.The
API key
itself is a secret and should not be shared. You can always recompute an API key’s identity. -
Configure KES Server
Create the KES server configuration file:
config.yml
.Make sure that the identity in the policy section matches the
client.crt
identity. Add the approlerole_id
andsecret_id
obtained earlier.admin: # Use the identity generated above by 'kes identity new'. identity: "" # For example: cf6c535e738c1dd47a1d746366fde7f0309d1e0a8471b9f6e909833906afbbfa tls: key: private.key # The KES server TLS private key cert: public.crt # The KES server TLS certificate keystore: vault: endpoint: https://127.0.0.1:8200 version: v1 # The K/V engine version - either "v1" or "v2". engine: kv # The engine path of the K/V engine. The default is "kv". approle: id: "" # Your AppRole ID secret: "" # Your AppRole Secret
-
Start KES Server
KES CLI Access
-
Set
KES_SERVER
endpointThe following environment variable specifies the KES server the KES CLI should talk to:
export KES_SERVER=https://127.0.0.1:7373
-
Define the CLI access credentials
The following environment variable sets the key the client uses to talk to a KES server:
export KES_API_KEY=kes:v1:ABfa1xsnIV0lltXQC8tHXic8lte7J6hT7EoGv6+s5QCW
Replace the value with your server’s API Key. The server’s API key displays in the output when you start the server.
-
Test the Configuration
For example, check the status of the server:
kes status -k
Use the key to generate a new data encryption key:
kes key dek my-key-1 -k
The command output resembles the following:
{ plaintext : UGgcVBgyQYwxKzve7UJNV5x8aTiPJFoR+s828reNjh0= ciphertext: eyJhZWFkIjoiQUVTLTI1Ni1HQ00tSE1BQy1TSEEtMjU2IiwiaWQiOiIxMTc1ZjJjNDMyMjNjNjNmNjY1MDk5ZDExNmU3Yzc4NCIsIml2IjoiVHBtbHpWTDh5a2t4VVREV1RSTU5Tdz09Iiwibm9uY2UiOiJkeGl0R3A3bFB6S21rTE5HIiwiYnl0ZXMiOiJaaWdobEZrTUFuVVBWSG0wZDhSYUNBY3pnRWRsQzJqWFhCK1YxaWl2MXdnYjhBRytuTWx0Y3BGK0RtV1VoNkZaIn0= }
Using KES with a MinIO Server
MinIO Server requires KES to enable server-side data encryption.
See the KES for MinIO instruction guide for additional steps needed to use your new KES Server with a MinIO Server.
Configuration References
The following section describes the Key Encryption Service (KES) configuration settings to use Hashicorp Vault Keystore as the root KMS to store external keys, such as the keys used for Server-Side Encryption on a MinIO Server.
Advanced Configuration
These additional configuration steps may solve specific problems.
Multi-Tenancy with K/V prefixes
Vault can serve as backend for multiple, isolated KES tenants.
Each KES tenant can consist of N
replicas.
There can be M
KES tenants connected to the same Vault server/cluster.
This means N × M
KES server instances can connect to a single Vault.
In these configurations, each KES tenant has a separate prefix at the K/V secret engine. For each KES tenant, there must be a corresponding Vault policy.
-
For K/V
v1
:path "kv/<tenant-name>/*" { capabilities = [ "create", "read", "delete" ] }
-
For K/V
v2
:path "kv/data/<tenant-name>/*" { capabilities = [ "create", "read" ] } path "kv/metadata/<tenant-name>/*" { capabilities = [ "list", "delete" ] }
Create a different configuration file for each KES tenant. The file contains the Vault K/V prefix for the tenant to use.
keystore:
vault:
endpoint: https://127.0.0.1:8200
prefix: <tenant-name>
approle:
id: "" # Your AppRole ID
secret: "" # Your AppRole Secret
retry: 15s
status:
ping: 10s
tls:
ca: vault.crt # Manually trust the vault certificate since we use self-signed certificates
Multi-Tenancy with Vault Namespaces
Vault can serve as the backend for multiple, isolated KES tenants.
Each KES tenant can consist of N
replicas.
There can be M
KES tenants connected to the same Vault server/cluster.
This means N × M
KES server instances can connect to a single Vault.
Therefore, each KES tenant has a separate prefix at the K/V secret engine. For each KES tenant there has to be a corresponding Vault policy.
-
For K/V
v1
:path "kv/<tenant-name>/*" { capabilities = [ "create", "read", "delete" ] }
-
For K/V
v2
:path "kv/data/<tenant-name>/*" { capabilities = [ "create", "read" ] } path "kv/metadata/<tenant-name>/*" { capabilities = [ "list", "delete" ] }
Use a different configuration file for each KES tenant. The file contains the Vault namespace which the KES tenant should use.
keystore:
vault:
endpoint: https://127.0.0.1:8200
namespace: <vault-namespace>
approle:
id: "" # Your AppRole ID
secret: "" # Your AppRole Secret
retry: 15s
status:
ping: 10s
tls:
ca: vault.crt # Manually trust the vault certificate since we use self-signed certificates
Encrypt Vault-stored Keys
Hashicorp’s Transit functionality provides a means to encrypt and decrypt keys stored in the vault. This provides an additional layer of encryption that may be useful in specific cases.
When enabled, Hashicorp stores a key in the Vault to encrypt or decrypt the other keys stored in the vault. KES then uses the vault-managed key to store or retrieve keys from the Vault.
To configure Transit, add the following section to the KES Configuration YAML’s keystore.vault
section:
keystore:
vault:
transit: # Optionally encrypt keys stored on the K/V engine with a Vault-managed key.
engine: "" # The path of the transit engine - e.g. "my-transit". If empty, defaults to: transit (Vault default)
key: "" # The key name that should be used to encrypt entries stored on the K/V engine.