Giao diện
Git Security - Signing & Secret Management 🔐
ROLE: HPN (Security Engineering).
AUDIENCE: Engineers bảo vệ code integrity và credential safety.
Mỗi ngày có hàng ngàn secrets bị leak lên GitHub. Module này dạy bạn cách xác thực danh tính với GPG/SSH signing và xử lý disaster khi secrets bị commit nhầm.
🎯 Mục tiêu
Sau module này, bạn sẽ:
- Hiểu tại sao commits cần "Verified" badge
- Setup GPG/SSH signing cho commits và tags
- Xử lý secret leak disaster đúng cách
- Thiết lập prevention tools để không bao giờ lặp lại
✅ Commit Signing - The "Verified" Badge
The Problem: Identity Spoofing
bash
# Ai cũng có thể giả danh bạn!
git config user.name "Linus Torvalds"
git config user.email "torvalds@linux-foundation.org"
git commit -m "feat: definitely written by Linus"Git không verify identity. Bất kỳ ai cũng có thể set bất kỳ name/email nào.
The Solution: Cryptographic Signing
🔑 GPG Signing Setup
Step 1: Generate GPG Key
bash
# Generate new key
gpg --full-generate-key
# Chọn options:
# - Kind: RSA and RSA (default)
# - Keysize: 4096
# - Expiry: 0 (không hết hạn) hoặc 1y
# - Real name: Your Name
# - Email: your.email@example.com (PHẢI khớp với GitHub email)
# - Passphrase: Strong passwordStep 2: Get Your Key ID
bash
# List keys
gpg --list-secret-keys --keyid-format=long
# Output:
# sec rsa4096/3AA5C34371567BD2 2023-01-01 [SC]
# AB12CD34EF56GH78IJ90KL12MN34OP56QR78ST90
# uid [ultimate] Your Name <your.email@example.com>
# ssb rsa4096/1234567890ABCDEF 2023-01-01 [E]
# Key ID là phần sau "rsa4096/": 3AA5C34371567BD2Step 3: Configure Git
bash
# Set signing key
git config --global user.signingkey 3AA5C34371567BD2
# Auto-sign all commits
git config --global commit.gpgsign true
# Auto-sign all tags
git config --global tag.gpgsign true
# Specify GPG program (nếu cần)
git config --global gpg.program gpgStep 4: Add to GitHub/GitLab
bash
# Export public key
gpg --armor --export 3AA5C34371567BD2
# Copy output và add vào:
# GitHub: Settings → SSH and GPG keys → New GPG key
# GitLab: Settings → GPG KeysSigning Commands
bash
# Sign a commit manually (nếu không auto-sign)
git commit -S -m "feat: signed commit"
# Sign a tag
git tag -s v1.0.0 -m "Signed release"
# Verify a commit
git verify-commit HEAD
# Verify a tag
git verify-tag v1.0.0
# Show signature in log
git log --show-signature🔐 SSH Signing (Modern Alternative)
Git 2.34+ hỗ trợ SSH keys để signing - đơn giản hơn GPG!
Setup SSH Signing
bash
# 1. Sử dụng SSH key có sẵn hoặc tạo mới
ssh-keygen -t ed25519 -C "your.email@example.com"
# 2. Configure Git
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
# 3. Auto-sign
git config --global commit.gpgsign true
git config --global tag.gpgsign true
# 4. Allowed signers file (cho verification)
echo "your.email@example.com $(cat ~/.ssh/id_ed25519.pub)" >> ~/.ssh/allowed_signers
git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signersGPG vs SSH Signing
| Feature | GPG | SSH |
|---|---|---|
| Setup complexity | Higher | Lower |
| Key management | Separate keyring | Reuse SSH keys |
| Web of Trust | Yes | No |
| GitHub support | Yes | Yes (Git 2.34+) |
| Expiry/Revocation | Built-in | Manual |
HPN RECOMMENDATION
Dùng SSH signing nếu bạn đã có SSH key và không cần Web of Trust. Đơn giản hơn, không cần manage separate GPG keyring.
🚨 Disaster Recovery: Secrets in History
The Horror Scenario
bash
# Oops...
echo "AWS_SECRET_KEY=AKIAIOSFODNN7EXAMPLE" >> config.py
git add config.py
git commit -m "add config"
git push origin main
# 😱 Secret đã ở trong PUBLIC history forever!Xóa file trong commit mới KHÔNG đủ. Secret vẫn trong history.
Step 1: Damage Control (Ngay lập tức!)
bash
# 1. ROTATE credentials NGAY (quan trọng nhất!)
# - AWS: IAM Console → Deactivate key → Create new key
# - Database: Change password
# - API keys: Regenerate
# 2. Check GitHub Secret Scanning alerts
# GitHub tự động scan và notify nếu detect secretsCRITICAL
Rotate credentials TRƯỚC khi clean history. Bots scan GitHub real-time. Trong 5 phút secret bị push, nó có thể đã bị exploit.
Step 2: Clean History với git filter-repo
Modern, fast alternative cho deprecated git filter-branch.
bash
# Install
pip install git-filter-repo
# Clone fresh copy (required)
git clone --mirror https://github.com/you/repo.git repo-mirror
cd repo-mirror
# Remove file from ALL history
git filter-repo --path config.py --invert-paths
# Hoặc replace text trong ALL history
git filter-repo --replace-text expressions.txt
# expressions.txt:
# AKIAIOSFODNN7EXAMPLE==>***REMOVED***
# Push rewritten history
git push --forceAlternative: BFG Repo-Cleaner
Java-based, very fast cho large repos.
bash
# Download BFG
# https://rtyley.github.io/bfg-repo-cleaner/
# Clone fresh mirror
git clone --mirror https://github.com/you/repo.git repo-mirror
# Remove file
java -jar bfg.jar --delete-files config.py repo-mirror
# Remove specific text
echo "AKIAIOSFODNN7EXAMPLE" > passwords.txt
java -jar bfg.jar --replace-text passwords.txt repo-mirror
# Cleanup và push
cd repo-mirror
git reflog expire --expire=now --all
git gc --prune=now --aggressive
git push --forceComparison
| Tool | Speed | Use Case |
|---|---|---|
git filter-repo | Fast | Modern, Python-based, recommended |
BFG Repo-Cleaner | Very fast | Large repos, simple operations |
git filter-branch | Slow | ❌ Deprecated, avoid |
Step 3: Notify Collaborators
bash
# After force push, collaborators cần:
git fetch origin
git reset --hard origin/main
# Hoặc re-clone repositoryTEAM COMMUNICATION
Báo team TRƯỚC khi force push. Họ cần reset local branches.
🛡️ Prevention: Never Commit Secrets Again
1. Global .gitignore
bash
# Setup global gitignore
git config --global core.excludesFile ~/.gitignore_global
# Edit ~/.gitignore_global
cat >> ~/.gitignore_global << 'EOF'
# Secrets
.env
.env.*
*.pem
*.key
*_rsa
*_ed25519
*.p12
*.pfx
# AWS
.aws/credentials
aws-credentials.json
# IDE
.idea/
.vscode/settings.json
*.swp
# OS
.DS_Store
Thumbs.db
EOF2. Pre-commit Hook (Secret Detection)
bash
#!/bin/bash
# .git/hooks/pre-commit
# Patterns to detect
PATTERNS=(
'AKIA[0-9A-Z]{16}' # AWS Access Key
'-----BEGIN.*PRIVATE KEY-----' # Private keys
'ghp_[a-zA-Z0-9]{36}' # GitHub PAT
'sk-[a-zA-Z0-9]{48}' # OpenAI
'xox[baprs]-[a-zA-Z0-9-]+' # Slack tokens
'password\s*[:=]\s*["\047][^"\047]+' # Hardcoded passwords
)
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
FOUND=0
for FILE in $STAGED_FILES; do
for PATTERN in "${PATTERNS[@]}"; do
if git show ":$FILE" 2>/dev/null | grep -qE "$PATTERN"; then
echo "🚨 Potential secret in: $FILE"
echo " Pattern: $PATTERN"
FOUND=1
fi
done
done
if [ $FOUND -eq 1 ]; then
echo ""
echo "⛔ Commit blocked! Secrets detected."
echo "Use environment variables instead of hardcoding."
exit 1
fi
exit 03. git-secrets (AWS Tool)
bash
# Install
# macOS
brew install git-secrets
# Linux
git clone https://github.com/awslabs/git-secrets.git
cd git-secrets && make install
# Setup trong repo
cd your-repo
git secrets --install
git secrets --register-aws
# Add custom patterns
git secrets --add 'private_key'
git secrets --add 'api[_-]?key.*[:=]'
# Scan existing history
git secrets --scan-history4. Trufflehog (Deep Scanning)
bash
# Install
pip install trufflehog
# Scan repo
trufflehog git https://github.com/you/repo.git
# Scan local
trufflehog filesystem ./
# Scan only recent commits
trufflehog git file://. --since-commit HEAD~505. GitHub Secret Scanning
GitHub tự động scan public repos và notify khi detect:
- AWS keys
- Azure credentials
- Google Cloud keys
- Stripe API keys
- 100+ partner patterns
Enable for private repos: Settings → Security → Secret scanning → Enable
📊 Quick Reference
Signing Commands
| Command | Purpose |
|---|---|
git commit -S | Sign commit |
git tag -s v1.0 | Sign tag |
git verify-commit HEAD | Verify commit signature |
git log --show-signature | Show signatures in log |
gpg --list-secret-keys | List GPG keys |
Secret Removal Commands
| Tool | Command |
|---|---|
git filter-repo | git filter-repo --path secret.txt --invert-paths |
BFG | java -jar bfg.jar --delete-files secret.txt |
| Replace text | git filter-repo --replace-text secrets.txt |
Prevention Tools
| Tool | Type | Best For |
|---|---|---|
| Pre-commit hook | Local | Custom patterns |
| git-secrets | Local | AWS credentials |
| Trufflehog | Scanner | Deep history scan |
| GitHub Secret Scanning | Cloud | Automatic alerts |
💡 Key Takeaways
HPN'S INSIGHT
"Secrets in git history = Secrets on the internet forever. Prevention tốn 5 phút. Recovery tốn 5 giờ. Breach tốn millions."
- Sign your commits: Protect identity, enable "Verified" badge
- SSH signing is easier: Reuse existing SSH keys, simpler setup
- Rotate FIRST, clean SECOND: Khi leak xảy ra, rotate credentials ngay
- filter-repo > filter-branch: Modern, faster, easier
- Prevention is mandatory: Global gitignore + pre-commit hooks + scanning tools
The Security Stack
┌─────────────────────────────────────────┐
│ GitHub Secret Scanning (Cloud) │ ← Last resort alert
├─────────────────────────────────────────┤
│ CI/CD: Trufflehog scan │ ← Pre-merge check
├─────────────────────────────────────────┤
│ Pre-commit: git-secrets hook │ ← Before commit
├─────────────────────────────────────────┤
│ Global .gitignore │ ← Never stage
├─────────────────────────────────────────┤
│ Environment variables / Vault │ ← Don't hardcode
└─────────────────────────────────────────┘SECURITY IS LAYERS
Không tool nào 100% effective. Dùng multiple layers để maximize protection.