diff --git a/.github/SECRET_SCANNING.md b/.github/SECRET_SCANNING.md new file mode 100644 index 000000000000..878ddce56051 --- /dev/null +++ b/.github/SECRET_SCANNING.md @@ -0,0 +1,171 @@ +# Secret Scanning with Gitleaks + +This repository uses [Gitleaks](https://github.com/gitleaks/gitleaks) to prevent secrets (API keys, passwords, private keys, tokens) from being committed to the codebase. + +## How It Works + +### Automated CI Scanning +- **Runs on:** All pull requests and pushes to `main` and `release-*` branches +- **What it scans:** Only new commits in your PR via `gitleaks-action@v2` with `GITLEAKS_ARGS: --log-opts="main..HEAD"` (not the entire git history despite `fetch-depth: 0`) +- **Speed:** ~4 mins for full repository scan +- **Action:** Blocks PR merge if secrets are detected + +### What Gitleaks Detects +- API keys (AWS, GitHub, GitLab, Slack, etc.) +- Private keys (RSA, SSH, PGP, TLS) +- Database credentials and connection strings +- OAuth and JWT tokens +- Generic secrets (password=, api_key=, etc.) +- High entropy strings (randomized secrets) + +### What It Ignores +- Test fixtures in `test/` directories +- Vendor code in `vendor/` +- Example files in `examples/` +- Mock/placeholder credentials +- Variable names like `password` or `apiKey` + +## Running Locally + +### Installation + +**macOS (Homebrew):** +```bash +brew install gitleaks +``` + +**Linux:** +```bash +# Docker/Podman +docker pull ghcr.io/gitleaks/gitleaks:latest + +# Or download binary +wget https://github.com/gitleaks/gitleaks/releases/latest/download/gitleaks_linux_x64.tar.gz +tar -xzf gitleaks_linux_x64.tar.gz +sudo mv gitleaks /usr/local/bin/ +``` + +### Scan Before Committing + +**Scan staged changes (recommended):** +```bash +gitleaks protect --staged --verbose +``` + +**Scan entire working directory:** +```bash +gitleaks detect --source . --config .gitleaks.toml --verbose +``` + +**Scan specific file:** +```bash +gitleaks detect --source path/to/file.go --no-git +``` + +## Handling Detections + +### If Gitleaks Flags Your Commit + +**1. Is it a real secret?** + +If YES: +- **Remove the secret immediately** +- Use environment variables instead: `os.Getenv("API_KEY")` +- Store secrets in Kubernetes Secrets, Vault, or similar +- Rotate/revoke the exposed secret if it was already pushed + +If NO (false positive): +- Continue to step 2 + +**2. For legitimate test fixtures or examples:** + +Add to `.gitleaks.toml` allowlist: + +```toml +[allowlist] +paths = [ + '''path/to/test/file\.go$''', +] + +# OR for specific values +regexes = [ + '''specific-test-value-to-ignore''', +] +``` + +**3. For one-time overrides (use sparingly):** + +Add inline comment in your code: +```go +password := "test-password" // gitleaks:allow +``` + +## Configuration + +The `.gitleaks.toml` file controls what gets scanned and ignored: + +- **Excluded paths:** `test/`, `vendor/`, `examples/`, `*.md` +- **Excluded patterns:** Test credentials, base64 test values, common examples +- **Rules:** Extends default gitleaks ruleset + +To modify exclusions, edit `.gitleaks.toml` and test: +```bash +gitleaks detect --source . --config .gitleaks.toml --verbose +``` + +## Best Practices + +### DO: +- ✅ Use environment variables for secrets +- ✅ Use Kubernetes Secrets or external secret management +- ✅ Run `gitleaks protect --staged` before committing sensitive changes +- ✅ Use placeholder values in examples: `YOUR_API_KEY_HERE` + +### DON'T: +- ❌ Commit real credentials, even temporarily +- ❌ Use `--no-verify` to bypass the check +- ❌ Add broad exclusions to `.gitleaks.toml` without review +- ❌ Assume deleted secrets are safe (git history remembers) + +## Troubleshooting + +### CI fails but local scan passes +```bash +# Ensure you're using the config file +gitleaks detect --source . --config .gitleaks.toml --no-git + +# Check which gitleaks version CI uses +grep 'gitleaks-action@' .github/workflows/secret-scan.yml +``` + +### Too many false positives +1. Review the findings carefully +2. Update `.gitleaks.toml` with specific exclusions +3. Test the config change locally +4. Submit the config update in your PR + +### Need to scan git history +```bash +# Scan all commits (WARNING: can be slow on large repos) +gitleaks detect --source . --verbose + +# Scan specific commit range +gitleaks detect --log-opts="main..HEAD" +``` + +## Additional Resources + +- [Gitleaks Documentation](https://github.com/gitleaks/gitleaks) +- [Gitleaks Configuration Reference](https://github.com/gitleaks/gitleaks#configuration) +- [GitHub Secret Scanning](https://docs.github.com/en/code-security/secret-scanning) + +## Questions? + +For issues with secret scanning: +1. Check this guide first +2. Review `.gitleaks.toml` configuration +3. Ask in your PR or open an issue + +--- + +**Remember:** It's easier to prevent secrets from being committed than to clean them up from git history! diff --git a/.github/workflows/secret-scan.yml b/.github/workflows/secret-scan.yml new file mode 100644 index 000000000000..012f628efbb9 --- /dev/null +++ b/.github/workflows/secret-scan.yml @@ -0,0 +1,43 @@ +name: Secret Scan + +# Prevents secrets (API keys, passwords, tokens) from being committed. +# For setup and troubleshooting, see: .github/SECRET_SCANNING.md +# To run locally: gitleaks protect --staged --verbose + +on: + pull_request: + branches: + - main + - 'release-*' + push: + branches: + - main + +permissions: + contents: read + pull-requests: write + +jobs: + gitleaks: + name: Scan for secrets + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Full history for comprehensive scanning + + - name: Run Gitleaks + uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} # Optional: for Gitleaks Pro features + GITLEAKS_ENABLE_COMMENTS: true + GITLEAKS_ARGS: --log-opts="main..HEAD" # Scan only PR commits, not full history + + - name: Upload SARIF report + if: failure() + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: results.sarif + category: gitleaks diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 000000000000..2c78a71d67c7 --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,67 @@ +# Gitleaks configuration for OpenShift Origin +# This config excludes common false positives while catching real secrets +# +# To test this config locally: +# gitleaks detect --source . --config .gitleaks.toml --verbose +# +# For full documentation, see: .github/SECRET_SCANNING.md + +title = "gitleaks config for openshift/origin" + +# Extend the default gitleaks config +[extend] +useDefault = true + +[allowlist] +description = "Allowlist for test fixtures, examples, and vendor code" + +# Paths to exclude from scanning +paths = [ + # Test directories and files + '''test/''', + '''.*_test\.go$''', + '''testdata/''', + + # Vendor dependencies + '''vendor/''', + + # Examples and demo files + '''examples/''', + + # Generated binary data files + '''bindata\.go$''', + + # Lock files and checksums + '''go\.sum$''', + '''package-lock\.json$''', + '''yarn\.lock$''', + + # Documentation + '''\.md$''', +] + +# Specific regexes to exclude (for base64 encoded test values, etc.) +regexes = [ + # Base64 encoded placeholder values commonly used in tests + '''c2VjcmV0dmFsdWU=''', # "secretvalue" in base64 + '''bXktc2VjcmV0LXZhbHVl''', # "my-secret-value" in base64 + '''cGFzc3dvcmQ=''', # "password" in base64 + + # Common test/example credentials + '''admin:admin''', + '''system:admin''', + '''secretvalue1''', + + # Grafana default example secret + '''SW2YcwTIb9zpOOhoPsMm''', +] + +# Stopwords - tokens that if found in the match will cause it to be ignored +stopwords = [ + # Common variable names and placeholders + '''YOUR_API_KEY''', + '''REPLACE_ME''', + '''CHANGEME''', + '''example\.com''', + '''localhost''', +]