Go Container Security Scanning: 6 Key Practices for Trivy SBOM Supply Chain Security

云原生

When Supply Chain Attacks Meet Image Vulnerabilities: Container Security's Darkest Hour

3 AM, alerts are screaming. Your production container is running a crypto miner, CPU at 99%. Investigation reveals: the base image golang:1.22-alpine contains an unpatched CVE-2024-1234, attackers injected malicious code through transitive dependencies, and your CI/CD has zero security gates. Worse — you have no idea what's actually inside your image. No SBOM, no signature verification, and compliance audits draw a blank.

This isn't hypothetical. The XZ Utils backdoor, Log4Shell, and the SolarWinds supply chain attack all prove that container security isn't optional — it's a survival baseline. You need vulnerability scanning to find risks, SBOM to make dependencies transparent, image signing for trust, and CI/CD gates to block threats. This article covers 6 key practices to build your Go container supply chain security defense.


Core Concepts Reference

Concept Core Idea Key Tool Typical Scenario
Container Security Full lifecycle protection from build to runtime Trivy, Clair Image vulnerability scanning, runtime protection
SBOM (Software Bill of Materials) List all software components and dependencies syft, trivy sbom Dependency transparency, compliance audit
CVE (Common Vulnerabilities and Exposures) Standardized vulnerability identification and rating NVD, OSV Vulnerability tracking and fix prioritization
Trivy All-in-one container security scanner trivy Image/filesystem/Git repo scanning
Cosign Container image signing and verification cosign Image provenance trust verification
SLSA (Supply-chain Levels for Software Artifacts) Software supply chain integrity framework SLSA spec Build process trust assurance
Sigstore Free open-source code signing platform cosign, rekor Image/artifact signing and auditing
Image Signing Sign image digest with key pair cosign sign Prevent image tampering
Vulnerability Severity CRITICAL > HIGH > MEDIUM > LOW CVSS score Fix prioritization decisions
CIS Benchmark Container/orchestration security configuration standards trivy misconfig Docker/K8s security hardening

Table of Contents

  1. Problem Analysis: 5 Container Security Challenges
  2. Practice 1: Trivy Image Vulnerability Scanning Integration
  3. Practice 2: SBOM Generation and Verification
  4. Practice 3: Cosign Image Signing and Verification
  5. Practice 4: CI/CD Security Gate Configuration
  6. Practice 5: Go Module Dependency Auditing
  7. Practice 6: Runtime Security Monitoring
  8. 5 Common Pitfalls
  9. 10 Error Troubleshooting
  10. Advanced Optimization Tips
  11. Scanner Comparison
  12. Recommended Online Tools
  13. Summary and Outlook

Problem Analysis: 5 Container Security Challenges

Challenge 1: Lagging Image Vulnerability Fixes — The Go base image golang:1.22 contains hundreds of system packages. CVEs take an average of 97 days from disclosure to fix. Your images may run with known vulnerabilities for months.

Challenge 2: Transitive Dependency Risks — Indirect dependencies pulled by go mod tidy may contain malicious code. The XZ Utils incident proved that even widely-used libraries can be backdoored, and go.sum only verifies integrity, not security.

Challenge 3: Missing Image Signature Verification — Without signature verification, anyone can push tampered images to your registry. K8s doesn't verify image provenance by default — it runs whatever it pulls.

Challenge 4: SBOM Generation and Management — Without an SBOM, you can't answer "what's in this image?" Compliance audits require SBOMs, but most teams have never generated one.

Challenge 5: Compliance Audit Automation — SOC2 and similar frameworks require continuous security scanning records. Manual audits are inefficient and prone to gaps.


Practice 1: Trivy Image Vulnerability Scanning Integration

Installation and Basic Scanning

# Install Trivy
brew install trivy
# Or use Docker
docker run aquasec/trivy:latest version

Scan Go Container Images

# Scan local image
trivy image myapp:latest

# Show only CRITICAL and HIGH severity
trivy image --severity CRITICAL,HIGH myapp:latest

# Output JSON format for integration
trivy image --format json --output result.json myapp:latest

# Scan specific architecture
trivy image --platform linux/amd64 myapp:latest

Go Project Integration

package main

import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
)

type TrivyReport struct {
	Results []TrivyResult `json:"Results"`
}

type TrivyResult struct {
	Target    string        `json:"Target"`
	Type      string        `json:"Type"`
	Vulnerabilities []Vuln `json:"Vulnerabilities"`
}

type Vuln struct {
	VulnerabilityID string `json:"VulnerabilityID"`
	Severity        string `json:"Severity"`
	PkgName         string `json:"PkgName"`
	InstalledVersion string `json:"InstalledVersion"`
	FixedVersion    string `json:"FixedVersion"`
	Title           string `json:"Title"`
}

func scanImage(imageRef string) (*TrivyReport, error) {
	cmd := exec.Command("trivy", "image",
		"--format", "json",
		"--severity", "CRITICAL,HIGH",
		imageRef,
	)
	output, err := cmd.Output()
	if err != nil {
		return nil, fmt.Errorf("trivy scan failed: %w", err)
	}

	var report TrivyReport
	if err := json.Unmarshal(output, &report); err != nil {
		return nil, fmt.Errorf("parse report failed: %w", err)
	}
	return &report, nil
}

func main() {
	imageRef := os.Getenv("SCAN_IMAGE")
	if imageRef == "" {
		imageRef = "myapp:latest"
	}

	report, err := scanImage(imageRef)
	if err != nil {
		fmt.Fprintf(os.Stderr, "scan error: %v\n", err)
		os.Exit(1)
	}

	criticalCount := 0
	for _, result := range report.Results {
		for _, v := range result.Vulnerabilities {
			if v.Severity == "CRITICAL" {
				criticalCount++
				fmt.Printf("[CRITICAL] %s: %s (%s -> %s)\n",
					v.VulnerabilityID, v.Title,
					v.InstalledVersion, v.FixedVersion)
			}
		}
	}

	if criticalCount > 0 {
		fmt.Printf("\nFound %d CRITICAL vulnerabilities. Blocking deploy.\n", criticalCount)
		os.Exit(1)
	}
	fmt.Println("No CRITICAL vulnerabilities found. Safe to deploy.")
}

Trivy Configuration File

# trivy.yaml
severity:
  - CRITICAL
  - HIGH

skipDirs:
  - /tmp
  - /var/cache

ignorefile: .trivyignore

db:
  skipUpdate: false

vulnerability:
  type:
    - os
    - library

misconfiguration:
  type:
    - dockerfile
    - kubernetes

Practice 2: SBOM Generation and Verification

Generate SBOM with Trivy

# Generate SPDX format SBOM
trivy image --format spdx-json --output sbom.spdx.json myapp:latest

# Generate CycloneDX format SBOM
trivy image --format cyclonedx --output sbom.cyclonedx.json myapp:latest

Generate SBOM with Syft

# Install Syft
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin

# Generate SBOM
syft myapp:latest -o spdx-json > sbom.spdx.json
syft myapp:latest -o cyclonedx-json > sbom.cyclonedx.json

Programmatic SBOM Management in Go

package main

import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"time"
)

type SBOMMetadata struct {
	ImageRef      string    `json:"imageRef"`
	GeneratedAt   time.Time `json:"generatedAt"`
	Tool          string    `json:"tool"`
	Format        string    `json:"format"`
	ComponentCount int     `json:"componentCount"`
}

func generateSBOM(imageRef, format, outputPath string) error {
	args := []string{"image", "--format", format, "--output", outputPath, imageRef}
	cmd := exec.Command("trivy", args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

func validateSBOM(sbomPath string) error {
	data, err := os.ReadFile(sbomPath)
	if err != nil {
		return fmt.Errorf("read sbom failed: %w", err)
	}

	if !json.Valid(data) {
		return fmt.Errorf("invalid SBOM JSON format")
	}

	var sbom map[string]interface{}
	if err := json.Unmarshal(data, &sbom); err != nil {
		return fmt.Errorf("parse SBOM failed: %w", err)
	}

	if _, ok := sbom["components"]; !ok {
		if _, ok2 := sbom["packages"]; !ok2 {
			return fmt.Errorf("SBOM missing components/packages field")
		}
	}

	fmt.Printf("SBOM validation passed: %s\n", sbomPath)
	return nil
}

func main() {
	imageRef := "myapp:latest"
	sbomPath := fmt.Sprintf("sbom-%s.json", time.Now().Format("20060102"))

	fmt.Printf("Generating SBOM for %s...\n", imageRef)
	if err := generateSBOM(imageRef, "cyclonedx", sbomPath); err != nil {
		fmt.Fprintf(os.Stderr, "generate SBOM failed: %v\n", err)
		os.Exit(1)
	}

	if err := validateSBOM(sbomPath); err != nil {
		fmt.Fprintf(os.Stderr, "validate SBOM failed: %v\n", err)
		os.Exit(1)
	}

	meta := SBOMMetadata{
		ImageRef:      imageRef,
		GeneratedAt:   time.Now(),
		Tool:          "trivy",
		Format:        "cyclonedx",
		ComponentCount: 0,
	}
	metaData, _ := json.MarshalIndent(meta, "", "  ")
	fmt.Println(string(metaData))
}

Practice 3: Cosign Image Signing and Verification

Key Pair Generation and Signing

# Generate key pair
cosign generate-key-pair

# Sign image (using private key)
cosign sign --key cosign.key myregistry/myapp:latest

# Verify signature (using public key)
cosign verify --key cosign.pub myregistry/myapp:latest

# Keyless signing (Sigstore)
cosign sign myregistry/myapp:latest

# Keyless verification
cosign verify myregistry/myapp:latest

Go Image Verification Integration

package main

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
)

func verifyImageSignature(imageRef, publicKey string) error {
	args := []string{"verify", "--key", publicKey, imageRef}
	cmd := exec.Command("cosign", args...)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("signature verification failed: %s", string(output))
	}

	if !strings.Contains(string(output), "Verified OK") {
		return fmt.Errorf("signature not verified for %s", imageRef)
	}

	fmt.Printf("Image verified: %s\n", imageRef)
	return nil
}

func signImage(imageRef, keyPath string) error {
	args := []string{"sign", "--key", keyPath, imageRef}
	cmd := exec.Command("cosign", args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

func main() {
	action := os.Args[1]
	imageRef := os.Args[2]

	switch action {
	case "sign":
		if err := signImage(imageRef, "cosign.key"); err != nil {
			fmt.Fprintf(os.Stderr, "sign failed: %v\n", err)
			os.Exit(1)
		}
	case "verify":
		if err := verifyImageSignature(imageRef, "cosign.pub"); err != nil {
			fmt.Fprintf(os.Stderr, "verify failed: %v\n", err)
			os.Exit(1)
		}
	default:
		fmt.Fprintf(os.Stderr, "unknown action: %s\n", action)
		os.Exit(1)
	}
}

K8s Admission Controller Verification Policy

apiVersion: policies.kubewarden.io/v1
kind: ClusterAdmissionPolicy
metadata:
  name: verify-image-signatures
spec:
  module: registry://ghcr.io/kubewarden/policies/verify-image-signatures:v0.2.5
  rules:
    - apiGroups: [""]
      apiVersions: ["v1"]
      resources: ["pods"]
      operations: ["CREATE", "UPDATE"]
  settings:
    signatures:
      - image: "myregistry.io/*"
        pubKeys:
          - |
            -----BEGIN PUBLIC KEY-----
            YOUR_PUBLIC_KEY_HERE
            -----END PUBLIC KEY-----

Practice 4: CI/CD Security Gate Configuration

GitHub Actions Security Pipeline

name: Security Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  security-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build Image
        run: docker build -t myapp:${{ github.sha }} .

      - name: Trivy Vulnerability Scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: "myapp:${{ github.sha }}"
          format: "sarif"
          output: "trivy-results.sarif"
          severity: "CRITICAL,HIGH"
          exit-code: "1"

      - name: Generate SBOM
        uses: anchore/sbom-action@v0
        with:
          image: "myapp:${{ github.sha }}"
          format: cyclonedx-json
          output-file: sbom.json

      - name: Sign Image
        run: |
          cosign sign --key env://COSIGN_PRIVATE_KEY myapp:${{ github.sha }}
        env:
          COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
          COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}

      - name: Go Module Audit
        run: |
          go install golang.org/x/vuln/cmd/govulncheck@latest
          govulncheck ./...

      - name: Upload Trivy Results
        uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: trivy-results.sarif

GitLab CI Security Gate

stages:
  - build
  - scan
  - sign
  - deploy

build-image:
  stage: build
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .

trivy-scan:
  stage: scan
  image: aquasec/trivy:latest
  script:
    - trivy image --exit-code 1 --severity CRITICAL,HIGH $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - trivy image --format cyclonedx --output sbom.json $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  artifacts:
    paths:
      - sbom.json

cosign-verify:
  stage: sign
  script:
    - cosign sign --key cosign.key $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  only:
    - main

deploy:
  stage: deploy
  script:
    - cosign verify --key cosign.pub $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - kubectl set image deployment/myapp myapp=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  only:
    - main

Practice 5: Go Module Dependency Auditing

govulncheck Deep Scanning

# Install govulncheck
go install golang.org/x/vuln/cmd/govulncheck@latest

# Scan current project
govulncheck ./...

# Output JSON format
govulncheck -json ./...

# Show only called vulnerabilities (more precise)
govulncheck -mode binary ./...

Go Dependency Audit Program

package main

import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"strings"
)

type VulnEntry struct {
	OSV      string `json:"osv"`
	Module   string `json:"module"`
	Version  string `json:"version"`
	Package  string `json:"package"`
	Call     string `json:"call"`
	Severity string `json:"severity"`
}

func auditGoModules(projectPath string) ([]VulnEntry, error) {
	cmd := exec.Command("govulncheck", "-json", "./...")
	cmd.Dir = projectPath
	output, err := cmd.Output()
	if err != nil {
		return nil, fmt.Errorf("govulncheck failed: %w", err)
	}

	var vulns []VulnEntry
	decoder := json.NewDecoder(strings.NewReader(string(output)))
	for decoder.More() {
		var entry map[string]interface{}
		if err := decoder.Decode(&entry); err != nil {
			continue
		}
		if vulnData, ok := entry["vulnerability"]; ok {
			v := VulnEntry{}
			if m, ok := vulnData.(map[string]interface{}); ok {
				if id, ok := m["id"].(string); ok {
					v.OSV = id
				}
				if mod, ok := m["module"].(string); ok {
					v.Module = mod
				}
			}
			vulns = append(vulns, v)
		}
	}
	return vulns, nil
}

func checkGoModTidy(projectPath string) error {
	cmd := exec.Command("go", "mod", "tidy", "-diff")
	cmd.Dir = projectPath
	output, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("go.mod needs tidy: %s", string(output))
	}
	return nil
}

func main() {
	projectPath := "."
	if len(os.Args) > 1 {
		projectPath = os.Args[1]
	}

	fmt.Println("Checking go.mod tidiness...")
	if err := checkGoModTidy(projectPath); err != nil {
		fmt.Fprintf(os.Stderr, "[WARN] %v\n", err)
	}

	fmt.Println("Running govulncheck...")
	vulns, err := auditGoModules(projectPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "audit failed: %v\n", err)
		os.Exit(1)
	}

	if len(vulns) > 0 {
		fmt.Printf("Found %d vulnerabilities:\n", len(vulns))
		for _, v := range vulns {
			fmt.Printf("  - %s: %s@%s\n", v.OSV, v.Module, v.Version)
		}
		os.Exit(1)
	}
	fmt.Println("No known vulnerabilities found.")
}

go.mod Security Configuration

// go.mod
module github.com/myorg/myapp

go 1.22.0

require (
    github.com/gin-gonic/gin v1.9.1
    github.com/redis/go-redis/v9 v9.5.1
)

// Exclude known vulnerable versions
exclude (
    github.com/example/vulnerable v1.0.0
)

// Specify safe version replacement
replace github.com/example/vulnerable => github.com/example/vulnerable v1.0.1

Practice 6: Runtime Security Monitoring

Falco Runtime Detection Rules

# falco-rules/go-container.yaml
- rule: Unexpected Process in Go Container
  desc: Detect unexpected processes running in Go containers
  condition: >
    container and container.image contains "myapp" and
    proc.name not in (myapp, sh, cat, ls)
  output: >
    Unexpected process in Go container
    (user=%user.name container=%container.name
     image=%container.image.proc=%proc.name)
  priority: WARNING
  tags: [container, go, runtime]

- rule: Crypto Mining Detected
  desc: Detect crypto mining activity in containers
  condition: >
    container and
    (proc.name in (xmrig, minerd, cpuminer) or
     proc.cmdline contains "stratum+tcp")
  output: >
    Crypto mining detected
    (user=%user.name container=%container.name
     image=%container.image.proc=%proc.name)
  priority: CRITICAL
  tags: [crypto, container, runtime]

- rule: Container Drift Detected
  desc: Detect new files created in running container
  condition: >
    container and evt.type = openat and
    evt.arg.flags contains O_CREAT and
    not fd.name startswith /tmp and
    not fd.name startswith /var/log
  output: >
    Container drift detected
    (user=%user.name container=%container.name
     file=%fd.name)
  priority: WARNING
  tags: [drift, container, runtime]

Go Runtime Security Checks

package main

import (
	"fmt"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"time"
)

type SecurityCheck struct {
	Name   string
	Status string
	Detail string
}

func checkRunningAsRoot() SecurityCheck {
	if os.Getuid() == 0 {
		return SecurityCheck{
			Name:   "Root User Check",
			Status: "FAIL",
			Detail: "Container running as root",
		}
	}
	return SecurityCheck{
		Name:   "Root User Check",
		Status: "PASS",
		Detail: fmt.Sprintf("Running as UID %d", os.Getuid()),
	}
}

func checkReadOnlyFilesystem() SecurityCheck {
	if err := os.WriteFile("/tmp/.security-test", []byte("test"), 0644); err != nil {
		return SecurityCheck{
			Name:   "Read-Only FS Check",
			Status: "PASS",
			Detail: "Filesystem is read-only",
		}
	}
	os.Remove("/tmp/.security-test")
	return SecurityCheck{
		Name:   "Read-Only FS Check",
		Status: "WARN",
		Detail: "Filesystem is writable",
	}
}

func checkDistroless() SecurityCheck {
	_, err := exec.LookPath("sh")
	if err != nil {
		return SecurityCheck{
			Name:   "Distroless Check",
			Status: "PASS",
			Detail: "No shell available (distroless)",
		}
	}
	return SecurityCheck{
		Name:   "Distroless Check",
		Status: "WARN",
		Detail: "Shell available in image",
	}
}

func runSecurityAudit() []SecurityCheck {
	return []SecurityCheck{
		checkRunningAsRoot(),
		checkReadOnlyFilesystem(),
		checkDistroless(),
	}
}

func main() {
	fmt.Printf("Runtime Security Audit - %s\n", time.Now().Format(time.RFC3339))
	fmt.Printf("Platform: %s/%s\n", runtime.GOOS, runtime.GOARCH)
	fmt.Println(strings.Repeat("-", 60))

	checks := runSecurityAudit()
	failCount := 0
	for _, c := range checks {
		status := c.Status
		if status == "FAIL" {
			failCount++
		}
		fmt.Printf("[%s] %s: %s\n", status, c.Name, c.Detail)
	}

	fmt.Println(strings.Repeat("-", 60))
	if failCount > 0 {
		fmt.Printf("Audit FAILED: %d checks failed\n", failCount)
		os.Exit(1)
	}
	fmt.Println("Audit PASSED")
}

Hardened Dockerfile

FROM golang:1.22-alpine AS builder

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /myapp .

FROM gcr.io/distroless/static-debian12:nonroot

COPY --from=builder /myapp /myapp

USER nonroot:nonroot

HEALTHCHECK --interval=30s --timeout=3s \
  CMD ["/myapp", "healthcheck"]

ENTRYPOINT ["/myapp"]

5 Common Pitfalls

# Pitfall Wrong Approach Right Approach
1 ❌ Scan but don't block Archive scan results, CI/CD continues deploying ✅ Use --exit-code 1 to block deployments with CRITICAL vulnerabilities
2 ❌ Ignore indirect dependencies Only check go.mod direct dependencies ✅ Use govulncheck ./... to scan the full dependency tree
3 ❌ Use latest tag FROM golang:latest is not reproducible ✅ Pin versions: FROM golang:1.22.3-alpine3.19
4 ❌ Run containers as root Dockerfile defaults to root user USER nonroot:nonroot + distroless base image
5 ❌ Separate signing from deployment Sign but don't verify before deploying ✅ K8s Admission Controller enforces signature verification

10 Error Troubleshooting

# Error Message Cause Solution
1 FATAL: error in DB download Trivy vulnerability DB download failed Run trivy image --download-db-only then retry; configure HTTP_PROXY
2 unsupported format: cyclonedx Trivy version too old Upgrade to v0.40+: brew upgrade trivy
3 cosign: signing failed: KEY_REF Key environment variable not set export COSIGN_PRIVATE_KEY=... or use --key cosign.key
4 verification failed: no signatures Image not signed Sign first with cosign sign then verify
5 govulncheck: module not found Go module cache corrupted go clean -modcache && go mod download
6 trivy: permission denied Docker socket permission denied sudo usermod -aG docker $USER or use rootless mode
7 SBOM: empty components Scanned builder stage instead of final image Scan the final image, not the builder stage
8 cosign verify: REKOR error Rekor transparency log unreachable Check network; or use --insecure-ignore-tlog (test only)
9 trivy: image not found locally Image doesn't exist locally docker pull first or specify remote registry
10 Falco: rule syntax error YAML indentation or field name error Validate with falco -V

Advanced Optimization Tips

1. Trivy Operator for K8s Cluster-Wide Auto-Scanning — Deploy Trivy Operator to your K8s cluster to automatically scan all Pod images and generate VulnerabilityReports, combined with Prometheus alerts for continuous monitoring.

2. SBOM Attestation Attached to Images — Use cosign attest to attach SBOMs as attachments to image manifests, ensuring SBOMs travel with images and never get lost.

3. VEX Documents to Suppress False Positives — Generate VEX (Vulnerability Exploitability eXchange) documents to mark vulnerabilities assessed as non-exploitable, reducing scan noise and focusing on real risks.

4. Multi-Arch Image Unified Signing — Use cosign sign on manifest lists rather than individual manifests, ensuring unified verification across linux/amd64 and linux/arm64.

5. SLSA Level 3 Build Assurance — Use Sigstore signing + Rekor transparency log + SLSA provenance in CI/CD to achieve SLSA Level 3, ensuring auditable and verifiable build processes.


Scanner Comparison

Feature Trivy Grype Clair Snyk
Scan Speed ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐
Vulnerability DB Coverage Comprehensive (OS+language) Good OS-layer focused Comprehensive
SBOM Generation ✅ SPDX/CycloneDX ❌ Needs Syft
Image Signing ❌ Use with Cosign
IaC Scanning
Secret Detection
CI/CD Integration ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐⭐
Open Source Free ✅ Apache 2.0 ✅ Apache 2.0 ✅ Apache 2.0 ❌ Commercial
K8s Operator
Go Module Support
Best For All-around first choice Lightweight scanning K8s cluster-level Enterprise compliance

Recommendation: Small-to-mid teams should start with Trivy (open source, full-featured); large K8s clusters consider Trivy Operator + Clair combo; enterprise compliance scenarios evaluate Snyk.


Tool Purpose Link
JSON Formatter SBOM/scan result formatting /en/json/format
Hash Calculator Image digest/file integrity verification /en/encode/hash
Curl to Code Security scan API call generation /en/dev/curl-to-code
Base64 Codec Key/certificate encoding/decoding /en/encode/base64
Regex Tester Falco rule/log matching debug /en/dev/regex

Summary and Outlook

Container security scanning isn't a one-time action — it's a full lifecycle practice from build to runtime. The core logic of the 6 key practices: Trivy scanning discovers vulnerabilities → SBOM makes dependencies transparent → Cosign ensures image trust → CI/CD gates auto-block → govulncheck audits Go dependencies → Falco monitors runtime anomalies.

2026 trends: The SLSA framework is becoming the de facto standard for supply chain security, Sigstore Keyless signing lowers the signing barrier, SBOM attestation binds bills of materials to images, and AI-assisted vulnerability fix prioritization. Container security is shifting from "reactive patching" to "shift-left built-in" — the earlier you integrate security practices, the lower the fix cost.

Remember: Security isn't a wall blocking delivery — it's a gate ensuring delivery quality. Start with Trivy scanning and progressively build your container security defense line.

Try these browser-local tools — no sign-up required →

#容器安全#Go#镜像扫描#Trivy#SBOM#供应链安全#2026#云原生