DevSecOps integrates security practices into every stage of the software development lifecycle. By automating security scanning, vulnerability management, and compliance checks, teams can identify and fix security issues early when they're cheapest to remediate. This guide covers implementing DevSecOps practices, automating security in CI/CD pipelines, and building a security-first culture.
What is DevSecOps?
DevSecOps, short for Development, Security, and Operations, embeds security practices throughout the DevOps pipeline. Instead of treating security as an afterthought or gate at the end of development, DevSecOps shifts security left—introducing security testing and validation as early as possible in the development process.
Traditional security models create bottlenecks: developers ship features, security teams find issues weeks later, and fixes require costly rework. DevSecOps automates security checks so developers receive immediate feedback, fixing issues while context is fresh and before code reaches production.
1. Static Application Security Testing (SAST)
SAST analyzes source code for security vulnerabilities without executing the program. Integrate SAST tools into your CI/CD pipeline to catch issues before code is merged.
Example: SonarQube Integration
# .github/workflows/security.yml
name: Security Scans
on:
push:
branches: [main, develop]
pull_request:
jobs:
sast:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for SonarQube
- name: SonarQube Scan
uses: sonarsource/sonarqube-scan-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
with:
args: >
-Dsonar.projectKey=my-project
-Dsonar.sources=src
-Dsonar.tests=tests
-Dsonar.exclusions=**/node_modules/**,**/*.test.js
- name: Check Quality Gate
run: |
STATUS=$(curl -s -u ${{ secrets.SONAR_TOKEN }}: \
"${SONAR_HOST_URL}/api/qualitygates/project_status?projectKey=my-project" \
| jq -r '.projectStatus.status')
if [ "$STATUS" != "OK" ]; then
echo "Quality gate failed: $STATUS"
exit 1
fi
- name: Semgrep Security Scan
uses: returntocorp/semgrep-action@v1
with:
config: >
p/security-audit
p/owasp-top-ten
p/cwe-top-252. Dynamic Application Security Testing (DAST)
DAST tests running applications by simulating attacks. It finds runtime vulnerabilities like injection flaws, authentication issues, and misconfigurations.
# OWASP ZAP DAST scan
jobs:
dast:
runs-on: ubuntu-latest
steps:
- name: ZAP Scan
uses: zaproxy/action-baseline@v0.7.0
with:
target: 'https://staging.example.com'
rules_file_name: '.zap/rules.tsv'
cmd_options: '-a'
- name: Upload DAST Results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: results.sarif3. Dependency Scanning
Most applications use hundreds of open-source dependencies. Scanning dependencies for known vulnerabilities is critical.
jobs:
dependency-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Snyk Security Scan
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
- name: npm audit
run: |
npm audit --audit-level=moderate
npm audit fix
- name: Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload Trivy results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'4. Container Security
Scan container images for vulnerabilities and misconfigurations before deploying to production.
jobs:
container-security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build Docker image
run: docker build -t myapp:${{ github.sha }} .
- name: Run Trivy scan on image
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
format: 'sarif'
output: 'trivy-image-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Scan with Anchore
uses: anchore/scan-action@v3
with:
image: 'myapp:${{ github.sha }}'
fail-build: true
severity-cutoff: high
- name: Docker Scout CVE scan
uses: docker/scout-action@v1
with:
command: cves
image: myapp:${{ github.sha }}
only-severities: critical,high
exit-code: true5. Secrets Detection
Prevent secrets like API keys, passwords, and tokens from being committed to version control.
jobs:
secrets-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: TruffleHog Secrets Scan
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: ${{ github.event.repository.default_branch }}
head: HEAD
- name: GitGuardian scan
uses: GitGuardian/ggshield-action@master
env:
GITGUARDIAN_API_KEY: ${{ secrets.GITGUARDIAN_API_KEY }}
with:
args: scan ciPre-commit Hook for Local Secrets Detection
#!/bin/bash
# .git/hooks/pre-commit
set -e
echo "Running secrets detection..."
# Run gitleaks
if ! command -v gitleaks &> /dev/null; then
echo "gitleaks not installed. Install: brew install gitleaks"
exit 1
fi
gitleaks protect --staged --verbose
if [ $? -ne 0 ]; then
echo "⚠️ Secrets detected! Commit blocked."
echo "Remove secrets and try again."
exit 1
fi
echo "✓ No secrets detected"6. Infrastructure as Code (IaC) Security
Scan Terraform, CloudFormation, and Kubernetes manifests for security misconfigurations.
jobs:
iac-security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Checkov on Terraform
uses: bridgecrewio/checkov-action@master
with:
directory: terraform/
framework: terraform
output_format: sarif
output_file_path: checkov-results.sarif
- name: KICS scan
uses: checkmarx/kics-github-action@v1
with:
path: './'
output_path: './kics-results.sarif'
platform_type: terraform,kubernetes
fail_on: high,critical
- name: Terraform security scan
run: |
tfsec . --format sarif > tfsec-results.sarif7. Compliance as Code
Automate compliance checks using tools like Open Policy Agent (OPA) and InSpec.
# policy/kubernetes.rego - OPA Policy
package kubernetes.admission
import data.kubernetes.namespaces
# Deny pods running as root
deny[msg] {
input.request.kind.kind == "Pod"
input.request.object.spec.securityContext.runAsNonRoot != true
msg := "Pods must not run as root"
}
# Require resource limits
deny[msg] {
input.request.kind.kind == "Pod"
container := input.request.object.spec.containers[_]
not container.resources.limits
msg := sprintf("Container %v must have resource limits", [container.name])
}
# Require network policies
deny[msg] {
input.request.kind.kind == "Namespace"
namespace := input.request.object.metadata.name
not has_network_policy(namespace)
msg := sprintf("Namespace %v must have a NetworkPolicy", [namespace])
}InSpec Compliance Profiles
# controls/docker.rb - InSpec profile
control 'docker-1' do
impact 1.0
title 'Docker daemon configuration'
desc 'Ensure Docker daemon is configured securely'
describe json('/etc/docker/daemon.json') do
its(['live-restore']) { should eq true }
its(['userland-proxy']) { should eq false }
its(['no-new-privileges']) { should eq true }
end
end
control 'docker-2' do
impact 1.0
title 'Docker images must be signed'
desc 'Verify Docker Content Trust is enabled'
describe os_env('DOCKER_CONTENT_TRUST') do
its('content') { should eq '1' }
end
end8. Security Monitoring and Incident Response
Implement runtime security monitoring to detect and respond to threats in production.
# Falco rules for runtime security
- rule: Unexpected outbound connection
desc: Detect unexpected outbound network connections
condition: >
outbound and
not proc.name in (allowed_processes) and
not fd.sip in (allowed_ips)
output: >
Unexpected outbound connection
(command=%proc.cmdline connection=%fd.name)
priority: WARNING
- rule: Write to /etc
desc: Detect writes to /etc directory
condition: >
open_write and
fd.name startswith /etc
output: >
File write to /etc directory
(user=%user.name command=%proc.cmdline file=%fd.name)
priority: ERROR
- rule: Shell spawned in container
desc: Detect shell execution in containers
condition: >
spawned_process and
container and
proc.name in (shell_binaries)
output: >
Shell spawned in container
(user=%user.name container=%container.name command=%proc.cmdline)
priority: WARNING9. Security Gates in CI/CD
Implement quality gates that block deployments if security thresholds aren't met.
# Complete security pipeline
name: Security Pipeline
on:
pull_request:
push:
branches: [main]
jobs:
security-gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: SAST
run: npm run security:sast
- name: Dependency Scan
run: npm audit --audit-level=high
- name: Secrets Scan
run: gitleaks protect --verbose
- name: Build and scan container
run: |
docker build -t app:${{ github.sha }} .
trivy image --exit-code 1 --severity HIGH,CRITICAL app:${{ github.sha }}
- name: Security Score Check
run: |
SCORE=$(cat security-report.json | jq .score)
if [ $SCORE -lt 80 ]; then
echo "Security score $SCORE below threshold 80"
exit 1
fi
deploy:
needs: security-gate
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- name: Deploy to production
run: echo "Deploying..."10. Security Metrics and Reporting
Track security metrics to measure DevSecOps maturity:
- Mean Time to Remediate (MTTR): Average time to fix vulnerabilities
- Vulnerability density: Vulnerabilities per 1000 lines of code
- Security coverage: Percentage of code covered by security scans
- False positive rate: Invalid security findings / total findings
- Security gate pass rate: Builds passing security checks
- Critical vulnerabilities in production: High/critical issues in prod
- Security training completion: Percentage of developers trained
Building a Security-First Culture
- Security champions: Designate security advocates in each team
- Regular training: Quarterly security workshops and certifications
- Threat modeling: Include security in design reviews
- Blameless postmortems: Learn from security incidents
- Security automation: Make secure choices the easy choices
- Shift left mindset: Address security early in development
- Continuous improvement: Regular security retrospectives
Conclusion
DevSecOps transforms security from a bottleneck into an accelerator. By automating security scanning, integrating checks into CI/CD pipelines, and fostering a security-first culture, organizations ship secure software faster. Start small—add one security scan this week, then incrementally expand coverage. The goal isn't perfection but continuous improvement toward more secure, resilient systems.
DevSecOps Checklist
✓ SAST scanning in CI/CD pipeline
✓ Dependency vulnerability scanning
✓ Container image security scanning
✓ Secrets detection (pre-commit + CI)
✓ DAST testing on staging environments
✓ IaC security scanning (Terraform, K8s)
✓ Runtime security monitoring
✓ Automated compliance checks
✓ Security gates blocking unsafe deployments
✓ Security metrics dashboard
✓ Incident response runbooks
✓ Regular security training
Contact Jishu Labs to implement DevSecOps practices or conduct a security assessment of your development pipeline.
About Lisa Thompson
Lisa Thompson is the Security Architecture Lead at Jishu Labs with over 14 years of experience in application security and DevSecOps. She has implemented security automation for Fortune 500 companies and has helped organizations achieve compliance certifications including SOC 2, ISO 27001, and PCI DSS. Lisa is passionate about making security accessible and automated.