Skip to content

Data-at-rest encryption

Data-at-rest encryption ensures that stored data remains protected even if the underlying storage is compromised. Percona Operator for MongoDB uses the data-at-rest encryption implementation in Percona Server for MongoDB to protect your data.

Data-at-rest encryption is turned on by default. It uses two-tiered key architecture to secure your data:

  • Each database instance generates a unique encryption key for every database. These keys are stored internally, close to the data they encrypt
  • The master encryption key is used to encrypt database keys. It is stored separately from database keys, either in a Secret or in an external key management service like HashiCorp Vault.

Use encryption key Secret

  1. Specify the name of the encryption key Secret in the secrets.encryptionKey key in the deploy/cr.yaml file:

    secrets:
      ...
      encryptionKey: my-cluster-name-mongodb-encryption-key
    

    The Operator creates the encryption key Secret automatically if it doesn’t exist. If you would like to create it yourself, take into account that the key must be a 32 character string encoded in base64 .

  2. Specify the following MongoDB encryption-specific options in the replsets.configuration, replsets.nonvoting.configuration, and sharding.configsvrReplSet.configuration keys:

    ...
    configuration: |
      ...
      security:
        enableEncryption: true
        encryptionCipherMode: "AES256-CBC"
        ...
    

    Set the enableEncryption option to true (the default value). Specify a proper cipher mode for decryption in the security.encryptionCipherMode option. It should be either AES256-CBC (the default value) or AES256-GCM.

Apply the modified cr.yaml configuration file:

$ kubectl deploy -f deploy/cr.yaml

Use HashiCorp Vault storage for encryption keys

Starting from the version 1.13, you can configure the Operator to use HashiCorp Vault to securely store and manage master encryption keys, enabling automatic key rotation, audit logging, and compliance with enterprise security standards.

To use Vault, the deploy/cr.yaml configuration file must include the following items:

  • a secrets.vault key equal to the name of a specially created Secret,
  • configuration keys for mongod and config servers with a number of Vault-specific options.

The Operator itself neither installs Vault, nor configures it. You must do both operations manually. Refer to the following sections for steps.

Create the namespace

It is a good practice to isolate workloads in Kubernetes using namespaces. Create a namespace with the following command:

$ kubectl create namespace vault

Export the namespace as an environment variable to simplify further configuration and management

NAMESPACE="vault"

Install Vault

For this setup, we install Vault in Kubernetes using the Helm 3 package manager . However, Helm is not required — any supported Vault deployment (on-premises, in the cloud, or a managed Vault service) works as long as the Operator can reach it.

Read more about installation in Vault documentation .

  1. Add and update the Vault Helm repository.

    $ helm repo add hashicorp https://helm.releases.hashicorp.com
    $ helm repo update
    
  2. Install Vault:

    $ helm install vault hashicorp/vault --namespace $NAMESPACE
    
    Sample output
    NAME: vault
    LAST DEPLOYED: Thu Sep 18 12:11:08 2025
    NAMESPACE: vault
    STATUS: deployed
    REVISION: 1
    NOTES:
    Thank you for installing HashiCorp Vault!
    
    Now that you have deployed Vault, you should look over the docs on using
    Vault with Kubernetes available here:
    https://developer.hashicorp.com/vault/docs
    
  3. Retrieve the Pod name where Vault is running:

    $ kubectl -n $NAMESPACE get pod -l app.kubernetes.io/name=vault -o jsonpath='{.items[0].metadata.name}'
    
    Sample output
    vault-0
    
  4. After Vault is installed, you need to initialize it. Run the following command:

    $ kubectl exec -it pod/vault-0 -n $NAMESPACE -- vault operator init -key-shares=1 -key-threshold=1 -format=json > /tmp/vault-init
    $ unsealKey=$(jq -r ".unseal_keys_b64[]" < /tmp/vault-init)
    

    The command does the following:

    • Connects to the Vault Pod
    • Initializes Vault server
    • Creates 1 unseal key share which is required to unseal the server
    • Outputs the init response in JSON format to a local file /tmp/vault-init. It includes unseal keys and root token.
  5. Vault is started in a sealed state. In this state Vault can access the storage but it cannot decrypt data. In order to use Vault, you need to unseal it.

    Retrieve the unseal key from the file:

    $ unsealKey=$(jq -r ".unseal_keys_b64[]" < /tmp/vault-init)
    
  6. Now, unseal Vault. Run the following command on every Pod where Vault is running:

    $ kubectl exec -it pod/vault-0 -n $NAMESPACE -- vault operator unseal "$unsealKey"
    
    Sample output
    Key             Value
    ---             -----
    Seal Type       shamir
    Initialized     true
    Sealed          false
    Total Shares    1
    Threshold       1
    Version         1.20.1
    Build Date      2025-07-24T13:33:51Z
    Storage Type    file
    Cluster Name    vault-cluster-55062a37
    Cluster ID      37d0c2e4-8f47-14f7-ca49-905b66a1804d
    HA Enabled      false
    

Configure Vault

At this step you need to configure Vault and enable secrets within it. To do so you must first authenticate in Vault.

When you started Vault, it generates and starts with a root token that provides full access to Vault. Use this token to authenticate.

Note

For the purposes of this tutorial we use the root token in further sections. For security considerations, the use of root token is not recommended. Refer to the Create token in Vault documentation how to create user tokens.

  1. Extract the Vault root token from the file where you saved the init response output:

    $ cat /tmp/vault-init | jq -r ".root_token"
    
    Sample output
    hvs.CvmS......gXWMJg9r
    
  2. Authenticate in Vault with this token:

    $ kubectl exec -it vault-0 -n $NAMESPACE -- /bin/sh
    $ vault login hvs.CvmS......gXWMJg9r
    
    Expected output
    Success! You are now authenticated. The token information displayed below
    is already stored in the token helper. You do NOT need to run "vault login"
    again. Future Vault requests will automatically use this token.
    
    Key                  Value
    ---                  -----
    token                hvs.CvmS......gXWMJg9r
    token_accessor       iMGp477aReYkPBWrR42Z3L6R
    token_duration       ∞
    token_renewable      false
    token_policies       ["root"]
    identity_policies    []
    policies             ["root"]`
    
  3. Now enable the key-value secrets engine at the path secret with the following command:

    $ vault secrets enable -path secret kv-v2
    
    Expected output
    Success! Enabled the kv-v2 secrets engine at: secret/
    
  4. (Optional) You can also enable audit. This is not mandatory, but useful:

    $ vault audit enable file file_path=/vault/vault-audit.log
    
    Expected output
    Success! Enabled the file audit device at: file/
    

Create a Secret for Vault

To enable Vault for the Operator, create a Secret object for it using the Vault token.

$ kubectl create secret generic vault-secret --from-literal=token="hvs.CvmS......gXWMJg9r"

=== “HTTPS access with TLS”

 If you [deployed Vault with TLS :octicons-link-external-16:](https://developer.hashicorp.com/vault/docs/auth/cert), include the path to TLS certificates when you create a Secret.

``` {.bash data-prompt="$" }
$ kubectl create secret generic vault-secret --from-literal=token="hvs.CvmS......gXWMJg9r" --from-file=ca.crt=<path to CA>/ca.crt
```

Reference the Secret in your Custom Resource manifest

Now, reference the Vault Secret in the Operator Custom Resource manifest. You also need the following Vault-related information:

  • A Vault server name and port
  • Path to the token file. When you apply the new configuration, the Operator creates the required directories and places the token file there.
  • The secrets mount path in the format <mount-path>/data/dc/<cluster name>/<path>.
  • Path to TLS certificates if you deployed Vault with TLS
  • Contents of the ca.cert certificate file

Modify your deploy/cr.yaml as follows:

  1. Set the secrets.vault key to the name of your Secret created on the previous step.
  2. Add Vault-specific options to the replsets.configuration, replsets.nonvoting.configuration, and sharding.configsvrReplSet.configuration keys, using the following template:

    secrets:
      vault: vault-secret
    ...
    configuration: |
      ...
      security:
        enableEncryption: true
        vault:
          serverName: vault
          port: 8200
          tokenFile: /etc/mongodb-vault/token
          secret: secret/data/dc/<cluster name>/<path>
          disableTLSForTesting: true
        ...
    
  1. Set the secrets.vault key to the name of your Secret created on the previous step.
  2. Add Vault-specific options to the replsets.configuration, replsets.nonvoting.configuration, and sharding.configsvrReplSet.configuration keys, using the following template:

    ...
    configuration: |
      ...
      security:
        enableEncryption: true
        vault:
          serverName: vault
          port: 8200
          tokenFile: /etc/mongodb-vault/token
          secret: secret/data/dc/<cluster name>/<path>
          serverCAFile: /etc/mongodb-vault/ca.crt
        ...
    

While adding options, modify this template as follows:

  • substitute the <cluster name> placeholder with your real cluster name,
  • substitute the placeholder with rs0 when adding options to replsets.configuration and replsets.nonvoting.configuration,
  • substitute the placeholder with cfg when adding options to sharding.configsvrReplSet.configuration.
  1. Apply your modified cr.yaml file:

    $ kubectl deploy -f deploy/cr.yaml
    
  2. To verify that everything was configured properly, use the following log filtering command (substitute the <cluster name> and <namespace> placeholders with your real cluster name and namespace):

    $ kubectl logs <cluster name>-rs0-0 -c mongod -n <namespace> | grep -i "Encryption keys DB is initialized successfully"
    

Find more details on how to install and configure Vault in Vault documentation .


Last update: 2025-09-22