Effortless HashiCorp Vault unsealing - a step-by-step guide using systemd services
· ☕ 9 min read
· 🐧 sysadmin
Introduction
Vault by HashiCorp requires unsealing after every restart to ensure the security of the secrets it stores. This tutorial will guide you through automating the unseal process using a systemd service on a Linux system.
Log in via SSH: Connect to your server as a standard user and switch to root.
1
sudo -i
Start a new bash session: Execute a new bash shell and disable history.
Explanation: For the highest security, run the command in a new shell session where history is disabled, and ensure no sensitive information is stored.
1
2
bash
set +o history
3.Create a file to store the GPG passphrase: Ensure the file is accessible only to the root user.
1
echo"your-passphrase" > /root/.gpg_passphrase
4.Set the permissions to make it readable only by the root user.
1
chmod 400 /root/.gpg_passphrase
Step 2: Encrypt the Unseal Keys
Create an encrypted file to store your unseal keys:
#!/bin/bash
exportVAULT_ADDR='https://<vault IP address>:8200'# Create log file if it doesn't existLOGFILE=/var/log/unseal_vault.log
if[ ! -f "$LOGFILE"];then touch "$LOGFILE" chown vault:vault "$LOGFILE"elseecho"$LOGFILE exists"fi# Log the start timeecho"Starting unseal at $(date)" >> $LOGFILE# Wait for Vault to be readywhile ! vault status 2>&1| grep -q "Sealed.*true";doecho"Waiting for Vault to be sealed and ready..." >> $LOGFILE sleep 5doneecho"Vault is sealed and ready at $(date)" >> $LOGFILE# Load the GPG passphraseGPG_PASSPHRASE=$(cat /root/.gpg_passphrase)# Decrypt the unseal keysUNSEAL_KEYS=$(gpg --quiet --batch --yes --decrypt --passphrase "$GPG_PASSPHRASE" /root/.vault_unseal_keys.gpg)if[$? -ne 0];thenecho"Failed to decrypt unseal keys at $(date)" >> $LOGFILEexit1fiecho"Unseal keys decrypted successfully at $(date)" >> $LOGFILE# Convert decrypted keys to an arrayUNSEAL_KEYS_ARRAY=($(echo"$UNSEAL_KEYS"))# Unseal Vaultfor key in "${UNSEAL_KEYS_ARRAY[@]}";do# commented out because I do not want to debug it anymore vault operator unseal "$key"# >> $LOGFILE 2>&1#if [ $? -ne 0 ]; then# echo "Failed to unseal with key $key at $(date)" >> $LOGFILE# exit 1#fi#echo "Successfully used unseal key $key at $(date)" >> $LOGFILEdoneecho"Vault unsealed successfully at $(date)" >> $LOGFILE
Make the script executable:
1
chmod 500 /usr/local/bin/unseal_vault.sh
Step 4: Modify Vault Service
Modify the /etc/systemd/system/vault.service file to include a dependency on the vault-unseal.service.
[Unit]Description=HashiCorp VaultDocumentation=https://www.vaultproject.io/docs/Requires=network-online.targetAfter=network-online.targetRequires=vault-unseal.service[Service]User=vaultGroup=vaultEnvironmentFile=/etc/vault.d/vault.envExecStart=/usr/local/bin/vault server -config=/etc/vault.d/vault.hclExecReload=/bin/kill --signal HUP $MAINPIDKillMode=processKillSignal=SIGINTRestart=on-failureRestartSec=5LimitNOFILE=65536LimitMEMLOCK=infinity[Install]WantedBy=multi-user.target
Step 5: Create Vault Unseal Service
Create a new service file at /etc/systemd/system/vault-unseal.service with the following content:
1
2
3
4
5
6
7
8
9
10
11
12
13
[Unit]Description=Unseal VaultAfter=vault.serviceRequires=vault.service[Service]Type=oneshotExecStart=/usr/local/bin/unseal_vault.shEnvironment=VAULT_ADDR=https://<vault IP address>:8200Environment=DBUS_SESSION_BUS_ADDRESS=$XDG_RUNTIME_DIR/bus[Install]WantedBy=multi-user.target
Step 6: Create vault.env file
1
2
3
4
cat << 'EOF' > /etc/vault.d/vault.env
VAULT_ADDR=https://<vault IP address>:8200
DBUS_SESSION_BUS_ADDRESS=$XDG_RUNTIME_DIR/bus
EOF
Step 7: export variables to .bashrc
1
2
3
4
BASHRC_PATH="$HOME/.bashrc"echo"export VAULT_ADDR='https://<vault IP address>:8200'" >> $BASHRC_PATHecho"export DBUS_SESSION_BUS_ADDRESS=\$XDG_RUNTIME_DIR/bus" >> $BASHRC_PATHsource$BASHRC_PATH
With these modifications, the vault-unseal.service will be considered part of the vault.service process. Restarting vault.service will now also trigger the vault-unseal.service.
Step 6: Reload Systemd and Start Services
Reload systemd to apply the changes and start the services:
When your system boots up, the following sequence happens:
vault.service starts: This is the main service for Vault. It will start according to its configuration.
vault-unseal.service starts: This service is configured to start after vault.service because of the After=vault.service directive. This means that vault-unseal.service will not start until vault.service has fully started.
The vault-unseal.service depends on vault.service, and it will only execute the unseal script after the Vault service is running.
Behavior on Manual Restart
Manual restart of vault.service
When you manually restart vault.service using the command:
1
systemctl restart vault.service
Here’s what happens:
vault.service stops: The Vault service stops and then starts again.
vault-unseal.service automatically restarts: The service vault-unseal.service automatically restarts just because vault.service was restarted. The vault-unseal.service is set to run after vault.service during the boot process.
Ensuring Unseal After Restart
To ensure that the vault-unseal.service runs every time vault.service is restarted, run the below command:
1
tail -f /var/log/unseal_vault.log
In another SSH session, restart the vault.service:
1
systemctl restart vault.service
Then, check the status of both services to ensure they are working as expected:
1
2
systemctl status vault.service
systemctl status vault-unseal.service
Summary
This configuration ensures a secure method of unsealing Vault by encrypting the unseal keys with GPG and securely storing the passphrase. The script fetches the passphrase and decrypts the keys at runtime, enhancing the security of your setup.
By following this guide, you ensure that sensitive unseal keys are not exposed in plaintext, and access to the passphrase is restricted to the root user, providing an additional layer of security.
The vault-unseal.service will run both during the boot process and any manual restarts of vault.service, keeping Vault automatically unsealed and operational.