Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions docs/week-17-notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Week 17 Notes — DevSecOps Pre-Flight Gates 1-4

## What we built
The first 4 gates of the DevSecOps pipeline — pre-flight checks
that run on every push before any code is built or tested.

## File created
- .github/workflows/devsecops-preflight.yml

## Gates implemented

### Gate 1: TruffleHog — Secret Scanning
Replaced Gitleaks (requires paid license) with TruffleHog (free, open source).
Scans every commit for verified secrets: AWS access keys, GitHub tokens,
database passwords, API keys, JWT secrets.
Runs with --only-verified flag — only blocks on confirmed secrets,
not potential false positives.

Why this matters: Earlier in this project, AWS credentials were
accidentally exposed in a chat session. Bots scan GitHub for leaked
credentials within minutes. TruffleHog prevents this at the pipeline level.

### Gate 2: Hadolint — Dockerfile Lint
Lints both backend/Dockerfile and frontend/Dockerfile.
Catches: running as root, using latest tags, missing HEALTHCHECK,
ADD instead of COPY, apt-get without --no-install-recommends.
failure-threshold: error — only blocks on ERROR level, not warnings.

### Gate 3: Checkov — IaC Security Scan
Scans infra/terraform/ and k8s/ directories.
Findings uploaded to GitHub Security tab as SARIF format.
soft_fail: true — reports findings without blocking (dev environment).

Findings it caught in our Terraform:
- CKV2_AWS_11: VPC flow logging not enabled → fixed: added aws_flow_log resource
- CKV2_AWS_12: Default security group not restricted → fixed: aws_default_security_group
- CKV_AWS_37: EKS control plane logging disabled → fixed: enabled_cluster_log_types

Findings it caught in K8s manifests:
- CKV_K8S_30: No seccomp profile → fixed: seccompProfile: RuntimeDefault
- CKV_K8S_40: Container running as low UID → fixed: runAsUser: 10001
- CKV_K8S_22: Filesystem not read-only → fixed: readOnlyRootFilesystem: true
- CKV2_K8S_6: No NetworkPolicy → fixed: added networkpolicy.yaml for all 5 pods

### Gate 4: TerraSecure — ML-powered IaC Scan
Our own tool integrated into the pipeline.
Uses XGBoost classifier trained on real breach patterns.
Outputs SARIF to GitHub Security tab + JSON artifact.
fail-on: none — reports findings without blocking.

## Key lesson
This week showed that running Checkov against your own infrastructure
is humbling. Every resource we created for the project had at least
one finding. We fixed them all properly instead of skipping — that
distinction matters in interviews.

## NetworkPolicy — what we added
Created k8s/base/networkpolicy.yaml with 5 policies:
- backend: ingress from frontend only, egress to db + kafka
- frontend: ingress on port 80 only, egress to backend
- db: ingress from backend only
- kafka: ingress from backend, egress to zookeeper
- zookeeper: ingress from kafka only

This is microsegmentation — even if an attacker breaches one pod,
they cannot reach other pods in the namespace.

## Security context changes
Added to all K8s deployments:
- runAsNonRoot: true
- runAsUser: 10001
- readOnlyRootFilesystem: true
- allowPrivilegeEscalation: false
- capabilities: drop: [ALL]
- seccompProfile: type: RuntimeDefault
- emptyDir volumes for /tmp and cache directories

## Commands used
```bash
# Check what Checkov finds
pip install checkov
checkov -d infra/terraform --framework terraform
checkov -d k8s --framework kubernetes

# Verify NetworkPolicy works
kubectl get networkpolicies -n crms
```

## Issues encountered and fixed
- Gitleaks requires paid license for private repos → replaced with TruffleHog
- Checkov SARIF path: checkov-k8s.sarif/results_sarif.sarif not checkov-k8s.sarif
- Checkov action env var bug with CHECKOV_RESULTS → upgraded to bridgecrewio/checkov-action@v12

## Interview answer
"Gate 3 Checkov found that none of our Kubernetes pods had NetworkPolicy,
all containers ran as root, and our EKS cluster had no audit logging.
We fixed every finding properly in the source files rather than adding
skip rules. That's the difference between DevSecOps theater and real security."

## Next week (Week 18)
SAST gates — static analysis of the actual application code.
100 changes: 100 additions & 0 deletions docs/week-18-notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Week 18 Notes — DevSecOps SAST Gates 5-7

## What we built
Three static analysis gates that scan the application source code
for security vulnerabilities and code quality issues.

## File created
- .github/workflows/devsecops-sast.yml
- sonar-project.properties

## Gates implemented

### Gate 5: Bandit — Python SAST
Scans backend/app/ for Python security vulnerabilities.
Severity levels: LOW, MEDIUM, HIGH, CRITICAL.
Pipeline blocks on HIGH severity findings.

What Bandit catches:
- SQL injection via string formatting (use parameterised queries)
- Hardcoded passwords and secrets
- Use of weak cryptographic functions (MD5, SHA1)
- Subprocess calls with shell=True
- Use of assert statements in production code
- Insecure use of yaml.load (use yaml.safe_load)
- Binding to 0.0.0.0 without restriction

Findings in CRMS backend: 0 HIGH severity — our FastAPI
code uses SQLAlchemy ORM (parameterised by default),
python-jose for JWT (no weak crypto), and no subprocess calls.

### Gate 6: ESLint Security Plugin
Adds eslint-plugin-security and eslint-plugin-no-unsanitized
to the existing ESLint setup.

What it catches:
- detect-unsafe-regex: ReDoS (regex denial of service)
- detect-object-injection: prototype pollution
- no-unsanitized/method: XSS via innerHTML/outerHTML
- no-unsanitized/property: DOM-based XSS

Findings in CRMS frontend: 0 errors — our React components
use JSX rendering (not innerHTML) and no user input is
passed directly to DOM APIs.

### Gate 7: SonarQube — Quality Gate
SonarCloud integration (free for public repositories).
Runs pytest with --cov to generate coverage.xml.
Sends results to sonarcloud.io for analysis.

Metrics tracked:
- Code coverage percentage
- Code smells (maintainability issues)
- Technical debt (estimated fix time)
- Security hotspots
- Duplicated code blocks
- Bugs and vulnerabilities

Setup required:
1. sonarcloud.io → sign in with GitHub
2. Create organization: crms-devops
3. Create project: crms-devops_crms
4. Generate token → add SONAR_TOKEN to GitHub secrets
5. Add SONAR_HOST_URL = https://sonarcloud.io to GitHub secrets
6. sonar-project.properties in repo root

Result: Quality Gate PASSED — 0 new issues, 0 security hotspots.

## sonar-project.properties
```properties
sonar.projectKey=crms-devops_crms
sonar.organization=crms-devops
sonar.projectName=CRMS
sonar.sources=backend/app,frontend/src
sonar.python.coverage.reportPaths=backend/coverage.xml
sonar.python.version=3.13
sonar.exclusions=**/node_modules/**,**/__pycache__/**,**/migrations/**
```

## What we learned
- SAST catches vulnerabilities before the code runs — cheaper to fix early
- SQLAlchemy ORM is inherently safer than raw SQL string formatting
- React JSX rendering escapes HTML by default — built-in XSS protection
- SonarCloud is free for public repos and takes 10 minutes to set up
- Coverage reporting requires running tests with pytest-cov first

## Difference between SAST and DAST
SAST (Static): analyses source code without running it — fast, runs in CI
DAST (Dynamic): attacks the running application — slower, finds runtime issues
Both are needed — SAST catches code issues, DAST catches deployment issues.

## Interview answer
"Bandit gave us confidence that our FastAPI code has no SQL injection
or weak cryptography. ESLint security confirmed no XSS vectors in
our React frontend. SonarQube passed with zero new issues. Together
these three gates mean every pull request is reviewed by three
independent security analyzers before a human ever looks at it."

## Next week (Week 19)
Supply chain security — scanning the dependencies we import,
not just the code we write.
70 changes: 70 additions & 0 deletions docs/week-19-notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Week 19 Notes — DevSecOps Supply Chain Gates 8-9

## What we built
Two gates focused on the software supply chain — the third-party
packages and libraries that CRMS depends on.

## File created
- .github/workflows/devsecops-supply-chain.yml

## Why supply chain security matters
The SolarWinds attack (2020) and Log4Shell (2021) showed that
attackers target the libraries you import, not just your code.
Your application is only as secure as its dependencies.

## Gates implemented

### Gate 8: Snyk — Dependency CVE Scanning
Scans backend/requirements.txt and frontend/package.json for
known CVEs (Common Vulnerabilities and Exposures).

What it does:
- Checks every package version against Snyk's vulnerability database
- Identifies transitive dependencies (dependencies of dependencies)
- Shows upgrade paths to fix vulnerabilities
- snyk monitor tracks dependencies over time and alerts on new CVEs

Severity threshold: HIGH — blocks if any HIGH or CRITICAL CVEs found.

Relevance to CRMS: This is where CVE-2024-33663 in python-jose 3.3.0
would have been caught at the dependency level (Trivy caught it at
the container level in Week 5 — now we catch it earlier).

### Gate 9: Syft — SBOM Generation
SBOM = Software Bill of Materials.
A complete list of every package inside a Docker image.

Syft generates SBOMs in two industry-standard formats:
- SPDX JSON (Linux Foundation standard)
- CycloneDX JSON (OWASP standard)

What goes into a backend SBOM example:
- Python 3.13.x
- FastAPI 0.115.12
- SQLAlchemy 2.0.41
- psycopg2-binary 2.9.10
- uvicorn 0.34.3
- ... (every package, every version)

Why SBOMs matter:
- US Executive Order 14028 (2021) requires SBOMs for federal software
- When a new CVE is discovered, you can instantly check if you're affected
- Compliance requirements (SOC2, ISO 27001) increasingly require SBOMs
- Retained as compliance artifacts (90 days in our pipeline)

## What we learned
- Supply chain attacks are now more common than direct code attacks
- Every npm install or pip install is a trust decision
- SBOMs are becoming a legal requirement in many industries
- Snyk monitor gives continuous visibility, not just point-in-time scans

## Interview answer
"Gate 9 generates a complete SBOM for every Docker image we build.
When Log4Shell was discovered, teams with SBOMs knew within minutes
whether they were affected. Teams without them spent days manually
checking. We generate SBOMs in both SPDX and CycloneDX formats and
store them as 90-day retention artifacts for compliance."

## Next week (Week 20)
OWASP ZAP DAST — the most impressive gate. It actually runs
the application and attacks it like a real hacker would.
81 changes: 81 additions & 0 deletions docs/week-20-notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Week 20 Notes — DevSecOps DAST Gate 10

## What we built
Dynamic Application Security Testing — the pipeline spins up
the full CRMS stack and attacks it with OWASP ZAP.

## File created
- .github/workflows/devsecops-dast.yml
- .zap/rules.tsv

## What is DAST?
DAST = Dynamic Application Security Testing.
Unlike SAST (which reads source code), DAST attacks the
running application — exactly like a real attacker would.

OWASP ZAP (Zed Attack Proxy) is the industry standard open-source
DAST tool, maintained by the OWASP Foundation.

## What happens in Gate 10

### Step 1: Stack startup
CI runner spins up:
- PostgreSQL 16 container via Docker
- Alembic migrations run automatically
- FastAPI backend starts on port 8000
- Health check confirms backend is live

### Step 2: ZAP Baseline Scan
ZAP crawls every URL it can find on http://localhost:8000.
Tests each URL for 100+ vulnerability types including:
- Cross-Site Scripting (XSS)
- SQL Injection
- Path traversal
- Insecure HTTP headers
- Missing security headers (CSP, HSTS, X-Frame-Options)
- CORS misconfiguration
- Information disclosure

### Step 3: ZAP API Scan
ZAP reads our OpenAPI spec (http://localhost:8000/openapi.json)
and tests every endpoint defined in it — including endpoints
ZAP might not discover by crawling alone.

### Step 4: Report generation
Results saved as HTML + JSON + Markdown artifacts (30-day retention).

## Findings from our CRMS scan
- WARN: Missing X-Content-Type-Options header → added to nginx config
- WARN: Server version disclosed in response headers → suppressed
- PASS: No XSS vulnerabilities (React JSX escapes by default)
- PASS: No SQL injection (SQLAlchemy ORM parameterises queries)
- PASS: No authentication bypass
- PASS: JWT implementation correct

## Rules file (.zap/rules.tsv)
Some alerts are intentionally suppressed for dev environment:
- HSTS not set (no HTTPS in dev — expected)
- CSP not set (added in production nginx config)
These are documented suppressions, not ignored findings.

## Issues encountered
ZAP action v0.12.0 internally hardcodes artifact name as zap_scan
which is incompatible with GitHub Actions artifact API v6.
Fix: continue-on-error: true on ZAP steps — scan runs and finds
vulnerabilities, only the artifact upload fails due to action bug.

## What we learned
- DAST finds vulnerabilities that SAST misses (runtime config issues)
- Running DAST in CI requires a real running instance of the app
- ZAP is a full penetration testing tool — same tool security researchers use
- The OWASP Top 10 is a checklist ZAP tests against automatically

## Interview answer
"Gate 10 runs OWASP ZAP against our live FastAPI application on
every push to develop or main. It confirmed no SQL injection
(our ORM parameterises all queries), no XSS (React escapes JSX),
and no authentication bypass. This is the same tool professional
penetration testers use — we run it automatically in our pipeline."

## Next week (Week 21)
OPA policy as code and Vault secrets management validation.
Loading
Loading