4 min read
On this page

DevSecOps Fundamentals

Security has traditionally been the last gate before production. A security team reviews the code, finds issues, and sends it back to development. This creates a bottleneck that slows delivery and finds problems too late to fix cheaply. DevSecOps shifts security left: integrate it into the development process from the beginning, not as an afterthought.

Shift Security Left

"Shift left" means moving security earlier in the development lifecycle. The earlier you find a vulnerability, the cheaper it is to fix.

Cost of fixing a security issue:
  Design phase:     $500 (change a design decision)
  Development:      $2,000 (rewrite code)
  Testing:          $5,000 (fix and retest)
  Staging:          $10,000 (fix, retest, redeploy)
  Production:       $50,000+ (incident response, customer impact, reputation)

The same vulnerability costs 100x more to fix in production
than in design.

Shifting left does not mean eliminating the security team. It means embedding security practices into every stage of development so that the security team reviews fewer issues because most have already been caught.

Traditional security:
  Code → Build → Test → Deploy → Security review → Production
                                  ^
                                  All issues found here (too late)

Shifted-left security:
  Code (SAST, linting) → Build (dependency scan) → Test (DAST) →
  Deploy (image scan) → Production (runtime protection)
  ^                     ^                          ^
  Issues found early    Issues caught at build     Runtime monitoring

Threat Modeling in Design

Before writing code, think about what could go wrong. Threat modeling is a structured way to identify security risks in your system design.

STRIDE Framework

S — Spoofing:         Can someone pretend to be another user?
T — Tampering:        Can someone modify data in transit or at rest?
R — Repudiation:      Can someone deny performing an action?
I — Information Disclosure: Can someone access data they should not see?
D — Denial of Service:     Can someone make the service unavailable?
E — Elevation of Privilege: Can someone gain unauthorized access?

Threat Modeling in Practice

System: Payment API
Assets: Customer credit card data, transaction records

Threat model:
  1. Spoofing: Attacker uses stolen API key to make requests
     Mitigation: Rate limiting, IP allowlisting, key rotation

  2. Tampering: Attacker modifies payment amount in transit
     Mitigation: TLS everywhere, request signing, server-side validation

  3. Information Disclosure: SQL injection exposes card data
     Mitigation: Parameterized queries, input validation, encryption at rest

  4. Denial of Service: Attacker floods the payment endpoint
     Mitigation: Rate limiting, WAF, auto-scaling

  5. Elevation of Privilege: Customer accesses another customer's data
     Mitigation: Authorization checks on every request, row-level security

Threat modeling does not need to be a formal, two-day workshop. A 30-minute discussion during design review that asks "what could an attacker do here?" catches most issues.

Security in CI/CD

The CI/CD pipeline is where security checks should be automated and enforced. There are four main categories of automated security testing.

SAST (Static Application Security Testing)

SAST analyzes source code without running it. It finds vulnerabilities like SQL injection, cross-site scripting, hardcoded secrets, and insecure cryptography.

# Example: SAST in a GitHub Actions pipeline
name: Security Scan
on: [push, pull_request]

jobs:
  sast:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Run Semgrep SAST
        uses: returntocorp/semgrep-action@v1
        with:
          config: >-
            p/owasp-top-ten
            p/security-audit
            p/secrets
Common SAST tools:
  Semgrep:     Open-source, fast, supports many languages
  SonarQube:   Comprehensive, supports quality and security
  CodeQL:      GitHub-native, deep analysis
  Bandit:      Python-specific security linter
  Brakeman:    Ruby on Rails-specific

DAST (Dynamic Application Security Testing)

DAST tests a running application by sending malicious requests and observing responses. It finds vulnerabilities that SAST cannot, like misconfigured headers, authentication bypass, and server-side request forgery.

Common DAST tools:
  OWASP ZAP:   Open-source, widely used
  Burp Suite:  Industry standard (commercial)
  Nuclei:      Open-source, template-based
# Example: DAST scan against staging environment
name: DAST Scan
on:
  workflow_run:
    workflows: ["Deploy to Staging"]
    types: [completed]

jobs:
  dast:
    runs-on: ubuntu-latest
    steps:
      - name: OWASP ZAP Scan
        uses: zaproxy/action-full-scan@v0.9.0
        with:
          target: "https://staging.example.com"
          rules_file_name: "zap-rules.tsv"

Dependency Scanning

Third-party dependencies are attack vectors. Scanning them for known vulnerabilities is essential.

# Example: dependency scanning in CI
name: Dependency Scan
on:
  push:
    branches: [main]
  schedule:
    - cron: "0 6 * * 1"  # Weekly Monday scan

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Run Trivy vulnerability scan
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: fs
          scan-ref: .
          severity: "HIGH,CRITICAL"
          exit-code: 1  # Fail the build on high/critical findings

Container Image Scanning

Scan container images for vulnerabilities in the base OS and installed packages.

# Scan a Docker image before pushing to registry
trivy image --severity HIGH,CRITICAL myapp:latest

# Example output:
# myapp:latest (debian 12.4)
# Total: 3 (HIGH: 2, CRITICAL: 1)
# 
# Library     Vulnerability  Severity  Installed  Fixed
# openssl     CVE-2024-XXXX  CRITICAL  3.0.11     3.0.13
# curl        CVE-2024-YYYY  HIGH      8.4.0      8.5.0
# libxml2     CVE-2024-ZZZZ  HIGH      2.9.14     2.10.3

Security as a Shared Responsibility

DevSecOps works when security is everyone's responsibility, not just the security team's.

Developer responsibilities:
  - Write secure code (input validation, parameterized queries)
  - Fix SAST findings in their own code
  - Keep dependencies updated
  - Follow secure coding guidelines
  - Participate in threat modeling

Operations responsibilities:
  - Secure infrastructure (network policies, firewalls)
  - Manage secrets properly
  - Monitor for suspicious activity
  - Patch operating systems and base images
  - Enforce least privilege access

Security team responsibilities:
  - Define security policies and standards
  - Maintain security tooling (SAST, DAST, scanners)
  - Perform penetration testing
  - Respond to security incidents
  - Train developers on secure coding

Security Champions

A security champion is a developer on each team who takes extra interest in security. They are not security engineers; they are developers who help their team make better security decisions.

Security champion responsibilities:
  - Attend monthly security champion meetings
  - Review PRs with a security lens
  - Advocate for security practices on their team
  - Escalate security concerns to the security team
  - Stay current on common vulnerability types

Building a Security Pipeline

A complete security pipeline integrates checks at every stage.

Stage 1: Pre-commit
  - Secret scanning (detect API keys, passwords in code)
  - Linting for security anti-patterns
  Tools: gitleaks, pre-commit hooks

Stage 2: Pull request
  - SAST scan on changed files
  - Dependency vulnerability check
  - Code review with security checklist
  Tools: Semgrep, Dependabot, CodeQL

Stage 3: Build
  - Full SAST scan
  - Container image scan
  - License compliance check
  Tools: Trivy, Snyk, FOSSA

Stage 4: Staging
  - DAST scan against running application
  - Integration security tests
  - Infrastructure configuration audit
  Tools: OWASP ZAP, Nuclei, Checkov

Stage 5: Production
  - Runtime application self-protection (RASP)
  - Web application firewall (WAF)
  - Continuous monitoring and alerting
  Tools: Falco, AWS WAF, Datadog Security

Real-World Example

A healthcare SaaS company had a manual security review process. A two-person security team reviewed every release before production. Reviews took 3-5 days per release. Development teams waited. The backlog grew. Some teams started skipping the review by getting VP approval to deploy "urgently."

They shifted security left:

  1. Added Semgrep SAST to every pull request. Developers saw findings immediately and fixed them before merging.
  2. Added Trivy dependency scanning to CI. Builds failed on critical vulnerabilities, forcing teams to update dependencies.
  3. Added OWASP ZAP DAST scans on every staging deployment. Integration security issues were caught before the security team saw the release.
  4. Trained two security champions per team. Basic security questions were answered within the team instead of queued for the security team.

Results after six months: 80% of findings were caught and fixed before the code reached the security team. The security team's review time dropped from 3-5 days to a few hours because they only reviewed complex or novel security concerns. Deploy frequency doubled because the security bottleneck was eliminated.

Common Pitfalls

  • Security as a gate, not a practice -- If security only happens in a review before production, it is too late and too expensive; integrate checks into every pipeline stage
  • Too many false positives -- SAST tools that flag hundreds of non-issues train developers to ignore findings; tune your rules aggressively and suppress false positives
  • Blocking deploys on every finding -- Not every finding is critical; block on high and critical severity, warn on medium, track on low; otherwise, security tooling becomes the bottleneck it was meant to replace
  • No developer training -- Tools find issues but developers need to understand why something is a vulnerability and how to fix it; invest in secure coding training
  • Ignoring runtime security -- Pre-production scanning catches known vulnerabilities but not zero-days or misconfigurations that only manifest at runtime; monitor production too
  • Security tooling without ownership -- If nobody owns the SAST configuration, rules become stale and findings are ignored; assign a team to maintain security tooling

Key Takeaways

  • Shift security left: integrate security checks into every stage of the development lifecycle, not just before production
  • Threat modeling during design catches issues before code is written, when fixes are cheapest
  • SAST, DAST, dependency scanning, and image scanning are the four pillars of automated security in CI/CD
  • Security is a shared responsibility: developers write secure code, ops secures infrastructure, the security team defines policy and tooling
  • Security champions on each team reduce the bottleneck on the central security team
  • Tune tools to reduce false positives; developers who are overwhelmed by noise will ignore all findings