Devops
DevopsIntermediate

DevSecOps Implementation: A Complete Security Guide

DevHub Team
5 min read
DevSecOpsSecurityDevOpsCompliance

TL;DR

Master DevSecOps implementation with this comprehensive guide covering security automation, compliance as code, and best practices for secure software delivery

DevSecOps Implementation: A Complete Security Guide

DevSecOps integrates security practices into the DevOps lifecycle, enabling continuous security and compliance. This guide explores implementation patterns, tools, and best practices for building secure delivery pipelines.

$1

``mermaid

graph TB

subgraph "Development"

A[Code Analysis]

B[Dependency Scanning]

C[SAST]

end

subgraph "Build & Test"

D[Container Scanning]

E[DAST]

F[Secret Detection]

end

subgraph "Operations"

G[Runtime Security]

H[Compliance Checks]

I[Threat Detection]

end

A --> D

B --> D

C --> D

D --> G

E --> G

F --> G

G --> H

G --> I

classDef dev fill:#1a73e8,stroke:#fff,color:#fff

classDef build fill:#34a853,stroke:#fff,color:#fff

classDef ops fill:#fbbc04,stroke:#fff,color:#fff

class A,B,C dev

class D,E,F build

class G,H,I ops

`

$1

$1

`yaml

.github/workflows/security-scan.yml

name: Security Scan

on:

push:

branches: [ main ]

pull_request:

branches: [ main ]

jobs:

security:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v2

- name: SonarQube Scan

uses: sonarsource/sonarqube-scan-action@master

env:

SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}

- name: Snyk Code Test

uses: snyk/actions/node@master

env:

SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

with:

args: --severity-threshold=high

`

$1

`dockerfile

Dockerfile.secure

FROM alpine:3.17

Add security packages

RUN apk add --no-cache \

ca-certificates \

tzdata \

&& update-ca-certificates

Create non-root user

RUN addgroup -S appgroup && adduser -S appuser -G appgroup

Set working directory

WORKDIR /app

Copy application files

COPY --chown=appuser:appgroup . .

Use non-root user

USER appuser

Expose port

EXPOSE 8080

Start application

CMD ["./app"]

`

$1

$1

`rego

policy.rego

package devsecops.policy

Enforce container security

deny[msg] {

input.kind == "Deployment"

container := input.spec.template.spec.containers[_]

not container.securityContext.runAsNonRoot

msg := "Containers must run as non-root"

}

Enforce resource limits

deny[msg] {

input.kind == "Deployment"

container := input.spec.template.spec.containers[_]

not container.resources.limits

msg := "Resource limits are required"

}

Enforce network policies

deny[msg] {

input.kind == "NetworkPolicy"

not input.spec.ingress

msg := "Ingress rules are required"

}

`

$1

`yaml

compliance-check.yaml

apiVersion: constraints.gatekeeper.sh/v1beta1

kind: K8sRequiredLabels

metadata:

name: ns-must-have-env

spec:

match:

kinds:

- apiGroups: [""]

kinds: ["Namespace"]

parameters:

labels: ["environment"]

---

apiVersion: constraints.gatekeeper.sh/v1beta1

kind: K8sAllowedRepos

metadata:

name: allowed-repos

spec:

match:

kinds:

- apiGroups: [""]

kinds: ["Pod"]

parameters:

repos:

- "gcr.io/secure-images/"

- "docker.io/official/"

`

$1

$1

`yaml

falco-rules.yaml

  • rule: Detect Shell in Container
  • desc: Alert on shell execution in container

    condition: >

    container.id != host and

    proc.name = bash

    output: Shell executed in container (user=%user.name container=%container.name)

    priority: WARNING

  • rule: Unauthorized Process
  • desc: Alert on unauthorized process execution

    condition: >

    container.id != host and

    not proc.name in (allowed_processes)

    output: Unauthorized process %proc.name started (user=%user.name container=%container.name)

    priority: WARNING

  • rule: Sensitive File Access
  • desc: Alert on sensitive file access

    condition: >

    container.id != host and

    fd.name startswith /etc/shadow

    output: Sensitive file accessed (user=%user.name file=%fd.name)

    priority: CRITICAL

    `

    $1

    `typescript

    // audit-logger.ts

    import { createLogger, format, transports } from 'winston';

    interface AuditEvent {

    userId: string;

    action: string;

    resource: string;

    timestamp: Date;

    status: 'success' | 'failure';

    details?: Record;

    }

    class AuditLogger {

    private logger;

    constructor() {

    this.logger = createLogger({

    format: format.combine(

    format.timestamp(),

    format.json()

    ),

    transports: [

    new transports.File({ filename: 'audit.log' }),

    new transports.Console({

    format: format.combine(

    format.colorize(),

    format.simple()

    )

    })

    ]

    });

    }

    logAuditEvent(event: AuditEvent): void {

    this.logger.info('Security Audit', {

    ...event,

    timestamp: event.timestamp.toISOString()

    });

    }

    }

    `

    $1

    $1

    `typescript

    // vault-client.ts

    import { Client } from '@hashicorp/vault-client';

    class SecretManager {

    private client: Client;

    constructor() {

    this.client = new Client({

    address: process.env.VAULT_ADDR,

    token: process.env.VAULT_TOKEN

    });

    }

    async getSecret(path: string): Promise {

    try {

    const { data } = await this.client.read(secret/data/${path});

    return data.data;

    } catch (error) {

    console.error('Failed to retrieve secret:', error);

    throw error;

    }

    }

    async setSecret(path: string, value: string): Promise {

    try {

    await this.client.write(secret/data/${path}, {

    data: { value }

    });

    } catch (error) {

    console.error('Failed to store secret:', error);

    throw error;

    }

    }

    }

    `

    $1

    $1

    `yaml

    rbac.yaml

    apiVersion: rbac.authorization.k8s.io/v1

    kind: Role

    metadata:

    name: security-role

    namespace: security

    rules:

  • apiGroups: ["security.openshift.io"]
  • resources: ["securitycontextconstraints"]

    verbs: ["use"]

  • apiGroups: [""]
  • resources: ["pods/log", "pods/exec"]

    verbs: ["get", "list", "create"]

    ---

    apiVersion: rbac.authorization.k8s.io/v1

    kind: RoleBinding

    metadata:

    name: security-role-binding

    namespace: security

    subjects:

  • kind: ServiceAccount
  • name: security-sa

    namespace: security

    roleRef:

    kind: Role

    name: security-role

    apiGroup: rbac.authorization.k8s.io

    `

    $1

    $1

    `typescript

    // security-tests.ts

    import { test } from '@jest/globals';

    import { SecureClient } from './secure-client';

    describe('Security Tests', () => {

    let client: SecureClient;

    beforeEach(() => {

    client = new SecureClient({

    baseUrl: process.env.API_URL,

    token: process.env.API_TOKEN

    });

    });

    test('should enforce TLS', async () => {

    const response = await client.testTLS();

    expect(response.protocol).toBe('TLSv1.3');

    expect(response.cipherSuite).toMatch(/^TLS_AES/);

    });

    test('should validate JWT tokens', async () => {

    const invalidToken = 'invalid.token.here';

    await expect(

    client.makeRequest('/secure', invalidToken)

    ).rejects.toThrow('Invalid token');

    });

    test('should prevent SQL injection', async () => {

    const maliciousInput = "'; DROP TABLE users; --";

    await expect(

    client.searchUsers(maliciousInput)

    ).rejects.toThrow('Invalid input');

    });

    });

    ``

    $1

    $1

    Alert Condition Response
    Unauthorized Access Failed auth > 5 Block IP
    Malware Detected Signature match Isolate container
    Data Leak Sensitive data access Revoke credentials

    $1

    $1

    Practice Description Implementation
    Least Privilege Minimal access RBAC/IAM
    Immutable Infrastructure No runtime changes GitOps
    Security Testing Automated scans CI/CD pipeline

    $1

    $1

    Issue Cause Solution
    Failed Scans Policy violation Fix findings
    Access Issues RBAC config Check permissions
    Compliance Failure Missing controls Add policies

    $1

    1. [OWASP DevSecOps](https://owasp.org/www-project-devsecops-guideline/)

    2. [NIST Application Security](https://csrc.nist.gov/publications/detail/sp/800-218/final)

    3. [CIS Benchmarks](https://www.cisecurity.org/cis-benchmarks/)

    4. [DevSecOps Maturity Model](https://dsomm.timo-pagel.de/)

    5. [Cloud Native Security](https://www.cncf.io/blog/2020/08/13/cloud-native-security-whitepaper/)

    6. [Container Security](https://kubernetes.io/docs/concepts/security/)

  • [GitOps Tools Comparison](/posts/devops/gitops-tools-comparison) - Modern deployment
  • [DevOps AI Integration](/posts/devops/ai-integration) - AI in DevOps
  • [Platform Engineering](/posts/devops/platform-engineering) - Modern platforms
  • [Kubernetes Operators](/posts/kubernetes/operators) - Custom controllers
  • Why This Matters

    Understanding the business and technical context helps you make informed decisions rather than blindly following patterns.

    Trade-offs to Consider

    Every architectural decision involves trade-offs. Consider your specific requirements, team expertise, and scale when evaluating options.

    When NOT to Use This

    Knowing when a solution doesn't apply is as valuable as knowing when it does. Consider alternatives for your specific situation.

    Decision Framework

    Use this framework to evaluate whether this approach is right for your use case based on your specific constraints and requirements.