Policy templates and examples
This page provides complete, working policy examples you can copy and adapt. The examples are organized into two sections: getting started policies for quick adoption, and production templates for comprehensive security.
If you're new to policies, start with the tutorials: Introduction, Image validation, and Git validation. Those pages teach individual techniques. This page shows complete policies combining those techniques.
How to use these examples
- Copy the policy code into a
Dockerfile.regofile next to your Dockerfile - Customize any todo comments with your specific values
- Test by running
docker build .and verifying the policy works as expected - Refine based on your team's needs
Using examples with bake
These policies work with both docker buildx build and docker buildx bake.
For bake, place the policy alongside your Dockerfile and it loads
automatically. To use additional policies:
target "default" {
dockerfile = "Dockerfile"
policy = ["extra.rego"]
}See the Usage guide for complete bake integration details.
Getting started
These policies work immediately with minimal or no customization. Use them to adopt policies quickly and demonstrate value to your team.
Development-friendly baseline
A permissive policy that allows typical development workflows while blocking obvious security issues.
package docker
default allow := false
allow if input.local
allow if input.git
# Allow common public registries
allow if {
input.image.host == "docker.io" # Docker Hub
}
allow if {
input.image.host == "ghcr.io" # GitHub Container Registry
}
allow if {
input.image.host == "dhi.io" # Docker Hardened Images
}
# Require HTTPS for all downloads
allow if {
input.http.schema == "https"
}
decision := {"allow": allow}This policy allows local and Git contexts, images from Docker Hub, GitHub
Container Registry, and
Docker Hardened Images, and ADD downloads
over HTTPS. It blocks HTTP downloads and non-standard registries.
When to use: Starting point for teams new to policies. Provides basic security without disrupting development workflows.
Registry allowlist
Control which registries your builds can pull images from.
package docker
default allow := false
allow if input.local
# TODO: Add your internal registry hostname
allowed_registries := ["docker.io", "ghcr.io", "dhi.io", "registry.company.com"]
allow if {
input.image.host in allowed_registries
}
# Allow mirrored DHI images from Docker Hub (DHI Enterprise users)
# TODO: Replace with your organization namespace
allow if {
input.image.host == "docker.io"
startswith(input.image.repo, "myorg/dhi-")
}
deny_msg contains msg if {
not allow
input.image
msg := sprintf("registry %s is not in the allowlist", [input.image.host])
}
decision := {"allow": allow, "deny_msg": deny_msg}This policy restricts image pulls to approved registries. Customize and add your internal registry to the list. If you have a DHI Enterprise subscription and have mirrored Docker Hardened Images to Docker Hub, add a rule to allow images from your organization's namespace.
When to use: Enforce corporate policies about approved image sources. Prevents developers from using arbitrary public registries.
Pin base images to digests
Require digest references for reproducible builds.
package docker
default allow := false
allow if input.local
# Require digest references for all images
allow if {
input.image.isCanonical
}
deny_msg contains msg if {
not allow
input.image
msg := sprintf("image %s must use digest reference (e.g., @sha256:...)", [input.image.ref])
}
decision := {"allow": allow, "deny_msg": deny_msg}This policy requires images use digest references like
alpine@sha256:abc123... instead of tags like alpine:3.19. Digests are
immutable - the same digest always resolves to the same image content.
When to use: Ensure build reproducibility. Prevents builds from breaking when upstream tags are updated. Required for compliance in some environments.
Control external dependencies
Pin specific versions of dependencies downloaded during builds.
package docker
default allow := false
allow if input.local
# Allow any image (add restrictions as needed)
allow if input.image
# TODO: Add your allowed Git repositories and tags
allowed_repos := {
"https://github.com/moby/buildkit.git": ["v0.26.1", "v0.27.0"],
}
# Only allow Git input from allowed_repos
allow if {
some repo, versions in allowed_repos
input.git.remote == repo
input.git.tagName in versions
}
# TODO: Add your allowed downloads
allow if {
input.http.url == "https://example.com/app-v1.0.tar.gz"
}
decision := {"allow": allow}This policy creates allowlists for external dependencies. Add your Git repositories with approved version tags, and URLs.
When to use: Control which external dependencies can be used in builds. Prevents builds from pulling arbitrary versions or unverified downloads.
Production templates
These templates demonstrate comprehensive security patterns. They require customization but show best practices for production environments.
Image attestation and provenance
Require images have provenance attestations from trusted builders.
package docker
default allow := false
allow if input.local
# TODO: Add your repository names
allowed_repos := ["myorg/backend", "myorg/frontend", "myorg/worker"]
# Production images need full attestations
allow if {
some repo in allowed_repos
input.image.repo == repo
input.image.hasProvenance
some sig in input.image.signatures
trusted_github_builder(sig, repo)
}
# Helper to validate GitHub Actions build from main branch
trusted_github_builder(sig, repo) if {
sig.signer.certificateIssuer == "CN=sigstore-intermediate,O=sigstore.dev"
sig.signer.issuer == "https://token.actions.githubusercontent.com"
startswith(sig.signer.buildSignerURI, sprintf("https://github.com/myorg/%s/.github/workflows/", [repo]))
sig.signer.sourceRepositoryRef == "refs/heads/main"
sig.signer.runnerEnvironment == "github-hosted"
}
# Allow Docker Hardened Images with built-in attestations
allow if {
input.image.host == "dhi.io"
input.image.isCanonical
input.image.hasProvenance
}
# Allow official base images with digests
allow if {
input.image.repo == "alpine"
input.image.host == "docker.io"
input.image.isCanonical
}
decision := {"allow": allow}This template validates that your application images have provenance attestations, and were built by GitHub Actions from your main branch. Docker Hardened Images are allowed when using digests since they include comprehensive attestations by default. Other base images must use digests.
Customize:
- Replace
allowed_reposwith your image names - Update the organization name in
trusted_github_builder() - Add rules for other base images you use
When to use: Enforce supply chain security for production deployments. Ensures images are built by trusted CI/CD pipelines with auditable provenance.
Signed Git releases
Enforce signed tags from trusted maintainers for Git dependencies.
package docker
default allow := false
allow if input.local
allow if input.image
# TODO: Replace with your repository URL
is_buildkit if {
input.git.remote == "https://github.com/moby/buildkit.git"
}
is_version_tag if {
is_buildkit
regex.match(`^v[0-9]+\.[0-9]+\.[0-9]+$`, input.git.tagName)
}
# Version tags must be signed
allow if {
is_version_tag
input.git.tagName != ""
verify_git_signature(input.git.tag, "maintainers.asc")
}
# Allow unsigned refs for development
allow if {
is_buildkit
not is_version_tag
}
decision := {"allow": allow}This template requires production release tags to be signed by trusted maintainers. Development branches and commits can be unsigned.
Setup:
- Export maintainer PGP public keys to
maintainers.asc:$ gpg --export --armor user1@example.com user2@example.com > maintainers.asc - Place
maintainers.ascin the same directory as your policy file
Customize:
- Replace the repository URL in
is_buildkit - Update the maintainers in the PGP keyring file
- Adjust the version tag regex pattern if needed
When to use: Validate that production dependencies come from signed releases. Protects against compromised releases or unauthorized updates.
Multi-registry policy
Apply different validation rules for internal and external registries.
package docker
default allow := false
allow if input.local
# TODO: Replace with your internal registry hostname
internal_registry := "registry.company.com"
# Internal registry: basic validation
allow if {
input.image.host == internal_registry
}
# External registries: strict validation
allow if {
input.image.host != internal_registry
input.image.host != ""
input.image.isCanonical
input.image.hasProvenance
}
# Docker Hub: allowlist specific images
allow if {
input.image.host == "docker.io"
# TODO: Add your approved base images
input.image.repo in ["alpine", "golang", "node"]
input.image.isCanonical
}
# Docker Hardened Images: trusted by default with built-in attestations
allow if {
input.image.host == "dhi.io"
input.image.isCanonical
}
decision := {"allow": allow}This template defines a trust boundary between internal and external image
sources. Internal images require minimal validation, while external images need
digests and provenance. Docker Hardened Images from dhi.io are treated as
trusted since they include comprehensive attestations and security guarantees.
Customize:
- Set your internal registry hostname
- Add your approved Docker Hub base images
- Adjust validation requirements based on your security policies
When to use: Organizations with internal registries that need different rules for internal and external sources. Balances security with practical workflow needs.
Multi-environment policy
Apply different rules based on the build target or stage. For example,
package docker
default allow := false
allow if input.local
# TODO: Define your environment detection logic
is_production if {
input.env.target == "production"
}
is_development if {
input.env.target == "development"
}
# Production: strict rules - only digest images with provenance
allow if {
is_production
input.image.isCanonical
input.image.hasProvenance
}
# Development: permissive rules - any image
allow if {
is_development
input.image
}
# Staging inherits production rules (default target detection)
allow if {
not is_production
not is_development
input.image.isCanonical
}
decision := {"allow": allow}This template uses build targets to apply different validation levels. Production requires attestations and digests, development is permissive, and staging uses moderate rules.
Customize:
- Update environment detection logic (target names, build args, etc.)
- Adjust validation requirements for each environment
- Add more environments as needed
When to use: Teams with separate build configurations for different deployment stages. Allows flexibility in development while enforcing strict rules for production.
Complete dependency pinning
Pin all external dependencies to specific versions across all input types.
package docker
default allow := false
allow if input.local
# TODO: Add your pinned images with exact digests
# Docker Hub images use docker.io as host
allowed_dockerhub := {
"alpine": "sha256:4b7ce07002c69e8f3d704a9c5d6fd3053be500b7f1c69fc0d80990c2ad8dd412",
"golang": "sha256:abc123...",
}
allow if {
input.image.host == "docker.io"
some repo, digest in allowed_dockerhub
input.image.repo == repo
input.image.checksum == digest
}
# TODO: Add your pinned DHI images
allowed_dhi := {
"python": "sha256:def456...",
"node": "sha256:ghi789...",
}
allow if {
input.image.host == "dhi.io"
some repo, digest in allowed_dhi
input.image.repo == repo
input.image.checksum == digest
}
# TODO: Add your pinned Git dependencies
allowed_git := {
"https://github.com/moby/buildkit.git": {
"tag": "v0.26.1",
"commit": "abc123...",
},
}
allow if {
some url, version in allowed_git
input.git.remote == url
input.git.tagName == version.tag
input.git.commitChecksum == version.commit
}
# TODO: Add your pinned HTTP downloads
allowed_downloads := {
"https://releases.example.com/app-v1.0.tar.gz": "sha256:def456...",
}
allow if {
some url, checksum in allowed_downloads
input.http.url == url
input.http.checksum == checksum
}
decision := {"allow": allow}This template pins every external dependency to exact versions with cryptographic verification. Images use digests, Git repos use commit SHAs, and downloads use checksums.
Customize:
- Add all your dependencies with exact versions/checksums
- Maintain this file when updating dependencies
- Consider automating updates through CI/CD
When to use: Maximum reproducibility and security. Ensures builds always use exact versions of all dependencies. Required for high-security or regulated environments.
Manual signature verification
Verify image signatures by inspecting signature metadata fields.
package docker
default allow := false
allow if input.local
# Require valid GitHub Actions signatures
allow if {
input.image
input.image.hasProvenance
some sig in input.image.signatures
valid_github_signature(sig)
}
# Helper function to validate GitHub Actions signature
valid_github_signature(sig) if {
# Sigstore keyless signing
sig.signer.certificateIssuer == "CN=sigstore-intermediate,O=sigstore.dev"
sig.signer.issuer == "https://token.actions.githubusercontent.com"
# TODO: Replace with your organization
startswith(sig.signer.buildSignerURI, "https://github.com/myorg/.github/workflows/")
startswith(sig.signer.sourceRepositoryURI, "https://github.com/myorg/")
# Verify GitHub hosted runner
sig.signer.runnerEnvironment == "github-hosted"
# Require timestamp
count(sig.timestamps) > 0
}
decision := {"allow": allow}This policy validates that images were built by GitHub Actions using Sigstore keyless signing.
Customize:
- Replace
myorgwith your GitHub organization - Adjust workflow path restrictions
- Add additional signature field checks as needed
When to use: Enforce that images are built by CI/CD with verifiable signatures, not manually pushed by developers.
Next steps
- Write unit tests for your policies: Test build policies
- Review Built-in functions for signature verification and attestation checking
- Check the Input reference for all available fields you can validate
- Read the tutorials for detailed explanations: Introduction, Image validation, Git validation