Watch
1
0
Fork
You've already forked RedFlag
0
RedFlag/RAF/scanners/02-docker-scanner.md

3.8 KiB

Docker Scanner

Docker image scanning for container-based agents.


Component Details

Property Value
Method Read /var/run/docker.sock via Docker SDK
Platform Linux (Docker agents)
Execution time ~5 seconds per scan
Output format []client.UpdateReportItem with full metadata in Metadata map
Failure modes Docker daemon unavailable, socket permission denied, registry rate-limited

Implementation

File: agent/internal/orchestrator/docker_scanner.go

The Docker scanner connects directly to the local Docker daemon via the Docker SDK, lists all containers, inspects each image, then queries the remote registry (Docker Hub or custom) to compare digests.

// agent/internal/orchestrator/docker_scanner.go
func (s *DockerScanner) Scan() ([]client.UpdateReportItem, error) {
    containers, err := s.client.ContainerList(ctx, container.ListOptions{All: true})
    // ... inspect each image, compare local vs remote digest ...
    items = append(items, client.UpdateReportItem{
        PackageType:      "docker_image",
        PackageName:      imageName,
        CurrentVersion:   localShortDigest,
        AvailableVersion: remoteShortDigest,
        Severity:         severity,
        RepositorySource: baseImage,
        Metadata: map[string]interface{}{
            "has_update":       hasUpdate,
            "image_id":         localShortDigest,
            "latest_image_id":  remoteShortDigest,
            // ... container info, labels, etc.
        },
    })
    return items, nil
}

Registry Client

The RegistryClient within docker_scanner.go handles:

  • Docker Hub token authentication (auth.docker.io)
  • Registry API v2 manifest fetch via Docker-Content-Digest header
  • 5-minute TTL cache to avoid rate limits
  • Custom registry support (gcr.io, etc.) via domain detection in parseImageName()

Integration Points

1. Orchestrator Registration

Registered in agent/internal/agent/loop.go as a direct orchestrator.Scanner implementation:

dockerScanner, _ := orchestrator.NewDockerScanner()
scanOrchestrator.RegisterScanner("docker", dockerScanner, dockerCB, ...)

2. Command Dispatch

The HandleScanDocker handler in agent/internal/handlers/scan.go runs the scan once through the orchestrator and reads results from result.Updates[] — no double-scanning.

3. Server-Side Storage

Scan results are reported via client.ReportDockerImages() to POST /api/v1/agents/:id/docker-images. The server stores them in docker_images table via server/internal/database/queries/docker.go (CreateDockerEventsBatch, GetDockerImages, etc.).


Data Flow

Agent Poll → Server creates "scan_docker" command
    ↓
Agent receives command → orchestrator.ScanSingle("docker")
    ↓
DockerScanner.Scan() connects to local Docker daemon
    ↓
List containers, inspect images, check registry digests
    ↓
Return UpdateReportItems with full metadata
    ↓
Handler reports results to server API endpoint
    ↓
Server stores in docker_images table

Assumption: Docker daemon is available on the agent host (/var/run/docker.sock). Registry access requires outbound internet (or mirror configuration).

Connection: Scanner registration (agent/internal/agent/loop.go) wires Docker into the orchestrator alongside APT, DNF, Windows, and Winget scanners — all now implement orchestrator.Scanner directly (no wrapper layer).

Connection: Registry client (orchestrator/docker_scanner.go) uses ETHOS [TAG] [system] [component] logging for registry failures.

Connection: Server-side docker_images table (server/internal/database/queries/docker.go) stores reported scan results for dashboard display.


Last reviewed: 2026-05-27