Skip to main content

Gitops: Ensure Secret Files Are Encrypted Before Commits

·3 mins

Overview #

A Git pre-commit hook that automatically encrypts secret files before they’re committed prevents accidental exposure of sensitive data.

The Problem #

Manually encrypting secrets is error-prone:

  • Forget to encrypt → secrets leak to Git history
  • Committed secrets are permanent (even if deleted later)
  • Removing from history requires force-pushing and invalidating secrets

The Solution #

Automate encryption with a pre-commit hook that:

  1. Detects staged files matching secret patterns
  2. Checks if they’re encrypted (looks for sops: marker)
  3. Auto-encrypts unencrypted files
  4. Re-stages the encrypted version

Implementation #

Save to .git/hooks/pre-commit:

#!/bin/bash
# Pre-commit hook: Auto-encrypt secrets based on .sops.yaml patterns

set -e

REPO_ROOT=$(git rev-parse --show-toplevel)
cd "$REPO_ROOT"

SOPS_CONFIG=".sops.yaml"
if [ ! -f "$SOPS_CONFIG" ]; then
  exit 0
fi

# Extract path_regex patterns from .sops.yaml
PATTERNS=$(grep -E '^\s+- path_regex:' "$SOPS_CONFIG" | \
           sed -E 's/^\s+- path_regex:\s+//' | \
           tr -d '"' | \
           sed 's/\.\*/*/g' | \
           sed 's/\\\././g' | \
           sed 's/\$$//')

if [ -z "$PATTERNS" ]; then
  exit 0
fi

# Get staged files
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)

if [ -z "$STAGED_FILES" ]; then
  exit 0
fi

# Find unencrypted files matching patterns
UNENCRYPTED=""
while IFS= read -r file; do
  if [ ! -f "$file" ]; then
    continue
  fi

  # Check if file matches any pattern
  MATCHES=false
  while IFS= read -r pattern; do
    case "$file" in
      $pattern)
        MATCHES=true
        break
        ;;
    esac
  done <<< "$PATTERNS"

  if [ "$MATCHES" = true ] && ! grep -q "sops:" "$file" 2>/dev/null; then
    UNENCRYPTED="$UNENCRYPTED$file"$'\n'
  fi
done <<< "$STAGED_FILES"

# Remove trailing newline
UNENCRYPTED=$(echo "$UNENCRYPTED" | sed '/^$/d')

if [ -n "$UNENCRYPTED" ]; then
  echo "🔒 SOPS: Auto-encrypting unencrypted secrets..."
  while IFS= read -r file; do
    if [ -n "$file" ]; then
      echo "  - $file"
      if sops --encrypt --in-place "$file" 2>/dev/null; then
        git add "$file"  # Re-add encrypted version
      else
        echo "  ⚠️  Failed to encrypt $file (skipping)"
      fi
    fi
  done <<< "$UNENCRYPTED"
  echo "✅ SOPS: Secrets encrypted and re-staged"
fi

exit 0

Make it executable:

chmod +x .git/hooks/pre-commit

How It Works #

Step 1: Configuration Detection #

Reads encryption rules from .sops.yaml:

creation_rules:
  - path_regex: .*secret.*\.yaml$
    age: age1nav5lwz...
    encrypted_regex: ^(data|stringData)$

Step 2: Pattern Matching #

Converts SOPS regex patterns (.*secret.*\.yaml$) to shell patterns (*secret*.yaml)

Step 3: Encryption Check #

For each staged file matching the pattern:

  • Checks if file contains sops: metadata
  • If missing → file is unencrypted

Step 4: Auto-Encryption #

Runs sops --encrypt --in-place on unencrypted files and re-stages them

Example Output #

$ git commit -m "Add API keys"
🔒 SOPS: Auto-encrypting unencrypted secrets...
  - config/api-keys-secret.yaml
  - deployments/db-secret.yaml
✅ SOPS: Secrets encrypted and re-staged
[main abc123] Add API keys
 2 files changed, 15 insertions(+)

Prerequisites #

Benefits #

  • Zero-effort security: Developers don’t need to remember to encrypt
  • No leaked secrets: Hook prevents unencrypted commits
  • Clean history: Only encrypted secrets in Git
  • Team-friendly: Works for everyone with the hook installed

Limitations #

  • Only protects new commits (doesn’t fix history)
  • Requires hook installed locally (not enforced by remote)
  • Consider: Server-side hooks or CI checks for enforcement

Alternative: CI/CD Validation #

Add to CI pipeline for additional safety:

# Check for unencrypted secrets
unencrypted=$(find . -name '*secret*.yaml' -type f ! -exec grep -q 'sops:' {} \; -print)
if [ -n "$unencrypted" ]; then
  echo "❌ Unencrypted secrets found: $unencrypted"
  exit 1
fi

Conclusion #

Automating secret encryption eliminates human error and protects sensitive data before it enters version control. Combined with proper SOPS setup, it creates a robust, developer-friendly security workflow.