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_ADDRendpointThe Vault CLI needs to know the Vault endpoint: export VAULT_ADDR='https://127.0.0.1:8200'
- 
Set VAULT_TOKENThe Vault CLI needs an authentication token to perform operations. export VAULT_TOKEN=hvs.O6QNQB33ksXtMxtlRKlRZL0RReplace the token value to your own Vault access token, such as the Root tokenprovided in the output of thevault server -devcommand.
- 
Enable K/VBackendKES stores the secret keys at the Vault K/V backend. Vault provides two K/V engines, v1andv2.MinIO recommends the K/V v1engine.The Vault policy for KES depends on the chosen K/V engine version. A policy designed for K/V v1will not work with a K/Vv2engine. Likewise, a policy designed for K/Vv2will not work with a K/Vv1engine.For more information about migrating from v1tov2refer 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 AppRoleauthentication method.vault auth enable approle
- 
Create KES Role The following command adds a new role called kes-serverat 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-serverrole 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-idThe 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.keyand a self-signed X.509 certificateserver.certfor the IP127.0.0.1and DNS namelocalhost(as SAN). If you want to refer to your KES server using another IP or DNS name, such as10.1.2.3orhttps://kes.example.net, adjust the--ipand/or--dnsparameters accordingly.kes identity new --key server.key --cert server.cert --ip "127.0.0.1" --dns localhostThe 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 newThe 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+s5QCWThe generated identityis 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 keyitself 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.crtidentity. Add the approlerole_idandsecret_idobtained 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_SERVERendpointThe 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+s5QCWReplace 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 -kUse the key to generate a new data encryption key: kes key dek my-key-1 -kThe 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.