spinny:~/writing $ less devsecops-shift-left-security-guide.md
12En sarbarhed der opdages mens du skriver kode, koster en udvikler minutter at rette. Den samme sarbarhed fanget i produktion koster en sprint. Og hvis en angriber finder den foerst, koster det millioner. Dette er kerneargumentet bag **shift-left security** - at flytte sikkerhedstjek sa tidligt som muligt i udviklingslivscyklussen.34DevSecOps tager denne ide og goer den til praksis: sikkerhed er ikke en separat fase i slutningen, men en kontinuerlig proces vaevet ind i hvert trin af udviklingen - fra den foerste kodelinje til produktionsudrulningen.56## Omkostningerne ved Sen Sikkerhed78IBM's Cost of a Data Breach Report har konsekvent vist, at omkostningerne ved at rette sikkerhedsproblemer vokser eksponentielt, jo senere de opdages:910| Fase | Omkostning at rette | Tid at rette |11|------|---------------------|--------------|12| **IDE / Lokal udvikling** | Minutter | Sekunder til minutter |13| **Code Review / PR** | Timer | Minutter til timer |14| **CI/CD Pipeline** | Dage | Timer til dage |15| **Staging / QA** | Uger | Dage |16| **Produktion** | Maneder | Uger til maneder |17| **Efter et brud** | Millioner ($) | Maneder til ar |1819Konklusionen er klar: hvert trin du rykker sikkerheden tidligere, sparer en stoerrelseorden i omkostninger og tid.2021## DevSecOps Pipeline2223En moden DevSecOps pipeline integrerer sikkerhedstjek i hvert trin:2425```mermaid26graph LR27 IDE[IDE / Editor] --> PC[Pre-commit Hooks]28 PC --> PR[Pull Request]29 PR --> CI[CI Pipeline]30 CI --> Build[Build / Package]31 Build --> Deploy[Deploy]32 Deploy --> Runtime[Runtime / Production]3334 IDE -.- S1[SAST\nSecret Detection\nLinting]35 PC -.- S2[Secrets Scan\nFormat Check]36 PR -.- S3[Code Review\nDependency Audit]37 CI -.- S4[SAST\nSCA\nContainer Scan\nSBOM]38 Build -.- S5[Image Signing\nArtifact Verification]39 Deploy -.- S6[Policy Enforcement\nAdmission Control]40 Runtime -.- S7[DAST\nWAF\nMonitoring]41```4243Lad os gennemga hvert trin med konkrete vaerktojer og konfiguration.4445## Trin 1: Sikkerhed i IDE'en4647Den hurtigste feedback-loop. Fang sarbarheder foer du overhovedet gemmer filen.4849### Anbefalede Vaerktojer5051- **Semgrep**: letvaegtigt statisk analyse med community-regler for OWASP-sarbarheder52- **Snyk IDE Extension**: realtidsskanning af sarbarheder i dependencies53- **GitLens + GitLeaks**: opdag secrets i din editor54- **ESLint Security Plugins**: `eslint-plugin-security` for Node.js, `eslint-plugin-no-unsanitized` for DOM XSS5556### Eksempel: ESLint Security-konfiguration5758```json59{60 "extends": ["eslint:recommended"],61 "plugins": ["security", "no-unsanitized"],62 "rules": {63 "security/detect-object-injection": "warn",64 "security/detect-non-literal-regexp": "warn",65 "security/detect-unsafe-regex": "error",66 "security/detect-buffer-noassert": "error",67 "security/detect-eval-with-expression": "error",68 "security/detect-no-csrf-before-method-override": "error",69 "security/detect-possible-timing-attacks": "warn",70 "no-unsanitized/method": "error",71 "no-unsanitized/property": "error"72 }73}74```7576## Trin 2: Pre-commit Hooks7778Den anden forsvarslinje. Koerer automatisk foer hver commit og blokerer farlig kode fra at na repositoryet.7980### Gitleaks: Fang Secrets foer de nar Git8182Den mest almindelige sikkerhedsfejl i kodebaser er at committe secrets - API keys, databaseadgangskoder, tokens. Nar en secret havner i git-historikken, er det ekstremt svaert at fjerne den helt (selv med force pushes kan forks og caches beholde den).8384```yaml85# .pre-commit-config.yaml86repos:87 - repo: https://github.com/gitleaks/gitleaks88 rev: v8.21.089 hooks:90 - id: gitleaks9192 - repo: https://github.com/semgrep/semgrep93 rev: v1.90.094 hooks:95 - id: semgrep96 args: ['--config', 'auto']97```9899Installer og aktiver:100101```bash102pip install pre-commit103pre-commit install104```105106Nu scanner hver `git commit` automatisk for laekkede secrets og almindelige sarbarheder. Hvis noget findes, blokeres committet.107108### Tilpassede Gitleaks-regler109110Du kan tilfoeje tilpassede moenstre for din organisations secrets:111112```toml113# .gitleaks.toml114title = "Custom Gitleaks Config"115116[[rules]]117id = "internal-api-key"118description = "Internal API key detected"119regex = '''INTERNAL_KEY_[A-Za-z0-9]{32}'''120tags = ["key", "internal"]121```122123## Trin 3: CI/CD Pipeline Security124125Her sker det tunge arbejde. Din CI pipeline boer koere flere sikkerhedsscanninger ved hvert pull request.126127### SAST (Static Application Security Testing)128129SAST-vaerktojer analyserer kildekode uden at koere den og leder efter moenstre der indikerer sarbarheder.130131```yaml132# .github/workflows/security.yml133name: Security Scan134on:135 pull_request:136 branches: [main]137138jobs:139 sast:140 name: Static Analysis141 runs-on: ubuntu-latest142 steps:143 - uses: actions/checkout@v4144145 - name: Run Semgrep146 uses: semgrep/semgrep-action@v1147 with:148 config: >-149 p/owasp-top-ten150 p/typescript151 p/nodejs152 p/react153 generateSarif: true154155 - name: Upload SARIF156 uses: github/codeql-action/upload-sarif@v3157 with:158 sarif_file: semgrep.sarif159```160161Semgreps ruleset `p/owasp-top-ten` fanger de mest almindelige sarbarheder: SQL injection, XSS, SSRF, path traversal, insecure deserialization og mere.162163### SCA (Software Composition Analysis)164165SCA scanner dine dependencies for kendte sarbarheder. Dette er kritisk - over 80% af koden i moderne applikationer kommer fra open-source dependencies.166167```yaml168 dependency-scan:169 name: Dependency Audit170 runs-on: ubuntu-latest171 steps:172 - uses: actions/checkout@v4173174 - name: Run Snyk175 uses: snyk/actions/node@master176 env:177 SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}178 with:179 args: --severity-threshold=high180181 - name: npm audit182 run: npm audit --audit-level=high183```184185### Container Security med Trivy186187Hvis du bygger Docker images, er det essentielt at scanne dem for sarbarheder. **Trivy** er den mest populaere open-source container scanner.188189```yaml190 container-scan:191 name: Container Security192 runs-on: ubuntu-latest193 steps:194 - uses: actions/checkout@v4195196 - name: Build image197 run: docker build -t my-app:${{ github.sha }} .198199 - name: Run Trivy200 uses: aquasecurity/trivy-action@master201 with:202 image-ref: my-app:${{ github.sha }}203 format: 'sarif'204 output: 'trivy-results.sarif'205 severity: 'CRITICAL,HIGH'206 exit-code: '1'207208 - name: Upload Trivy SARIF209 uses: github/codeql-action/upload-sarif@v3210 with:211 sarif_file: trivy-results.sarif212```213214### SBOM-generering215216En **Software Bill of Materials (SBOM)** er en komplet fortegnelse over hver komponent i din applikation. Den kraeves i stigende grad af compliance-rammer og statslige reguleringer (den amerikanske Executive Order on Cybersecurity paalaegger SBOM for foedealt software).217218```yaml219 sbom:220 name: Generate SBOM221 runs-on: ubuntu-latest222 steps:223 - uses: actions/checkout@v4224225 - name: Generate SBOM with Syft226 uses: anchore/sbom-action@v0227 with:228 format: spdx-json229 output-file: sbom.spdx.json230231 - name: Upload SBOM232 uses: actions/upload-artifact@v4233 with:234 name: sbom235 path: sbom.spdx.json236```237238## Trin 4: Sikre Docker Images239240Et produktions-Docker-image boer foelge princippet om mindste rettigheder. Sadan ser en haerdet Dockerfile ud:241242```dockerfile243# Build stage244FROM node:22-alpine AS builder245WORKDIR /app246COPY package.json package-lock.json ./247RUN npm ci248COPY . .249RUN npm run build250251# Production stage252FROM node:22-alpine AS runner253WORKDIR /app254255# Install dumb-init before dropping root256RUN apk add --no-cache dumb-init257258# Don't run as root259RUN addgroup -S app && adduser -S app -G app260261# Copy only what's needed262COPY --from=builder --chown=app:app /app/dist ./dist263COPY --from=builder --chown=app:app /app/node_modules ./node_modules264COPY --from=builder --chown=app:app /app/package.json ./265266# Drop to non-root user267USER app268ENTRYPOINT ["dumb-init", "--"]269270# Health check271HEALTHCHECK --interval=30s --timeout=3s --retries=3 \272 CMD wget -qO- http://localhost:3000/health || exit 1273274EXPOSE 3000275CMD ["node", "dist/server.js"]276```277278Vigtige principper:2792801. **Brug multi-stage builds**: builder-fasen har dev-dependencies; runner-fasen har kun produktionskode2812. **Koer ikke som root**: opret en ikke-root bruger og skift til den2823. **Brug Alpine images**: mindre angrebsflade (faerre pakker installeret som standard)2834. **Fastlags image-versioner**: `node:22-alpine` i stedet for `node:latest` for at undga supply chain-angreb2845. **Brug `npm ci`**: deterministiske installationer fra lock-filen, ikke `npm install`285286## Trin 5: Secret Management287288Hardkodede secrets er den foerste arsag til sikkerhedsbrud ved udviklerforsagede haaendelser.289290### Hvad du IKKE skal goere291292```typescript293// NEVER do this294const API_KEY = "sk-1234567890abcdef";295const DB_PASSWORD = "supersecret123";296297const client = new Client({298 connectionString: `postgres://admin:${DB_PASSWORD}@db.example.com/prod`299});300```301302### Hvad du skal goere i stedet303304```typescript305// Use environment variables306const client = new Client({307 connectionString: process.env.DATABASE_URL308});309310// Or use a secret manager311import { SecretManagerServiceClient } from '@google-cloud/secret-manager';312313const client = new SecretManagerServiceClient();314const [version] = await client.accessSecretVersion({315 name: 'projects/my-project/secrets/db-password/versions/latest',316});317const dbPassword = version.payload?.data?.toString();318```319320### Secret Management-hierarki321322```mermaid323graph TD324 A[Secret Manager\nAWS Secrets Manager\nGCP Secret Manager\nHashiCorp Vault] --> B[Best: Rotated, audited, centralized]325 C[Environment Variables\nInjected at deploy time] --> D[Good: Not in code, but static]326 E[.env files\nWith .gitignore] --> F[Acceptable: Local development only]327 G[Hard-coded in source] --> H[NEVER: Instant breach risk]328329 style A fill:#d4edda330 style C fill:#fff3cd331 style E fill:#ffeeba332 style G fill:#f8d7da333```334335## OWASP Top 10: En Hurtig Reference336337Enhver udvikler boer kende OWASP Top 10. Kort version:338339| # | Sarbarhed | Hvad det er | Forebyggelse |340|---|-----------|------------|--------------|341| 1 | **Broken Access Control** | Brugere der far adgang til ressourcer de ikke burde | Afvis som standard, valider pa serversiden |342| 2 | **Cryptographic Failures** | Svag kryptering, data i klartekst | Brug staerke algoritmer (AES-256, bcrypt), TLS overalt |343| 3 | **Injection** | SQL, NoSQL, OS command injection | Parametriserede foresoergelser, inputvalidering |344| 4 | **Insecure Design** | Mangelfuld arkitektur | Threat modeling, sikre designmoenstre |345| 5 | **Security Misconfiguration** | Standardloginoplysninger, abne cloud buckets | Haerdede standardvaerdier, automatiserede konfigurationsrevisioner |346| 6 | **Vulnerable Components** | Kendte CVEs i dependencies | SCA scanning, regelmaessige opdateringer |347| 7 | **Auth Failures** | Svage adgangskoder, defekte sessioner | MFA, rate limiting, sikker session management |348| 8 | **Data Integrity Failures** | Usignerede opdateringer, utrovaerdig CI/CD | Code signing, SBOM, pipeline-integritet |349| 9 | **Logging Failures** | Ingen revisionslog | Struktureret logging, alarmering ved afvigelser |350| 10 | **SSRF** | Server-side request forgery | Allowlist for udgaende URLs, valider input |351352## Komplet GitHub Actions Security Workflow353354Et komplet, produktionsklart workflow der kombinerer alt ovenstaende:355356```yaml357# .github/workflows/security.yml358name: Security Pipeline359on:360 pull_request:361 branches: [main]362 push:363 branches: [main]364365permissions:366 contents: read367 security-events: write368369jobs:370 secrets-scan:371 name: Secret Detection372 runs-on: ubuntu-latest373 steps:374 - uses: actions/checkout@v4375 with:376 fetch-depth: 0377 - uses: gitleaks/gitleaks-action@v2378 env:379 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}380381 sast:382 name: Static Analysis (SAST)383 runs-on: ubuntu-latest384 steps:385 - uses: actions/checkout@v4386 - uses: semgrep/semgrep-action@v1387 with:388 config: p/owasp-top-ten p/typescript p/nodejs389390 dependency-audit:391 name: Dependency Scan (SCA)392 runs-on: ubuntu-latest393 steps:394 - uses: actions/checkout@v4395 - uses: actions/setup-node@v4396 with:397 node-version: 22398 - run: npm ci399 - run: npm audit --audit-level=high400 - uses: snyk/actions/node@master401 env:402 SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}403 with:404 args: --severity-threshold=high405 continue-on-error: true406407 container-scan:408 name: Container Scan409 runs-on: ubuntu-latest410 needs: [sast, dependency-audit]411 steps:412 - uses: actions/checkout@v4413 - run: docker build -t app:${{ github.sha }} .414 - uses: aquasecurity/trivy-action@master415 with:416 image-ref: app:${{ github.sha }}417 severity: CRITICAL,HIGH418 exit-code: '1'419420 sbom:421 name: SBOM Generation422 runs-on: ubuntu-latest423 needs: [container-scan]424 steps:425 - uses: actions/checkout@v4426 - uses: anchore/sbom-action@v0427 with:428 format: spdx-json429 output-file: sbom.spdx.json430```431432```mermaid433graph TD434 PR[Pull Request] --> S1[Secret Detection]435 PR --> S2[SAST - Semgrep]436 PR --> S3[SCA - Snyk + npm audit]437 S2 --> S4[Container Scan - Trivy]438 S3 --> S4439 S4 --> S5[SBOM Generation]440 S5 --> Deploy[Deploy]441442 S1 -.- F1[Block if secrets found]443 S2 -.- F2[Block on critical vulns]444 S3 -.- F3[Block on high severity]445 S4 -.- F4[Block on critical CVEs]446```447448## Metrikker at Foelge449450Hvordan ved du, om dit DevSecOps-program virker? Foelg disse metrikker:451452- **Mean Time to Remediate (MTTR)**: hvor hurtigt du retter sarbarheder efter detektion453- **Vulnerability Escape Rate**: procentdelen af sarbarheder der nar produktion454- **False Positive Rate**: for mange false positives foerer til alarmtraethed og ignorerede advarsler455- **Dependency Freshness**: gennemsnitsalder pa dine dependencies (aeldre = stoerre sandsynlighed for kendte CVEs)456- **SBOM Coverage**: procentdelen af projekter med opdaterede SBOMs457458## Kom Godt I Gang: En Praktisk Koereplan459460Forsoeg ikke at implementere alt pa en gang. En trinvis tilgang fungerer bedre:461462```mermaid463flowchart TD464 A[Week 1-2: Foundations] --> B[Week 3-4: CI/CD Integration]465 B --> C[Month 2: Container Security]466 C --> D[Month 3+: Advanced]467468 A --> A1[Add Gitleaks pre-commit hooks]469 A --> A2[Enable npm audit in CI]470 A --> A3[Add .gitignore for .env files]471472 B --> B1[Add Semgrep to GitHub Actions]473 B --> B2[Add Snyk dependency scanning]474 B --> B3[Set up SARIF upload to GitHub]475476 C --> C1[Add Trivy container scanning]477 C --> C2[Harden Dockerfiles]478 C --> C3[Generate SBOMs]479480 D --> D1[Secret manager integration]481 D --> D2[Runtime protection - DAST]482 D --> D3[Policy as code - OPA]483```484485## Konklusion486487DevSecOps handler ikke om at tilfoeje flere vaerktojer til din pipeline - det handler om at goere sikkerhed til en naturlig del af, hvordan du bygger software. Malet er ikke at blokere hver PR med sikkerhedsadvarsler, men at give udviklere hurtig feedback, sa de kan rette problemer mens koden stadig er frisk i hukommelsen.488489Start med det grundlaeggende: pre-commit hooks for secrets, dependency scanning i CI og container scanning for Docker images. Iterer derefter baseret pa, hvad dit team har brug for.490491Sikkerhed er ikke en funktion du leverer en gang. Det er en praksis du bygger ind i hvert commit.492493> **DevSecOps Starter Tjekliste:**494>495> - [x] Gitleaks pre-commit hooks installeret496> - [x] .env og secret-filer i .gitignore497> - [x] Semgrep SAST i CI pipeline498> - [x] Snyk eller npm audit til dependency scanning499> - [x] Trivy til container image scanning500> - [x] Ikke-root bruger i Dockerfiles501> - [x] Secrets i miljoevariable eller secret manager502> - [x] SBOM-generering ved hver release503> - [x] OWASP Top 10-bevidsthed i hele teamet504
:DevSecOps for Udviklere: En Praktisk Guide til Shift-Left Securitylines 1-504 (END) — press q to close