Container Guardrails
Enforce container best practices including tag stability, registry allowlists, required labels, and security configurations for Dockerfiles.
container to your lunar-config.yml:uses: github://earthly/lunar-lib/policies/container@v1.0.0
Included Guardrails
This policy includes 6 guardrails that enforce standards for your devex build and ci.
no-latest
Prevents use of the :latest tag (explicit or implicit) in base images. Using :latest creates non-reproducible builds and makes debugging difficult.
stable-tags
Requires base images to use stable tags: digests (sha256:...) or full semver (1.2.3). Partial versions like "node:20" can change unexpectedly and break builds.
allowed-registries
Restricts base images to approved container registries only. Prevents supply chain attacks from untrusted image sources.
required-labels
Ensures Dockerfiles include required OCI labels for traceability. Common labels: org.opencontainers.image.source, version, maintainer.
healthcheck
Requires a HEALTHCHECK instruction in the final stage of multi-stage builds. Enables container orchestrators to detect and restart unhealthy containers.
user
Requires a USER instruction to run the container as a non-root user. Running as root inside containers is a security risk and violates least privilege.
How Guardrails Fit into Lunar
Lunar guardrails define your engineering standards as code. They evaluate data collected by integrations and produce pass/fail checks with actionable feedback.
Policies support gradual enforcement—from silent scoring to blocking PRs or deployments—letting you roll out standards at your own pace without disrupting existing workflows.
Learn How Lunar Works →Required Integrations
This policy evaluates data gathered by one or more of the following integration(s).
Make sure to enable them in your lunar-config.yml.
Configuration
Configure this policy in your lunar-config.yml.
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
allowed_registries
|
Optional |
docker.io
|
Comma-separated list of allowed registries |
required_labels
|
Required | — | Comma-separated list of required labels (empty = no requirement) |
Documentation
View on GitHubContainer Guardrails
Enforces best practices for container definitions including tag stability, registry allowlists, required labels, and security configurations.
Overview
This policy plugin validates container definitions (Dockerfiles, Containerfiles) against common best practices and security requirements. It helps ensure consistent, secure, and reproducible container builds across your organization.
Policies
This plugin provides the following policies (use include to select a subset):
| Policy | Description | Failure Meaning |
|---|---|---|
no-latest |
No :latest tags (explicit or implicit) |
Image uses :latest tag (explicit or implicit) |
stable-tags |
Tags must be digests or full semver (e.g., 1.2.3) |
Image uses unstable tag (partial version, branch name, etc.) |
allowed-registries |
Images must come from allowed registries | Image pulled from registry not in allowlist |
required-labels |
Required labels must be present | Dockerfile missing one or more required labels |
healthcheck |
HEALTHCHECK instruction must be present | Final stage missing HEALTHCHECK instruction |
user |
USER instruction must be present | Final stage missing USER instruction |
Required Data
This policy reads from the following Component JSON paths:
| Path | Type | Provided By |
|---|---|---|
.containers.definitions[] |
array | dockerfile collector |
Installation
Add to your lunar-config.yml:
policies:
- uses: github://earthly/lunar-lib/policies/container@v1.0.0
on: ["domain:your-domain"]
enforcement: report-pr
# include: [no-latest, stable-tags] # Only include specific policies
# with:
# allowed_registries: "docker.io,gcr.io,ghcr.io"
# required_labels: "org.opencontainers.image.source"
Examples
Passing Example
{
"containers": {
"definitions": [
{
"path": "Dockerfile",
"valid": true,
"base_images": [
{ "reference": "golang:1.21.5-alpine", "image": "golang", "tag": "1.21.5-alpine" },
{ "reference": "gcr.io/distroless/static:nonroot", "image": "gcr.io/distroless/static", "tag": "nonroot" }
],
"final_stage": {
"user": "nonroot",
"has_healthcheck": true
},
"labels": {}
}
]
}
}
Failing Examples
Using :latest tag (fails no-latest, stable-tags)
{
"containers": {
"definitions": [
{
"path": "Dockerfile",
"valid": true,
"base_images": [
{ "reference": "node:latest", "image": "node", "tag": "latest" }
]
}
]
}
}
Using unstable tag (fails stable-tags)
{
"containers": {
"definitions": [
{
"path": "Dockerfile",
"valid": true,
"base_images": [
{ "reference": "node:20-alpine", "image": "node", "tag": "20-alpine" }
]
}
]
}
}
Using disallowed registry (fails allowed-registries)
{
"containers": {
"definitions": [
{
"path": "Dockerfile",
"valid": true,
"base_images": [
{ "reference": "my-private-registry.com/app:1.0.0", "image": "my-private-registry.com/app", "tag": "1.0.0" }
]
}
]
}
}
Remediation
no-latest / stable-tags
Replace unstable tags with:
- Digest (most stable):
alpine@sha256:abc123... - Full semver (stable):
alpine:3.18.4
Avoid:
- Implicit latest:
FROM alpine - Explicit latest:
FROM alpine:latest - Partial versions:
FROM node:20orFROM node:20-alpine
allowed-registries
Use images from approved registries only. Update your Dockerfile or request the registry be added to the allowlist.
required-labels
Add the required labels to your Dockerfile:
LABEL org.opencontainers.image.source="https://github.com/org/repo"
LABEL org.opencontainers.image.version="1.0.0"
healthcheck
Add a HEALTHCHECK instruction:
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost/health || exit 1
user
Add a USER instruction to run as non-root:
USER nonroot
# or
USER 1000:1000
Open Source
This policy is open source and available on GitHub. Contribute improvements, report issues, or fork it for your own use.
Common Use Cases
Explore how individual guardrails work with specific integrations.
Ready to Automate Your Standards?
See how Lunar can turn your engineering wiki, compliance docs, or postmortem action items into automated guardrails with our 100+ built-in guardrails.