Integrate security into every stage of the DevOps lifecycle with DevSecOps practices and automation
DevSecOps integrates security practices into the DevOps process. Instead of security being a gate at the end, it's built into every stage from development to production.
"Shift left" means moving security earlier in the development lifecycle. Finding vulnerabilities in development is 100x cheaper than finding them in production.
Code Analysis (SAST)
Static analysis of source code for vulnerabilities
Dependency Scanning (SCA)
Check third-party libraries for known vulnerabilities
Container Scanning
Scan Docker images for vulnerabilities
Dynamic Testing (DAST)
Test running applications for security issues
Infrastructure Scanning
Check IaC for misconfigurations
Integrate security tools into your CI/CD pipeline to catch issues automatically before they reach production.
name: Security Pipeline
on: [push, pull_request]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# SAST - Static code analysis
- name: Run Semgrep
uses: returntocorp/semgrep-action@v1
with:
config: auto
# SCA - Dependency scanning
- name: Run Snyk
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
# Secret scanning
- name: TruffleHog Scan
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: main
head: HEAD
# Container scanning
- name: Build Docker image
run: docker build -t myapp:latest .
- name: Scan image with Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:latest
format: 'sarif'
output: 'trivy-results.sarif'
# Upload results
- name: Upload to GitHub Security
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
# IaC scanning
- name: Scan Terraform
uses: aquasecurity/tfsec-action@v1.0.0
with:
soft_fail: false# Use specific version, not 'latest'
FROM node:20.10-alpine
# Run as non-root user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001
# Set working directory
WORKDIR /app
# Copy only necessary files
COPY package*.json ./
RUN npm ci --only=production
COPY --chown=nodejs:nodejs . .
# Drop privileges
USER nodejs
# Expose port
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s \
CMD node healthcheck.js
CMD ["node", "server.js"]Scan images for:
Never store secrets in code or environment variables. Use dedicated secrets management tools to securely store, access, and rotate credentials.
# Store secret in Vault
vault kv put secret/myapp/db \
username="dbuser" \
password="secure-password"
# Read secret
vault kv get secret/myapp/db
# Application code (Node.js)
const vault = require('node-vault')({
endpoint: process.env.VAULT_ADDR,
token: process.env.VAULT_TOKEN
});
async function getDbCredentials() {
const result = await vault.read('secret/data/myapp/db');
return result.data.data;
}
// Use dynamic secrets (auto-rotate)
const dbCreds = await vault.read('database/creds/myapp-role');
// Credentials are temporary and auto-expire# ExternalSecret syncs from Vault to K8s Secret
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: myapp-secrets
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: myapp-secrets
creationPolicy: Owner
data:
- secretKey: db-password
remoteRef:
key: secret/myapp/db
property: password
---
# Use in Pod
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: app
image: myapp:latest
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: myapp-secrets
key: db-passwordCompliance as Code automates security and compliance checks. Define policies as code and enforce them automatically in your pipelines.
# policy.rego - Kubernetes admission policy
package kubernetes.admission
deny[msg] {
input.request.kind.kind == "Pod"
image := input.request.object.spec.containers[_].image
not startswith(image, "myregistry.com/")
msg := sprintf("Image %v is not from approved registry", [image])
}
deny[msg] {
input.request.kind.kind == "Pod"
container := input.request.object.spec.containers[_]
not container.securityContext.runAsNonRoot
msg := sprintf("Container %v must run as non-root", [container.name])
}
deny[msg] {
input.request.kind.kind == "Pod"
container := input.request.object.spec.containers[_]
container.securityContext.privileged
msg := sprintf("Container %v cannot run in privileged mode", [container.name])
}CI/CD Pipeline
Block builds that violate policies
Kubernetes Admission
Reject non-compliant resources
Terraform Plan
Validate IaC before apply
Runtime
Monitor and alert on violations
# Default deny all ingress
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
spec:
podSelector: {}
policyTypes:
- Ingress
---
# Allow specific traffic
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-network-policy
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
app: database
ports:
- protocol: TCP
port: 5432Istio provides:
Security monitoring tools detect anomaly and trigger alert
Isolate affected systems, revoke compromised credentials
Analyze logs, determine scope and impact
Patch vulnerabilities, restore from clean backups
Post-incident review, update security controls
You've learned comprehensive DevSecOps practices:
You've completed the DevOps & Site Reliability Engineering course! You now have the skills to build, deploy, monitor, and maintain reliable, secure, scalable systems.
Technical Skills:
SRE Practices: