Implement encryption for Consul backups using GPG with automated snapshots and secure storage

Intermediate 45 min Apr 09, 2026 880 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Learn to create encrypted Consul backups using GPG encryption with automated snapshot scripts, secure key management, and remote storage integration for production disaster recovery.

Prerequisites

  • Active Consul cluster
  • Root or sudo access
  • Basic knowledge of GPG and backup concepts
  • AWS S3 access (optional for remote storage)

What this solves

Consul cluster data requires regular encrypted backups to prevent data loss and ensure disaster recovery capabilities. This tutorial implements GPG encryption for Consul snapshots, automated backup scheduling, and secure storage strategies to protect sensitive service discovery and configuration data in production environments.

Prerequisites and system preparation

Update system packages

Start by updating your package manager to ensure you have the latest security patches and package versions.

sudo apt update && sudo apt upgrade -y
sudo dnf update -y

Install required packages

Install GPG, backup utilities, and compression tools needed for encrypted Consul backups.

sudo apt install -y gnupg2 gzip bzip2 curl jq rsync awscli
sudo dnf install -y gnupg2 gzip bzip2 curl jq rsync awscli

Verify Consul installation

Confirm that Consul is installed and accessible with the correct permissions for backup operations.

consul version
consul members
consul operator raft list-peers

Configure GPG encryption for backups

Create dedicated backup user

Create a system user specifically for handling Consul backups with minimal privileges.

sudo useradd -r -s /bin/bash -d /opt/consul-backup -m consul-backup
sudo mkdir -p /opt/consul-backup/{keys,scripts,backups,logs}
sudo chown -R consul-backup:consul-backup /opt/consul-backup
sudo chmod 700 /opt/consul-backup

Generate GPG key pair for encryption

Create a dedicated GPG key pair for encrypting Consul backups with strong security settings.

sudo -u consul-backup gpg --batch --full-generate-key <

Export and secure GPG keys

Export the public key for sharing and securely store the private key with proper permissions.

sudo -u consul-backup bash -c '
GPG_KEY_ID=$(gpg --list-secret-keys --keyid-format LONG | grep sec | cut -d"/" -f2 | cut -d" " -f1)
echo $GPG_KEY_ID > /opt/consul-backup/keys/key-id.txt
gpg --armor --export $GPG_KEY_ID > /opt/consul-backup/keys/public-key.asc
gpg --armor --export-secret-keys $GPG_KEY_ID > /opt/consul-backup/keys/private-key.asc
'
sudo chmod 600 /opt/consul-backup/keys/private-key.asc
sudo chmod 644 /opt/consul-backup/keys/public-key.asc
sudo chmod 644 /opt/consul-backup/keys/key-id.txt

Create GPG configuration

Configure GPG settings for automated operations without interactive prompts.

use-agent
pinentry-mode loopback
no-tty
batch
yes
quiet
no-greeting
no-permission-warning
no-secmem-warning
sudo chown consul-backup:consul-backup /opt/consul-backup/.gnupg/gpg.conf
sudo chmod 600 /opt/consul-backup/.gnupg/gpg.conf

Create automated backup scripts

Create main backup script

Develop a comprehensive script that creates Consul snapshots, compresses them, and encrypts with GPG.

#!/bin/bash

# Consul Encrypted Backup Script
set -euo pipefail

# Configuration
BACKUP_DIR="/opt/consul-backup/backups"
LOG_DIR="/opt/consul-backup/logs"
KEY_DIR="/opt/consul-backup/keys"
DATE=$(date +"%Y%m%d-%H%M%S")
HOSTNAME=$(hostname -s)
BACKUP_NAME="consul-snapshot-${HOSTNAME}-${DATE}"
LOG_FILE="${LOG_DIR}/backup-${DATE}.log"
RETENTION_DAYS=30
COMPRESSION_LEVEL=9

# Consul configuration
CONSUL_HTTP_ADDR=${CONSUL_HTTP_ADDR:-"127.0.0.1:8500"}
CONSUL_TOKEN_FILE=${CONSUL_TOKEN_FILE:-"/etc/consul/tokens/backup-token"}
CONSUL_CACERT=${CONSUL_CACERT:-"/etc/consul/tls/ca-cert.pem"}
CONSUL_CLIENT_CERT=${CONSUL_CLIENT_CERT:-"/etc/consul/tls/client-cert.pem"}
CONSUL_CLIENT_KEY=${CONSUL_CLIENT_KEY:-"/etc/consul/tls/client-key.pem"}

# GPG key ID
GPG_KEY_ID=$(cat ${KEY_DIR}/key-id.txt)

# Logging function
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}"
}

# Error handling
error_exit() {
    log "ERROR: $1"
    exit 1
}

# Start backup process
log "Starting Consul backup process"

# Check Consul connectivity
log "Checking Consul connectivity"
if ! consul members >/dev/null 2>&1; then
    error_exit "Cannot connect to Consul cluster"
fi

# Create temporary directory for processing
TEMP_DIR=$(mktemp -d)
trap "rm -rf ${TEMP_DIR}" EXIT

# Create snapshot
log "Creating Consul snapshot"
if [[ -f "${CONSUL_TOKEN_FILE}" ]]; then
    CONSUL_HTTP_TOKEN=$(cat "${CONSUL_TOKEN_FILE}")
    export CONSUL_HTTP_TOKEN
fi

consul snapshot save "${TEMP_DIR}/${BACKUP_NAME}.snap" 2>>"${LOG_FILE}" || error_exit "Failed to create Consul snapshot"

# Verify snapshot
log "Verifying snapshot integrity"
consul snapshot inspect "${TEMP_DIR}/${BACKUP_NAME}.snap" >/dev/null 2>>"${LOG_FILE}" || error_exit "Snapshot verification failed"

# Compress snapshot
log "Compressing snapshot with gzip level ${COMPRESSION_LEVEL}"
gzip -${COMPRESSION_LEVEL} "${TEMP_DIR}/${BACKUP_NAME}.snap" || error_exit "Compression failed"

# Encrypt compressed snapshot
log "Encrypting backup with GPG key ${GPG_KEY_ID}"
gpg --trust-model always --batch --yes --compress-algo 0 \
    --cipher-algo AES256 --digest-algo SHA512 \
    --s2k-digest-algo SHA512 --s2k-cipher-algo AES256 \
    --recipient "${GPG_KEY_ID}" \
    --encrypt "${TEMP_DIR}/${BACKUP_NAME}.snap.gz" \
    2>>"${LOG_FILE}" || error_exit "GPG encryption failed"

# Move encrypted backup to final location
log "Moving encrypted backup to storage directory"
mv "${TEMP_DIR}/${BACKUP_NAME}.snap.gz.gpg" "${BACKUP_DIR}/" || error_exit "Failed to move backup file"

# Create metadata file
log "Creating backup metadata"
cat > "${BACKUP_DIR}/${BACKUP_NAME}.meta" <
sudo chown consul-backup:consul-backup /opt/consul-backup/scripts/consul-backup.sh
sudo chmod 750 /opt/consul-backup/scripts/consul-backup.sh

Create backup restoration script

Build a script to decrypt and restore Consul snapshots from encrypted backups.

#!/bin/bash

# Consul Backup Restoration Script
set -euo pipefail

# Configuration
BACKUP_DIR="/opt/consul-backup/backups"
LOG_DIR="/opt/consul-backup/logs"
DATE=$(date +"%Y%m%d-%H%M%S")
LOG_FILE="${LOG_DIR}/restore-${DATE}.log"

# Usage function
usage() {
    echo "Usage: $0 
sudo chown consul-backup:consul-backup /opt/consul-backup/scripts/consul-restore.sh
sudo chmod 750 /opt/consul-backup/scripts/consul-restore.sh

Create backup verification script

Implement automated verification to ensure backup integrity and decryption capabilities.

#!/bin/bash

# Consul Backup Verification Script
set -euo pipefail

BACKUP_DIR="/opt/consul-backup/backups"
LOG_DIR="/opt/consul-backup/logs"
DATE=$(date +"%Y%m%d-%H%M%S")
LOG_FILE="${LOG_DIR}/verify-${DATE}.log"

# Logging function
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}"
}

log "Starting backup verification process"

# Verify recent backups
BACKUPS_VERIFIED=0
BACKUPS_FAILED=0

for backup_file in $(ls -t "${BACKUP_DIR}"/*.gpg 2>/dev/null | head -5); do
    backup_name=$(basename "$backup_file")
    log "Verifying ${backup_name}"
    
    # Create temporary directory
    TEMP_DIR=$(mktemp -d)
    
    # Try to decrypt and verify
    if gpg --batch --yes --decrypt "$backup_file" > "${TEMP_DIR}/test.snap.gz" 2>/dev/null; then
        if gunzip "${TEMP_DIR}/test.snap.gz" 2>/dev/null; then
            if consul snapshot inspect "${TEMP_DIR}/test.snap" >/dev/null 2>&1; then
                log "✓ ${backup_name} verification successful"
                ((BACKUPS_VERIFIED++))
            else
                log "✗ ${backup_name} snapshot integrity check failed"
                ((BACKUPS_FAILED++))
            fi
        else
            log "✗ ${backup_name} decompression failed"
            ((BACKUPS_FAILED++))
        fi
    else
        log "✗ ${backup_name} decryption failed"
        ((BACKUPS_FAILED++))
    fi
    
    rm -rf "${TEMP_DIR}"
done

log "Verification complete: ${BACKUPS_VERIFIED} successful, ${BACKUPS_FAILED} failed"

if [[ $BACKUPS_FAILED -gt 0 ]]; then
    exit 1
fi

exit 0
sudo chown consul-backup:consul-backup /opt/consul-backup/scripts/verify-backup.sh
sudo chmod 750 /opt/consul-backup/scripts/verify-backup.sh

Configure secure storage integration

Create S3 sync script for remote storage

Set up secure remote storage synchronization with S3-compatible storage for offsite backup retention.

#!/bin/bash

# S3 Backup Sync Script
set -euo pipefail

# Configuration - adjust these variables
S3_BUCKET="consul-backups-$(hostname -s)"
S3_PREFIX="consul/$(date +%Y/%m)"
BACKUP_DIR="/opt/consul-backup/backups"
LOG_DIR="/opt/consul-backup/logs"
DATE=$(date +"%Y%m%d-%H%M%S")
LOG_FILE="${LOG_DIR}/s3sync-${DATE}.log"
RETENTION_DAYS=90

# AWS CLI configuration check
if ! aws sts get-caller-identity >/dev/null 2>&1; then
    echo "Error: AWS CLI not configured or credentials invalid"
    exit 1
fi

# Logging function
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}"
}

log "Starting S3 backup synchronization"

# Sync recent backups to S3
log "Syncing backups to S3: s3://${S3_BUCKET}/${S3_PREFIX}/"
aws s3 sync "${BACKUP_DIR}" "s3://${S3_BUCKET}/${S3_PREFIX}/" \
    --exclude "*" \
    --include "*.gpg" \
    --include "*.meta" \
    --storage-class STANDARD_IA \
    --server-side-encryption AES256 \
    2>>"${LOG_FILE}" || {
    log "S3 sync failed"
    exit 1
}

# Clean old S3 backups
log "Cleaning S3 backups older than ${RETENTION_DAYS} days"
CUTOFF_DATE=$(date -d "${RETENTION_DAYS} days ago" +%Y-%m-%d)
aws s3 ls "s3://${S3_BUCKET}/consul/" --recursive | \
    awk '$1 <= "'${CUTOFF_DATE}'" {print $4}' | \
    while read -r key; do
        if [[ -n "$key" ]]; then
            log "Deleting old backup: s3://${S3_BUCKET}/${key}"
            aws s3 rm "s3://${S3_BUCKET}/${key}" 2>>"${LOG_FILE}" || true
        fi
    done

log "S3 synchronization completed"

exit 0
sudo chown consul-backup:consul-backup /opt/consul-backup/scripts/sync-to-s3.sh
sudo chmod 750 /opt/consul-backup/scripts/sync-to-s3.sh

Configure AWS credentials for backup user

Set up AWS credentials for the backup user with minimal required permissions for S3 operations.

sudo -u consul-backup mkdir -p /opt/consul-backup/.aws
sudo -u consul-backup tee /opt/consul-backup/.aws/credentials >/dev/null <
Note: Replace YOUR_ACCESS_KEY_ID and YOUR_SECRET_ACCESS_KEY with actual AWS credentials that have S3 permissions for your backup bucket.

Create S3 bucket and IAM policy

Create the S3 bucket and IAM policy with minimal permissions for secure backup storage.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetBucketLocation"
            ],
            "Resource": "arn:aws:s3:::consul-backups-*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject"
            ],
            "Resource": "arn:aws:s3:::consul-backups-*/consul/*"
        }
    ]
}
# Create S3 bucket
aws s3 mb s3://consul-backups-$(hostname -s) --region us-east-1

# Enable versioning
aws s3api put-bucket-versioning \
    --bucket consul-backups-$(hostname -s) \
    --versioning-configuration Status=Enabled

# Create IAM user and attach policy
aws iam create-user --user-name consul-backup-user
aws iam create-policy --policy-name ConsulBackupPolicy \
    --policy-document file://consul-backup-policy.json
aws iam attach-user-policy --user-name consul-backup-user \
    --policy-arn arn:aws:iam::ACCOUNT-ID:policy/ConsulBackupPolicy

Set up automated scheduling and monitoring

Configure systemd timer for automated backups

Create systemd service and timer units for reliable automated backup scheduling.

[Unit]
Description=Consul Encrypted Backup Service
After=consul.service
Requires=consul.service

[Service]
Type=oneshot
User=consul-backup
Group=consul-backup
WorkingDirectory=/opt/consul-backup
Environment="PATH=/usr/local/bin:/usr/bin:/bin"
ExecStart=/opt/consul-backup/scripts/consul-backup.sh
ExecStartPost=/opt/consul-backup/scripts/sync-to-s3.sh
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/consul-backup
NoNewPrivileges=true
[Unit]
Description=Run Consul Backup Every 6 Hours
Requires=consul-backup.service

[Timer]
OnCalendar=*-*-* 00,06,12,18:00:00
RandomizedDelaySec=300
Persistent=true

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable consul-backup.timer
sudo systemctl start consul-backup.timer

Configure backup verification timer

Set up daily verification of backup integrity to ensure recovery capabilities.

[Unit]
Description=Consul Backup Verification Service
After=consul.service

[Service]
Type=oneshot
User=consul-backup
Group=consul-backup
WorkingDirectory=/opt/consul-backup
Environment="PATH=/usr/local/bin:/usr/bin:/bin"
ExecStart=/opt/consul-backup/scripts/verify-backup.sh
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/consul-backup
NoNewPrivileges=true
[Unit]
Description=Verify Consul Backups Daily
Requires=consul-backup-verify.service

[Timer]
OnCalendar=daily
RandomizedDelaySec=1800
Persistent=true

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable consul-backup-verify.timer
sudo systemctl start consul-backup-verify.timer

Create monitoring and alerting scri

Automated install script

Run this to automate the entire setup

Nie chcesz zarządzać tym samodzielnie?

Zarządzamy infrastrukturą firm, które zależą od dostępności. W pełni zarządzana, z jednym stałym kontaktem, który zna Twoje środowisko.

Macie jednego stałego opiekuna, który zna Waszą konfigurację

Rotterdam 06:14 · dostępny w wiadomości, bez formularza zgłoszeń