mirror of
https://github.com/docker/docs.git
synced 2026-03-27 14:28:47 +07:00
Merge pull request #23782 from dvdksn/build-input-policy
build: rego source policies
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
(?i)[A-Z]{2,}'?s
|
||||
jq
|
||||
untracked
|
||||
ripgrep
|
||||
exfiltration
|
||||
sandboxing
|
||||
@@ -13,6 +14,7 @@ armhf
|
||||
[Aa]uditability
|
||||
auditable
|
||||
autolock
|
||||
[Aa]llowlist(ing)?
|
||||
Azure
|
||||
Azure AD
|
||||
bootup
|
||||
@@ -172,6 +174,7 @@ Qualcomm
|
||||
Quickview
|
||||
rebalance
|
||||
reimplement
|
||||
Rego
|
||||
Rekor
|
||||
ROCm
|
||||
rollback
|
||||
@@ -183,6 +186,7 @@ scrollable
|
||||
SELinux
|
||||
Slack
|
||||
snapshotters?
|
||||
Sigstore
|
||||
Snyk
|
||||
Solr
|
||||
SonarQube
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
---
|
||||
title: Checking your build configuration
|
||||
linkTitle: Build checks
|
||||
params:
|
||||
sidebar:
|
||||
badge:
|
||||
color: green
|
||||
text: New
|
||||
weight: 30
|
||||
weight: 20
|
||||
description: Learn how to use build checks to validate your build configuration.
|
||||
keywords: build, buildx, buildkit, checks, validate, configuration, lint
|
||||
---
|
||||
|
||||
167
content/manuals/build/policies/_index.md
Normal file
167
content/manuals/build/policies/_index.md
Normal file
@@ -0,0 +1,167 @@
|
||||
---
|
||||
title: Validating build inputs with policies
|
||||
linkTitle: Validating builds
|
||||
description: Secure your Docker builds by validating images, Git repositories, and dependencies with build policies
|
||||
keywords: build policies, opa, rego, docker security, supply chain, attestations
|
||||
weight: 70
|
||||
params:
|
||||
sidebar:
|
||||
badge:
|
||||
color: blue
|
||||
text: Experimental
|
||||
---
|
||||
|
||||
Building with Docker often involves downloading remote resources. These
|
||||
external dependencies, such as Docker images, Git repositories, remote files,
|
||||
and other artifacts, are called build inputs.
|
||||
|
||||
For example:
|
||||
|
||||
- Pulling images from a registry
|
||||
- Cloning a source code repository
|
||||
- Fetching files from a server over HTTPS
|
||||
|
||||
When consuming build inputs, it's a good idea to verify the contents are what
|
||||
you expect them to be. One way to do this is to use the `--checksum` option for
|
||||
the `ADD` Dockerfile instruction. This lets you verify the SHA256 checksum of a
|
||||
remote resource when pulling it into a build:
|
||||
|
||||
```dockerfile
|
||||
ADD --checksum=sha256:c0ff3312345… https://example.com/archive.tar.gz /
|
||||
```
|
||||
|
||||
If the remote `archive.tar.gz` file does not match the checksum that the
|
||||
Dockerfile expects, the build fails.
|
||||
|
||||
Checksums verify that content matches what you expect, but only for the `ADD`
|
||||
instruction. They don't tell you anything about where the content came from or
|
||||
how it was produced. You can't use checksums to enforce constraints like
|
||||
"images must be signed" or "dependencies must come from approved sources."
|
||||
|
||||
Build policies solve this problem. They let you define rules that validate all
|
||||
your build inputs, enforcing requirements like provenance attestations,
|
||||
approved registries, and signed Git tags across your entire build process.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Build policies is currently an experimental feature. To try it out, you'll
|
||||
need:
|
||||
|
||||
- Buildx 0.31.0 or later - Check your version: `docker buildx version`
|
||||
- BuildKit 0.27.0 or later - Verify with: `docker buildx inspect --bootstrap`
|
||||
|
||||
If you're using Docker Desktop, ensure you're on a version that includes these
|
||||
updates.
|
||||
|
||||
## Build policies
|
||||
|
||||
Buildx version 0.31.0 added support for build policies. Build policies are
|
||||
rules for securing your Docker build supply chain, and help protect against
|
||||
upstream compromises, malicious dependencies, and unauthorized modifications to
|
||||
your build inputs.
|
||||
|
||||
Build policies let you enforce extended verifications on inputs used to build
|
||||
your projects, such as:
|
||||
|
||||
- Docker images must use digest references (not tags alone)
|
||||
- Images must have provenance attestations and cosign signatures
|
||||
- Git tags are signed by maintainers with a PGP public key
|
||||
- All remote artifacts must use HTTPS and include a checksum for verification
|
||||
|
||||
Build policies are defined in a declarative policy language, called Rego,
|
||||
created for the [Open Policy Agent (OPA)](https://www.openpolicyagent.org/).
|
||||
The following example shows a minimal build policy in Rego.
|
||||
|
||||
```rego {title="Dockerfile.rego"}
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
# Allow any local inputs for this build
|
||||
# For example: a local build context, or a local Dockerfile
|
||||
allow if input.local
|
||||
|
||||
# Allow images, but only if they have provenance attestations
|
||||
allow if {
|
||||
input.image.hasProvenance
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
If the Dockerfile associated with this policy references an image with no
|
||||
provenance attestation in a `FROM` instruction, the policy would be violated
|
||||
and the build would fail.
|
||||
|
||||
## How policies work
|
||||
|
||||
When you run `docker buildx build`, Buildx:
|
||||
|
||||
1. Resolves all build inputs (images, Git repos, HTTP downloads)
|
||||
2. Looks for a policy file matching your Dockerfile name (e.g.,
|
||||
`Dockerfile.rego`)
|
||||
3. Evaluates each input against the policy before the build starts
|
||||
4. Allows the build to proceed only if all inputs pass the policy
|
||||
|
||||
Policies are written in Rego (Open Policy Agent's policy language). You don't
|
||||
need to be a Rego expert - the [Introduction](./intro.md) tutorial teaches you
|
||||
everything needed.
|
||||
|
||||
Policy files live alongside your Dockerfile:
|
||||
|
||||
```text
|
||||
project/
|
||||
├── Dockerfile
|
||||
├── Dockerfile.rego
|
||||
└── src/
|
||||
```
|
||||
|
||||
No additional configuration is needed - Buildx automatically finds and loads
|
||||
the policy when you build.
|
||||
|
||||
## Use cases
|
||||
|
||||
Build policies help you enforce security and compliance requirements on your
|
||||
Docker builds. Common scenarios where policies provide value:
|
||||
|
||||
### Enforce base image standards
|
||||
|
||||
Require all production Dockerfiles to use specific, approved base images with
|
||||
digest references. Prevent developers from using arbitrary images that haven't
|
||||
been vetted by your security team.
|
||||
|
||||
### Validate third-party dependencies
|
||||
|
||||
When your build downloads files, libraries, or tools from the internet, verify
|
||||
they come from trusted sources and match expected checksums or signatures. This
|
||||
protects against supply chain attacks where an upstream dependency is
|
||||
compromised.
|
||||
|
||||
### Ensure signed releases
|
||||
|
||||
Require that all dependencies have valid signatures from trusted parties.
|
||||
|
||||
- Check GPG signatures for Git repositories you clone in your builds
|
||||
- Verify provenance attestation signatures with Sigstore
|
||||
|
||||
### Meet compliance requirements
|
||||
|
||||
Some regulatory frameworks require evidence that you validate your build
|
||||
inputs. Build policies give you an auditable, declarative way to demonstrate
|
||||
you're checking dependencies against security standards.
|
||||
|
||||
### Separate development and production rules
|
||||
|
||||
Apply stricter validation for production builds while allowing more flexibility
|
||||
during development. The same policy file can contain conditional rules based on
|
||||
build context or target.
|
||||
|
||||
## Get started
|
||||
|
||||
Ready to start writing policies? The [Introduction](./intro.md) tutorial walks
|
||||
you through creating your first policy and teaches the Rego basics you need.
|
||||
|
||||
For practical usage guidance, see [Using build policies](./usage.md).
|
||||
|
||||
For practical examples you can copy and adapt, see the [Example
|
||||
policies](./examples.md) library.
|
||||
205
content/manuals/build/policies/built-ins.md
Normal file
205
content/manuals/build/policies/built-ins.md
Normal file
@@ -0,0 +1,205 @@
|
||||
---
|
||||
title: Built-in functions
|
||||
linkTitle: Built-in functions
|
||||
description: Buildx includes built-in helper functions to make writing policies easier
|
||||
keywords: build policies, built-in functions, rego functions, signature verification, policy helpers
|
||||
weight: 90
|
||||
---
|
||||
|
||||
Buildx provides built-in functions, in addition to the [Rego
|
||||
built-ins](#rego-built-in-functions), to extend Rego policies with
|
||||
Docker-specific operations like loading local files, verifying Git signatures,
|
||||
and pinning image digests.
|
||||
|
||||
## Rego built-in functions
|
||||
|
||||
The functions [documented on this page](#buildx-built-in-functions) are
|
||||
Buildx-specific functions, distinct from [Rego's standard built-in
|
||||
functions](https://www.openpolicyagent.org/docs/policy-language#built-in-functions)
|
||||
|
||||
Buildx also supports standard Rego built-in functions, but only a subset. To
|
||||
see the exact list of supported functions, refer to the Buildx [source
|
||||
code](https://github.com/docker/buildx/blob/master/policy/builtins.go).
|
||||
|
||||
## Buildx built-in functions
|
||||
|
||||
Buildx provides the following custom built-in functions for policy development:
|
||||
|
||||
- [`print`](#print)
|
||||
- [`load_json`](#load_json)
|
||||
- [`verify_git_signature`](#verify_git_signature)
|
||||
- [`pin_image`](#pin_image)
|
||||
|
||||
### `print`
|
||||
|
||||
Outputs debug information during policy evaluation.
|
||||
|
||||
Parameters:
|
||||
|
||||
- Any number of values to print
|
||||
|
||||
Returns: The values (pass-through)
|
||||
|
||||
Example:
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.image.repo == "alpine"
|
||||
print("Allowing alpine image:", input.image.tag)
|
||||
}
|
||||
```
|
||||
|
||||
Debug output appears when building with `--progress=plain`.
|
||||
|
||||
### `load_json`
|
||||
|
||||
Loads and parses JSON data from local files in the build context.
|
||||
|
||||
Parameters:
|
||||
|
||||
- `filename` (string) - Path to JSON file relative to policy directory
|
||||
|
||||
Returns: Parsed JSON data as Rego value
|
||||
|
||||
Example:
|
||||
|
||||
```rego
|
||||
# Load approved versions from external file
|
||||
approved_versions = load_json("versions.json")
|
||||
|
||||
allow if {
|
||||
input.image.repo == "alpine"
|
||||
some version in approved_versions.alpine
|
||||
input.image.tag == version
|
||||
}
|
||||
```
|
||||
|
||||
File structure:
|
||||
|
||||
```text
|
||||
project/
|
||||
├── Dockerfile
|
||||
├── Dockerfile.rego
|
||||
└── versions.json
|
||||
```
|
||||
|
||||
versions.json:
|
||||
|
||||
```json
|
||||
{
|
||||
"alpine": ["3.19", "3.20"],
|
||||
"golang": ["1.21", "1.22"]
|
||||
}
|
||||
```
|
||||
|
||||
The JSON file must be in the same directory as the policy or in a
|
||||
subdirectory accessible from the policy location.
|
||||
|
||||
### `verify_git_signature`
|
||||
|
||||
Verifies PGP signatures on Git commits or tags.
|
||||
|
||||
Parameters:
|
||||
|
||||
- `git_object` (object) - Either `input.git.commit` or `input.git.tag`
|
||||
- `keyfile` (string) - Path to PGP public key file (relative to policy
|
||||
directory)
|
||||
|
||||
Returns: Boolean - `true` if signature is valid, `false` otherwise
|
||||
|
||||
Example:
|
||||
|
||||
```rego
|
||||
# Require signed Git tags
|
||||
allow if {
|
||||
input.git.tagName != ""
|
||||
verify_git_signature(input.git.tag, "maintainer.asc")
|
||||
}
|
||||
|
||||
# Require signed commits
|
||||
allow if {
|
||||
input.git.commit
|
||||
verify_git_signature(input.git.commit, "keys/team.asc")
|
||||
}
|
||||
```
|
||||
|
||||
Directory structure:
|
||||
|
||||
```text
|
||||
project/
|
||||
├── Dockerfile.rego
|
||||
└── maintainer.asc # PGP public key
|
||||
```
|
||||
|
||||
Or with subdirectory:
|
||||
|
||||
```text
|
||||
project/
|
||||
├── Dockerfile.rego
|
||||
└── keys/
|
||||
├── maintainer.asc
|
||||
└── team.asc
|
||||
```
|
||||
|
||||
Obtaining public keys:
|
||||
|
||||
```console
|
||||
$ gpg --export --armor user@example.com > maintainer.asc
|
||||
```
|
||||
|
||||
### `pin_image`
|
||||
|
||||
Pins an image to a specific digest, overriding the tag-based reference. Use
|
||||
this to force builds to use specific image versions.
|
||||
|
||||
Parameters:
|
||||
|
||||
- `image_object` (object) - Must be `input.image` (the current image being
|
||||
evaluated)
|
||||
- `digest` (string) - Target digest in format `sha256:...`
|
||||
|
||||
Returns: Boolean - `true` if pinning succeeds
|
||||
|
||||
Example:
|
||||
|
||||
```rego
|
||||
# Pin alpine 3.19 to specific digest
|
||||
alpine_3_19_digest = "sha256:4b7ce07002c69e8f3d704a9c5d6fd3053be500b7f1c69fc0d80990c2ad8dd412"
|
||||
|
||||
allow if {
|
||||
input.image.repo == "alpine"
|
||||
input.image.tag == "3.19"
|
||||
pin_image(input.image, alpine_3_19_digest)
|
||||
}
|
||||
```
|
||||
|
||||
Automatic digest replacement:
|
||||
|
||||
```rego
|
||||
# Replace old digests with patched versions
|
||||
replace_map = {
|
||||
"3.22.0": "3.22.2",
|
||||
"3.22.1": "3.22.2",
|
||||
}
|
||||
|
||||
alpine_digests = {
|
||||
"3.22.0": "sha256:8a1f59ffb675680d47db6337b49d22281a139e9d709335b492be023728e11715",
|
||||
"3.22.2": "sha256:4b7ce07002c69e8f3d704a9c5d6fd3053be500b7f1c69fc0d80990c2ad8dd412",
|
||||
}
|
||||
|
||||
allow if {
|
||||
input.image.repo == "alpine"
|
||||
some old_version, new_version in replace_map
|
||||
input.image.checksum == alpine_digests[old_version]
|
||||
print("Replacing", old_version, "with", new_version)
|
||||
pin_image(input.image, alpine_digests[new_version])
|
||||
}
|
||||
```
|
||||
|
||||
This pattern automatically upgrades old image versions to patched releases.
|
||||
|
||||
## Next steps
|
||||
|
||||
- Browse complete examples: [Example policies](./examples.md)
|
||||
- Learn policy development workflow: [Using build policies](./usage.md)
|
||||
- Reference input fields: [Input reference](./inputs.md)
|
||||
188
content/manuals/build/policies/debugging.md
Normal file
188
content/manuals/build/policies/debugging.md
Normal file
@@ -0,0 +1,188 @@
|
||||
---
|
||||
title: Debugging build policies
|
||||
linkTitle: Debugging
|
||||
description: Debug policies during development with inspection and testing tools
|
||||
keywords: build policies, debugging, policy troubleshooting, log-level, policy eval, rego debugging
|
||||
weight: 70
|
||||
---
|
||||
|
||||
When policies don't work as expected, use the tools available to inspect policy
|
||||
evaluation and understand what's happening. This guide covers the debugging
|
||||
techniques and common gotchas.
|
||||
|
||||
## Quick reference
|
||||
|
||||
Essential debugging commands:
|
||||
|
||||
```console
|
||||
# See complete input data during builds (recommended)
|
||||
$ docker buildx build --progress=plain --policy log-level=debug .
|
||||
|
||||
# See policy checks and decisions
|
||||
$ docker buildx build --progress=plain .
|
||||
|
||||
# Explore input structure for different sources
|
||||
$ docker buildx policy eval --print .
|
||||
$ docker buildx policy eval --print https://github.com/org/repo.git
|
||||
$ docker buildx policy eval --print docker-image://alpine:3.19
|
||||
|
||||
# Test if policy allows a source
|
||||
$ docker buildx policy eval .
|
||||
```
|
||||
|
||||
## Policy output with `--progress=plain`
|
||||
|
||||
To see policy evaluation during builds, use `--progress=plain`:
|
||||
|
||||
```console
|
||||
$ docker buildx build --progress=plain .
|
||||
```
|
||||
|
||||
This shows all policy checks, decisions, and `print()` output. Without
|
||||
`--progress=plain`, policy evaluation is silent unless there's an error.
|
||||
|
||||
```plaintext
|
||||
#1 loading policies Dockerfile.rego
|
||||
#1 0.010 checking policy for source docker-image://alpine:3.19 (linux/arm64)
|
||||
#1 0.011 Dockerfile.rego:8: image: {"ref":"alpine:3.19","repo":"alpine","tag":"3.19"}
|
||||
#1 0.012 policy decision for source docker-image://alpine:3.19: ALLOW
|
||||
```
|
||||
|
||||
If a policy denies a source, you'll see:
|
||||
|
||||
```text
|
||||
#1 0.012 policy decision for source docker-image://nginx:latest: DENY
|
||||
ERROR: source "docker-image://nginx:latest" not allowed by policy
|
||||
```
|
||||
|
||||
## Debug logging
|
||||
|
||||
For detailed debugging, add `--policy log-level=debug` to see the full input
|
||||
JSON, unresolved fields, and policy responses:
|
||||
|
||||
```console
|
||||
$ docker buildx build --progress=plain --policy log-level=debug .
|
||||
```
|
||||
|
||||
This shows significantly more information than the default level, including the
|
||||
complete input structure for each source without needing `print()` statements
|
||||
in your policy.
|
||||
|
||||
Complete input JSON:
|
||||
|
||||
```text
|
||||
#1 0.007 policy input: {
|
||||
#1 0.007 "env": {
|
||||
#1 0.007 "filename": "."
|
||||
#1 0.007 },
|
||||
#1 0.007 "image": {
|
||||
#1 0.007 "ref": "docker.io/library/alpine:3.19",
|
||||
#1 0.007 "host": "docker.io",
|
||||
#1 0.007 "repo": "alpine",
|
||||
#1 0.007 "fullRepo": "docker.io/library/alpine",
|
||||
#1 0.007 "tag": "3.19",
|
||||
#1 0.007 "platform": "linux/arm64",
|
||||
#1 0.007 "os": "linux",
|
||||
#1 0.007 "arch": "arm64"
|
||||
#1 0.007 }
|
||||
#1 0.007 }
|
||||
```
|
||||
|
||||
Unresolved fields:
|
||||
|
||||
```text
|
||||
#1 0.007 unknowns for policy evaluation: [input.image.checksum input.image.labels input.image.user input.image.volumes input.image.workingDir input.image.env input.image.hasProvenance input.image.signatures]
|
||||
```
|
||||
|
||||
Policy response:
|
||||
|
||||
```text
|
||||
#1 0.008 policy response: map[allow:true]
|
||||
```
|
||||
|
||||
This detailed output is invaluable for understanding exactly what data your
|
||||
policy receives and which fields are not yet resolved. Use debug logging when
|
||||
developing policies to avoid needing extensive `print()` statements.
|
||||
|
||||
## Conditional debugging with print()
|
||||
|
||||
While `--policy log-level=debug` shows all input data automatically, the
|
||||
`print()` function is useful for debugging specific rule logic and conditional
|
||||
flows:
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.image
|
||||
print("Checking image:", input.image.repo, "isCanonical:", input.image.isCanonical)
|
||||
input.image.repo == "alpine"
|
||||
input.image.isCanonical
|
||||
}
|
||||
```
|
||||
|
||||
Use `print()` to debug conditional logic within rules or track which rules are
|
||||
evaluating. For general input inspection during development, use `--policy
|
||||
log-level=debug` instead - it requires no policy modifications.
|
||||
|
||||
> [!NOTE]
|
||||
> Print statements only execute when their containing rule evaluates. A rule
|
||||
> like `allow if { input.image; print(...) }` only prints for image inputs,
|
||||
> not for Git repos, HTTP downloads, or local files.
|
||||
|
||||
## Common issues
|
||||
|
||||
### Full repository path or repository name
|
||||
|
||||
Symptom: Policy checking repository names doesn't match as expected.
|
||||
|
||||
Cause: Docker Hub images use `input.image.repo` for the short name
|
||||
(`"alpine"`) but `input.image.fullRepo` includes the full path
|
||||
(`"docker.io/library/alpine"`).
|
||||
|
||||
Solution:
|
||||
|
||||
```rego
|
||||
# Match just the repo name (works for Docker Hub and other registries)
|
||||
allow if {
|
||||
input.image
|
||||
input.image.repo == "alpine"
|
||||
}
|
||||
|
||||
# Or match the full repository path
|
||||
allow if {
|
||||
input.image
|
||||
input.image.fullRepo == "docker.io/library/alpine"
|
||||
}
|
||||
```
|
||||
|
||||
### Policy evaluation happens multiple times
|
||||
|
||||
Symptom: Build output shows the same source evaluated multiple times.
|
||||
|
||||
Cause: BuildKit may evaluate policies at different stages (reference
|
||||
resolution, actual pull) or for different platforms.
|
||||
|
||||
This is normal behavior. Policies should be idempotent (produce same result
|
||||
each time for the same input).
|
||||
|
||||
### Fields missing with `policy eval --print`
|
||||
|
||||
Symptom: `docker buildx policy eval --print` doesn't show expected fields
|
||||
like `hasProvenance`, `labels`, or `checksum`.
|
||||
|
||||
Cause: `--print` shows only reference information by default, without
|
||||
fetching from registries.
|
||||
|
||||
Solution: Use `--fields` to fetch specific metadata fields:
|
||||
|
||||
```console
|
||||
$ docker buildx policy eval --print --fields image.labels docker-image://alpine:3.19
|
||||
```
|
||||
|
||||
See [Using build policies](./usage.md#testing-policies-with-policy-eval) for
|
||||
details.
|
||||
|
||||
## Next steps
|
||||
|
||||
- See complete field reference: [Input reference](./inputs.md)
|
||||
- Review example policies: [Examples](./examples.md)
|
||||
- Learn policy usage patterns: [Using build policies](./usage.md)
|
||||
585
content/manuals/build/policies/examples.md
Normal file
585
content/manuals/build/policies/examples.md
Normal file
@@ -0,0 +1,585 @@
|
||||
---
|
||||
title: Policy templates and examples
|
||||
linkTitle: Templates & examples
|
||||
description: Browse policy examples from quick-start configs to production-grade security templates
|
||||
keywords: build policies, policy examples, rego examples, docker security, registry allowlist, policy templates
|
||||
weight: 50
|
||||
---
|
||||
|
||||
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](./intro.md), [Image validation](./validate-images.md), and [Git
|
||||
validation](./validate-git.md). Those pages teach individual techniques. This
|
||||
page shows complete policies combining those techniques.
|
||||
|
||||
## How to use these examples
|
||||
|
||||
1. Copy the policy code into a `Dockerfile.rego` file next to your
|
||||
Dockerfile
|
||||
2. Customize any todo comments with your specific values
|
||||
3. Test by running `docker build .` and verifying the policy works as
|
||||
expected
|
||||
4. 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:
|
||||
|
||||
```hcl
|
||||
target "default" {
|
||||
dockerfile = "Dockerfile"
|
||||
policy = ["extra.rego"]
|
||||
}
|
||||
```
|
||||
|
||||
See the [Usage guide](./usage.md) 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.
|
||||
|
||||
```rego
|
||||
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](/dhi/), 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.
|
||||
|
||||
```rego
|
||||
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.
|
||||
|
||||
```rego
|
||||
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.
|
||||
|
||||
```rego
|
||||
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.
|
||||
|
||||
```rego
|
||||
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_repos` with 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.
|
||||
|
||||
```rego
|
||||
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:
|
||||
|
||||
1. Export maintainer PGP public keys to `maintainers.asc`:
|
||||
```console
|
||||
$ gpg --export --armor user1@example.com user2@example.com > maintainers.asc
|
||||
```
|
||||
2. Place `maintainers.asc` in 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.
|
||||
|
||||
```rego
|
||||
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,
|
||||
|
||||
```rego
|
||||
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.
|
||||
|
||||
```rego
|
||||
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.
|
||||
|
||||
```rego
|
||||
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 `myorg` with 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](./testing.md)
|
||||
- Review [Built-in functions](./built-ins.md) for signature verification and
|
||||
attestation checking
|
||||
- Check the [Input reference](./inputs.md) for all available fields you can
|
||||
validate
|
||||
- Read the tutorials for detailed explanations:
|
||||
[Introduction](./intro.md), [Image validation](./validate-images.md), [Git
|
||||
validation](./validate-git.md)
|
||||
539
content/manuals/build/policies/inputs.md
Normal file
539
content/manuals/build/policies/inputs.md
Normal file
@@ -0,0 +1,539 @@
|
||||
---
|
||||
title: Input reference
|
||||
linkTitle: Input reference
|
||||
description: Reference documentation for policy input fields
|
||||
keywords: build policies, input reference, policy fields, image metadata, git metadata
|
||||
weight: 80
|
||||
---
|
||||
|
||||
When Buildx evaluates policies, it provides information about build inputs
|
||||
through the `input` object. The structure of `input` depends on the type of
|
||||
resource your Dockerfile references.
|
||||
|
||||
## Input types
|
||||
|
||||
Build inputs correspond to Dockerfile instructions:
|
||||
|
||||
| Dockerfile instruction | Input type | Access pattern |
|
||||
| --------------------------------------- | ---------- | -------------- |
|
||||
| `FROM alpine:latest` | Image | `input.image` |
|
||||
| `COPY --from=builder /app /app` | Image | `input.image` |
|
||||
| `ADD https://example.com/file.tar.gz /` | HTTP | `input.http` |
|
||||
| `ADD git@github.com:user/repo.git /src` | Git | `input.git` |
|
||||
| Build context (`.`) | Local | `input.local` |
|
||||
|
||||
Each input type has specific fields available for policy evaluation.
|
||||
|
||||
## HTTP inputs
|
||||
|
||||
HTTP inputs represent files downloaded over HTTP or HTTPS using the `ADD`
|
||||
instruction.
|
||||
|
||||
### Example Dockerfile
|
||||
|
||||
```dockerfile
|
||||
FROM alpine
|
||||
ADD --checksum=sha256:abc123... https://example.com/app.tar.gz /app.tar.gz
|
||||
```
|
||||
|
||||
### Available fields
|
||||
|
||||
#### `input.http.url`
|
||||
|
||||
The complete URL of the resource.
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.http.url == "https://example.com/app.tar.gz"
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.http.schema`
|
||||
|
||||
The URL scheme (`http` or `https`).
|
||||
|
||||
```rego
|
||||
# Require HTTPS for all downloads
|
||||
allow if {
|
||||
input.http.schema == "https"
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.http.host`
|
||||
|
||||
The hostname from the URL.
|
||||
|
||||
```rego
|
||||
# Allow downloads from approved domains
|
||||
allow if {
|
||||
input.http.host == "cdn.example.com"
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.http.path`
|
||||
|
||||
The path component of the URL.
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
startswith(input.http.path, "/releases/")
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.http.checksum`
|
||||
|
||||
The checksum specified with `ADD --checksum=...`, if present. Empty string if
|
||||
no checksum was provided.
|
||||
|
||||
```rego
|
||||
# Require checksums for all downloads
|
||||
allow if {
|
||||
input.http.checksum != ""
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.http.hasAuth`
|
||||
|
||||
Boolean indicating if the request includes authentication (HTTP basic auth or
|
||||
bearer token).
|
||||
|
||||
```rego
|
||||
# Require authentication for internal servers
|
||||
allow if {
|
||||
input.http.host == "internal.company.com"
|
||||
input.http.hasAuth
|
||||
}
|
||||
```
|
||||
|
||||
## Image inputs
|
||||
|
||||
Image inputs represent container images from `FROM` instructions or
|
||||
`COPY --from` references.
|
||||
|
||||
### Example Dockerfile
|
||||
|
||||
```dockerfile
|
||||
FROM alpine:3.19@sha256:abc123...
|
||||
COPY --from=builder:latest /app /app
|
||||
```
|
||||
|
||||
### Available fields
|
||||
|
||||
#### `input.image.ref`
|
||||
|
||||
The complete image reference as written in the Dockerfile.
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.image.ref == "alpine:3.19@sha256:abc123..."
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.image.host`
|
||||
|
||||
The registry hostname. Docker Hub images use `"docker.io"`.
|
||||
|
||||
```rego
|
||||
# Only allow Docker Hub images
|
||||
allow if {
|
||||
input.image.host == "docker.io"
|
||||
}
|
||||
|
||||
# Only allow images from GitHub Container Registry
|
||||
allow if {
|
||||
input.image.host == "ghcr.io"
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.image.repo`
|
||||
|
||||
The repository name without the registry host.
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.image.repo == "library/alpine"
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.image.fullRepo`
|
||||
|
||||
The full repository path including registry host.
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.image.fullRepo == "docker.io/library/alpine"
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.image.tag`
|
||||
|
||||
The tag portion of the reference. Empty if using a digest reference.
|
||||
|
||||
```rego
|
||||
# Allow only specific tags
|
||||
allow if {
|
||||
input.image.tag == "3.19"
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.image.isCanonical`
|
||||
|
||||
Boolean indicating if the reference uses a digest (`@sha256:...`).
|
||||
|
||||
```rego
|
||||
# Require digest references
|
||||
allow if {
|
||||
input.image.isCanonical
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.image.checksum`
|
||||
|
||||
The SHA256 digest of the image manifest.
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.image.checksum == "sha256:abc123..."
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.image.platform`
|
||||
|
||||
The target platform for multi-platform images.
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.image.platform == "linux/amd64"
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.image.os`
|
||||
|
||||
The operating system from the image configuration.
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.image.os == "linux"
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.image.arch`
|
||||
|
||||
The CPU architecture from the image configuration.
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.image.arch == "amd64"
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.image.hasProvenance`
|
||||
|
||||
Boolean indicating if the image has provenance attestations.
|
||||
|
||||
```rego
|
||||
# Require provenance for production images
|
||||
allow if {
|
||||
input.image.hasProvenance
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.image.labels`
|
||||
|
||||
A map of image labels from the image configuration.
|
||||
|
||||
```rego
|
||||
# Check for specific labels
|
||||
allow if {
|
||||
input.image.labels["org.opencontainers.image.vendor"] == "Example Corp"
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.image.signatures`
|
||||
|
||||
Array of attestation signatures. Each signature in the array has the following
|
||||
fields:
|
||||
|
||||
- `kind`: Signature kind (e.g., `"docker-github-builder"`, `"self-signed"`)
|
||||
- `type`: Signature type (e.g., `"bundle-v0.3"`, `"simplesigning-v1"`)
|
||||
- `timestamps`: Trusted timestamps from transparency logs
|
||||
- `dockerReference`: Docker image reference
|
||||
- `isDHI`: Boolean indicating if this is a Docker Hardened Image
|
||||
- `signer`: Sigstore certificate details
|
||||
|
||||
```rego
|
||||
# Require at least one signature
|
||||
allow if {
|
||||
count(input.image.signatures) > 0
|
||||
}
|
||||
```
|
||||
|
||||
For Sigstore signatures, the `signer` object provides detailed certificate
|
||||
information from the signing workflow:
|
||||
|
||||
- `certificateIssuer`: Certificate issuer
|
||||
- `subjectAlternativeName`: Subject alternative name from certificate
|
||||
- `buildSignerURI`: URI of the build signer
|
||||
- `buildSignerDigest`: Digest of the build signer
|
||||
- `runnerEnvironment`: CI/CD runner environment
|
||||
- `sourceRepositoryURI`: Source repository URL
|
||||
- `sourceRepositoryDigest`: Source repository digest
|
||||
- `sourceRepositoryRef`: Source repository ref (branch/tag)
|
||||
- `sourceRepositoryIdentifier`: Source repository identifier
|
||||
- `sourceRepositoryOwnerURI`: Repository owner URI
|
||||
- `buildConfigURI`: Build configuration URI
|
||||
- `buildTrigger`: What triggered the build
|
||||
- `runInvocationURI`: CI/CD run invocation URI
|
||||
|
||||
```rego
|
||||
# Require signatures from GitHub Actions
|
||||
allow if {
|
||||
some sig in input.image.signatures
|
||||
sig.signer.runnerEnvironment == "github-hosted"
|
||||
startswith(sig.signer.sourceRepositoryURI, "https://github.com/myorg/")
|
||||
}
|
||||
```
|
||||
|
||||
## Git inputs
|
||||
|
||||
Git inputs represent Git repositories referenced in `ADD` instructions or used
|
||||
as build context.
|
||||
|
||||
### Example Dockerfile
|
||||
|
||||
```dockerfile
|
||||
ADD git@github.com:moby/buildkit.git#v0.12.0 /src
|
||||
```
|
||||
|
||||
### Available fields
|
||||
|
||||
#### `input.git.schema`
|
||||
|
||||
The URL scheme (`https`, `http`, `git`, or `ssh`).
|
||||
|
||||
```rego
|
||||
# Require HTTPS for Git clones
|
||||
allow if {
|
||||
input.git.schema == "https"
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.git.host`
|
||||
|
||||
The Git host (e.g., `github.com`, `gitlab.com`).
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.git.host == "github.com"
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.git.remote`
|
||||
|
||||
The complete Git URL.
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.git.remote == "https://github.com/moby/buildkit.git"
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.git.ref`
|
||||
|
||||
The Git reference.
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.git.ref == "refs/heads/master"
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.git.tagName`
|
||||
|
||||
The tag name if the reference is a tag.
|
||||
|
||||
```rego
|
||||
# Only allow version tags
|
||||
allow if {
|
||||
regex.match(`^v[0-9]+\.[0-9]+\.[0-9]+$`, input.git.tagName)
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.git.branch`
|
||||
|
||||
The branch name if the reference is a branch.
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.git.branch == "main"
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.git.subDir`
|
||||
|
||||
The subdirectory path within the repository, if specified.
|
||||
|
||||
```rego
|
||||
# Ensure clones are from the root
|
||||
allow if {
|
||||
input.git.subDir == ""
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.git.isCommitRef`
|
||||
|
||||
Boolean indicating if the reference is a commit SHA (as opposed to a branch or
|
||||
tag name).
|
||||
|
||||
```rego
|
||||
# Require commit SHAs for production
|
||||
allow if {
|
||||
input.env.target == "production"
|
||||
input.git.isCommitRef
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.git.checksum`
|
||||
|
||||
The checksum of the Git reference. For commit references and branches, this is
|
||||
the commit hash. For annotated tags, this is the tag object hash.
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.git.checksum == "abc123..."
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.git.commitChecksum`
|
||||
|
||||
The commit hash that the reference points to. For annotated tags, this differs
|
||||
from `checksum` (which is the tag object hash). For commit references and
|
||||
branches, this is the same as `checksum`.
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.git.commitChecksum == "abc123..."
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.git.isAnnotatedTag`
|
||||
|
||||
Boolean indicating if the reference is an annotated tag (as opposed to a
|
||||
lightweight tag).
|
||||
|
||||
```rego
|
||||
# Require annotated tags
|
||||
allow if {
|
||||
input.git.tagName != ""
|
||||
input.git.isAnnotatedTag
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.git.commit`
|
||||
|
||||
Object containing commit metadata:
|
||||
|
||||
- `author`: Author name, email, when
|
||||
- `committer`: Committer name, email, when
|
||||
- `message`: Commit message
|
||||
- `pgpSignature`: PGP signature details if signed
|
||||
- `sshSignature`: SSH signature details if signed
|
||||
|
||||
```rego
|
||||
# Check commit author
|
||||
allow if {
|
||||
input.git.commit.author.email == "maintainer@example.com"
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.git.tag`
|
||||
|
||||
Object containing tag metadata for annotated tags:
|
||||
|
||||
- `tagger`: Tagger name, email, when
|
||||
- `message`: Tag message
|
||||
- `pgpSignature`: PGP signature details if signed
|
||||
- `sshSignature`: SSH signature details if signed
|
||||
|
||||
```rego
|
||||
# Require signed tags
|
||||
allow if {
|
||||
input.git.tag.pgpSignature != null
|
||||
}
|
||||
```
|
||||
|
||||
## Local inputs
|
||||
|
||||
Local inputs represent the build context directory.
|
||||
|
||||
### Available fields
|
||||
|
||||
#### `input.local.name`
|
||||
|
||||
The name or path of the local context.
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.local.name == "."
|
||||
}
|
||||
```
|
||||
|
||||
Local inputs are typically less restricted than remote inputs, but you can
|
||||
still write policies to enforce context requirements.
|
||||
|
||||
## Environment fields
|
||||
|
||||
The `input.env` object provides build configuration information set by user on
|
||||
invoking the build, not specific to a resource type.
|
||||
|
||||
### Available fields
|
||||
|
||||
#### `input.env.filename`
|
||||
|
||||
The name of the Dockerfile being built.
|
||||
|
||||
```rego
|
||||
# Stricter rules for production Dockerfile
|
||||
allow if {
|
||||
input.env.filename == "Dockerfile"
|
||||
input.image.isCanonical
|
||||
}
|
||||
|
||||
# Relaxed rules for development
|
||||
allow if {
|
||||
input.env.filename == "Dockerfile.dev"
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.env.target`
|
||||
|
||||
The build target from multi-stage builds.
|
||||
|
||||
```rego
|
||||
# Require signing only for release builds
|
||||
allow if {
|
||||
input.env.target == "release"
|
||||
input.git.tagName != ""
|
||||
verify_git_signature(input.git.tag, "maintainer.asc")
|
||||
}
|
||||
```
|
||||
|
||||
#### `input.env.args`
|
||||
|
||||
Build arguments passed with `--build-arg`. Access specific arguments by key.
|
||||
|
||||
```rego
|
||||
# Check build argument values
|
||||
allow if {
|
||||
input.env.args.ENVIRONMENT == "production"
|
||||
input.image.hasProvenance
|
||||
}
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
- See [Built-in functions](./built-ins.md) for built-in helper functions to
|
||||
check and validate input properties
|
||||
- Browse [Example policies](./examples.md) for common patterns
|
||||
- Read about [Rego](https://www.openpolicyagent.org/docs/latest/policy-language/)
|
||||
for advanced policy logic
|
||||
334
content/manuals/build/policies/intro.md
Normal file
334
content/manuals/build/policies/intro.md
Normal file
@@ -0,0 +1,334 @@
|
||||
---
|
||||
title: Introduction to build policies
|
||||
linkTitle: Introduction
|
||||
description: Get started with writing and evaluating build policies
|
||||
keywords: build policies, opa, rego, policy tutorial, docker build, security
|
||||
weight: 10
|
||||
---
|
||||
|
||||
Build policies let you validate the inputs to your Docker builds before they
|
||||
run. This tutorial walks you through creating your first policy, teaching the
|
||||
Rego basics you need along the way.
|
||||
|
||||
## What you'll learn
|
||||
|
||||
By the end of this tutorial, you'll understand:
|
||||
|
||||
- How to create and organize policy files
|
||||
- Basic Rego syntax and patterns
|
||||
- How to write policies that validate URLs, checksums, and images
|
||||
- How policies evaluate during builds
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Buildx version 0.31 or later
|
||||
- Basic familiarity with Dockerfiles and building images
|
||||
|
||||
## How policies work
|
||||
|
||||
When you build an image, Buildx resolves all the inputs your
|
||||
Dockerfile references: base images from `FROM` instructions, files
|
||||
from `ADD` or `COPY` or build contexts, and Git repositories. Before
|
||||
running the build, Buildx evaluates your policies against these
|
||||
inputs. If any input violates a policy, the build fails before any
|
||||
instructions execute.
|
||||
|
||||
Policies are written in Rego, a declarative language designed for expressing
|
||||
rules and constraints. You don't need to know Rego to get started - this
|
||||
tutorial teaches you what you need.
|
||||
|
||||
## Create your first policy
|
||||
|
||||
Create a new directory for this tutorial and add a Dockerfile:
|
||||
|
||||
```console
|
||||
$ mkdir policy-tutorial
|
||||
$ cd policy-tutorial
|
||||
```
|
||||
|
||||
Create a `Dockerfile` that downloads a file with `ADD`:
|
||||
|
||||
```dockerfile
|
||||
FROM scratch
|
||||
ADD https://example.com/index.html /index.html
|
||||
```
|
||||
|
||||
Now create a policy file. Policies use the `.rego` extension and live alongside
|
||||
your Dockerfile. Create `Dockerfile.rego`:
|
||||
|
||||
```rego {title="Dockerfile.rego"}
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
allow if {
|
||||
input.http.host == "example.com"
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
Save this file as `Dockerfile.rego` in the same directory as your Dockerfile.
|
||||
|
||||
Let's break down what this policy does:
|
||||
|
||||
- `package docker` - All build policies must start with this package declaration
|
||||
- `default allow := false` - This example uses a deny-by-default rule: if inputs do not match an `allow` rule, the policy check fails
|
||||
- `allow if input.local` - The first rule allows any local files (your build context)
|
||||
- `allow if { input.http.host == "example.com" }` - The second rule allows HTTP downloads from `example.com`
|
||||
- `decision := {"allow": allow}` - The final decision object tells Buildx whether to allow or deny the input
|
||||
|
||||
This policy says: "Only allow local files and HTTP downloads from
|
||||
`example.com`". Rego evaluates all the policy rules to figure out the return
|
||||
value for the `decision` variable, for each build input. The evaluations happen
|
||||
in parallel and on-demand; the order of the policy rules has no significance.
|
||||
|
||||
### About `input.local`
|
||||
|
||||
You'll see `allow if input.local` in nearly every policy. This rule allows
|
||||
local file access, which includes your build context (typically, the `.`
|
||||
directory) and importantly, the Dockerfile itself. Without this rule, Buildx
|
||||
can't read your Dockerfile to start the build.
|
||||
|
||||
Even builds that don't reference any files from the build context often need
|
||||
`input.local` because the Dockerfile is a local file. The policy evaluates
|
||||
before the build starts, and denying local access means denying access to the
|
||||
Dockerfile.
|
||||
|
||||
In rare cases, you might want stricter local file policies - for example, in CI
|
||||
builds where the build context uses a Git URL as a context directly. In these
|
||||
cases, you may want to deny local sources to prevent untracked files or changes
|
||||
from making their way into your build.
|
||||
|
||||
## Automatic policy loading
|
||||
|
||||
Buildx automatically loads policies that match your Dockerfile name. When you
|
||||
build with `Dockerfile`, Buildx looks for `Dockerfile.rego` in the same
|
||||
directory. For a file named `app.Dockerfile`, it looks for
|
||||
`app.Dockerfile.rego`.
|
||||
|
||||
This automatic loading means you don't need any command-line flags in most
|
||||
cases - create the policy file and build.
|
||||
|
||||
The policy file must be in the same directory as the Dockerfile. If Buildx
|
||||
can't find a matching policy, the build proceeds without policy evaluation
|
||||
(unless you use `--policy strict=true`).
|
||||
|
||||
For more control over policy loading, see the [Usage guide](./usage.md).
|
||||
|
||||
## Run a build with your policy
|
||||
|
||||
Build the image with policy evaluation enabled:
|
||||
|
||||
```console
|
||||
$ docker build .
|
||||
```
|
||||
|
||||
The build succeeds because the URL in your Dockerfile matches the policy. Now
|
||||
try changing the URL in your Dockerfile to something else:
|
||||
|
||||
```dockerfile
|
||||
FROM scratch
|
||||
ADD https://api.github.com/users/octocat /user.json
|
||||
```
|
||||
|
||||
Build again:
|
||||
|
||||
```console
|
||||
$ docker build .
|
||||
```
|
||||
|
||||
This time the build fails with a policy violation. The `api.github.com`
|
||||
hostname doesn't match the rule in your policy, so Buildx rejects it before
|
||||
running any build steps.
|
||||
|
||||
## Debugging policy failures
|
||||
|
||||
If your build fails with a policy violation, use `--progress=plain` to see
|
||||
exactly what went wrong:
|
||||
|
||||
```console
|
||||
$ docker buildx build --progress=plain .
|
||||
```
|
||||
|
||||
This shows all policy checks, the input data for each source, and allow/deny
|
||||
decisions. For complete debugging guidance, see [Debugging](./debugging.md).
|
||||
|
||||
## Add helpful error messages
|
||||
|
||||
When a policy denies an input, users see a generic error message. You can
|
||||
provide custom messages that explain why the build was denied:
|
||||
|
||||
```rego {title="Dockerfile.rego"}
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
allow if {
|
||||
input.http.host == "example.com"
|
||||
input.http.schema == "https"
|
||||
}
|
||||
|
||||
deny_msg contains msg if {
|
||||
not allow
|
||||
input.http
|
||||
msg := "only HTTPS downloads from example.com are allowed"
|
||||
}
|
||||
|
||||
decision := {"allow": allow, "deny_msg": deny_msg}
|
||||
```
|
||||
|
||||
Now when a build is denied, users see your custom message explaining what went
|
||||
wrong:
|
||||
|
||||
```console
|
||||
$ docker buildx build .
|
||||
Policy: only HTTPS downloads from example.com are allowed
|
||||
ERROR: failed to build: ... source not allowed by policy
|
||||
```
|
||||
|
||||
The `deny_msg` rule uses `contains` to add messages to a set. You can add
|
||||
multiple deny messages for different failure conditions to help users understand
|
||||
exactly what needs to change.
|
||||
|
||||
## Understand Rego rules
|
||||
|
||||
Rego policies are built from rules. A rule defines when something is allowed.
|
||||
The basic pattern is:
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
condition_one
|
||||
condition_two
|
||||
condition_three
|
||||
}
|
||||
```
|
||||
|
||||
All conditions must be true for the rule to match. Think of it as an AND
|
||||
operation - the URL must match AND the checksum must match AND any other
|
||||
conditions you specify.
|
||||
|
||||
You can have multiple `allow` rules in one policy. If any rule matches, the
|
||||
input is allowed:
|
||||
|
||||
```rego
|
||||
# Allow downloads from example.com
|
||||
allow if {
|
||||
input.http.host == "example.com"
|
||||
}
|
||||
|
||||
# Also allow downloads from api.github.com
|
||||
allow if {
|
||||
input.http.host == "api.github.com"
|
||||
}
|
||||
```
|
||||
|
||||
This works like OR - the input can match the first rule OR the second rule.
|
||||
|
||||
## Access input fields
|
||||
|
||||
The `input` object gives you access to information about build inputs. The
|
||||
structure depends on the input type:
|
||||
|
||||
- `input.http` - Files downloaded with `ADD https://...`
|
||||
- `input.image` - Container images from `FROM` or `COPY --from`
|
||||
- `input.git` - Git repositories from `ADD git://...` or build context
|
||||
- `input.local` - Local file context
|
||||
|
||||
Refer to the [Input reference](./inputs.md) for all available input fields.
|
||||
|
||||
For HTTP downloads, you can access:
|
||||
|
||||
| Key | Description | Example |
|
||||
| ------------------- | ---------------------------------- | -------------------------------- |
|
||||
| `input.http.url` | The full URL | `https://example.com/index.html` |
|
||||
| `input.http.schema` | The protocol (HTTP/HTTPS) | `https` |
|
||||
| `input.http.host` | The hostname | `example.com` |
|
||||
| `input.http.path` | The URL path, including parameters | `/index.html` |
|
||||
|
||||
Update your policy to require HTTPS:
|
||||
|
||||
```rego
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if {
|
||||
input.http.host == "example.com"
|
||||
input.http.schema == "https"
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
Now the policy requires both the hostname to be `example.com` and the protocol
|
||||
to be HTTPS. HTTP URLs (without TLS) would fail the policy check.
|
||||
|
||||
## Pattern matching and strings
|
||||
|
||||
Rego provides [built-in functions] for pattern matching. Use `startswith()` to
|
||||
match URL prefixes:
|
||||
|
||||
[built-in functions]: https://www.openpolicyagent.org/docs/policy-language#built-in-functions
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
startswith(input.http.url, "https://example.com/")
|
||||
}
|
||||
```
|
||||
|
||||
This allows any URL that starts with `https://example.com/`.
|
||||
|
||||
Use `regex.match()` for complex patterns:
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
regex.match(`^https://example\.com/.+\.json$`, input.http.url)
|
||||
}
|
||||
```
|
||||
|
||||
This matches URLs that:
|
||||
|
||||
- Start with `https://example.com/`
|
||||
- End with `.json`
|
||||
- Have at least one character between the domain and extension
|
||||
|
||||
## Policy file location
|
||||
|
||||
Policy files live adjacent to the Dockerfile they validate, using the naming
|
||||
pattern `<dockerfile-name>.rego`:
|
||||
|
||||
```text
|
||||
project/
|
||||
├── Dockerfile # Main Dockerfile
|
||||
├── Dockerfile.rego # Policy for Dockerfile
|
||||
├── lint.Dockerfile # Linting Dockerfile
|
||||
└── lint.Dockerfile.rego # Policy for lint.Dockerfile
|
||||
```
|
||||
|
||||
When you build, Buildx automatically loads the corresponding policy file:
|
||||
|
||||
```console
|
||||
$ docker buildx build -f Dockerfile . # Loads Dockerfile.rego
|
||||
$ docker buildx build -f lint.Dockerfile . # Loads lint.Dockerfile.rego
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
You now understand how to write basic build policies for HTTP resources. To
|
||||
continue learning:
|
||||
|
||||
- Apply and test policies: [Using build policies](./usage.md)
|
||||
- Learn [Image validation](./validate-images.md) to validate container images
|
||||
from `FROM` instructions
|
||||
- Learn [Git validation](./validate-git.md) to validate Git repositories used
|
||||
in builds
|
||||
- See [Example policies](./examples.md) for copy-paste-ready policies covering
|
||||
common scenarios
|
||||
- Write unit tests for your policies: [Test build policies](./testing.md)
|
||||
- Debug policy failures: [Debugging](./debugging.md)
|
||||
- Read the [Input reference](./inputs.md) for all available input fields
|
||||
- Check the [Built-in functions](./built-ins.md) for signature verification,
|
||||
attestations, and other security checks
|
||||
214
content/manuals/build/policies/testing.md
Normal file
214
content/manuals/build/policies/testing.md
Normal file
@@ -0,0 +1,214 @@
|
||||
---
|
||||
title: Test build policies
|
||||
linkTitle: Testing
|
||||
description: Write and run unit tests for build policies, similar to the opa test command
|
||||
keywords: build policies, opa, rego, testing, unit tests, policy validation
|
||||
weight: 60
|
||||
---
|
||||
|
||||
The [`docker buildx policy test`](/reference/cli/docker/buildx/policy/test/)
|
||||
command runs unit tests for build policies using OPA's [standard test
|
||||
framework](https://www.openpolicyagent.org/docs/policy-testing).
|
||||
|
||||
```console
|
||||
$ docker buildx policy test <path>
|
||||
```
|
||||
|
||||
This validates policy logic with mocked inputs.
|
||||
|
||||
For testing against real sources (actual image metadata, Git repositories), use
|
||||
[`docker buildx policy eval`](/reference/cli/docker/buildx/policy/eval/)
|
||||
instead. You can use the `eval --print` option to resolve input for a specific
|
||||
source for writing a test case.
|
||||
|
||||
## Basic example
|
||||
|
||||
Start with a simple policy that only allows `alpine` images:
|
||||
|
||||
```rego {title="Dockerfile.rego"}
|
||||
package docker
|
||||
|
||||
default allow = false
|
||||
|
||||
allow if {
|
||||
input.image.repo == "alpine"
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
Create a test file with the `*_test.rego` suffix. Test functions must start
|
||||
with `test_`:
|
||||
|
||||
```rego {title="Dockerfile_test.rego"}
|
||||
package docker
|
||||
|
||||
test_alpine_allowed if {
|
||||
decision.allow with input as {"image": {"repo": "alpine"}}
|
||||
}
|
||||
|
||||
test_ubuntu_denied if {
|
||||
not decision.allow with input as {"image": {"repo": "ubuntu"}}
|
||||
}
|
||||
```
|
||||
|
||||
Run the tests:
|
||||
|
||||
```console
|
||||
$ docker buildx policy test .
|
||||
test_alpine_allowed: PASS (allow=true)
|
||||
test_ubuntu_denied: PASS (allow=false)
|
||||
```
|
||||
|
||||
`PASS` indicates that the tests defined in `Dockerfile_test.rego` executed
|
||||
successfully and all assertions were satisfied.
|
||||
|
||||
## Command options
|
||||
|
||||
Filter tests by name with `--run`:
|
||||
|
||||
```console
|
||||
$ docker buildx policy test --run alpine .
|
||||
test_alpine_allowed: PASS (allow=true)
|
||||
```
|
||||
|
||||
Test policies with non-default filenames using `--filename`:
|
||||
|
||||
```console
|
||||
$ docker buildx policy test --filename app.Dockerfile .
|
||||
```
|
||||
|
||||
This loads `app.Dockerfile.rego` and runs `*_test.rego` files against it.
|
||||
|
||||
## Test output
|
||||
|
||||
Passed tests show the allow status and any deny messages:
|
||||
|
||||
```console
|
||||
test_alpine_allowed: PASS (allow=true)
|
||||
test_ubuntu_denied: PASS (allow=false, deny_msg=only alpine images are allowed)
|
||||
```
|
||||
|
||||
Failed tests show input, decision output, and missing fields:
|
||||
|
||||
```console
|
||||
test_invalid: FAIL (allow=false)
|
||||
input:
|
||||
{
|
||||
"image": {}
|
||||
}
|
||||
decision:
|
||||
{
|
||||
"allow": false,
|
||||
"deny_msg": [
|
||||
"only alpine images are allowed"
|
||||
]
|
||||
}
|
||||
missing_input: input.image.repo
|
||||
```
|
||||
|
||||
## Test deny messages
|
||||
|
||||
To test custom error messages, capture the full decision result and assert on
|
||||
the `deny_msg` field.
|
||||
|
||||
For a policy with deny messages:
|
||||
|
||||
```rego {title="Dockerfile.rego"}
|
||||
package docker
|
||||
|
||||
default allow = false
|
||||
|
||||
allow if {
|
||||
input.image.repo == "alpine"
|
||||
}
|
||||
|
||||
deny_msg contains msg if {
|
||||
not allow
|
||||
msg := "only alpine images are allowed"
|
||||
}
|
||||
|
||||
decision := {"allow": allow, "deny_msg": deny_msg}
|
||||
```
|
||||
|
||||
Test the deny message:
|
||||
|
||||
```rego {title="Dockerfile_test.rego"}
|
||||
test_deny_message if {
|
||||
result := decision with input as {"image": {"repo": "ubuntu"}}
|
||||
not result.allow
|
||||
"only alpine images are allowed" in result.deny_msg
|
||||
}
|
||||
```
|
||||
|
||||
## Test patterns
|
||||
|
||||
**Test environment-specific rules:**
|
||||
|
||||
```rego
|
||||
test_production_requires_digest if {
|
||||
decision.allow with input as {
|
||||
"env": {"target": "production"},
|
||||
"image": {"isCanonical": true}
|
||||
}
|
||||
}
|
||||
|
||||
test_development_allows_tags if {
|
||||
decision.allow with input as {
|
||||
"env": {"target": "development"},
|
||||
"image": {"isCanonical": false}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Test multiple registries:**
|
||||
|
||||
```rego
|
||||
test_dockerhub_allowed if {
|
||||
decision.allow with input as {
|
||||
"image": {
|
||||
"ref": "docker.io/library/alpine",
|
||||
"host": "docker.io",
|
||||
"repo": "alpine"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test_ghcr_allowed if {
|
||||
decision.allow with input as {
|
||||
"image": {
|
||||
"ref": "ghcr.io/myorg/myapp",
|
||||
"host": "ghcr.io",
|
||||
"repo": "myorg/myapp"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For available input fields, see the [Input reference](./inputs.md).
|
||||
|
||||
## Organize test files
|
||||
|
||||
The test runner discovers all `*_test.rego` files recursively:
|
||||
|
||||
```plaintext
|
||||
build-policies/
|
||||
├── Dockerfile.rego
|
||||
├── Dockerfile_test.rego
|
||||
└── tests/
|
||||
├── registries_test.rego
|
||||
├── signatures_test.rego
|
||||
└── environments_test.rego
|
||||
```
|
||||
|
||||
Run all tests:
|
||||
|
||||
```console
|
||||
$ docker buildx policy test .
|
||||
```
|
||||
|
||||
Or test specific files:
|
||||
|
||||
```console
|
||||
$ docker buildx policy test tests/registries_test.rego
|
||||
```
|
||||
493
content/manuals/build/policies/usage.md
Normal file
493
content/manuals/build/policies/usage.md
Normal file
@@ -0,0 +1,493 @@
|
||||
---
|
||||
title: Using build policies
|
||||
linkTitle: Usage
|
||||
description: Apply policies to builds and develop policies iteratively
|
||||
keywords: build policies, policy eval, docker buildx, policy development, debugging
|
||||
weight: 20
|
||||
---
|
||||
|
||||
Build policies validate inputs before builds execute. This guide covers how to
|
||||
develop policies iteratively and apply them to real builds with `docker buildx
|
||||
build` and `docker buildx bake`.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Buildx 0.31.0 or later - Check your version: `docker buildx version`
|
||||
- BuildKit 0.26.0 or later - Verify with: `docker buildx inspect
|
||||
--bootstrap`
|
||||
|
||||
If you're using Docker Desktop, ensure you're on a version that includes these
|
||||
updates.
|
||||
|
||||
## Policy development workflow
|
||||
|
||||
Buildx automatically loads policies that match your Dockerfile name. When you
|
||||
build with `Dockerfile`, Buildx looks for `Dockerfile.rego` in the same
|
||||
directory. For a file named `app.Dockerfile`, it looks for
|
||||
`app.Dockerfile.rego`. See the [Advanced: Policy configuration](#advanced-policy-configuration)
|
||||
section for configuration options and manual policy loading.
|
||||
|
||||
Writing policies is an iterative process:
|
||||
|
||||
1. Start with a basic deny-all policy.
|
||||
2. Build with debug logging to see what inputs your Dockerfile uses.
|
||||
3. Add rules to allow specific sources based on the debug output.
|
||||
4. Test and refine.
|
||||
|
||||
### Viewing inputs from your Dockerfile
|
||||
|
||||
To see the inputs that your Dockerfile references (images, Git repos, HTTP
|
||||
downloads), build with debug logging:
|
||||
|
||||
```console
|
||||
$ docker buildx build --progress=plain --policy log-level=debug .
|
||||
```
|
||||
|
||||
Example output for an image source:
|
||||
|
||||
```text
|
||||
#1 0.010 checking policy for source docker-image://alpine:3.19 (linux/arm64)
|
||||
#1 0.011 policy input: {
|
||||
#1 0.011 "env": {
|
||||
#1 0.011 "filename": "."
|
||||
#1 0.011 },
|
||||
#1 0.011 "image": {
|
||||
#1 0.011 "ref": "docker.io/library/alpine:3.19",
|
||||
#1 0.011 "host": "docker.io",
|
||||
#1 0.011 "repo": "alpine",
|
||||
#1 0.011 "tag": "3.19",
|
||||
#1 0.011 "platform": "linux/arm64"
|
||||
#1 0.011 }
|
||||
#1 0.011 }
|
||||
#1 0.011 unknowns for policy evaluation: [input.image.checksum input.image.labels ...]
|
||||
#1 0.012 policy decision for source docker-image://alpine:3.19: ALLOW
|
||||
```
|
||||
|
||||
This shows the complete input structure, which fields are unresolved, and the
|
||||
policy decision for each source. See [Input reference](./inputs.md) for all
|
||||
available fields.
|
||||
|
||||
### Testing policies with policy eval
|
||||
|
||||
Use [`docker buildx policy eval`](/reference/cli/docker/buildx/policy/eval/) to
|
||||
test whether your policy allows a specific source without running a full build.
|
||||
|
||||
Note: `docker buildx policy eval` tests the source specified as the argument.
|
||||
It doesn't parse your Dockerfile to evaluate all inputs - for that, [build with
|
||||
--progress=plain](#viewing-inputs-from-your-dockerfile).
|
||||
|
||||
Test if your policy allows the local context:
|
||||
|
||||
```console
|
||||
$ docker buildx policy eval .
|
||||
```
|
||||
|
||||
No output means the policy allowed the source. If denied, you see:
|
||||
|
||||
```console
|
||||
ERROR: policy denied
|
||||
```
|
||||
|
||||
Test other sources:
|
||||
|
||||
```console
|
||||
$ docker buildx policy eval https://example.com # Test HTTP
|
||||
$ docker buildx policy eval https://github.com/org/repo.git # Test Git
|
||||
```
|
||||
|
||||
By default, `--print` shows reference information parsed from the source string
|
||||
(like `repo`, `tag`, `host`) without fetching from registries. To inspect
|
||||
metadata that requires fetching the source (like `labels`, `checksum`, or
|
||||
`hasProvenance`), specify which fields to fetch with `--fields`:
|
||||
|
||||
```console
|
||||
$ docker buildx policy eval --print --fields image.labels docker-image://alpine:3.19
|
||||
```
|
||||
|
||||
Multiple fields can be specified as a comma-separated list.
|
||||
|
||||
### Iterative development example
|
||||
|
||||
Here's a practical workflow for developing policies:
|
||||
|
||||
1. Start with basic deny-all policy:
|
||||
|
||||
```rego {title="Dockerfile.rego"}
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
2. Build with debug logging to see what inputs your Dockerfile uses:
|
||||
|
||||
```console
|
||||
$ docker buildx build --progress=plain --policy log-level=debug .
|
||||
```
|
||||
|
||||
The output shows the denied image and its input structure:
|
||||
|
||||
```text
|
||||
#1 0.026 checking policy for source docker-image://docker.io/library/alpine:3.19
|
||||
#1 0.027 policy input: {
|
||||
#1 0.027 "image": {
|
||||
#1 0.027 "repo": "alpine",
|
||||
#1 0.027 "tag": "3.19",
|
||||
#1 0.027 ...
|
||||
#1 0.027 }
|
||||
#1 0.027 }
|
||||
#1 0.028 policy decision for source docker-image://alpine:3.19: DENY
|
||||
#1 ERROR: source "docker-image://alpine:3.19" not allowed by policy
|
||||
```
|
||||
|
||||
3. Add a rule allowing the alpine image:
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.image.repo == "alpine"
|
||||
}
|
||||
```
|
||||
|
||||
4. Build again to verify the policy works:
|
||||
|
||||
```console
|
||||
$ docker buildx build .
|
||||
```
|
||||
|
||||
If it fails, see [Debugging](./debugging.md) for troubleshooting guidance.
|
||||
|
||||
## Using policies with `docker build`
|
||||
|
||||
Once you've developed and tested your policy, apply it to real builds.
|
||||
|
||||
### Basic usage
|
||||
|
||||
Create a policy alongside your Dockerfile:
|
||||
|
||||
```dockerfile {title="Dockerfile"}
|
||||
FROM alpine:3.19
|
||||
RUN echo "hello"
|
||||
```
|
||||
|
||||
```rego {title="Dockerfile.rego"}
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
|
||||
allow if {
|
||||
input.image.repo == "alpine"
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
Build normally:
|
||||
|
||||
```console
|
||||
$ docker buildx build .
|
||||
```
|
||||
|
||||
Buildx loads the policy automatically and validates the `alpine:3.19` image
|
||||
before building.
|
||||
|
||||
### Build with different Dockerfile names
|
||||
|
||||
Specify the Dockerfile with `-f`:
|
||||
|
||||
```console
|
||||
$ docker buildx build -f app.Dockerfile .
|
||||
```
|
||||
|
||||
Buildx looks for `app.Dockerfile.rego` in the same directory.
|
||||
|
||||
### Build with manual policy
|
||||
|
||||
Add an extra policy to the automatic one:
|
||||
|
||||
```console
|
||||
$ docker buildx build --policy filename=extra-checks.rego .
|
||||
```
|
||||
|
||||
Both `Dockerfile.rego` (automatic) and `extra-checks.rego` (manual) must pass.
|
||||
|
||||
### Build without automatic policy
|
||||
|
||||
Use only your specified policy:
|
||||
|
||||
```console
|
||||
$ docker buildx build --policy reset=true,filename=strict.rego .
|
||||
```
|
||||
|
||||
## Using policies with bake
|
||||
|
||||
[Bake](/build/bake/) supports automatic policy loading just like `docker buildx
|
||||
build`. Place `Dockerfile.rego` alongside your Dockerfile and run:
|
||||
|
||||
```console
|
||||
$ docker buildx bake
|
||||
```
|
||||
|
||||
### Manual policy in bake files
|
||||
|
||||
Specify additional policies in your `docker-bake.hcl`:
|
||||
|
||||
```hcl {title="docker-bake.hcl"}
|
||||
target "default" {
|
||||
dockerfile = "Dockerfile"
|
||||
policy = ["extra.rego"]
|
||||
}
|
||||
```
|
||||
|
||||
The `policy` attribute takes a list of policy files. Bake loads these in
|
||||
addition to the automatic `Dockerfile.rego` (if it exists).
|
||||
|
||||
### Multiple policies in bake
|
||||
|
||||
```hcl {title="docker-bake.hcl"}
|
||||
target "webapp" {
|
||||
dockerfile = "Dockerfile"
|
||||
policy = [
|
||||
"shared/base-policy.rego",
|
||||
"security/image-signing.rego"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
All policies must pass for the target to build successfully.
|
||||
|
||||
### Different policies per target
|
||||
|
||||
Apply different validation rules to different targets:
|
||||
|
||||
```hcl {title="docker-bake.hcl"}
|
||||
target "development" {
|
||||
dockerfile = "dev.Dockerfile"
|
||||
policy = ["policies/permissive.rego"]
|
||||
}
|
||||
|
||||
target "production" {
|
||||
dockerfile = "prod.Dockerfile"
|
||||
policy = ["policies/strict.rego", "policies/signing-required.rego"]
|
||||
}
|
||||
```
|
||||
|
||||
Build with the appropriate target:
|
||||
|
||||
```console
|
||||
$ docker buildx bake development # Uses permissive policy
|
||||
$ docker buildx bake production # Uses strict policies
|
||||
```
|
||||
|
||||
### Bake with policy options
|
||||
|
||||
Currently, bake doesn't support policy options (reset, strict, disabled) in the
|
||||
HCL file. Use command-line flags instead:
|
||||
|
||||
```console
|
||||
$ docker buildx bake --policy disabled=true production
|
||||
```
|
||||
|
||||
## Testing in CI/CD
|
||||
|
||||
Validate policies in continuous integration by running builds with the `--policy` flag. For unit testing policies before running builds, see [Test build policies](./testing.md).
|
||||
|
||||
Test policies during CI builds:
|
||||
|
||||
```yaml {title=".github/workflows/test-policies.yml"}
|
||||
name: Test Build Policies
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
- name: Test build with policy
|
||||
run: docker buildx build --policy strict=true .
|
||||
```
|
||||
|
||||
This ensures policy changes don't break builds and that new rules work as
|
||||
intended. The `strict=true` flag fails the build if policies aren't loaded (for
|
||||
example, if the BuildKit instance used by the build is too old and doesn't
|
||||
support policies).
|
||||
|
||||
## Advanced: Policy configuration
|
||||
|
||||
This section covers advanced policy loading mechanisms and configuration
|
||||
options.
|
||||
|
||||
### Automatic policy loading
|
||||
|
||||
Buildx automatically loads policies that match your Dockerfile name. When you
|
||||
build with `Dockerfile`, Buildx looks for `Dockerfile.rego` in the same
|
||||
directory. For a file named `app.Dockerfile`, it looks for
|
||||
`app.Dockerfile.rego`.
|
||||
|
||||
```text
|
||||
project/
|
||||
├── Dockerfile
|
||||
├── Dockerfile.rego # Loaded automatically for Dockerfile
|
||||
├── app.Dockerfile
|
||||
├── app.Dockerfile.rego # Loaded automatically for app.Dockerfile
|
||||
└── src/
|
||||
```
|
||||
|
||||
This automatic loading means you don't need command-line flags in most cases.
|
||||
Create the policy file alongside your Dockerfile and build:
|
||||
|
||||
```console
|
||||
$ docker buildx build .
|
||||
```
|
||||
|
||||
Buildx detects `Dockerfile.rego` and evaluates it before running the build.
|
||||
|
||||
> [!NOTE]
|
||||
> Policy files must be in the same directory as the Dockerfile they validate.
|
||||
> Buildx doesn't search parent directories or subdirectories.
|
||||
|
||||
### When policies don't load
|
||||
|
||||
If buildx can't find a matching `.rego` file, the build proceeds without policy
|
||||
evaluation. To require policies and fail if none are found, use strict mode:
|
||||
|
||||
```console
|
||||
$ docker buildx build --policy strict=true .
|
||||
```
|
||||
|
||||
This fails the build if no policy loads or if the BuildKit daemon doesn't
|
||||
support policies.
|
||||
|
||||
### Manual policy configuration
|
||||
|
||||
The `--policy` flag lets you specify additional policies, override automatic
|
||||
loading, or control policy behavior.
|
||||
|
||||
Basic syntax:
|
||||
|
||||
```console
|
||||
$ docker buildx build --policy filename=custom.rego .
|
||||
```
|
||||
|
||||
This loads `custom.rego` in addition to the automatic `Dockerfile.rego` (if it
|
||||
exists).
|
||||
|
||||
Multiple policies:
|
||||
|
||||
```console
|
||||
$ docker buildx build --policy filename=policy1.rego --policy filename=policy2.rego .
|
||||
```
|
||||
|
||||
All policies must pass for the build to succeed. Use this to enforce layered
|
||||
requirements (base policy + project-specific rules).
|
||||
|
||||
Available options:
|
||||
|
||||
| Option | Description | Example |
|
||||
| ------------------- | ------------------------------------------------------- | ----------------------------- |
|
||||
| `filename=<path>` | Load policy from specified file | `filename=custom.rego` |
|
||||
| `reset=true` | Ignore automatic policies, use only specified ones | `reset=true` |
|
||||
| `disabled=true` | Disable all policy evaluation | `disabled=true` |
|
||||
| `strict=true` | Fail if BuildKit doesn't support policies | `strict=true` |
|
||||
| `log-level=<level>` | Control policy logging (error, warn, info, debug, none). Use `debug` to see complete input JSON and unresolved fields | `log-level=debug` |
|
||||
|
||||
Combine options with commas:
|
||||
|
||||
```console
|
||||
$ docker buildx build --policy filename=extra.rego,strict=true .
|
||||
```
|
||||
|
||||
### Exploring sources with policy eval
|
||||
|
||||
The `docker buildx policy eval` command lets you quickly explore and test
|
||||
sources without running a build.
|
||||
|
||||
#### Inspect input structure with --print
|
||||
|
||||
Use `--print` to see the input structure for any source without running policy
|
||||
evaluation:
|
||||
|
||||
```console
|
||||
$ docker buildx policy eval --print https://github.com/moby/buildkit.git
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"git": {
|
||||
"schema": "https",
|
||||
"host": "github.com",
|
||||
"remote": "https://github.com/moby/buildkit.git"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Test different source types:
|
||||
|
||||
```console
|
||||
# HTTP downloads
|
||||
$ docker buildx policy eval --print https://releases.hashicorp.com/terraform/1.5.0/terraform.zip
|
||||
|
||||
# Images (requires docker-image:// prefix)
|
||||
$ docker buildx policy eval --print docker-image://alpine:3.19
|
||||
|
||||
# Local context
|
||||
$ docker buildx policy eval --print .
|
||||
```
|
||||
|
||||
Shows information parsed from the source without fetching. Use `--fields` to
|
||||
fetch specific metadata (see [above](#testing-policies-with-policy-eval)).
|
||||
|
||||
#### Test with specific policy files
|
||||
|
||||
The `--filename` flag specifies which policy file to load by providing the base
|
||||
Dockerfile name (without the `.rego` extension). This is useful for testing
|
||||
sources against policies associated with different Dockerfiles.
|
||||
|
||||
For example, to test a source against the policy for `app.Dockerfile`:
|
||||
|
||||
```console
|
||||
$ docker buildx policy eval --filename app.Dockerfile .
|
||||
```
|
||||
|
||||
This loads `app.Dockerfile.rego` and tests whether it allows the source `.`
|
||||
(the local directory). The flag defaults to `Dockerfile` if not specified.
|
||||
|
||||
Test different sources against your policy:
|
||||
|
||||
```console
|
||||
$ docker buildx policy eval --filename app.Dockerfile https://github.com/org/repo.git
|
||||
$ docker buildx policy eval --filename app.Dockerfile docker-image://alpine:3.19
|
||||
```
|
||||
|
||||
### Reset automatic loading
|
||||
|
||||
To use only your specified policies and ignore automatic `.rego` files:
|
||||
|
||||
```console
|
||||
$ docker buildx build --policy reset=true,filename=custom.rego .
|
||||
```
|
||||
|
||||
This skips `Dockerfile.rego` and loads only `custom.rego`.
|
||||
|
||||
### Disable policies temporarily
|
||||
|
||||
Disable policy evaluation for testing or emergencies:
|
||||
|
||||
```console
|
||||
$ docker buildx build --policy disabled=true .
|
||||
```
|
||||
|
||||
The build proceeds without any policy checks. Use this carefully - you're
|
||||
bypassing security controls.
|
||||
|
||||
## Next steps
|
||||
|
||||
- Write unit tests for your policies: [Test build policies](./testing.md)
|
||||
- Debug policy failures: [Debugging](./debugging.md)
|
||||
- Browse working examples: [Example policies](./examples.md)
|
||||
- Reference all input fields: [Input reference](./inputs.md)
|
||||
431
content/manuals/build/policies/validate-git.md
Normal file
431
content/manuals/build/policies/validate-git.md
Normal file
@@ -0,0 +1,431 @@
|
||||
---
|
||||
title: Validating Git repositories
|
||||
linkTitle: Git validation
|
||||
description: Write policies to validate Git repositories used in your builds
|
||||
keywords: build policies, git validation, git signatures, gpg, signed commits, signed tags
|
||||
weight: 40
|
||||
---
|
||||
|
||||
Git repositories often appear in Docker builds as source code inputs. The `ADD`
|
||||
instruction can clone repositories, and build contexts can reference Git URLs.
|
||||
Validating these inputs ensures you're building from trusted sources with
|
||||
verified versions.
|
||||
|
||||
This guide teaches you to write policies that validate Git inputs, from basic
|
||||
version pinning to verifying signed commits and tags.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
You should understand the policy basics from the [Introduction](./intro.md):
|
||||
creating policy files, basic Rego syntax, and how policies evaluate during
|
||||
builds.
|
||||
|
||||
## What are Git inputs?
|
||||
|
||||
Git inputs come from `ADD` instructions that reference Git repositories:
|
||||
|
||||
```dockerfile
|
||||
# Clone a specific tag
|
||||
ADD https://github.com/moby/buildkit.git#v0.26.1 /buildkit
|
||||
|
||||
# Clone a branch
|
||||
ADD https://github.com/user/repo.git#main /src
|
||||
|
||||
# Clone a commit
|
||||
ADD https://github.com/user/repo.git#abcde123 /src
|
||||
```
|
||||
|
||||
The build context can also be a Git repository when you build with:
|
||||
|
||||
```console
|
||||
$ docker build https://github.com/user/repo.git#main
|
||||
```
|
||||
|
||||
Each Git reference triggers a policy evaluation. Your policy can inspect
|
||||
repository URLs, validate versions, check commit metadata, and verify
|
||||
signatures.
|
||||
|
||||
## Match specific repositories
|
||||
|
||||
The simplest Git policy restricts which repositories can be used:
|
||||
|
||||
```rego {title="Dockerfile.rego"}
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
|
||||
allow if {
|
||||
input.git.host == "github.com"
|
||||
input.git.remote == "https://github.com/moby/buildkit.git"
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
This policy:
|
||||
|
||||
- Denies all inputs by default
|
||||
- Allows local build context
|
||||
- Allows only the BuildKit repository from GitHub
|
||||
|
||||
The `host` field contains the Git server hostname, and `remote` contains the
|
||||
full repository URL. Test it:
|
||||
|
||||
```dockerfile {title="Dockerfile"}
|
||||
FROM scratch
|
||||
ADD https://github.com/moby/buildkit.git#v0.26.1 /
|
||||
```
|
||||
|
||||
```console
|
||||
$ docker build .
|
||||
```
|
||||
|
||||
The build succeeds. Try a different repository and it fails.
|
||||
|
||||
You can match multiple repositories with additional rules:
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.git.host == "github.com"
|
||||
input.git.remote == "https://github.com/moby/buildkit.git"
|
||||
}
|
||||
|
||||
allow if {
|
||||
input.git.host == "github.com"
|
||||
input.git.remote == "https://github.com/docker/cli.git"
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
## Pin to specific versions
|
||||
|
||||
Tags and branches can change over time. Pin to specific versions to ensure
|
||||
reproducible builds:
|
||||
|
||||
```rego
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
|
||||
allow if {
|
||||
input.git.remote == "https://github.com/moby/buildkit.git"
|
||||
input.git.tagName == "v0.26.1"
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
The `tagName` field contains the tag name when the Git reference points to a
|
||||
tag. Use `branch` for branches:
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.git.remote == "https://github.com/user/repo.git"
|
||||
input.git.branch == "main"
|
||||
}
|
||||
```
|
||||
|
||||
Or use `ref` for any type of reference (branch, tag, or commit SHA):
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.git.ref == "v0.26.1"
|
||||
}
|
||||
```
|
||||
|
||||
## Use version allowlists
|
||||
|
||||
For repositories you trust but want to control versions, maintain an allowlist:
|
||||
|
||||
```rego
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allowed_versions = [
|
||||
{"tag": "v0.26.1", "annotated": true, "sha": "abc123"},
|
||||
]
|
||||
|
||||
is_buildkit if {
|
||||
input.git.remote == "https://github.com/moby/buildkit.git"
|
||||
}
|
||||
|
||||
allow if {
|
||||
not is_buildkit
|
||||
}
|
||||
|
||||
allow if {
|
||||
is_buildkit
|
||||
some version in allowed_versions
|
||||
input.git.tagName == version.tag
|
||||
input.git.isAnnotatedTag == version.annotated
|
||||
startswith(input.git.commitChecksum, version.sha)
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
This policy:
|
||||
|
||||
- Defines an allowlist of approved versions with metadata
|
||||
- Uses a helper rule (`is_buildkit`) for readability
|
||||
- Allows all non-BuildKit inputs
|
||||
- For BuildKit, checks the tag name, whether it's an annotated tag, and the commit SHA against the allowlist
|
||||
|
||||
The helper rule makes complex policies more maintainable. You can expand the
|
||||
allowlist as new versions are approved:
|
||||
|
||||
```rego
|
||||
allowed_versions = [
|
||||
{"tag": "v0.26.1", "annotated": true, "sha": "abc123"},
|
||||
{"tag": "v0.27.0", "annotated": true, "sha": "def456"},
|
||||
{"tag": "v0.27.1", "annotated": true, "sha": "789abc"},
|
||||
]
|
||||
```
|
||||
|
||||
## Validate with regex patterns
|
||||
|
||||
Use pattern matching for semantic versioning:
|
||||
|
||||
```rego
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
|
||||
allow if {
|
||||
input.git.remote == "https://github.com/moby/buildkit.git"
|
||||
regex.match(`^v[0-9]+\.[0-9]+\.[0-9]+$`, input.git.tagName)
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
This allows any BuildKit tag matching the pattern `vX.Y.Z` where X, Y, and Z
|
||||
are numbers. The regex ensures you're using release versions, not pre-release
|
||||
tags like `v0.26.0-rc1`.
|
||||
|
||||
Match major versions:
|
||||
|
||||
```rego
|
||||
# Only allow v0.x releases
|
||||
allow if {
|
||||
input.git.remote == "https://github.com/moby/buildkit.git"
|
||||
regex.match(`^v0\.[0-9]+\.[0-9]+$`, input.git.tagName)
|
||||
}
|
||||
```
|
||||
|
||||
## Inspect commit metadata
|
||||
|
||||
The `commit` object provides detailed information about commits:
|
||||
|
||||
```rego
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
|
||||
# Check commit author
|
||||
allow if {
|
||||
input.git.remote == "https://github.com/user/repo.git"
|
||||
input.git.commit.author.email == "trusted@example.com"
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
The `commit` object includes:
|
||||
|
||||
- `author.name`: Author's name
|
||||
- `author.email`: Author's email
|
||||
- `author.when`: When the commit was authored
|
||||
- `committer.name`: Committer's name
|
||||
- `committer.email`: Committer's email
|
||||
- `committer.when`: When the commit was committed
|
||||
- `message`: Commit message
|
||||
|
||||
Validate commit messages:
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.git.commit
|
||||
contains(input.git.commit.message, "Signed-off-by:")
|
||||
}
|
||||
```
|
||||
|
||||
Pin to specific commit SHA:
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.git.commitChecksum == "abc123def456..."
|
||||
}
|
||||
```
|
||||
|
||||
## Require signed commits
|
||||
|
||||
GPG-signed commits prove authenticity. Check for commit signatures:
|
||||
|
||||
```rego
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
|
||||
allow if {
|
||||
input.git.remote == "https://github.com/moby/buildkit.git"
|
||||
input.git.commit.pgpSignature != null
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
The `pgpSignature` field is `null` for unsigned commits. For signed commits, it
|
||||
contains signature details.
|
||||
|
||||
SSH signatures work similarly:
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.git.commit.sshSignature != null
|
||||
}
|
||||
```
|
||||
|
||||
## Require signed tags
|
||||
|
||||
Annotated tags can be signed, providing a cryptographic guarantee of the
|
||||
release:
|
||||
|
||||
```rego
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
|
||||
allow if {
|
||||
input.git.remote == "https://github.com/moby/buildkit.git"
|
||||
input.git.tag.pgpSignature != null
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
The `tag` object is only available for annotated tags. It includes:
|
||||
|
||||
- `tagger.name`: Who created the tag
|
||||
- `tagger.email`: Tagger's email
|
||||
- `tagger.when`: When the tag was created
|
||||
- `message`: Tag message
|
||||
- `pgpSignature`: GPP signature (if signed)
|
||||
- `sshSignature`: SSH signature (if signed)
|
||||
|
||||
Lightweight tags don't have a `tag` object, so this policy effectively requires
|
||||
annotated, signed tags.
|
||||
|
||||
## Verify signatures with public keys
|
||||
|
||||
Use the `verify_git_signature()` function to cryptographically verify Git
|
||||
signatures against trusted public keys:
|
||||
|
||||
```rego
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
|
||||
allow if {
|
||||
input.git.remote == "https://github.com/moby/buildkit.git"
|
||||
input.git.tagName != ""
|
||||
verify_git_signature(input.git.tag, "keys.asc")
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
This verifies that Git tags are signed by keys in the `keys.asc` public
|
||||
key file. To set this up:
|
||||
|
||||
1. Export maintainer public keys:
|
||||
```console
|
||||
$ curl https://github.com/user.gpg > keys.asc
|
||||
```
|
||||
2. Place `keys.asc` alongside your policy file
|
||||
|
||||
The function verifies PGP signatures on commits or tags. See [Built-in
|
||||
functions](./built-ins.md) for more details.
|
||||
|
||||
## Apply conditional rules
|
||||
|
||||
Use different rules for different contexts. Allow unsigned refs during
|
||||
development but require signing for production:
|
||||
|
||||
```rego
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
|
||||
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, "keys.asc")
|
||||
}
|
||||
|
||||
# Non-version refs allowed in development
|
||||
allow if {
|
||||
is_buildkit
|
||||
not is_version_tag
|
||||
input.env.target != "release"
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
This policy:
|
||||
|
||||
- Defines helper rules for readability
|
||||
- Requires signed version tags from maintainers
|
||||
- Allows unsigned refs (branches, commits) unless building the release target
|
||||
- Uses `input.env.target` to detect the build target
|
||||
|
||||
Build a development target without signatures:
|
||||
|
||||
```console
|
||||
$ docker buildx build --target=dev .
|
||||
```
|
||||
|
||||
Build the release target, and signing is enforced:
|
||||
|
||||
```console
|
||||
$ docker buildx build --target=release .
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
You now understand how to validate Git repositories in build policies. To
|
||||
continue learning:
|
||||
|
||||
- Browse [Example policies](./examples.md) for complete policy patterns
|
||||
- Read [Built-in functions](./built-ins.md) for Git signature verification
|
||||
functions
|
||||
- Check the [Input reference](./inputs.md) for all available Git fields
|
||||
424
content/manuals/build/policies/validate-images.md
Normal file
424
content/manuals/build/policies/validate-images.md
Normal file
@@ -0,0 +1,424 @@
|
||||
---
|
||||
title: Validating image inputs
|
||||
linkTitle: Image validation
|
||||
description: Write policies to validate container images used in your builds
|
||||
keywords: build policies, image validation, docker images, provenance, attestations, signatures
|
||||
weight: 30
|
||||
---
|
||||
|
||||
Container images are the most common build inputs. Every `FROM` instruction
|
||||
pulls an image, and `COPY --from` references pull additional images. Validating
|
||||
these images protects your build supply chain from compromised registries,
|
||||
unexpected updates, and unauthorized base images.
|
||||
|
||||
This guide teaches you to write policies that validate image inputs,
|
||||
progressing from basic allowlisting to advanced attestation checks.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
You should understand the policy basics from the [Introduction](./intro.md):
|
||||
creating policy files, basic Rego syntax, and how policies evaluate during
|
||||
builds.
|
||||
|
||||
## What are image inputs?
|
||||
|
||||
Image inputs come from two Dockerfile instructions:
|
||||
|
||||
```dockerfile
|
||||
# FROM instructions
|
||||
FROM alpine:3.22
|
||||
FROM golang:1.25-alpine AS builder
|
||||
|
||||
# COPY --from references
|
||||
COPY --from=builder /app /app
|
||||
COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf
|
||||
```
|
||||
|
||||
Each of these references triggers a policy evaluation. Your policy can inspect
|
||||
image metadata, verify attestations, and enforce constraints before the build
|
||||
proceeds.
|
||||
|
||||
## Allowlist specific repositories
|
||||
|
||||
The simplest image policy restricts which repositories can be used. This
|
||||
prevents developers from using arbitrary images that haven't been vetted.
|
||||
|
||||
Create a policy that only allows Alpine:
|
||||
|
||||
```rego {title="Dockerfile.rego"}
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
|
||||
allow if {
|
||||
input.image.repo == "alpine"
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
This policy:
|
||||
|
||||
- Denies all inputs by default
|
||||
- Allows local build context
|
||||
- Allows any image from the `alpine` repository (any tag or digest)
|
||||
|
||||
Test it with a Dockerfile:
|
||||
|
||||
```dockerfile {title="Dockerfile"}
|
||||
FROM alpine
|
||||
RUN echo "hello"
|
||||
```
|
||||
|
||||
```console
|
||||
$ docker build .
|
||||
```
|
||||
|
||||
The build succeeds. Try changing to `FROM ubuntu`:
|
||||
|
||||
```console
|
||||
$ docker build .
|
||||
```
|
||||
|
||||
The build fails because `ubuntu` doesn't match the allowed repository.
|
||||
|
||||
## Compare semantic versions
|
||||
|
||||
Restrict images to specific version ranges using Rego's `semver` functions:
|
||||
|
||||
```rego
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
|
||||
# Allow Go 1.21 or newer
|
||||
allow if {
|
||||
input.image.repo == "golang"
|
||||
semver.is_valid(input.image.tag)
|
||||
semver.compare(input.image.tag, "1.21.0") >= 0
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
The `semver.compare(a, b)` function compares semantic versions and returns:
|
||||
|
||||
- `-1` if version `a` is less than `b`
|
||||
- `0` if versions are equal
|
||||
- `1` if version `a` is greater than `b`
|
||||
|
||||
Use `semver.is_valid()` to check if a tag is a valid semantic version before
|
||||
comparing.
|
||||
|
||||
Restrict to specific version ranges:
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.image.repo == "node"
|
||||
version := input.image.tag
|
||||
semver.is_valid(version)
|
||||
semver.compare(version, "20.0.0") >= 0 # 20.0.0 or newer
|
||||
semver.compare(version, "21.0.0") < 0 # older than 21.0.0
|
||||
}
|
||||
```
|
||||
|
||||
This allows only Node.js 20.x versions. The pattern works for any image using
|
||||
semantic versioning.
|
||||
|
||||
These `semver` functions are standard Rego built-ins documented in the [OPA
|
||||
policy
|
||||
reference](https://www.openpolicyagent.org/docs/latest/policy-reference/#semver).
|
||||
|
||||
## Require digest references
|
||||
|
||||
Tags like `alpine:3.22` can change - someone could push a new image with the
|
||||
same tag. Digests like `alpine@sha256:abc123...` are immutable.
|
||||
|
||||
### Requiring users to provide digests
|
||||
|
||||
You can require that users always specify digests in their Dockerfiles:
|
||||
|
||||
```rego
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
|
||||
allow if {
|
||||
input.image.isCanonical
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
The `isCanonical` field is `true` when the user's reference includes a digest.
|
||||
This policy would allow:
|
||||
|
||||
```dockerfile
|
||||
FROM alpine@sha256:4b7ce07002c69e8f3d704a9c5d6fd3053be500b7f1c69fc0d80990c2ad8dd412
|
||||
```
|
||||
|
||||
But reject tag-only references like `FROM alpine:3.22`.
|
||||
|
||||
### Pinning to specific digests
|
||||
|
||||
Alternatively (or additionally), you can validate that an image's actual digest
|
||||
matches a specific value, regardless of how the user wrote the reference:
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.image.repo == "alpine"
|
||||
input.image.checksum == "sha256:4b7ce07002c69e8f3d704a9c5d6fd3053be500b7f1c69fc0d80990c2ad8dd412"
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
This checks the actual content digest of the pulled image. It would allow both:
|
||||
|
||||
```dockerfile
|
||||
FROM alpine:3.22
|
||||
FROM alpine@sha256:4b7ce...
|
||||
```
|
||||
|
||||
As long as the resolved image has the specified digest. This is useful for
|
||||
pinning critical base images to known-good versions.
|
||||
|
||||
## Restrict registries
|
||||
|
||||
Control which registries your builds can pull from. This helps enforce
|
||||
corporate policies or restrict to trusted sources.
|
||||
|
||||
```rego
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
|
||||
# Allow Docker Hub images
|
||||
allow if {
|
||||
input.image.host == "docker.io" # Docker Hub
|
||||
input.image.repo == "alpine"
|
||||
}
|
||||
|
||||
# Allow images from internal registry
|
||||
allow if {
|
||||
input.image.host == "registry.company.com"
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
The `host` field contains the registry hostname. Docker Hub images use
|
||||
`"docker.io"` as the host value. Test with:
|
||||
|
||||
```dockerfile
|
||||
FROM alpine # Allowed (Docker Hub)
|
||||
FROM registry.company.com/myapp:latest # Allowed (company registry)
|
||||
FROM ghcr.io/someorg/image:latest # Denied (wrong registry)
|
||||
```
|
||||
|
||||
Use `fullRepo` when you need the complete path including registry:
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.image.fullRepo == "docker.io/library/alpine"
|
||||
}
|
||||
```
|
||||
|
||||
## Validate platform constraints
|
||||
|
||||
Multi-architecture images support different operating systems and CPU
|
||||
architectures. You can restrict builds to specific platforms:
|
||||
|
||||
```rego
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
|
||||
allow if {
|
||||
input.image.os == "linux"
|
||||
input.image.arch in ["amd64", "arm64"]
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
This policy:
|
||||
|
||||
- Defines supported architectures in a list
|
||||
- Checks `input.image.os` matches Linux
|
||||
- Verifies `input.image.arch` is in the supported list
|
||||
|
||||
The `os` and `arch` fields come from the image manifest, reflecting the actual
|
||||
image platform. This works with Docker's automatic platform selection -
|
||||
policies validate what Buildx resolves, not what you specify.
|
||||
|
||||
## Inspect image metadata
|
||||
|
||||
Images contain metadata like environment variables, labels, and working
|
||||
directories. You can validate these to ensure images meet requirements.
|
||||
|
||||
Check for specific environment variables:
|
||||
|
||||
```rego
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
|
||||
allow if {
|
||||
input.image.repo == "golang"
|
||||
input.image.workingDir == "/go"
|
||||
some ver in input.image.env
|
||||
startswith(ver, "GOLANG_VERSION=")
|
||||
some toolchain in input.image.env
|
||||
toolchain == "GOTOOLCHAIN=local"
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
This policy validates the official Go image by checking:
|
||||
|
||||
- The working directory is `/go`
|
||||
- The environment has `GOLANG_VERSION` set
|
||||
- The environment includes `GOTOOLCHAIN=local`
|
||||
|
||||
The `input.image.env` field is an array of strings in `KEY=VALUE` format.
|
||||
Use Rego's `some` iteration to search the array.
|
||||
|
||||
Check image labels:
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.image.labels["org.opencontainers.image.vendor"] == "Example Corp"
|
||||
input.image.labels["org.opencontainers.image.version"] != ""
|
||||
}
|
||||
```
|
||||
|
||||
The `labels` field is a map, so you access values with bracket notation.
|
||||
|
||||
## Require attestations and provenance
|
||||
|
||||
Modern images include [attestations](/build/metadata/attestations/):
|
||||
machine-readable metadata about how the image was built.
|
||||
[Provenance](/build/metadata/attestations/slsa-provenance/) attestations
|
||||
describe the build process, and [SBOMs](/build/metadata/attestations/sbom/)
|
||||
list the software inside.
|
||||
|
||||
Require provenance:
|
||||
|
||||
```rego
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
|
||||
allow if {
|
||||
input.image.hasProvenance
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
The `hasProvenance` field is `true` when the image has provenance or SBOM
|
||||
[attestations](../metadata/attestations/_index.md).
|
||||
|
||||
## Verify GitHub Actions signatures
|
||||
|
||||
For images built with GitHub Actions, verify they came from trusted workflows by
|
||||
inspecting signature metadata:
|
||||
|
||||
```rego
|
||||
allow if {
|
||||
input.image.repo == "myapp"
|
||||
input.image.hasProvenance
|
||||
some sig in input.image.signatures
|
||||
valid_github_signature(sig)
|
||||
}
|
||||
|
||||
# Helper to validate GitHub Actions signature
|
||||
valid_github_signature(sig) if {
|
||||
sig.signer.certificateIssuer == "CN=sigstore-intermediate,O=sigstore.dev"
|
||||
sig.signer.issuer == "https://token.actions.githubusercontent.com"
|
||||
startswith(sig.signer.buildSignerURI, "https://github.com/myorg/")
|
||||
sig.signer.runnerEnvironment == "github-hosted"
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
This pattern works with any GitHub Actions workflow using Sigstore keyless
|
||||
signing. The signature metadata provides cryptographic proof of the build's
|
||||
origin. For complete signature verification examples, see [Example
|
||||
policies](./examples.md).
|
||||
|
||||
## Combine multiple checks
|
||||
|
||||
Real policies often combine several checks. Multiple conditions in one `allow`
|
||||
rule means AND - all must be true:
|
||||
|
||||
```rego
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
|
||||
# Production images need everything
|
||||
allow if {
|
||||
input.image.repo == "alpine"
|
||||
input.image.isCanonical
|
||||
input.image.hasProvenance
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
Multiple `allow` rules means OR - any rule can match:
|
||||
|
||||
```rego
|
||||
package docker
|
||||
|
||||
default allow := false
|
||||
|
||||
allow if input.local
|
||||
|
||||
# Allow Alpine with strict checks
|
||||
allow if {
|
||||
input.image.repo == "alpine"
|
||||
input.image.isCanonical
|
||||
}
|
||||
|
||||
# Allow Go with different checks
|
||||
allow if {
|
||||
input.image.repo == "golang"
|
||||
input.image.workingDir == "/go"
|
||||
}
|
||||
|
||||
decision := {"allow": allow}
|
||||
```
|
||||
|
||||
Use this pattern to apply different requirements to different base images.
|
||||
|
||||
## Next steps
|
||||
|
||||
You now understand how to validate container images in build policies. To
|
||||
continue learning:
|
||||
|
||||
- Learn [Git repository validation](./validate-git.md) for source code inputs
|
||||
- Browse [Example policies](./examples.md) for complete policy patterns
|
||||
- Read [Built-in functions](./built-ins.md) for signature verification and
|
||||
attestation checking
|
||||
- Check the [Input reference](./inputs.md) for all available image fields
|
||||
14
content/reference/cli/docker/buildx/policy/_index.md
Normal file
14
content/reference/cli/docker/buildx/policy/_index.md
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
datafolder: buildx
|
||||
datafile: docker_buildx_policy
|
||||
title: docker buildx policy
|
||||
layout: cli
|
||||
---
|
||||
|
||||
<!--
|
||||
This page is automatically generated from Docker's source code. If you want to
|
||||
suggest a change to the text that appears here, open a ticket or pull request
|
||||
in the source repository on GitHub:
|
||||
|
||||
https://github.com/docker/buildx
|
||||
-->
|
||||
14
content/reference/cli/docker/buildx/policy/eval.md
Normal file
14
content/reference/cli/docker/buildx/policy/eval.md
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
datafolder: buildx
|
||||
datafile: docker_buildx_policy_eval
|
||||
title: docker buildx policy eval
|
||||
layout: cli
|
||||
---
|
||||
|
||||
<!--
|
||||
This page is automatically generated from Docker's source code. If you want to
|
||||
suggest a change to the text that appears here, open a ticket or pull request
|
||||
in the source repository on GitHub:
|
||||
|
||||
https://github.com/docker/buildx
|
||||
-->
|
||||
14
content/reference/cli/docker/buildx/policy/test.md
Normal file
14
content/reference/cli/docker/buildx/policy/test.md
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
datafolder: buildx
|
||||
datafile: docker_buildx_policy_test
|
||||
title: docker buildx policy test
|
||||
layout: cli
|
||||
---
|
||||
|
||||
<!--
|
||||
This page is automatically generated from Docker's source code. If you want to
|
||||
suggest a change to the text that appears here, open a ticket or pull request
|
||||
in the source repository on GitHub:
|
||||
|
||||
https://github.com/docker/buildx
|
||||
-->
|
||||
Reference in New Issue
Block a user