Files
nixos/scripts/update-secrets-keys

171 lines
4.3 KiB
Bash
Executable File

#!/usr/bin/env bash
set -Euo pipefail
# Script to update sops keys for all secrets.yaml files in the project
# Uses .sops.yaml configuration to determine encryption keys
AGE_KEY_FILE=""
DRY_RUN=false
VERBOSE=false
# Parse options
while [[ $# -gt 0 ]]; do
case $1 in
-k|--age-key-file)
AGE_KEY_FILE="$2"
shift 2
;;
-n|--dry-run)
DRY_RUN=true
shift
;;
-v|--verbose)
VERBOSE=true
shift
;;
-h|--help)
cat <<EOF
Usage: $0 [OPTIONS]
Updates sops encryption keys for all secrets.yaml files in the project.
Uses .sops.yaml configuration to determine which keys to use.
OPTIONS:
-k, --age-key-file PATH Path to age key file for decryption (default: uses SOPS_AGE_KEY_FILE env var)
-n, --dry-run Show which files would be updated without making changes
-v, --verbose Show detailed output
-h, --help Show this help message
EXAMPLES:
# Update all secrets using default age key
$0
# Use specific age key file
$0 --age-key-file ~/.config/sops/age/keys.txt
# Dry run to see which files would be updated
$0 --dry-run --verbose
ENVIRONMENT:
SOPS_AGE_KEY_FILE Default age key file location (if -k not specified)
EOF
exit 0
;;
*)
echo "ERROR: Unknown option: $1" >&2
echo "Use --help for usage information." >&2
exit 1
;;
esac
done
# Check if 'sops' command is available
if ! command -v sops > /dev/null; then
echo "ERROR: 'sops' command not found. Please ensure it is installed and in your PATH." >&2
echo "Install with: nix-shell -p sops" >&2
exit 1
fi
# Determine the absolute directory where the script itself is located
SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
PROJECT_ROOT=$(readlink -f "$SCRIPT_DIR/..")
# Check if .sops.yaml exists
SOPS_CONFIG="$PROJECT_ROOT/.sops.yaml"
if [ ! -f "$SOPS_CONFIG" ]; then
echo "ERROR: .sops.yaml not found at '$SOPS_CONFIG'" >&2
exit 1
fi
# Export age key file if provided
if [ -n "$AGE_KEY_FILE" ]; then
if [ ! -f "$AGE_KEY_FILE" ]; then
echo "ERROR: Age key file not found at '$AGE_KEY_FILE'" >&2
exit 1
fi
export SOPS_AGE_KEY_FILE="$AGE_KEY_FILE"
if [ "$VERBOSE" = true ]; then
echo "INFO: Using age key file: $AGE_KEY_FILE"
fi
elif [ -z "${SOPS_AGE_KEY_FILE:-}" ]; then
echo "WARNING: SOPS_AGE_KEY_FILE not set. You may not be able to decrypt secrets." >&2
echo " Use --age-key-file to specify a key file, or set SOPS_AGE_KEY_FILE environment variable." >&2
fi
# Find all secrets.yaml files
echo "INFO: Searching for secrets.yaml files in $PROJECT_ROOT..."
mapfile -t SECRET_FILES < <(find "$PROJECT_ROOT" -name "secrets.yaml" -type f | sort)
if [ ${#SECRET_FILES[@]} -eq 0 ]; then
echo "WARNING: No secrets.yaml files found in the project." >&2
exit 0
fi
echo "INFO: Found ${#SECRET_FILES[@]} secrets.yaml file(s)"
if [ "$VERBOSE" = true ] || [ "$DRY_RUN" = true ]; then
for file in "${SECRET_FILES[@]}"; do
relative_path="${file#$PROJECT_ROOT/}"
echo " - $relative_path"
done
fi
if [ "$DRY_RUN" = true ]; then
echo "INFO: Dry-run mode enabled. No files will be modified."
exit 0
fi
# Update keys for each file
UPDATED_COUNT=0
FAILED_COUNT=0
SKIPPED_COUNT=0
for file in "${SECRET_FILES[@]}"; do
relative_path="${file#$PROJECT_ROOT/}"
if [ "$VERBOSE" = true ]; then
echo "INFO: Updating keys for: $relative_path"
else
echo -n "Updating $relative_path... "
fi
# Check if file is encrypted with sops
if ! grep -q "^sops:" "$file" 2>/dev/null; then
echo "SKIP (not encrypted)"
((SKIPPED_COUNT++))
continue
fi
# Run sops updatekeys
if sops updatekeys --yes "$file" 2>&1 | {
if [ "$VERBOSE" = true ]; then
cat
else
grep -v "^$" || true
fi
}; then
if [ "$VERBOSE" != true ]; then
echo "OK"
fi
((UPDATED_COUNT++))
else
EXIT_STATUS=$?
echo "FAILED (exit code: $EXIT_STATUS)" >&2
((FAILED_COUNT++))
fi
done
# Summary
echo ""
echo "===== Summary ====="
echo "Total files found: ${#SECRET_FILES[@]}"
echo "Successfully updated: $UPDATED_COUNT"
echo "Failed: $FAILED_COUNT"
echo "Skipped: $SKIPPED_COUNT"
if [ $FAILED_COUNT -gt 0 ]; then
exit 1
fi
echo "INFO: All secrets.yaml files have been updated successfully."
exit 0