443 lines
15 KiB
Markdown
443 lines
15 KiB
Markdown
|
---
|
||
|
layout: "docs"
|
||
|
page_title: "Google Cloud KMS - Secrets Engines"
|
||
|
sidebar_title: "Google Cloud KMS <sup>1.0 BETA</sup>"
|
||
|
sidebar_current: "docs-secrets-gcpkms"
|
||
|
description: |-
|
||
|
The Google Cloud KMS secrets engine for Vault interfaces with Google Cloud
|
||
|
KMS for encryption/decryption of data and KMS key management through Vault.
|
||
|
---
|
||
|
|
||
|
# Google Cloud KMS Secrets Engine
|
||
|
|
||
|
The Google Cloud KMS Vault secrets engine provides encryption and key management
|
||
|
via [Google Cloud KMS][kms]. It supports management of keys, including creation,
|
||
|
rotation, and revocation, as well as encrypting and decrypting data with managed
|
||
|
keys. This enables management of KMS keys through Vault's policies and IAM
|
||
|
system.
|
||
|
|
||
|
## Setup
|
||
|
|
||
|
Most secrets engines must be configured in advance before they can perform their
|
||
|
functions. These steps are usually completed by an operator or configuration
|
||
|
management tool.
|
||
|
|
||
|
1. Enable the Google Cloud KMS secrets engine:
|
||
|
|
||
|
```text
|
||
|
$ vault secrets enable gcpkms
|
||
|
Success! Enabled the gcpkms secrets engine at: gcpkms/
|
||
|
```
|
||
|
|
||
|
By default, the secrets engine will mount at the name of the engine. To
|
||
|
enable the secrets engine at a different path, use the `-path` argument.
|
||
|
|
||
|
1. Configure the secrets engine with account credentials and/or scopes:
|
||
|
|
||
|
```text
|
||
|
$ vault write gcpkms/config \
|
||
|
credentials=@my-credentials.json
|
||
|
Success! Data written to: gcpkms/config
|
||
|
```
|
||
|
|
||
|
If you are running Vault from inside [Google Compute Engine][gce] or [Google
|
||
|
Kubernetes Engine][gke], the instance or pod service account can be used in
|
||
|
place or specifying the credentials JSON file. For more information on
|
||
|
authentication, see the [authentication section](#authentication) below.
|
||
|
|
||
|
1. Create a Google Cloud KMS key:
|
||
|
|
||
|
```text
|
||
|
$ vault write gcpkms/keys/my-key \
|
||
|
key_ring=projects/my-project/locations/my-location/keyRings/my-keyring \
|
||
|
rotation_period=72h
|
||
|
```
|
||
|
|
||
|
The `key_ring` parameter is specified in the following format:
|
||
|
|
||
|
```text
|
||
|
projects/<project>/locations/<location>/keyRings/<keyring>
|
||
|
```
|
||
|
|
||
|
where:
|
||
|
- `<project>` - the name of the GCP project (e.g. "my-project")
|
||
|
- `<location>` - the location of the KMS key ring (e.g. "us-east1", "global")
|
||
|
- `<keyring>` - the name of the KMS key ring (e.g. "my-keyring")
|
||
|
|
||
|
## Usage
|
||
|
|
||
|
After the secrets engine is configured and a user/machine has a Vault token with
|
||
|
the proper permission, it can be used to encrypt, decrypt, and manage keys. The
|
||
|
following sections describe the different ways in which keys can be managed.
|
||
|
|
||
|
### Symmetric Encryption/Decryption
|
||
|
|
||
|
This section describes using a Cloud KMS key for symmetric
|
||
|
encryption/decryption. This is probably the most common and familiar type of
|
||
|
encryption. Google Cloud manages the key ring which is used to encrypt and
|
||
|
decrypt data.
|
||
|
|
||
|
<table>
|
||
|
<thead>
|
||
|
<tr>
|
||
|
<th>Purpose</th>
|
||
|
<th>Supported Algorithms</th>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td valign="top"><code>encrypt_decrypt</code></td>
|
||
|
<td valign="top">
|
||
|
<code>symmetric_encryption</code>
|
||
|
</td>
|
||
|
</tr>
|
||
|
</thead>
|
||
|
</table>
|
||
|
|
||
|
1. Create or use an existing key eligible for symmetric encryption/decryption:
|
||
|
|
||
|
```text
|
||
|
$ vault write gcpkms/keys/my-key \
|
||
|
key_ring=projects/.../my-keyring \
|
||
|
purpose=encrypt_decrypt \
|
||
|
algorithm=symmetric_encryption
|
||
|
```
|
||
|
|
||
|
1. Encrypt plaintext data using the `/encrypt` endpoint with a named key:
|
||
|
|
||
|
```text
|
||
|
$ vault write gcpkms/encrypt/my-key plaintext="hello world"
|
||
|
Key Value
|
||
|
--- -----
|
||
|
ciphertext CiQAuMv0lTiKjrF43Lgr4...
|
||
|
key_version 1
|
||
|
```
|
||
|
|
||
|
Unlike Vault's transit backend, plaintext data does not need to be base64
|
||
|
encoded. The endpoint will automatically convert data.
|
||
|
|
||
|
Note that Vault is not _storing_ this data. The caller is responsible for
|
||
|
storing the resulting ciphertext.
|
||
|
|
||
|
1. Decrypt ciphertext using the `/decrypt` endpoint with a named key:
|
||
|
|
||
|
```text
|
||
|
$ vault write gcpkms/decrypt/my-key ciphertext=CiQAuMv0lTiKjrF43Lgr4...
|
||
|
Key Value
|
||
|
--- -----
|
||
|
plaintext hello world
|
||
|
```
|
||
|
|
||
|
For easier scripting, it is also possible to extract the plaintext directly:
|
||
|
|
||
|
```text
|
||
|
$ vault write -field=plaintext gcpkms/decrypt/my-key ciphertext=CiQAuMv0lTiKjrF43Lgr4...
|
||
|
hello world
|
||
|
```
|
||
|
|
||
|
1. Rotate the underlying encryption key. This will generate a new crypto key
|
||
|
version on Google Cloud KMS and set that version as the active key.
|
||
|
|
||
|
```text
|
||
|
$ vault write -f gcpkms/keys/rotate/my-key
|
||
|
WARNING! The following warnings were returned from Vault:
|
||
|
|
||
|
* The crypto key version was rotated successfully, but it can take up to 2
|
||
|
hours for the new crypto key version to become the primary. In practice, it
|
||
|
is usually much shorter. Be sure to issue a read operation and verify the
|
||
|
key version if you require new data to be encrypted with this key.
|
||
|
|
||
|
Key Value
|
||
|
--- -----
|
||
|
key_version 2
|
||
|
```
|
||
|
|
||
|
As the message says, rotation is not immediate. Depending on a number of
|
||
|
factors, the propagation of the new key can take quite some time. If you
|
||
|
have a need to immediately encrypt data with this new key, query the API to
|
||
|
wait for the key to become the primary.
|
||
|
|
||
|
1. Re-encrypt already-encrypted ciphertext to be encrypted with a new version of
|
||
|
the crypto key. Vault will decrypt the value using the appropriate key in the
|
||
|
keyring and then encrypted the resulting plaintext with the newest key in the
|
||
|
keyring.
|
||
|
|
||
|
```text
|
||
|
$ vault write gcpkms/reencrypt/my-key ciphertext=CiQAuMv0lTiKjrF43Lgr4...
|
||
|
Key Value
|
||
|
--- -----
|
||
|
ciphertext CiQAuMv0lZTTozQA/ElqM...
|
||
|
key_version 2
|
||
|
```
|
||
|
|
||
|
This process **does not** reveal the plaintext data. As such, a Vault policy
|
||
|
could grant almost an untrusted process the ability to re-encrypt ciphertext
|
||
|
data, since the process would not be able to get access to the plaintext data.
|
||
|
|
||
|
1. Trim old key versions by deleting Cloud KMS crypto key versions that are
|
||
|
older than the `min_version` allowed on the key.
|
||
|
|
||
|
```text
|
||
|
$ vault write gcpkms/keys/config/my-key min_version=10
|
||
|
```
|
||
|
|
||
|
Then delete all keys older than version 10. This will make it impossible to
|
||
|
encrypt, decrypt, or sign values with the older key by conventional means.
|
||
|
|
||
|
```text
|
||
|
$ vault write -f gcpkms/keys/trim/my-key
|
||
|
```
|
||
|
|
||
|
1. Delete the key to delete all key versions and Vault's record of the key.
|
||
|
|
||
|
```text
|
||
|
$ vault delete gcpkms/keys/my-key
|
||
|
```
|
||
|
|
||
|
This will make it impossible to encrypt, decrypt, or sign values by
|
||
|
conventional means.
|
||
|
|
||
|
### Asymmetric Decryption
|
||
|
|
||
|
This section describes using a Cloud KMS key for asymmetric decryption. In this
|
||
|
model Google Cloud manages the key ring and exposes the public key via an API
|
||
|
endpoint. The public key encrypts data offline to produce ciphertext. When the
|
||
|
plaintext is desired, the user submits the ciphertext to Cloud KMS which
|
||
|
decrypts the value using the corresponding public key.
|
||
|
|
||
|
<table>
|
||
|
<thead>
|
||
|
<tr>
|
||
|
<th>Purpose</th>
|
||
|
<th>Supported Algorithms</th>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td valign="top"><code>asymmetric_decrypt</code></td>
|
||
|
<td valign="top">
|
||
|
<code>rsa_decrypt_oaep_2048_sha256</code><br>
|
||
|
<code>rsa_decrypt_oaep_3072_sha256</code><br>
|
||
|
<code>rsa_decrypt_oaep_4096_sha256</code>
|
||
|
</td>
|
||
|
</tr>
|
||
|
</thead>
|
||
|
</table>
|
||
|
|
||
|
1. Create or use an existing key eligible for symmetric encryption/decryption:
|
||
|
|
||
|
```text
|
||
|
$ vault write gcpkms/keys/my-key \
|
||
|
key_ring=projects/.../my-keyring \
|
||
|
purpose=asymmetric_decrypt \
|
||
|
algorithm=rsa_decrypt_oaep_4096_sha256
|
||
|
```
|
||
|
|
||
|
1. Retrieve the public key from Cloud KMS:
|
||
|
|
||
|
```text
|
||
|
$ gcloud alpha kms keys versions get-public-key [CRYPTO_KEY_VERSION] \
|
||
|
--location [LOCATION] \
|
||
|
--keyring [KEY_RING] \
|
||
|
--key [KEY] \
|
||
|
--output-file ~/mykey.pub
|
||
|
```
|
||
|
|
||
|
1. Encrypt plaintext data with the public key. Note this varies widely between
|
||
|
programming languages. The following example uses OpenSSL, but you can use your
|
||
|
language's built-ins as well.
|
||
|
|
||
|
```text
|
||
|
$ openssl pkeyutl -in ~/my-secret-file \
|
||
|
-encrypt -pubin \
|
||
|
-inkey ~/mykey.pub \
|
||
|
-pkeyopt rsa_padding_mode:oaep \
|
||
|
-pkeyopt rsa_oaep_md:sha256 \
|
||
|
-pkeyopt rsa_mgf1_md:sha256
|
||
|
```
|
||
|
|
||
|
Note that this encryption happens offline (meaning outside of Vault), and
|
||
|
the encryption is happening with a _public_ key. Only Cloud KMS has the
|
||
|
corresponding _private_ key.
|
||
|
|
||
|
1. Decrypt ciphertext using the `/decrypt` endpoint with a named key:
|
||
|
|
||
|
```text
|
||
|
$ vault write gcpkms/decrypt/my-key key_verison=1 ciphertext=CiQAuMv0lTiKjrF43Lgr4...
|
||
|
Key Value
|
||
|
--- -----
|
||
|
plaintext hello world
|
||
|
```
|
||
|
|
||
|
### Asymmetric Signing
|
||
|
|
||
|
This section describes using a Cloud KMS key for asymmetric signing. In this
|
||
|
model Google Cloud manages the key ring and exposes the public key via an API
|
||
|
endpoint. A message or digest is signed with the corresponding private key, and
|
||
|
can be verified using the public key.
|
||
|
|
||
|
<table>
|
||
|
<thead>
|
||
|
<tr>
|
||
|
<th>Purpose</th>
|
||
|
<th>Supported Algorithms</th>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td valign="top"><code>asymmetric_sign</code></td>
|
||
|
<td valign="top">
|
||
|
<code>rsa_sign_pss_2048_sha256</code><br>
|
||
|
<code>rsa_sign_pss_3072_sha256</code><br>
|
||
|
<code>rsa_sign_pss_4096_sha256</code><br>
|
||
|
<code>rsa_sign_pkcs1_2048_sha256</code><br>
|
||
|
<code>rsa_sign_pkcs1_3072_sha256</code><br>
|
||
|
<code>rsa_sign_pkcs1_4096_sha256</code><br>
|
||
|
<code>ec_sign_p256_sha256</code><br>
|
||
|
<code>ec_sign_p384_sha384</code>
|
||
|
</td>
|
||
|
</tr>
|
||
|
</thead>
|
||
|
</table>
|
||
|
|
||
|
1. Create or use an existing key eligible for symmetric encryption/decryption:
|
||
|
|
||
|
```text
|
||
|
$ vault write gcpkms/keys/my-key \
|
||
|
key_ring=projects/.../my-keyring \
|
||
|
purpose=asymmetric_sign \
|
||
|
algorithm=ec_sign_p384_sha384
|
||
|
```
|
||
|
|
||
|
1. Calculate the base64-encoded binary digest. Use the hashing algorithm that
|
||
|
corresponds to they key type:
|
||
|
|
||
|
```text
|
||
|
$ export DIGEST=$(openssl dgst -sha256 -binary /my/file | base64)
|
||
|
```
|
||
|
|
||
|
Ask Cloud KMS to sign the digest:
|
||
|
|
||
|
```text
|
||
|
$ vault write gcpkms/sign/my-key key_version=1 digest=$DIGEST
|
||
|
Key Value
|
||
|
--- -----
|
||
|
signature MGYCMQDbOS2462SKMsGdh2GQ...
|
||
|
```
|
||
|
|
||
|
1. Verify the signature of the digest:
|
||
|
|
||
|
```text
|
||
|
$ vault write gcpkms/verify/my-key key_version=1 digest=$DIGEST signature=$SIGNATURE
|
||
|
Key Value
|
||
|
--- -----
|
||
|
valid true
|
||
|
```
|
||
|
|
||
|
|
||
|
## Authentication
|
||
|
|
||
|
The Google Cloud KMS Vault secrets backend uses the official Google Cloud Golang
|
||
|
SDK. This means it supports the common ways of [providing credentials to Google
|
||
|
Cloud][cloud-creds]. In addition to specifying `credentials` directly via Vault
|
||
|
configuration, you can also get configuration from the following values **on the
|
||
|
Vault server**:
|
||
|
|
||
|
1. The environment variables `GOOGLE_APPLICATION_CREDENTIALS`. This is specified
|
||
|
as the **path** to a Google Cloud credentials file, typically for a service
|
||
|
account. If this environment variable is present, the resulting credentials are
|
||
|
used. If the credentials are invalid, an error is returned.
|
||
|
|
||
|
1. Default instance credentials. When no environment variable is present, the
|
||
|
default service account credentials are used. This is useful when running Vault
|
||
|
on [Google Compute Engine][gce] or [Google Kubernetes Engine][gke]
|
||
|
|
||
|
For more information on service accounts, please see the [Google Cloud Service
|
||
|
Accounts documentation][service-accounts].
|
||
|
|
||
|
To use this storage backend, the service account must have the following
|
||
|
minimum scope(s):
|
||
|
|
||
|
```text
|
||
|
https://www.googleapis.com/auth/kms
|
||
|
```
|
||
|
|
||
|
### Required Permissions
|
||
|
|
||
|
The credentials given to Vault must have the following permissions:
|
||
|
|
||
|
```text
|
||
|
locations.keyRings.create
|
||
|
locations.keyRings.cryptoKeys.list
|
||
|
locations.keyRings.cryptoKeys.get
|
||
|
locations.keyRings.cryptoKeys.create
|
||
|
locations.keyRings.cryptoKeys.encrypt
|
||
|
locations.keyRings.cryptoKeys.decrypt
|
||
|
locations.keyRings.cryptoKeys.patch
|
||
|
locations.keyRings.cryptoKeys.updatePrimaryVersion
|
||
|
locations.keyRings.cryptoKeys.cryptoKeyVersions.list
|
||
|
locations.keyRings.cryptoKeys.cryptoKeyVersions.get
|
||
|
locations.keyRings.cryptoKeys.cryptoKeyVersions.create
|
||
|
locations.keyRings.cryptoKeys.cryptoKeyVersions.patch
|
||
|
locations.keyRings.cryptoKeys.cryptoKeyVersions.destroy
|
||
|
```
|
||
|
|
||
|
For simplicity, you can use this role instead:
|
||
|
|
||
|
```text
|
||
|
roles/cloudkms.admin
|
||
|
```
|
||
|
|
||
|
If Vault will not be creating keys, you can reduce the permissions. For example,
|
||
|
to create keys out of band and have Vault manage the encryption/decryption, you
|
||
|
only need the following permissions:
|
||
|
|
||
|
```text
|
||
|
roles/cloudkms.cryptoKeyEncrypterDecrypter
|
||
|
```
|
||
|
|
||
|
For more information, please see the [Google Cloud KMS IAM documentation][kms-iam]
|
||
|
|
||
|
## FAQ
|
||
|
|
||
|
**How is this different than Vault's transit secrets engine?**<br>
|
||
|
Vault's [transit][vault-transit] secrets engine uses in-memory keys to
|
||
|
encrypt/decrypt keys. In general it will be faster and more performant. However,
|
||
|
users who need physical, off-site, or out-of-band key management can use the
|
||
|
[Google Cloud KMS][kms] secrets engine to get those benefits while leveraging
|
||
|
Vault's policy and identity system.
|
||
|
|
||
|
**Can Vault use an existing KMS key?**<br>
|
||
|
You can use the `/register` endpoint to configure Vault to talk to an existing
|
||
|
Google Cloud KMS key. As long as the IAM permissions are correct, Vault will be
|
||
|
able to encrypt/decrypt data and rotate the key. See the [api][api] for more
|
||
|
information.
|
||
|
|
||
|
**Can this be used with a hardware key like an HSM?**<br>
|
||
|
Yes! You can set `protection_level` to "hsm" when creating a key, or use an
|
||
|
existing Cloud KMS key that is backed by an HSM.
|
||
|
|
||
|
**How much does this cost?**<br>
|
||
|
The plugin is free and open source. KMS costs vary by key type and the number of
|
||
|
operations. Please see the [Cloud KMS pricing page][kms-pricing] for more
|
||
|
details.
|
||
|
|
||
|
## Help & Support
|
||
|
|
||
|
The Google Cloud KMS Vault secrets engine is written as an external Vault
|
||
|
plugin. The code lives outside the main Vault repository. It is automatically
|
||
|
bundled with Vault releases, but the code is managed separately.
|
||
|
|
||
|
Please report issues, add feature requests, and submit contributions to the
|
||
|
[vault-plugin-secrets-gcpkms repo on GitHub][repo].
|
||
|
|
||
|
## API
|
||
|
|
||
|
The Google Cloud KMS secrets engine has a full HTTP API. Please see the
|
||
|
[Google Cloud KMS secrets engine API docs][api] for more details.
|
||
|
|
||
|
|
||
|
[cloud-creds]: https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application
|
||
|
[gce]: https://cloud.google.com/compute/
|
||
|
[gke]: https://cloud.google.com/kubernetes-engine/
|
||
|
[kms]: https://cloud.google.com/kms
|
||
|
[kms-iam]: https://cloud.google.com/kms/docs/reference/permissions-and-roles
|
||
|
[kms-pricing]: https://cloud.google.com/kms/pricing
|
||
|
[repo]: https://github.com/hashicorp/vault-plugin-secrets-gcpkms
|
||
|
[service-accounts]: https://cloud.google.com/compute/docs/access/service-accounts
|
||
|
[vault-transit]: /docs/secrets/transit/index.html
|