fix(ci): make the hardcoded-secret scan blocking and close the .gitignore/.sops.yaml gaps that let a plaintext deploy key through — also untracks tfplan binaries and skills-lock.json
This commit is contained in:
@@ -156,21 +156,43 @@ jobs:
|
|||||||
- name: Check for Secrets in Code
|
- name: Check for Secrets in Code
|
||||||
run: |
|
run: |
|
||||||
echo "=== Scanning for hardcoded secrets ==="
|
echo "=== Scanning for hardcoded secrets ==="
|
||||||
SECRETS_FOUND=0
|
# BLOCKING. This step used to only count findings and then exit 0, so a
|
||||||
|
# plaintext deploy key rode through it into a public remote. Two failure
|
||||||
|
# modes fixed: it now fails the build, and it matches key material by
|
||||||
|
# PEM header rather than only `private_key:`-style YAML field names.
|
||||||
|
# Findings are captured into variables and tested for emptiness rather than
|
||||||
|
# branching on grep's exit status: implementations disagree on the rc of a
|
||||||
|
# `-v` filter fed empty input, and a wrong rc here fails open.
|
||||||
|
# NOTE: --include must precede `--`; after `--` grep treats it as a filename
|
||||||
|
# and silently scans nothing.
|
||||||
|
FAILED=0
|
||||||
|
|
||||||
for pattern in "password:" "secret:" "token:" "api_key:" "apikey:" "private_key:" "privatekey:"; do
|
# Any private key block is fatal, regardless of the field name carrying it.
|
||||||
if grep -r "$pattern" k8s/ --include="*.yaml" --include="*.yml" | grep -v "^Binary"; then
|
KEYS=$(grep -rIE --include="*.yaml" --include="*.yml" \
|
||||||
echo "⚠️ Found potential secret pattern: $pattern"
|
-- "-----BEGIN ([A-Z]+ )?PRIVATE KEY-----" k8s/ \
|
||||||
SECRETS_FOUND=$((SECRETS_FOUND + 1))
|
| grep -v "\.enc\.yaml" || true)
|
||||||
|
if [ -n "$KEYS" ]; then
|
||||||
|
echo "❌ Unencrypted private key material found:"
|
||||||
|
echo "$KEYS"
|
||||||
|
FAILED=1
|
||||||
fi
|
fi
|
||||||
done
|
|
||||||
|
|
||||||
if [ $SECRETS_FOUND -gt 0 ]; then
|
# Plaintext values in secret-ish YAML fields. SOPS output is ENC[...],
|
||||||
echo "⚠️ Warning: Found $SECRETS_FOUND potential secrets"
|
# so encrypted files never trip this.
|
||||||
echo "Secrets should be encrypted with SOPS or stored in ArgoCD Sealed Secrets"
|
VALS=$(grep -rInE --include="*.yaml" --include="*.yml" \
|
||||||
else
|
-- "^[[:space:]]*(password|token|apiKey|api_key|sshPrivateKey|client_secret):[[:space:]]*[\"']?[^\"'[:space:]{\$]{8,}" k8s/ \
|
||||||
|
| grep -v "ENC\[" | grep -v "\.enc\.yaml" || true)
|
||||||
|
if [ -n "$VALS" ]; then
|
||||||
|
echo "❌ Plaintext secret value found:"
|
||||||
|
echo "$VALS"
|
||||||
|
FAILED=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$FAILED" -ne 0 ]; then
|
||||||
|
echo "Encrypt with SOPS (see .sops.yaml) — *.enc.yaml files are exempt."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
echo "✓ No hardcoded secrets found"
|
echo "✓ No hardcoded secrets found"
|
||||||
fi
|
|
||||||
|
|
||||||
# === Check K8s Security Best Practices ===
|
# === Check K8s Security Best Practices ===
|
||||||
- name: Check K8s Security Best Practices
|
- name: Check K8s Security Best Practices
|
||||||
|
|||||||
+11
-2
@@ -50,10 +50,19 @@ terraform/*.tfstate.*
|
|||||||
terraform.tfvars.local
|
terraform.tfvars.local
|
||||||
skills-lock.json
|
skills-lock.json
|
||||||
secrets-plaintext.yaml
|
secrets-plaintext.yaml
|
||||||
skills-lock.json
|
|
||||||
|
# Saved plan files — binary, environment-specific, may embed resource attributes
|
||||||
|
terraform/tfplan
|
||||||
|
terraform/tfplan-*
|
||||||
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
CLAUDE.md
|
CLAUDE.md
|
||||||
docs/
|
docs/
|
||||||
|
|
||||||
k8s/argocd/seed-repo-secret.yamlbootstrap-argocd.log
|
bootstrap-argocd.log
|
||||||
|
|
||||||
|
# Any plaintext (non-SOPS) secret manifest. Encrypted ones are *.enc.yaml and
|
||||||
|
# ARE committed — see .sops.yaml. A missing newline once merged two patterns on
|
||||||
|
# one line here, which is how a plaintext deploy key reached a public remote.
|
||||||
|
k8s/**/*-secret.yaml
|
||||||
|
!k8s/**/*.enc.yaml
|
||||||
|
|||||||
+3
-1
@@ -1,3 +1,5 @@
|
|||||||
creation_rules:
|
creation_rules:
|
||||||
- path_regex: k8s/.*secrets.*\.ya?ml
|
# `secrets?` — singular too. A `seed-repo-secret.yaml` once slipped this regex
|
||||||
|
# and was committed in plaintext to a public remote.
|
||||||
|
- path_regex: k8s/.*secrets?.*\.ya?ml
|
||||||
age: age1e5fq3hwxy78psus2nfvmtmua36g0u3suk78ephw6246l974d2utsvn0hla
|
age: age1e5fq3hwxy78psus2nfvmtmua36g0u3suk78ephw6246l974d2utsvn0hla
|
||||||
|
|||||||
Reference in New Issue
Block a user