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.
🧠 Quiz
Câu 1: Khi phát hiện đã commit secret (API key) vào repository, bước đầu tiên phải làm gì?
- [ ] A) Dùng
git filter-branchxóa commit chứa secret - [ ] B) Tạo commit mới xóa file chứa secret
- [x] C) Rotate (đổi mới) credentials ngay lập tức, vì secret có thể đã bị expose
- [ ] D) Đổi tên file chứa secret
💡 Giải thích: "Rotate FIRST, clean SECOND." Ngay khi secret bị commit, coi như nó đã public (có thể đã được cache, clone, mirror). Đổi credentials ngay, sau đó mới dọn dẹp lịch sử Git.
Câu 2: Tại sao nên ký commit bằng GPG/SSH key?
- [ ] A) Để commit nhanh hơn
- [ ] B) Để encrypt nội dung commit
- [x] C) Để xác minh danh tính người commit, hiển thị badge "Verified" và ngăn impersonation
- [ ] D) Để tự động backup commit lên cloud
💡 Giải thích: Git cho phép ai cũng set tên/email bất kỳ trong
git config. Signing commit với GPG/SSH chứng minh commit thực sự từ bạn, hiển thị "Verified" badge trên GitHub, ngăn ngừa identity spoofing.
Câu 3: "Defense in Depth" trong Git security nghĩa là gì?
- [ ] A) Chỉ cần một tool scanning mạnh là đủ
- [ ] B) Encrypt toàn bộ repository
- [x] C) Sử dụng nhiều lớp bảo vệ: gitignore → pre-commit hooks → CI scanning → cloud scanning
- [ ] D) Giới hạn quyền push chỉ cho team lead
💡 Giải thích: Không tool nào 100% effective. Kiến trúc bảo mật nhiều lớp: environment variables (don't hardcode) → global .gitignore → pre-commit hooks (git-secrets) → CI/CD scanning (Trufflehog) → GitHub Secret Scanning.