Skip to content

Commit

Permalink
Merge pull request #5193 from EnterpriseDB/tde-docs-suggested-fix
Browse files Browse the repository at this point in the history
TDE - suggested fixes for CSP KMS
  • Loading branch information
gvasquezvargas authored Jul 10, 2024
2 parents cc74b74 + 8407bda commit 803543f
Showing 1 changed file with 15 additions and 29 deletions.
44 changes: 15 additions & 29 deletions product_docs/docs/tde/15/key_stores.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ If you don't want key wrapping, for example for testing, then you must set the w

Postgres leaves this configuration up to the user, which allows tailoring the setup to local requirements and integrating with existing key management software or similar. To configure the data key protection, you must specify a pair of external commands that take care of the wrapping (encrypting) and unwrapping (decryption).

## Using a passphrase
## Using a passphrase

You can protect the data key with a passphrase using the openssl command line utility. The following is an example that sets up this protection:

```shell
initdb -D datadir -y --key-wrap-command='openssl enc -e -aes-128-cbc -pbkdf2 -out "%p"' --key-unwrap-command='openssl enc -d -aes-128-cbc -pbkdf2 -in "%p"'
```

This example wraps the randomly generated data key (done internally by initdb) by encrypting it using the AES-128-CBC (AESKW) algorithm. The encryption uses a key derived from a passphrase using the PBKDF2 key derivation function and a randomly generated salt. The terminal prompts for the passphrase. (See the openssl-enc manual page for details about these options. Available options vary across versions.) The placeholder `%p` is replaced with the name of the file to store the wrapped key.
This example wraps the randomly generated data key (done internally by initdb) by encrypting it with the AES-128-CBC (AESKW) algorithm. The encryption uses a key derived from a passphrase with the PBKDF2 key derivation function and a randomly generated salt. The terminal prompts for the passphrase. (See the openssl-enc manual page for details about these options. Available options vary across versions.) The initdb utility replaces `%p` with the name of the file that stores the wrapped key.

The unwrap command performs the opposite operation. initdb doesn't need the unwrap operation. However, it stores it in the `postgresql.conf` file of the initialized cluster, which uses it when it starts up.


The key wrap command receives the plaintext key on standard input and needs to put the wrapped key at the file system location specified by the `%p` placeholder. The key unwrap command needs to read the wrapped key from the file system location specified by the `%p` placeholder and write the unwrapped key to the standard output.

Expand All @@ -43,7 +43,7 @@ export PGDATAKEYWRAPCMD PGDATAKEYUNWRAPCMD
```

Key unwrap commands that prompt for passwords on the terminal don't work when the server is started by pg_ctl or through service managers such as systemd. The server is detached from the terminal in those environments. If you want an interactive password prompt on server start, you need a more elaborate configuration that fetches the password using some indirect mechanism.

For example, for systemd, you can use `systemd-ask-password`:

```
Expand All @@ -52,12 +52,12 @@ PGDATAKEYUNWRAPCMD="bash -c 'openssl enc -d -aes-128-cbc -pbkdf2 -in %p -pass fi
```

You also need an entry like in `/etc/sudoers`:

```
postgres ALL = NOPASSWD: /usr/bin/systemd-ask-password
```

## Using a key store
## Using a key store
You can use the key store in an external key management system to manage the data encryption key. The tested and supported key stores are:

- Amazon AWS Key Management Service (KMS)
Expand All @@ -70,7 +70,7 @@ You can use the key store in an external key management system to manage the dat

### AWS Key Management Service example

Create a key with AWS Key Management Service:
Create a key with AWS Key Management Service:

```shell
aws kms create-key
Expand All @@ -86,52 +86,38 @@ PGDATAKEYUNWRAPCMD='aws kms decrypt --key-id alias/pg-tde-master-1 --ciphertext-
!!! Note
Shell commands with pipes, as in this example, are problematic because the exit status of the pipe is that of the last command. A failure of the first, more interesting command isn't reported properly. Postgres handles this somewhat by recognizing whether the wrap or unwrap command wrote nothing. However, it's better to make this more robust. For example, use the `pipefail` option available in some shells or the `mispipe` command available on some operating systems. Put more complicated commands into an external shell script or other program instead of defining them inline.

Alternatively, you can use the [crypt utility](https://github.com/VirtusLab/crypt) to wrap and unwrap the data encryption key:

```shell
PGDATAKEYWRAPCMD='crypt encrypt aws --out %p --region us-east-1 --kms alias/pg-tde-master-1'
PGDATAKEYUNWRAPCMD='crypt decrypt aws --in %p --region us-east-1'
```

### Azure Key Vault example

Create a key with Azure Key Vault:
Create a key with Azure Key Vault:

```shell
az keyvault key create --vault-name pg-tde --name pg-tde-master-1
```

Use the `az keyvault` command with the `pg-tde-master-1` key to wrap and unwrap the data encryption key:
Use the `az keyvault key` command with the `pg-tde-master-1` key to wrap and unwrap the data encryption key:

```shell
PGDATAKEYWRAPCMD='crypt encrypt azure --vaultURL https://pg-tde.vault.azure.net --name pg-tde-master-1 --version fa2bf368449e432085318c5bf666754c --out %p'
PGDATAKEYUNWRAPCMD='crypt decrypt azure --vaultURL https://pg-tde.vault.azure.net --name pg-tde-master-1 --version fa2bf368449e432085318c5bf666754c --in %p'
PGDATAKEYWRAPCMD='az keyvault key encrypt --name pg-tde-master-1 --vault-name pg-tde --algorithm A256GCM --value @- --data-type plaintext --only-show-errors --output json | jq -r .result > "%p"'
PGDATAKEYUNWRAPCMD='az keyvault key decrypt --name pg-tde-master-1 --vault-name pg-tde --algorithm A256GCM --value @"%p" --data-type plaintext --only-show-errors --output json | jq -r .result'
```

This example uses [crypt](https://github.com/VirtusLab/crypt). You can't use the Azure CLI directly for this purpose because it lacks some functionality.
!!! Note
Shell commands with pipes, as in this example, are problematic because the exit status of the pipe is that of the last command. A failure of the first, more interesting command isn't reported properly. Postgres handles this somewhat by recognizing whether the wrap or unwrap command wrote nothing. However, it's better to make this more robust. For example, use the `pipefail` option available in some shells or the `mispipe` command available on some operating systems. Put more complicated commands into an external shell script or other program instead of defining them inline.

### Google Cloud KMS example

Create a key with Google Cloud KMS:
Create a key with Google Cloud KMS:

```shell
gcloud kms keys create pg-tde-master-1 --location=global --keyring=pg-tde --purpose=encryption
```

Use the `az keyvault` command with the `pg-tde-master-1` key to wrap and unwrap the data encryption key:
Use the `gcloud kms` command with the `pg-tde-master-1` key to wrap and unwrap the data encryption key:

```shell
PGDATAKEYWRAPCMD='gcloud kms encrypt --plaintext-file=- --ciphertext-file=%p --location=global --keyring=pg-tde --key=pg-tde-master-1'
PGDATAKEYUNWRAPCMD='gcloud kms decrypt --plaintext-file=- --ciphertext-file=%p --location=global --keyring=pg-tde --key=pg-tde-master-1'
```

Alternatively, you can use the [crypt utility](https://github.com/VirtusLab/crypt) to wrap and unwrap the data encryption key:

```shell
PGDATAKEYWRAPCMD='crypt encrypt gcp --out=%p --location=global --keyring=pg-tde --key=pg-tde-master-1 --project your-project-123456'
PGDATAKEYUNWRAPCMD='crypt decrypt gcp --in=%p --location=global --keyring=pg-tde --key=pg-tde-master-1 --project your-project-123456'
```

### HashiCorp Vault Transit Secrets Engine example

```shell
Expand Down

1 comment on commit 803543f

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.