<!-- Copyright (c) 2026 defconxt. All rights reserved. -->
<!-- Licensed under AGPL-3.0 — see LICENSE file for details. -->
---
name: implementing-container-image-scanning-pipeline
description: >-
  Scan container images for OS and application vulnerabilities using Trivy, Grype,
  and Snyk Container. Integrate scanning into Docker build pipelines, enforce
  image signing with Cosign, and block deployment of unscanned images.
domain: cybersecurity
subdomain: devsecops
tags:
  - container-scanning
  - trivy
  - grype
  - docker
  - cosign
  - image-signing
  - supply-chain
  - admission-control
version: "1.0"
author: defconxt
license: AGPL-3.0
metadata:
  mitre-attack: ["T1195.002"]
---

# Implementing Container Image Scanning Pipeline

## Overview

Container image scanning detects OS package vulnerabilities, application dependency
CVEs, misconfigurations, and embedded secrets in Docker and OCI images. This skill
covers integrating image scanning into build pipelines, enforcing signing policies
with Cosign/Sigstore, and blocking unsigned or vulnerable images at admission.

Mode: `[MODE: BLUE]` — Container supply chain security through image analysis.

## Prerequisites

| Requirement | Details |
|---|---|
| Trivy CLI or Grype CLI | Required |
| Docker or Podman for image builds | Required |
| Cosign (`go install github.com/sigstore/cosign/v2/cmd/cosign@latest`) | Required |
| Container registry (GHCR, ECR, GCR, Docker Hub) | Required |
| Kubernetes admission controller (OPA Gatekeeper or Kyverno) for enforcement | Required |

## Key Concepts

### Trivy Image Scan in GitHub Actions

```yaml
name: Container Image Scan
on:
  push:
    branches: [main]
  pull_request:

jobs:
  build-and-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build image
        run: docker build -t myapp:${{ github.sha }} .
      - name: Trivy image scan
        uses: aquasecurity/trivy-action@0.28.0
        with:
          image-ref: myapp:${{ github.sha }}
          format: sarif
          output: trivy-image.sarif
          severity: CRITICAL,HIGH
          exit-code: 1
      - name: Upload SARIF
        if: always()
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: trivy-image.sarif
```

### Image Signing with Cosign

```yaml
name: Sign and Push Image
on:
  push:
    tags: ['v*']

jobs:
  sign:
    runs-on: ubuntu-latest
    permissions:
      packages: write
      id-token: write
    steps:
      - uses: actions/checkout@v4
      - uses: sigstore/cosign-installer@v3
      - name: Login to GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Build and push
        run: |
          docker build -t ghcr.io/${{ github.repository }}:${{ github.ref_name }} .
          docker push ghcr.io/${{ github.repository }}:${{ github.ref_name }}
      - name: Sign image
        run: |
          cosign sign --yes ghcr.io/${{ github.repository }}:${{ github.ref_name }}
```

### Kyverno Admission Policy

```yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-image-signature
spec:
  validationFailureAction: Enforce
  rules:
    - name: check-signature
      match:
        any:
          - resources:
              kinds: ["Pod"]
      verifyImages:
        - imageReferences: ["ghcr.io/myorg/*"]
          attestors:
            - entries:
                - keyless:
                    issuer: "https://token.actions.githubusercontent.com"
                    subject: "https://github.com/myorg/*"
```

### Distroless / Minimal Base Images

```dockerfile
# Multi-stage build with distroless
FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --target=/app/deps -r requirements.txt

FROM gcr.io/distroless/python3-debian12
WORKDIR /app
COPY --from=builder /app/deps /app/deps
COPY src/ /app/src/
ENV PYTHONPATH=/app/deps
CMD ["src/main.py"]
```

## Workflow

### Step 1: Scan Container Image

```bash
node scripts/agent.js --action scan --image myapp:latest --output /tmp/image-scan.json
```

### Step 2: Check Image Configuration

```bash
node scripts/agent.js --action config --image myapp:latest --output /tmp/image-config.json
```

### Step 3: Verify Image Signature

```bash
node scripts/agent.js --action verify --image ghcr.io/org/app:v1.0 --output /tmp/verify.json
```

## Detection

```yaml
title: Container Image Scanning Pipeline Detection
id: d97641e7-497a-4b75-af42-9221573619eb
status: experimental
description: Detects suspicious activity related to implementing container image scanning pipeline techniques in devsecops context
logsource:
  category: process_creation
  product: linux
detection:
  selection:
    CommandLine: "*implementing*container*"
  condition: selection
level: medium
tags:
  - attack.t1195.002
  - attack.execution
falsepositives:
  - CI/CD pipeline executing authorized security scanning tools
```


**Detection Opportunities**

| Indicator | Source | Detection Logic |
|---|---|---|
| Container Image Scanning Pipeline Detection | linux/process_creation | Sigma rule (medium) |
| ATT&CK Coverage | MITRE ATT&CK | T1195.002 |

## Verification

- [ ] Every image scanned before push to registry
- [ ] Critical CVEs block image promotion to production
- [ ] Images signed with Cosign after successful scan
- [ ] Admission controller rejects unsigned images
- [ ] Base images updated on weekly schedule
- [ ] SBOM attached to image as attestation

## References

- [Trivy Container Scanning](https://aquasecurity.github.io/trivy/latest/docs/target/container_image/)
- [Cosign / Sigstore](https://docs.sigstore.dev/cosign/overview/)
- [Kyverno Image Verification](https://kyverno.io/docs/writing-policies/verify-images/)
- [Distroless Images](https://github.com/GoogleContainerTools/distroless)
