Initial commit
This commit is contained in:
598
skills/devsecops/container-hadolint/SKILL.md
Normal file
598
skills/devsecops/container-hadolint/SKILL.md
Normal file
@@ -0,0 +1,598 @@
|
||||
---
|
||||
name: container-hadolint
|
||||
description: >
|
||||
Dockerfile security linting and best practice validation using Hadolint with 100+ built-in
|
||||
rules aligned to CIS Docker Benchmark. Use when: (1) Analyzing Dockerfiles for security
|
||||
misconfigurations and anti-patterns, (2) Enforcing container image security best practices
|
||||
in CI/CD pipelines, (3) Detecting hardcoded secrets and credentials in container builds,
|
||||
(4) Validating compliance with CIS Docker Benchmark requirements, (5) Integrating shift-left
|
||||
container security into developer workflows, (6) Providing remediation guidance for insecure
|
||||
Dockerfile instructions.
|
||||
version: 0.1.0
|
||||
maintainer: SirAppSec
|
||||
category: devsecops
|
||||
tags: [docker, hadolint, dockerfile, container-security, cis-benchmark, linting, ci-cd]
|
||||
frameworks: [CIS, OWASP]
|
||||
dependencies:
|
||||
tools: [hadolint, docker]
|
||||
references:
|
||||
- https://github.com/hadolint/hadolint
|
||||
- https://www.cisecurity.org/benchmark/docker
|
||||
- https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
|
||||
---
|
||||
|
||||
# Dockerfile Security Linting with Hadolint
|
||||
|
||||
## Overview
|
||||
|
||||
Hadolint is a Dockerfile linter that validates container build files against security best practices and the CIS Docker Benchmark. It analyzes Dockerfile instructions to identify misconfigurations, anti-patterns, and security vulnerabilities before images are built and deployed.
|
||||
|
||||
Hadolint integrates ShellCheck to validate RUN instructions, ensuring shell commands follow security best practices. With 100+ built-in rules mapped to CIS Docker Benchmark controls, Hadolint provides comprehensive security validation for container images.
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Install Hadolint
|
||||
|
||||
```bash
|
||||
# macOS via Homebrew
|
||||
brew install hadolint
|
||||
|
||||
# Linux via binary
|
||||
wget -O /usr/local/bin/hadolint https://github.com/hadolint/hadolint/releases/latest/download/hadolint-Linux-x86_64
|
||||
chmod +x /usr/local/bin/hadolint
|
||||
|
||||
# Via Docker
|
||||
docker pull hadolint/hadolint
|
||||
```
|
||||
|
||||
### Scan Dockerfile
|
||||
|
||||
```bash
|
||||
# Scan Dockerfile in current directory
|
||||
hadolint Dockerfile
|
||||
|
||||
# Scan with specific Dockerfile path
|
||||
hadolint path/to/Dockerfile
|
||||
|
||||
# Using Docker
|
||||
docker run --rm -i hadolint/hadolint < Dockerfile
|
||||
```
|
||||
|
||||
### Generate Report
|
||||
|
||||
```bash
|
||||
# JSON output for automation
|
||||
hadolint -f json Dockerfile > hadolint-report.json
|
||||
|
||||
# GitLab Code Quality format
|
||||
hadolint -f gitlab_codeclimate Dockerfile > hadolint-codeclimate.json
|
||||
|
||||
# Checkstyle format for CI integration
|
||||
hadolint -f checkstyle Dockerfile > hadolint-checkstyle.xml
|
||||
```
|
||||
|
||||
## Core Workflows
|
||||
|
||||
### 1. Local Development Scanning
|
||||
|
||||
Validate Dockerfiles during development:
|
||||
|
||||
```bash
|
||||
# Basic scan with colored output
|
||||
hadolint Dockerfile
|
||||
|
||||
# Scan with specific severity threshold
|
||||
hadolint --failure-threshold error Dockerfile
|
||||
|
||||
# Show only warnings and errors
|
||||
hadolint --no-color --format tty Dockerfile | grep -E "^(warning|error)"
|
||||
|
||||
# Verbose output with rule IDs
|
||||
hadolint -t style -t warning -t error Dockerfile
|
||||
```
|
||||
|
||||
**Output Format:**
|
||||
```
|
||||
Dockerfile:3 DL3008 warning: Pin versions in apt get install
|
||||
Dockerfile:7 DL3025 error: Use JSON notation for CMD and ENTRYPOINT
|
||||
Dockerfile:12 DL3059 info: Multiple RUN instructions detected
|
||||
```
|
||||
|
||||
**When to use**: Developer workstation, pre-commit validation, iterative Dockerfile development.
|
||||
|
||||
### 2. CI/CD Pipeline Integration
|
||||
|
||||
Automate Dockerfile validation in build pipelines:
|
||||
|
||||
#### GitHub Actions
|
||||
|
||||
```yaml
|
||||
name: Hadolint
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Hadolint Dockerfile
|
||||
uses: hadolint/hadolint-action@v3.1.0
|
||||
with:
|
||||
dockerfile: Dockerfile
|
||||
failure-threshold: warning
|
||||
format: sarif
|
||||
output-file: hadolint.sarif
|
||||
|
||||
- name: Upload SARIF to GitHub Security
|
||||
if: always()
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
with:
|
||||
sarif_file: hadolint.sarif
|
||||
```
|
||||
|
||||
#### GitLab CI
|
||||
|
||||
```yaml
|
||||
hadolint:
|
||||
image: hadolint/hadolint:latest-debian
|
||||
stage: lint
|
||||
script:
|
||||
- hadolint -f gitlab_codeclimate Dockerfile > hadolint-report.json
|
||||
artifacts:
|
||||
reports:
|
||||
codequality: hadolint-report.json
|
||||
when: always
|
||||
```
|
||||
|
||||
**When to use**: Automated security gates, pull request checks, deployment validation.
|
||||
|
||||
### 3. Configuration Customization
|
||||
|
||||
Create `.hadolint.yaml` to customize rules:
|
||||
|
||||
```yaml
|
||||
# .hadolint.yaml
|
||||
failure-threshold: warning
|
||||
ignored:
|
||||
- DL3008 # Allow unpinned apt-get packages (assess risk first)
|
||||
- DL3059 # Allow multiple RUN instructions
|
||||
|
||||
trustedRegistries:
|
||||
- docker.io/library # Official Docker Hub images
|
||||
- gcr.io/distroless # Google distroless images
|
||||
- registry.access.redhat.com # Red Hat registry
|
||||
|
||||
override:
|
||||
error:
|
||||
- DL3001 # Enforce: never use yum/dnf/zypper without version pins
|
||||
warning:
|
||||
- DL3015 # Warn: use --no-install-recommends with apt-get
|
||||
info:
|
||||
- DL3059 # Info: multiple RUN instructions reduce layer caching
|
||||
|
||||
label-schema:
|
||||
maintainer: text
|
||||
org.opencontainers.image.vendor: text
|
||||
org.opencontainers.image.version: semver
|
||||
```
|
||||
|
||||
Use bundled templates in `assets/`:
|
||||
- `assets/hadolint-strict.yaml` - Strict security enforcement (CRITICAL/HIGH only)
|
||||
- `assets/hadolint-balanced.yaml` - Balanced validation (recommended)
|
||||
- `assets/hadolint-permissive.yaml` - Permissive for legacy Dockerfiles
|
||||
|
||||
**When to use**: Reducing false positives, organizational standards, legacy Dockerfile migration.
|
||||
|
||||
### 4. Security-Focused Validation
|
||||
|
||||
Enforce critical security rules:
|
||||
|
||||
```bash
|
||||
# Only fail on security issues (error severity)
|
||||
hadolint --failure-threshold error Dockerfile
|
||||
|
||||
# Check specific security rules
|
||||
hadolint --trusted-registry docker.io/library Dockerfile
|
||||
|
||||
# Scan all Dockerfiles in project
|
||||
find . -name "Dockerfile*" -exec hadolint {} \;
|
||||
|
||||
# Generate security report with only errors
|
||||
hadolint -f json Dockerfile | jq '.[] | select(.level == "error")'
|
||||
```
|
||||
|
||||
**Critical Security Rules:**
|
||||
- **DL3000**: Use absolute WORKDIR (prevents directory traversal)
|
||||
- **DL3001**: Always use version pinning for package managers
|
||||
- **DL3002**: Never switch to root USER in Dockerfile
|
||||
- **DL3020**: Use COPY instead of ADD (prevents arbitrary URL fetching)
|
||||
- **DL3025**: Use JSON notation for CMD/ENTRYPOINT (prevents shell injection)
|
||||
|
||||
See `references/security_rules.md` for complete security rule catalog with CIS mappings.
|
||||
|
||||
### 5. Multi-Stage Build Validation
|
||||
|
||||
Scan complex multi-stage Dockerfiles:
|
||||
|
||||
```bash
|
||||
# Validate all stages
|
||||
hadolint Dockerfile
|
||||
|
||||
# Stage-specific validation (use custom script)
|
||||
./scripts/hadolint_multistage.py Dockerfile
|
||||
```
|
||||
|
||||
**Common Multi-Stage Issues:**
|
||||
- Using same user across build and runtime stages
|
||||
- Copying unnecessary build tools to production image
|
||||
- Missing security hardening in final stage
|
||||
- Secrets present in build stage propagating to runtime
|
||||
|
||||
**When to use**: Complex builds, security-hardened images, production containerization.
|
||||
|
||||
### 6. Pre-Commit Hook Integration
|
||||
|
||||
Prevent insecure Dockerfiles from being committed:
|
||||
|
||||
```bash
|
||||
# Install pre-commit hook using bundled script
|
||||
./scripts/install_precommit.sh
|
||||
|
||||
# Or manually create hook
|
||||
cat << 'EOF' > .git/hooks/pre-commit
|
||||
#!/bin/bash
|
||||
for dockerfile in $(git diff --cached --name-only | grep -E 'Dockerfile'); do
|
||||
hadolint --failure-threshold warning "$dockerfile" || exit 1
|
||||
done
|
||||
EOF
|
||||
|
||||
chmod +x .git/hooks/pre-commit
|
||||
```
|
||||
|
||||
**When to use**: Developer workstations, team onboarding, mandatory security controls.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Sensitive Data Handling
|
||||
|
||||
- **Secret Detection**: Hadolint flags hardcoded secrets in ENV, ARG, LABEL instructions
|
||||
- **Build Secrets**: Use Docker BuildKit secrets (`RUN --mount=type=secret`) instead of ARG for credentials
|
||||
- **Multi-Stage Security**: Ensure secrets in build stages don't leak to final image
|
||||
- **Image Scanning**: Hadolint validates Dockerfile - combine with image scanning (Trivy, Grype) for runtime security
|
||||
|
||||
### Access Control
|
||||
|
||||
- **CI/CD Permissions**: Hadolint scans require read access to Dockerfile and build context
|
||||
- **Report Storage**: Treat scan reports as internal documentation - may reveal security practices
|
||||
- **Trusted Registries**: Configure `trustedRegistries` to enforce approved base image sources
|
||||
|
||||
### Audit Logging
|
||||
|
||||
Log the following for compliance and security auditing:
|
||||
- Scan execution timestamps and Dockerfile paths
|
||||
- Rule violations by severity (error, warning, info)
|
||||
- Suppressed rules and justifications
|
||||
- Base image registry validation results
|
||||
- Remediation actions and timeline
|
||||
|
||||
### Compliance Requirements
|
||||
|
||||
- **CIS Docker Benchmark 1.6**: Hadolint rules map to CIS controls (see `references/cis_mapping.md`)
|
||||
- 4.1: Create a user for the container (DL3002)
|
||||
- 4.6: Add HEALTHCHECK instruction (DL3025)
|
||||
- 4.7: Do not use update alone in Dockerfile (DL3009)
|
||||
- 4.9: Use COPY instead of ADD (DL3020)
|
||||
- **OWASP Docker Security**: Validates against OWASP container security best practices
|
||||
- **NIST SP 800-190**: Application container security guidance
|
||||
|
||||
## Bundled Resources
|
||||
|
||||
### Scripts (`scripts/`)
|
||||
|
||||
- `hadolint_scan.py` - Comprehensive scanning with multiple Dockerfiles and output formats
|
||||
- `hadolint_multistage.py` - Multi-stage Dockerfile analysis with stage-specific validation
|
||||
- `install_precommit.sh` - Automated pre-commit hook installation
|
||||
- `ci_integration.sh` - CI/CD integration examples for multiple platforms
|
||||
|
||||
### References (`references/`)
|
||||
|
||||
- `security_rules.md` - Complete Hadolint security rules with CIS Benchmark mappings
|
||||
- `cis_mapping.md` - Detailed CIS Docker Benchmark control mapping
|
||||
- `remediation_guide.md` - Rule-by-rule remediation guidance with secure examples
|
||||
- `shellcheck_integration.md` - ShellCheck rules for RUN instruction validation
|
||||
|
||||
### Assets (`assets/`)
|
||||
|
||||
- `hadolint-strict.yaml` - Strict security configuration
|
||||
- `hadolint-balanced.yaml` - Production-ready configuration (recommended)
|
||||
- `hadolint-permissive.yaml` - Legacy Dockerfile migration configuration
|
||||
- `github-actions.yml` - Complete GitHub Actions workflow
|
||||
- `gitlab-ci.yml` - Complete GitLab CI pipeline
|
||||
- `precommit-config.yaml` - Pre-commit framework configuration
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Pattern 1: Initial Dockerfile Security Audit
|
||||
|
||||
First-time security assessment:
|
||||
|
||||
```bash
|
||||
# 1. Find all Dockerfiles
|
||||
find . -type f -name "Dockerfile*" > dockerfile-list.txt
|
||||
|
||||
# 2. Scan all Dockerfiles with JSON output
|
||||
mkdir -p security-reports
|
||||
while read dockerfile; do
|
||||
output_file="security-reports/$(echo $dockerfile | tr '/' '_').json"
|
||||
hadolint -f json "$dockerfile" > "$output_file" 2>&1
|
||||
done < dockerfile-list.txt
|
||||
|
||||
# 3. Generate summary report
|
||||
./scripts/hadolint_scan.py --input-dir . --output summary-report.html
|
||||
|
||||
# 4. Review critical/high findings
|
||||
cat security-reports/*.json | jq '.[] | select(.level == "error")' > critical-findings.json
|
||||
```
|
||||
|
||||
### Pattern 2: Progressive Remediation
|
||||
|
||||
Gradual security hardening:
|
||||
|
||||
```bash
|
||||
# Phase 1: Baseline (don't fail builds yet)
|
||||
hadolint --failure-threshold none -f json Dockerfile > baseline.json
|
||||
|
||||
# Phase 2: Fix critical issues (fail on errors only)
|
||||
hadolint --failure-threshold error Dockerfile
|
||||
|
||||
# Phase 3: Address warnings
|
||||
hadolint --failure-threshold warning Dockerfile
|
||||
|
||||
# Phase 4: Full compliance (including style/info)
|
||||
hadolint Dockerfile
|
||||
```
|
||||
|
||||
### Pattern 3: Security-Hardened Production Image
|
||||
|
||||
Build security-first container image:
|
||||
|
||||
```dockerfile
|
||||
# Example secure Dockerfile following Hadolint best practices
|
||||
|
||||
# Use specific base image version from trusted registry
|
||||
FROM docker.io/library/node:18.19.0-alpine3.19
|
||||
|
||||
# Install packages with version pinning and cleanup
|
||||
RUN apk add --no-cache \
|
||||
dumb-init=1.2.5-r2 \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
# Create non-root user
|
||||
RUN addgroup -g 1001 -S appuser && \
|
||||
adduser -S -u 1001 -G appuser appuser
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Copy application files (use COPY not ADD)
|
||||
COPY --chown=appuser:appuser package*.json ./
|
||||
COPY --chown=appuser:appuser . .
|
||||
|
||||
# Install dependencies
|
||||
RUN npm ci --only=production && \
|
||||
npm cache clean --force
|
||||
|
||||
# Switch to non-root user
|
||||
USER appuser
|
||||
|
||||
# Expose port (document only, not security control)
|
||||
EXPOSE 3000
|
||||
|
||||
# Add healthcheck
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD node healthcheck.js || exit 1
|
||||
|
||||
# Use JSON notation for entrypoint/cmd
|
||||
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
|
||||
CMD ["node", "server.js"]
|
||||
```
|
||||
|
||||
Validate with Hadolint:
|
||||
```bash
|
||||
hadolint Dockerfile # Should pass with no errors
|
||||
```
|
||||
|
||||
### Pattern 4: CI/CD with Automated Remediation Suggestions
|
||||
|
||||
Provide actionable feedback in pull requests:
|
||||
|
||||
```bash
|
||||
# In CI pipeline
|
||||
hadolint -f json Dockerfile > hadolint.json
|
||||
|
||||
# Generate remediation suggestions
|
||||
./scripts/hadolint_scan.py \
|
||||
--input hadolint.json \
|
||||
--format markdown \
|
||||
--output pr-comment.md
|
||||
|
||||
# Post to PR comment (using gh CLI)
|
||||
gh pr comment --body-file pr-comment.md
|
||||
```
|
||||
|
||||
## Integration Points
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
- **GitHub Actions**: Native hadolint-action with SARIF support for Security tab
|
||||
- **GitLab CI**: GitLab Code Quality format integration
|
||||
- **Jenkins**: Checkstyle format for Jenkins Warnings plugin
|
||||
- **CircleCI**: Docker-based executor with artifact retention
|
||||
- **Azure Pipelines**: Task integration with results publishing
|
||||
|
||||
### Security Tools Ecosystem
|
||||
|
||||
- **Image Scanning**: Combine with Trivy, Grype, Clair for runtime vulnerability scanning
|
||||
- **Secret Scanning**: Integrate with Gitleaks, TruffleHog for comprehensive secret detection
|
||||
- **IaC Security**: Chain with Checkov for Kubernetes/Terraform validation
|
||||
- **SBOM Generation**: Export findings alongside Syft/Trivy SBOM reports
|
||||
- **Security Dashboards**: Export JSON to Grafana, Kibana, Datadog for centralized monitoring
|
||||
|
||||
### SDLC Integration
|
||||
|
||||
- **Development**: Pre-commit hooks provide immediate feedback
|
||||
- **Code Review**: PR checks prevent insecure Dockerfiles from merging
|
||||
- **Testing**: Scan test environment Dockerfiles
|
||||
- **Staging**: Validation gate before production promotion
|
||||
- **Production**: Periodic audits of deployed container configurations
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Issue: Too Many False Positives
|
||||
|
||||
**Symptoms**: Legitimate patterns flagged (legacy Dockerfiles, specific use cases)
|
||||
|
||||
**Solution**:
|
||||
```yaml
|
||||
# Create .hadolint.yaml
|
||||
ignored:
|
||||
- DL3059 # Multiple RUN instructions (valid for complex builds)
|
||||
|
||||
# Or use inline ignores
|
||||
# hadolint ignore=DL3008
|
||||
RUN apt-get update && apt-get install -y curl
|
||||
```
|
||||
|
||||
Consult `references/remediation_guide.md` for rule-specific guidance.
|
||||
|
||||
### Issue: Base Image Registry Not Trusted
|
||||
|
||||
**Symptoms**: Error about untrusted registry even for legitimate images
|
||||
|
||||
**Solution**:
|
||||
```yaml
|
||||
# Add to .hadolint.yaml
|
||||
trustedRegistries:
|
||||
- mycompany.azurecr.io
|
||||
- gcr.io/my-project
|
||||
- docker.io/library
|
||||
```
|
||||
|
||||
### Issue: ShellCheck Warnings in RUN Instructions
|
||||
|
||||
**Symptoms**: SC2086, SC2046 warnings from ShellCheck integration
|
||||
|
||||
**Solution**:
|
||||
```dockerfile
|
||||
# Bad: Unquoted variables
|
||||
RUN echo $MY_VAR > file.txt
|
||||
|
||||
# Good: Quoted variables
|
||||
RUN echo "$MY_VAR" > file.txt
|
||||
|
||||
# Or disable specific ShellCheck rule
|
||||
# hadolint ignore=DL4006
|
||||
RUN echo $MY_VAR > file.txt
|
||||
```
|
||||
|
||||
See `references/shellcheck_integration.md` for complete ShellCheck guidance.
|
||||
|
||||
### Issue: Multi-Stage Build Not Recognized
|
||||
|
||||
**Symptoms**: Errors about missing USER instruction despite proper multi-stage setup
|
||||
|
||||
**Solution**:
|
||||
```dockerfile
|
||||
# Ensure each stage has appropriate USER
|
||||
FROM node:18 AS builder
|
||||
# Build operations...
|
||||
|
||||
FROM node:18-alpine AS runtime
|
||||
USER node # Add USER in final stage
|
||||
CMD ["node", "app.js"]
|
||||
```
|
||||
|
||||
### Issue: CI Pipeline Failing on Warnings
|
||||
|
||||
**Symptoms**: Build fails on low-severity issues
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Adjust failure threshold in CI
|
||||
hadolint --failure-threshold error Dockerfile
|
||||
|
||||
# Or configure per-environment
|
||||
if [ "$CI_ENVIRONMENT" == "production" ]; then
|
||||
hadolint --failure-threshold warning Dockerfile
|
||||
else
|
||||
hadolint --failure-threshold error Dockerfile
|
||||
fi
|
||||
```
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Custom Rule Severity Override
|
||||
|
||||
```yaml
|
||||
# .hadolint.yaml
|
||||
override:
|
||||
error:
|
||||
- DL3001 # Package versioning is critical
|
||||
- DL3020 # COPY vs ADD is security-critical
|
||||
warning:
|
||||
- DL3059 # Multiple RUN is warning, not info
|
||||
info:
|
||||
- DL3008 # Downgrade apt-get pinning to info for dev images
|
||||
```
|
||||
|
||||
### Inline Suppression
|
||||
|
||||
```dockerfile
|
||||
# Suppress single rule for one instruction
|
||||
# hadolint ignore=DL3018
|
||||
RUN apk add --no-cache curl
|
||||
|
||||
# Suppress multiple rules
|
||||
# hadolint ignore=DL3003,DL3009
|
||||
WORKDIR /tmp
|
||||
RUN apt-get update && apt-get install -y wget
|
||||
|
||||
# Global suppression (use sparingly)
|
||||
# hadolint global ignore=DL3059
|
||||
```
|
||||
|
||||
### Trusted Registry Enforcement
|
||||
|
||||
```yaml
|
||||
# .hadolint.yaml
|
||||
trustedRegistries:
|
||||
- docker.io/library # Official images only
|
||||
- gcr.io/distroless # Google distroless
|
||||
- cgr.dev/chainguard # Chainguard images
|
||||
|
||||
# This will error on:
|
||||
# FROM nginx:latest ❌ (docker.io/nginx)
|
||||
# FROM docker.io/library/nginx:latest ✅ (trusted)
|
||||
```
|
||||
|
||||
### Label Schema Validation
|
||||
|
||||
```yaml
|
||||
# .hadolint.yaml
|
||||
label-schema:
|
||||
maintainer: text
|
||||
org.opencontainers.image.created: rfc3339
|
||||
org.opencontainers.image.version: semver
|
||||
org.opencontainers.image.vendor: text
|
||||
```
|
||||
|
||||
Ensures Dockerfile LABELs conform to OCI image specification.
|
||||
|
||||
## References
|
||||
|
||||
- [Hadolint GitHub Repository](https://github.com/hadolint/hadolint)
|
||||
- [CIS Docker Benchmark](https://www.cisecurity.org/benchmark/docker)
|
||||
- [Docker Best Practices](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)
|
||||
- [ShellCheck Documentation](https://www.shellcheck.net/)
|
||||
- [OCI Image Specification](https://github.com/opencontainers/image-spec)
|
||||
9
skills/devsecops/container-hadolint/assets/.gitkeep
Normal file
9
skills/devsecops/container-hadolint/assets/.gitkeep
Normal file
@@ -0,0 +1,9 @@
|
||||
# Assets Directory
|
||||
|
||||
Place files that will be used in the output Claude produces:
|
||||
- Templates
|
||||
- Configuration files
|
||||
- Images/logos
|
||||
- Boilerplate code
|
||||
|
||||
These files are NOT loaded into context but copied/modified in output.
|
||||
@@ -0,0 +1,99 @@
|
||||
# GitHub Actions workflow for Hadolint Dockerfile linting
|
||||
# Place this file at: .github/workflows/hadolint.yml
|
||||
|
||||
name: Hadolint Dockerfile Security Scan
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
paths:
|
||||
- '**/Dockerfile*'
|
||||
- '**/*.dockerfile'
|
||||
- '.github/workflows/hadolint.yml'
|
||||
pull_request:
|
||||
branches: [ main, develop ]
|
||||
paths:
|
||||
- '**/Dockerfile*'
|
||||
- '**/*.dockerfile'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write # For SARIF upload
|
||||
pull-requests: write # For PR comments
|
||||
|
||||
jobs:
|
||||
hadolint:
|
||||
name: Lint Dockerfiles
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run Hadolint
|
||||
uses: hadolint/hadolint-action@v3.1.0
|
||||
with:
|
||||
dockerfile: "Dockerfile" # Change to your Dockerfile path
|
||||
failure-threshold: warning
|
||||
format: sarif
|
||||
output-file: hadolint-results.sarif
|
||||
config: .hadolint.yaml # Optional: use custom config
|
||||
|
||||
- name: Upload SARIF to GitHub Security
|
||||
if: always()
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: hadolint-results.sarif
|
||||
category: hadolint
|
||||
|
||||
- name: Generate readable report
|
||||
if: failure()
|
||||
uses: hadolint/hadolint-action@v3.1.0
|
||||
with:
|
||||
dockerfile: "Dockerfile"
|
||||
format: tty
|
||||
|
||||
hadolint-all:
|
||||
name: Lint All Dockerfiles
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Find all Dockerfiles
|
||||
id: find-dockerfiles
|
||||
run: |
|
||||
# Find all Dockerfile* in repository
|
||||
DOCKERFILES=$(find . -type f \( -name "Dockerfile*" -o -name "*.dockerfile" \) | tr '\n' ' ')
|
||||
echo "dockerfiles=$DOCKERFILES" >> $GITHUB_OUTPUT
|
||||
echo "Found Dockerfiles: $DOCKERFILES"
|
||||
|
||||
- name: Run Hadolint on all Dockerfiles
|
||||
run: |
|
||||
# Install hadolint
|
||||
wget -O /usr/local/bin/hadolint https://github.com/hadolint/hadolint/releases/latest/download/hadolint-Linux-x86_64
|
||||
chmod +x /usr/local/bin/hadolint
|
||||
|
||||
# Scan each Dockerfile
|
||||
FAILED=0
|
||||
for dockerfile in ${{ steps.find-dockerfiles.outputs.dockerfiles }}; do
|
||||
echo "Scanning: $dockerfile"
|
||||
if ! hadolint --failure-threshold warning "$dockerfile"; then
|
||||
FAILED=1
|
||||
fi
|
||||
done
|
||||
|
||||
exit $FAILED
|
||||
|
||||
- name: Comment PR with results
|
||||
if: github.event_name == 'pull_request' && failure()
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: '❌ Hadolint found security issues in Dockerfiles. Please review the workflow logs and fix the issues.'
|
||||
})
|
||||
82
skills/devsecops/container-hadolint/assets/gitlab-ci.yml
Normal file
82
skills/devsecops/container-hadolint/assets/gitlab-ci.yml
Normal file
@@ -0,0 +1,82 @@
|
||||
# GitLab CI configuration for Hadolint Dockerfile linting
|
||||
# Add this to your .gitlab-ci.yml file
|
||||
|
||||
stages:
|
||||
- lint
|
||||
- build
|
||||
|
||||
# Hadolint Dockerfile security scanning
|
||||
hadolint:
|
||||
stage: lint
|
||||
image: hadolint/hadolint:latest-debian
|
||||
script:
|
||||
# Find all Dockerfiles
|
||||
- |
|
||||
DOCKERFILES=$(find . -type f \( -name "Dockerfile*" -o -name "*.dockerfile" \))
|
||||
echo "Found Dockerfiles:"
|
||||
echo "$DOCKERFILES"
|
||||
|
||||
# Scan each Dockerfile and generate reports
|
||||
- |
|
||||
FAILED=0
|
||||
for dockerfile in $DOCKERFILES; do
|
||||
echo "Scanning: $dockerfile"
|
||||
|
||||
# Generate GitLab Code Quality report
|
||||
hadolint -f gitlab_codeclimate "$dockerfile" >> hadolint-report.json || FAILED=1
|
||||
|
||||
# Also print human-readable output
|
||||
hadolint "$dockerfile" || true
|
||||
done
|
||||
|
||||
exit $FAILED
|
||||
|
||||
artifacts:
|
||||
reports:
|
||||
codequality: hadolint-report.json
|
||||
paths:
|
||||
- hadolint-report.json
|
||||
when: always
|
||||
expire_in: 1 week
|
||||
|
||||
# Only run on branches with Dockerfile changes
|
||||
rules:
|
||||
- changes:
|
||||
- "**/Dockerfile*"
|
||||
- "**/*.dockerfile"
|
||||
- ".gitlab-ci.yml"
|
||||
|
||||
# Alternative: Scan specific Dockerfile
|
||||
hadolint-main:
|
||||
stage: lint
|
||||
image: hadolint/hadolint:latest-debian
|
||||
script:
|
||||
- hadolint --failure-threshold warning Dockerfile
|
||||
only:
|
||||
changes:
|
||||
- Dockerfile
|
||||
|
||||
# Advanced: Multiple Dockerfiles with matrix
|
||||
hadolint-matrix:
|
||||
stage: lint
|
||||
image: hadolint/hadolint:latest-debian
|
||||
parallel:
|
||||
matrix:
|
||||
- DOCKERFILE:
|
||||
- "Dockerfile"
|
||||
- "Dockerfile.dev"
|
||||
- "services/api/Dockerfile"
|
||||
- "services/web/Dockerfile"
|
||||
script:
|
||||
- |
|
||||
if [ -f "$DOCKERFILE" ]; then
|
||||
echo "Scanning: $DOCKERFILE"
|
||||
hadolint --failure-threshold warning "$DOCKERFILE"
|
||||
else
|
||||
echo "File not found: $DOCKERFILE"
|
||||
exit 1
|
||||
fi
|
||||
only:
|
||||
changes:
|
||||
- Dockerfile*
|
||||
- services/**/Dockerfile*
|
||||
@@ -0,0 +1,40 @@
|
||||
# Hadolint Balanced Configuration
|
||||
# Recommended for most production use cases
|
||||
# Balances security enforcement with practical development needs
|
||||
|
||||
failure-threshold: warning
|
||||
|
||||
# Allow common development patterns that don't compromise security
|
||||
ignored:
|
||||
- DL3059 # Multiple RUN instructions (improves layer caching in development)
|
||||
|
||||
# Trusted registries - add your organization's registries
|
||||
trustedRegistries:
|
||||
- docker.io/library # Official Docker Hub images
|
||||
- gcr.io/distroless # Google distroless images
|
||||
- cgr.dev/chainguard # Chainguard images
|
||||
# Add your private registries below:
|
||||
# - mycompany.azurecr.io
|
||||
# - gcr.io/my-project
|
||||
|
||||
# Balanced severity levels
|
||||
override:
|
||||
error:
|
||||
- DL3002 # Never switch to root (critical security)
|
||||
- DL3020 # Use COPY instead of ADD (prevent URL injection)
|
||||
warning:
|
||||
- DL3000 # Use absolute WORKDIR
|
||||
- DL3001 # Version pinning for package managers
|
||||
- DL3006 # Always tag images
|
||||
- DL3008 # Version pinning for apt
|
||||
- DL3013 # Version pinning for pip
|
||||
- DL3025 # Use JSON notation for CMD/ENTRYPOINT
|
||||
info:
|
||||
- DL3007 # Use image digests (nice to have)
|
||||
- DL3009 # Delete apt cache (optimization)
|
||||
|
||||
# Recommended OCI labels
|
||||
label-schema:
|
||||
maintainer: text
|
||||
org.opencontainers.image.version: semver
|
||||
org.opencontainers.image.vendor: text
|
||||
@@ -0,0 +1,35 @@
|
||||
# Hadolint Permissive Configuration
|
||||
# For legacy Dockerfiles during migration or development environments
|
||||
# Use temporarily while remediating existing issues
|
||||
|
||||
failure-threshold: error # Only fail on critical security issues
|
||||
|
||||
# Ignore common legacy patterns (review and remove as you fix them)
|
||||
ignored:
|
||||
- DL3006 # Image versioning (fix gradually)
|
||||
- DL3008 # apt-get version pinning (fix gradually)
|
||||
- DL3009 # apt cache cleanup (optimization, not security)
|
||||
- DL3013 # pip version pinning (fix gradually)
|
||||
- DL3015 # apt --no-install-recommends (optimization)
|
||||
- DL3059 # Multiple RUN instructions (caching)
|
||||
|
||||
# Still enforce trusted registries
|
||||
trustedRegistries:
|
||||
- docker.io
|
||||
- gcr.io
|
||||
- ghcr.io
|
||||
# Add your registries
|
||||
|
||||
# Minimal enforcement - only critical security issues
|
||||
override:
|
||||
error:
|
||||
- DL3002 # Never switch to root (always enforce)
|
||||
- DL3020 # Use COPY instead of ADD (security critical)
|
||||
warning:
|
||||
- DL3001 # Package manager version pinning
|
||||
- DL3025 # JSON notation for CMD/ENTRYPOINT
|
||||
info:
|
||||
# Everything else is informational
|
||||
- DL3000
|
||||
- DL3003
|
||||
- DL3007
|
||||
@@ -0,0 +1,48 @@
|
||||
# Hadolint Strict Configuration
|
||||
# Enforces maximum security with minimal exceptions
|
||||
# Use for: Production Dockerfiles, security-critical applications
|
||||
|
||||
failure-threshold: error
|
||||
|
||||
# Minimal ignores - only critical exceptions
|
||||
ignored: []
|
||||
|
||||
# Only trust official and verified registries
|
||||
trustedRegistries:
|
||||
- docker.io/library # Official Docker Hub images
|
||||
- gcr.io/distroless # Google distroless base images
|
||||
- cgr.dev/chainguard # Chainguard minimal images
|
||||
|
||||
# Enforce strict severity levels
|
||||
override:
|
||||
error:
|
||||
- DL3000 # Use absolute WORKDIR
|
||||
- DL3001 # Version pinning for yum
|
||||
- DL3002 # Never switch to root
|
||||
- DL3003 # Use WORKDIR instead of cd
|
||||
- DL3006 # Always tag images
|
||||
- DL3008 # Version pinning for apt
|
||||
- DL3013 # Version pinning for pip
|
||||
- DL3016 # Version pinning for npm
|
||||
- DL3018 # Version pinning for apk
|
||||
- DL3020 # Use COPY instead of ADD
|
||||
- DL3028 # Use build secrets for credentials
|
||||
warning:
|
||||
- DL3007 # Use specific digests (recommended)
|
||||
- DL3009 # Delete apt cache
|
||||
- DL3015 # Avoid additional packages
|
||||
- DL3025 # Use JSON notation
|
||||
|
||||
# Enforce OCI image labels
|
||||
label-schema:
|
||||
maintainer: text
|
||||
org.opencontainers.image.created: rfc3339
|
||||
org.opencontainers.image.authors: text
|
||||
org.opencontainers.image.url: url
|
||||
org.opencontainers.image.documentation: url
|
||||
org.opencontainers.image.source: url
|
||||
org.opencontainers.image.version: semver
|
||||
org.opencontainers.image.revision: text
|
||||
org.opencontainers.image.vendor: text
|
||||
org.opencontainers.image.title: text
|
||||
org.opencontainers.image.description: text
|
||||
40
skills/devsecops/container-hadolint/references/EXAMPLE.md
Normal file
40
skills/devsecops/container-hadolint/references/EXAMPLE.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Reference Document Template
|
||||
|
||||
This file contains detailed reference material that Claude should load only when needed.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Section 1](#section-1)
|
||||
- [Section 2](#section-2)
|
||||
- [Security Standards](#security-standards)
|
||||
|
||||
## Section 1
|
||||
|
||||
Detailed information, schemas, or examples that are too large for SKILL.md.
|
||||
|
||||
## Section 2
|
||||
|
||||
Additional reference material.
|
||||
|
||||
## Security Standards
|
||||
|
||||
### OWASP Top 10
|
||||
|
||||
Reference relevant OWASP categories:
|
||||
- A01: Broken Access Control
|
||||
- A02: Cryptographic Failures
|
||||
- etc.
|
||||
|
||||
### CWE Mappings
|
||||
|
||||
Map to relevant Common Weakness Enumeration categories:
|
||||
- CWE-79: Cross-site Scripting
|
||||
- CWE-89: SQL Injection
|
||||
- etc.
|
||||
|
||||
### MITRE ATT&CK
|
||||
|
||||
Reference relevant tactics and techniques if applicable:
|
||||
- TA0001: Initial Access
|
||||
- T1190: Exploit Public-Facing Application
|
||||
- etc.
|
||||
439
skills/devsecops/container-hadolint/references/security_rules.md
Normal file
439
skills/devsecops/container-hadolint/references/security_rules.md
Normal file
@@ -0,0 +1,439 @@
|
||||
# Hadolint Security Rules Reference
|
||||
|
||||
Complete reference of Hadolint security rules with CIS Docker Benchmark mappings and remediation guidance.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Critical Security Rules](#critical-security-rules)
|
||||
- [CIS Docker Benchmark Mappings](#cis-docker-benchmark-mappings)
|
||||
- [Rule Categories](#rule-categories)
|
||||
|
||||
## Critical Security Rules
|
||||
|
||||
### DL3000: Use absolute WORKDIR
|
||||
|
||||
**Severity**: Error
|
||||
**CIS Mapping**: 4.10 - Ensure secrets are not stored in Dockerfiles
|
||||
|
||||
**Issue**: Relative WORKDIR can lead to path confusion and security vulnerabilities.
|
||||
|
||||
**Bad**:
|
||||
```dockerfile
|
||||
WORKDIR app
|
||||
```
|
||||
|
||||
**Good**:
|
||||
```dockerfile
|
||||
WORKDIR /app
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### DL3001: Version pinning for package managers
|
||||
|
||||
**Severity**: Warning
|
||||
**CIS Mapping**: 4.3 - Do not install unnecessary packages
|
||||
|
||||
**Issue**: Unpinned versions lead to non-reproducible builds and potential security vulnerabilities from package updates.
|
||||
|
||||
**Bad**:
|
||||
```dockerfile
|
||||
RUN yum install httpd
|
||||
```
|
||||
|
||||
**Good**:
|
||||
```dockerfile
|
||||
RUN yum install -y httpd-2.4.51
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### DL3002: Never switch back to root
|
||||
|
||||
**Severity**: Error
|
||||
**CIS Mapping**: 4.1 - Create a user for the container
|
||||
|
||||
**Issue**: Switching back to root defeats container isolation and violates least privilege principle.
|
||||
|
||||
**Bad**:
|
||||
```dockerfile
|
||||
USER node
|
||||
RUN npm install
|
||||
USER root # ❌ Don't switch back to root
|
||||
```
|
||||
|
||||
**Good**:
|
||||
```dockerfile
|
||||
USER node
|
||||
RUN npm install
|
||||
# Stay as non-root user
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### DL3003: Use WORKDIR instead of cd
|
||||
|
||||
**Severity**: Warning
|
||||
**CIS Mapping**: Best practices
|
||||
|
||||
**Issue**: Using `cd` in RUN commands doesn't persist across instructions and can cause confusion.
|
||||
|
||||
**Bad**:
|
||||
```dockerfile
|
||||
RUN cd /app && npm install
|
||||
```
|
||||
|
||||
**Good**:
|
||||
```dockerfile
|
||||
WORKDIR /app
|
||||
RUN npm install
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### DL3006: Always tag image versions
|
||||
|
||||
**Severity**: Warning
|
||||
**CIS Mapping**: 4.3 - Ensure base images are verified
|
||||
|
||||
**Issue**: Using `:latest` or no tag creates non-reproducible builds and security risks.
|
||||
|
||||
**Bad**:
|
||||
```dockerfile
|
||||
FROM node
|
||||
FROM ubuntu:latest
|
||||
```
|
||||
|
||||
**Good**:
|
||||
```dockerfile
|
||||
FROM node:18.19.0-alpine3.19
|
||||
FROM ubuntu:22.04
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### DL3007: Pin Docker image versions to specific digest
|
||||
|
||||
**Severity**: Info
|
||||
**CIS Mapping**: 4.3 - Ensure base images are verified
|
||||
|
||||
**Issue**: Tags can be overwritten; digests are immutable.
|
||||
|
||||
**Good**:
|
||||
```dockerfile
|
||||
FROM node:18.19.0-alpine3.19
|
||||
```
|
||||
|
||||
**Better**:
|
||||
```dockerfile
|
||||
FROM node:18.19.0-alpine3.19@sha256:abc123...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### DL3008: Pin apt-get package versions
|
||||
|
||||
**Severity**: Warning
|
||||
**CIS Mapping**: 4.3 - Do not install unnecessary packages
|
||||
|
||||
**Issue**: Unpinned apt packages lead to non-reproducible builds.
|
||||
|
||||
**Bad**:
|
||||
```dockerfile
|
||||
RUN apt-get update && apt-get install -y curl
|
||||
```
|
||||
|
||||
**Good**:
|
||||
```dockerfile
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
curl=7.68.0-1ubuntu2.14 && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### DL3009: Delete apt cache after installation
|
||||
|
||||
**Severity**: Info
|
||||
**CIS Mapping**: 4.6 - Reduce image size
|
||||
|
||||
**Issue**: Unnecessary cache increases image size and attack surface.
|
||||
|
||||
**Bad**:
|
||||
```dockerfile
|
||||
RUN apt-get update && apt-get install -y curl
|
||||
```
|
||||
|
||||
**Good**:
|
||||
```dockerfile
|
||||
RUN apt-get update && \
|
||||
apt-get install -y curl && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### DL3013: Pin pip package versions
|
||||
|
||||
**Severity**: Warning
|
||||
**CIS Mapping**: 4.3 - Do not install unnecessary packages
|
||||
|
||||
**Issue**: Unpinned pip packages compromise build reproducibility.
|
||||
|
||||
**Bad**:
|
||||
```dockerfile
|
||||
RUN pip install flask
|
||||
```
|
||||
|
||||
**Good**:
|
||||
```dockerfile
|
||||
RUN pip install --no-cache-dir flask==2.3.2
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### DL3020: Use COPY instead of ADD
|
||||
|
||||
**Severity**: Error
|
||||
**CIS Mapping**: 4.9 - Use COPY instead of ADD
|
||||
|
||||
**Issue**: ADD has implicit behavior (auto-extraction, URL support) that can be exploited.
|
||||
|
||||
**Bad**:
|
||||
```dockerfile
|
||||
ADD app.tar.gz /app/
|
||||
ADD https://example.com/file.txt /tmp/
|
||||
```
|
||||
|
||||
**Good**:
|
||||
```dockerfile
|
||||
COPY app.tar.gz /app/
|
||||
# For URLs, use RUN wget/curl instead
|
||||
RUN curl -O https://example.com/file.txt
|
||||
```
|
||||
|
||||
**Exception**: ADD is acceptable only when you explicitly need tar auto-extraction.
|
||||
|
||||
---
|
||||
|
||||
### DL3025: Use JSON notation for CMD and ENTRYPOINT
|
||||
|
||||
**Severity**: Warning
|
||||
**CIS Mapping**: 4.6 - Add HEALTHCHECK instruction
|
||||
|
||||
**Issue**: Shell form enables shell injection attacks and doesn't properly handle signals.
|
||||
|
||||
**Bad**:
|
||||
```dockerfile
|
||||
CMD node server.js
|
||||
ENTRYPOINT /app/start.sh
|
||||
```
|
||||
|
||||
**Good**:
|
||||
```dockerfile
|
||||
CMD ["node", "server.js"]
|
||||
ENTRYPOINT ["/app/start.sh"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### DL3028: Use credentials via build secrets
|
||||
|
||||
**Severity**: Warning
|
||||
**CIS Mapping**: 4.10 - Do not store secrets in Dockerfiles
|
||||
|
||||
**Issue**: Credentials in ENV or ARG end up in image layers.
|
||||
|
||||
**Bad**:
|
||||
```dockerfile
|
||||
ARG API_KEY=secret123
|
||||
RUN curl -H "Authorization: $API_KEY" https://api.example.com
|
||||
```
|
||||
|
||||
**Good** (BuildKit secrets):
|
||||
```dockerfile
|
||||
# syntax=docker/dockerfile:1.4
|
||||
RUN --mount=type=secret,id=api_key \
|
||||
curl -H "Authorization: $(cat /run/secrets/api_key)" https://api.example.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### DL3059: Multiple RUN instructions
|
||||
|
||||
**Severity**: Info
|
||||
**CIS Mapping**: 4.6 - Optimize layers
|
||||
|
||||
**Issue**: Multiple RUN instructions create unnecessary layers, increasing image size.
|
||||
|
||||
**Less Optimal**:
|
||||
```dockerfile
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y curl
|
||||
RUN curl -O https://example.com/file
|
||||
```
|
||||
|
||||
**Better**:
|
||||
```dockerfile
|
||||
RUN apt-get update && \
|
||||
apt-get install -y curl && \
|
||||
curl -O https://example.com/file && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
```
|
||||
|
||||
**Note**: Balance between layer caching and image size. For development, separate RUN instructions may aid caching.
|
||||
|
||||
---
|
||||
|
||||
## CIS Docker Benchmark Mappings
|
||||
|
||||
### CIS 4.1: Create a user for the container
|
||||
|
||||
**Hadolint Rules**: DL3002
|
||||
|
||||
**Requirement**: Don't run containers as root.
|
||||
|
||||
**Implementation**:
|
||||
```dockerfile
|
||||
RUN groupadd -r appuser && useradd -r -g appuser appuser
|
||||
USER appuser
|
||||
# Don't switch back to root
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### CIS 4.3: Do not install unnecessary packages
|
||||
|
||||
**Hadolint Rules**: DL3001, DL3008, DL3013, DL3015
|
||||
|
||||
**Requirement**: Minimize attack surface by installing only required packages with pinned versions.
|
||||
|
||||
**Implementation**:
|
||||
```dockerfile
|
||||
# Use --no-install-recommends
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
package1=version1 \
|
||||
package2=version2 && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### CIS 4.6: Add HEALTHCHECK instruction
|
||||
|
||||
**Hadolint Rules**: DL3025 (related to proper CMD/ENTRYPOINT)
|
||||
|
||||
**Requirement**: Include HEALTHCHECK to enable container health monitoring.
|
||||
|
||||
**Implementation**:
|
||||
```dockerfile
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost:8080/health || exit 1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### CIS 4.7: Do not use update instructions alone
|
||||
|
||||
**Hadolint Rules**: DL3009, DL3014, DL3015
|
||||
|
||||
**Requirement**: Update and install should be in same RUN instruction to prevent cache issues.
|
||||
|
||||
**Implementation**:
|
||||
```dockerfile
|
||||
# Bad
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y package
|
||||
|
||||
# Good
|
||||
RUN apt-get update && \
|
||||
apt-get install -y package && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### CIS 4.9: Use COPY instead of ADD
|
||||
|
||||
**Hadolint Rules**: DL3020
|
||||
|
||||
**Requirement**: Use COPY for file operations; ADD only for tar extraction.
|
||||
|
||||
**Implementation**: See DL3020 above.
|
||||
|
||||
---
|
||||
|
||||
### CIS 4.10: Do not store secrets in Dockerfiles
|
||||
|
||||
**Hadolint Rules**: DL3028, DL3000 (indirectly)
|
||||
|
||||
**Requirement**: Use build secrets or external secret management.
|
||||
|
||||
**Implementation**: See DL3028 above.
|
||||
|
||||
---
|
||||
|
||||
## Rule Categories
|
||||
|
||||
### Base Image Security
|
||||
- DL3006: Always tag image versions
|
||||
- DL3007: Use specific image digests
|
||||
- DL3026: Use trusted registries only
|
||||
|
||||
### Package Management
|
||||
- DL3001: Version pinning (yum/dnf/zypper)
|
||||
- DL3008: Version pinning (apt-get)
|
||||
- DL3013: Version pinning (pip)
|
||||
- DL3016: Version pinning (npm)
|
||||
- DL3018: Version pinning (apk)
|
||||
- DL3028: Use build secrets for credentials
|
||||
|
||||
### Instruction Best Practices
|
||||
- DL3000: Use absolute WORKDIR
|
||||
- DL3003: Use WORKDIR instead of cd
|
||||
- DL3020: Use COPY instead of ADD
|
||||
- DL3025: Use JSON notation for CMD/ENTRYPOINT
|
||||
|
||||
### User and Permissions
|
||||
- DL3002: Never switch back to root
|
||||
- DL4001: Use SHELL to switch shells securely
|
||||
|
||||
### Image Optimization
|
||||
- DL3009: Delete apt cache
|
||||
- DL3014: Use -y for apt-get
|
||||
- DL3015: Avoid additional packages
|
||||
- DL3059: Minimize RUN instructions
|
||||
|
||||
### ShellCheck Integration
|
||||
- DL4000-DL4006: Shell script best practices in RUN
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference Table
|
||||
|
||||
| Rule | Severity | CIS | Description |
|
||||
|------|----------|-----|-------------|
|
||||
| DL3000 | Error | 4.10 | Use absolute WORKDIR |
|
||||
| DL3001 | Warning | 4.3 | Pin yum versions |
|
||||
| DL3002 | Error | 4.1 | Don't switch to root |
|
||||
| DL3003 | Warning | - | Use WORKDIR not cd |
|
||||
| DL3006 | Warning | 4.3 | Tag image versions |
|
||||
| DL3007 | Info | 4.3 | Use image digests |
|
||||
| DL3008 | Warning | 4.3 | Pin apt versions |
|
||||
| DL3009 | Info | 4.7 | Delete apt cache |
|
||||
| DL3013 | Warning | 4.3 | Pin pip versions |
|
||||
| DL3020 | Error | 4.9 | Use COPY not ADD |
|
||||
| DL3025 | Warning | 4.6 | JSON notation CMD |
|
||||
| DL3028 | Warning | 4.10 | Use build secrets |
|
||||
| DL3059 | Info | - | Multiple RUN instructions |
|
||||
|
||||
---
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Hadolint Rules Wiki](https://github.com/hadolint/hadolint/wiki)
|
||||
- [CIS Docker Benchmark v1.6](https://www.cisecurity.org/benchmark/docker)
|
||||
- [Docker Security Best Practices](https://docs.docker.com/develop/security-best-practices/)
|
||||
- [NIST SP 800-190](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-190.pdf)
|
||||
Reference in New Issue
Block a user