e2e81a
% CONTAINERS-POLICY.JSON 5 policy.json Man Page
5dd126
% Miloslav Trmač
5dd126
% September 2016
5dd126
5dd126
# NAME
5dd126
containers-policy.json - syntax for the signature verification policy file
5dd126
5dd126
## DESCRIPTION
5dd126
5dd126
Signature verification policy files are used to specify policy, e.g. trusted keys,
5dd126
applicable when deciding whether to accept an image, or individual signatures of that image, as valid.
5dd126
5dd126
By default, the policy is read from `$HOME/.config/containers/policy.json`, if it exists, otherwise from `/etc/containers/policy.json`;  applications performing verification may allow using a different policy instead.
5dd126
5dd126
## FORMAT
5dd126
5dd126
The signature verification policy file, usually called `policy.json`,
5dd126
uses a JSON format.  Unlike some other JSON files, its parsing is fairly strict:
5dd126
unrecognized, duplicated or otherwise invalid fields cause the entire file,
5dd126
and usually the entire operation, to be rejected.
5dd126
5dd126
The purpose of the policy file is to define a set of *policy requirements* for a container image,
5dd126
usually depending on its location (where it is being pulled from) or otherwise defined identity.
5dd126
5dd126
Policy requirements can be defined for:
5dd126
5dd126
- An individual *scope* in a *transport*.
5dd126
  The *transport* values are the same as the transport prefixes when pushing/pulling images (e.g. `docker:`, `atomic:`),
5dd126
  and *scope* values are defined by each transport; see below for more details.
5dd126
5dd126
  Usually, a scope can be defined to match a single image, and various prefixes of
5dd126
  such a most specific scope define namespaces of matching images.
c929c0
5dd126
- A default policy for a single transport, expressed using an empty string as a scope
c929c0
5dd126
- A global default policy.
5dd126
5dd126
If multiple policy requirements match a given image, only the requirements from the most specific match apply,
5dd126
the more general policy requirements definitions are ignored.
5dd126
5dd126
This is expressed in JSON using the top-level syntax
5dd126
```js
5dd126
{
5dd126
    "default": [/* policy requirements: global default */]
5dd126
    "transports": {
5dd126
        transport_name: {
5dd126
            "": [/* policy requirements: default for transport $transport_name */],
5dd126
            scope_1: [/* policy requirements: default for $scope_1 in $transport_name */],
5dd126
            scope_2: [/*…*/]
5dd126
            /*…*/
5dd126
        },
5dd126
        transport_name_2: {/*…*/}
5dd126
        /*…*/
5dd126
    }
5dd126
}
5dd126
```
5dd126
5dd126
The global `default` set of policy requirements is mandatory; all of the other fields
5dd126
(`transports` itself, any specific transport, the transport-specific default, etc.) are optional.
5dd126
5dd126
5dd126
## Supported transports and their scopes
5dd126
5dd126
### `atomic:`
5dd126
5dd126
The `atomic:` transport refers to images in an Atomic Registry.
5dd126
5dd126
Supported scopes use the form _hostname_[`:`_port_][`/`_namespace_[`/`_imagestream_ [`:`_tag_]]],
5dd126
i.e. either specifying a complete name of a tagged image, or prefix denoting
5dd126
a host/namespace/image stream or a wildcarded expression for matching all
5dd126
subdomains. For wildcarded subdomain matching, `*.example.com` is a valid case, but `example*.*.com` is not.
5dd126
5dd126
*Note:* The _hostname_ and _port_ refer to the container registry host and port (the one used
5dd126
e.g. for `docker pull`), _not_ to the OpenShift API host and port.
5dd126
5dd126
### `dir:`
5dd126
5dd126
The `dir:` transport refers to images stored in local directories.
5dd126
5dd126
Supported scopes are paths of directories (either containing a single image or
5dd126
subdirectories possibly containing images).
5dd126
5dd126
*Note:* The paths must be absolute and contain no symlinks. Paths violating these requirements may be silently ignored.
5dd126
5dd126
The top-level scope `"/"` is forbidden; use the transport default scope `""`,
5dd126
for consistency with other transports.
5dd126
5dd126
### `docker:`
5dd126
5dd126
The `docker:` transport refers to images in a registry implementing the "Docker Registry HTTP API V2".
5dd126
5dd126
Scopes matching individual images are named Docker references *in the fully expanded form*, either
5dd126
using a tag or digest. For example, `docker.io/library/busybox:latest` (*not* `busybox:latest`).
5dd126
5dd126
More general scopes are prefixes of individual-image scopes, and specify a repository (by omitting the tag or digest),
5dd126
a repository namespace, or a registry host (by only specifying the host name)
5dd126
or a wildcarded expression for matching all subdomains. For wildcarded subdomain
5dd126
matching, `*.example.com` is a valid case, but `example*.*.com` is not.
5dd126
5dd126
### `oci:`
5dd126
5dd126
The `oci:` transport refers to images in directories compliant with "Open Container Image Layout Specification".
5dd126
5dd126
Supported scopes use the form _directory_`:`_tag_, and _directory_ referring to
5dd126
a directory containing one or more tags, or any of the parent directories.
5dd126
5dd126
*Note:* See `dir:` above for semantics and restrictions on the directory paths, they apply to `oci:` equivalently.
5dd126
5dd126
### `tarball:`
5dd126
5dd126
The `tarball:` transport refers to tarred up container root filesystems.
5dd126
5dd126
Scopes are ignored.
5dd126
5dd126
## Policy Requirements
5dd126
5dd126
Using the mechanisms above, a set of policy requirements is looked up.  The policy requirements
5dd126
are represented as a JSON array of individual requirement objects.  For an image to be accepted,
5dd126
*all* of the requirements must be satisfied simultaneously.
5dd126
5dd126
The policy requirements can also be used to decide whether an individual signature is accepted (= is signed by a recognized key of a known author);
5dd126
in that case some requirements may apply only to some signatures, but each signature must be accepted by *at least one* requirement object.
5dd126
5dd126
The following requirement objects are supported:
5dd126
5dd126
### `insecureAcceptAnything`
5dd126
5dd126
A simple requirement with the following syntax
5dd126
5dd126
```json
5dd126
{"type":"insecureAcceptAnything"}
5dd126
```
5dd126
5dd126
This requirement accepts any image (but note that other requirements in the array still apply).
5dd126
5dd126
When deciding to accept an individual signature, this requirement does not have any effect; it does *not* cause the signature to be accepted, though.
5dd126
5dd126
This is useful primarily for policy scopes where no signature verification is required;
5dd126
because the array of policy requirements must not be empty, this requirement is used
5dd126
to represent the lack of requirements explicitly.
5dd126
5dd126
### `reject`
5dd126
5dd126
A simple requirement with the following syntax:
5dd126
5dd126
```json
5dd126
{"type":"reject"}
5dd126
```
5dd126
5dd126
This requirement rejects every image, and every signature.
5dd126
5dd126
### `signedBy`
5dd126
169ddb
This requirement requires an image to be signed using “simple signing” with an expected identity, or accepts a signature if it is using an expected identity and key.
5dd126
5dd126
```js
5dd126
{
5dd126
    "type":    "signedBy",
5dd126
    "keyType": "GPGKeys", /* The only currently supported value */
5dd126
    "keyPath": "/path/to/local/keyring/file",
169ddb
    "keyPaths": ["/path/to/local/keyring/file1","/path/to/local/keyring/file2"…],
5dd126
    "keyData": "base64-encoded-keyring-data",
5dd126
    "signedIdentity": identity_requirement
5dd126
}
5dd126
```
5dd126
5dd126
169ddb
Exactly one of `keyPath`, `keyPaths` and `keyData` must be present, containing a GPG keyring of one or more public keys.  Only signatures made by these keys are accepted.
5dd126
5dd126
The `signedIdentity` field, a JSON object, specifies what image identity the signature claims about the image.
5dd126
One of the following alternatives are supported:
5dd126
5dd126
- The identity in the signature must exactly match the image identity.  Note that with this, referencing an image by digest (with a signature claiming a _repository_`:`_tag_ identity) will fail.
5dd126
5dd126
  ```json
5dd126
  {"type":"matchExact"}
5dd126
  ```
5dd126
- If the image identity carries a tag, the identity in the signature must exactly match;
5dd126
  if the image identity uses a digest reference, the identity in the signature must be in the same repository as the image identity (using any tag).
5dd126
5dd126
  (Note that with images identified using digest references, the digest from the reference is validated even before signature verification starts.)
5dd126
5dd126
  ```json
5dd126
  {"type":"matchRepoDigestOrExact"}
5dd126
  ```
5dd126
- The identity in the signature must be in the same repository as the image identity.  This is useful e.g. to pull an image using the `:latest` tag when the image is signed with a tag specifying an exact image version.
5dd126
5dd126
  ```json
5dd126
  {"type":"matchRepository"}
5dd126
  ```
5dd126
- The identity in the signature must exactly match a specified identity.
5dd126
  This is useful e.g. when locally mirroring images signed using their public identity.
5dd126
5dd126
  ```js
5dd126
  {
5dd126
      "type": "exactReference",
5dd126
      "dockerReference": docker_reference_value
5dd126
  }
5dd126
  ```
5dd126
- The identity in the signature must be in the same repository as a specified identity.
5dd126
  This combines the properties of `matchRepository` and `exactReference`.
5dd126
5dd126
  ```js
5dd126
  {
5dd126
      "type": "exactRepository",
5dd126
      "dockerRepository": docker_repository_value
5dd126
  }
5dd126
  ```
5dd126
- Prefix remapping:
5dd126
5dd126
  If the image identity matches the specified prefix, that prefix is replaced by the specified “signed prefix”
5dd126
  (otherwise it is used as unchanged and no remapping takes place);
5dd126
  matching then follows the `matchRepoDigestOrExact` semantics documented above
5dd126
  (i.e. if the image identity carries a tag, the identity in the signature must exactly match,
5dd126
  if it uses a digest reference, the repository must match).
5dd126
5dd126
  The `prefix` and `signedPrefix` values can be either host[:port] values
5dd126
  (matching exactly the same host[:port], string),
5dd126
  repository namespaces, or repositories (i.e. they must not contain tags/digests),
5dd126
  and match as prefixes *of the fully expanded form*.
5dd126
  For example, `docker.io/library/busybox` (*not* `busybox`) to specify that single repository,
5dd126
  or `docker.io/library` (not an empty string) to specify the parent namespace of `docker.io/library/busybox`==`busybox`).
5dd126
5dd126
  The `prefix` value is usually the same as the scope containing the parent `signedBy` requirement.
5dd126
5dd126
  ```js
5dd126
  {
5dd126
      "type": "remapIdentity",
5dd126
      "prefix": prefix,
5dd126
      "signedPrefix": prefix,
5dd126
  }
5dd126
  ```
5dd126
5dd126
If the `signedIdentity` field is missing, it is treated as `matchRepoDigestOrExact`.
5dd126
5dd126
*Note*: `matchExact`, `matchRepoDigestOrExact` and `matchRepository` can be only used if a Docker-like image identity is
5dd126
provided by the transport.  In particular, the `dir:` and `oci:` transports can be only
5dd126
used with `exactReference` or `exactRepository`.
5dd126
5dd126
5dd126
169ddb
169ddb
### `sigstoreSigned`
169ddb
169ddb
This requirement requires an image to be signed using a sigstore signature with an expected identity and key.
169ddb
169ddb
```js
169ddb
{
169ddb
    "type":    "sigstoreSigned",
c929c0
    "keyPath": "/path/to/local/public/key/file",
c929c0
    "keyData": "base64-encoded-public-key-data",
c929c0
    "fulcio": {
c929c0
        "caPath": "/path/to/local/CA/file",
c929c0
        "caData": "base64-encoded-CA-data",
c929c0
        "oidcIssuer": "https://expected.OIDC.issuer/",
c929c0
        "subjectEmail", "expected-signing-user@example.com",
c929c0
    },
c929c0
    "rekorPublicKeyPath": "/path/to/local/public/key/file",
c929c0
    "rekorPublicKeyData": "base64-encoded-public-key-data",
169ddb
    "signedIdentity": identity_requirement
169ddb
}
169ddb
```
c929c0
Exactly one of `keyPath`, `keyData` and `fulcio` must be present.
c929c0
c929c0
If `keyPath` or `keyData` is present, it contains a sigstore public key.
c929c0
Only signatures made by this key are accepted.
c929c0
c929c0
If `fulcio` is present, the signature must be based on a Fulcio-issued certificate.
c929c0
One of `caPath` and `caData` must be specified, containing the public key of the Fulcio instance.
c929c0
Both `oidcIssuer` and `subjectEmail` are mandatory,
c929c0
exactly specifying the expected identity provider,
c929c0
and the identity of the user obtaining the Fulcio certificate.
c929c0
c929c0
At most one of `rekorPublicKeyPath` and `rekorPublicKeyData` can be present;
c929c0
it is mandatory if `fulcio` is specified.
c929c0
If a Rekor public key is specified,
c929c0
the signature must have been uploaded to a Rekor server
c929c0
and the signature must contain an (offline-verifiable) “signed entry timestamp”
c929c0
proving the existence of the Rekor log record,
c929c0
signed by the provided public key.
169ddb
169ddb
The `signedIdentity` field has the same semantics as in the `signedBy` requirement described above.
169ddb
Note that `cosign`-created signatures only contain a repository, so only `matchRepository` and `exactRepository` can be used to accept them (and that does not protect against substitution of a signed image with an unexpected tag).
169ddb
169ddb
To use this with images hosted on image registries, the relevant registry or repository must have the `use-sigstore-attachments` option enabled in containers-registries.d(5).
169ddb
5dd126
## Examples
5dd126
5dd126
It is *strongly* recommended to set the `default` policy to `reject`, and then
5dd126
selectively allow individual transports and scopes as desired.
5dd126
5dd126
### A reasonably locked-down system
5dd126
5dd126
(Note that the `/*`…`*/` comments are not valid in JSON, and must not be used in real policies.)
5dd126
5dd126
```js
5dd126
{
5dd126
    "default": [{"type": "reject"}], /* Reject anything not explicitly allowed */
5dd126
    "transports": {
5dd126
        "docker": {
5dd126
            /* Allow installing images from a specific repository namespace, without cryptographic verification.
5dd126
               This namespace includes images like openshift/hello-openshift and openshift/origin. */
5dd126
            "docker.io/openshift": [{"type": "insecureAcceptAnything"}],
5dd126
            /* Similarly, allow installing the “official” busybox images.  Note how the fully expanded
5dd126
               form, with the explicit /library/, must be used. */
169ddb
            "docker.io/library/busybox": [{"type": "insecureAcceptAnything"}],
5dd126
            /* Allow installing images from all subdomains */
169ddb
            "*.temporary-project.example.com": [{"type": "insecureAcceptAnything"}],
169ddb
            /* A sigstore-signed repository */
169ddb
            "hostname:5000/myns/sigstore-signed-with-full-references": [
169ddb
                {
169ddb
                    "type": "sigstoreSigned",
169ddb
                    "keyPath": "/path/to/sigstore-pubkey.pub"
169ddb
                }
169ddb
            ],
c929c0
            /* A sigstore-signed repository using the community Fulcio+Rekor servers.
c929c0
c929c0
               The community servers’ public keys can be obtained from
c929c0
               https://github.com/sigstore/sigstore/tree/main/pkg/tuf/repository/targets .  */
c929c0
            "hostname:5000/myns/sigstore-signed-fulcio-rekor": [
c929c0
                {
c929c0
                    "type": "sigstoreSigned",
c929c0
                    "fulcio": {
c929c0
                        "caPath": "/path/to/fulcio_v1.crt.pem",
c929c0
                        "oidcIssuer": "https://github.com/login/oauth",
c929c0
                        "subjectEmail": "test-user@example.com"
c929c0
                    },
c929c0
                    "rekorPublicKeyPath": "/path/to/rekor.pub",
c929c0
                }
c929c0
            ],
169ddb
            /* A sigstore-signed repository, accepts signatures by /usr/bin/cosign */
169ddb
            "hostname:5000/myns/sigstore-signed-allows-malicious-tag-substitution": [
169ddb
                {
169ddb
                    "type": "sigstoreSigned",
169ddb
                    "keyPath": "/path/to/sigstore-pubkey.pub",
169ddb
                    "signedIdentity": {"type": "matchRepository"}
169ddb
                }
c929c0
            ],
c929c0
            /* A sigstore-signed repository using the community Fulcio+Rekor servers,
c929c0
               accepts signatures by /usr/bin/cosign.
c929c0
c929c0
               The community servers’ public keys can be obtained from
c929c0
               https://github.com/sigstore/sigstore/tree/main/pkg/tuf/repository/targets .  */
c929c0
            "hostname:5000/myns/sigstore-signed-fulcio-rekor- allows-malicious-tag-substitution": [
c929c0
                {
c929c0
                    "type": "sigstoreSigned",
c929c0
                    "fulcio": {
c929c0
                        "caPath": "/path/to/fulcio_v1.crt.pem",
c929c0
                        "oidcIssuer": "https://github.com/login/oauth",
c929c0
                        "subjectEmail": "test-user@example.com"
c929c0
                    },
c929c0
                    "rekorPublicKeyPath": "/path/to/rekor.pub",
c929c0
                    "signedIdentity": { "type": "matchRepository" }
c929c0
                }
169ddb
            ]
c929c0
              /* Other docker: images use the global default policy and are rejected */
5dd126
        },
5dd126
        "dir": {
5dd126
            "": [{"type": "insecureAcceptAnything"}] /* Allow any images originating in local directories */
5dd126
        },
5dd126
        "atomic": {
5dd126
            /* The common case: using a known key for a repository or set of repositories */
5dd126
            "hostname:5000/myns/official": [
5dd126
                {
5dd126
                    "type": "signedBy",
5dd126
                    "keyType": "GPGKeys",
5dd126
                    "keyPath": "/path/to/official-pubkey.gpg"
5dd126
                }
5dd126
            ],
5dd126
            /* A more complex example, for a repository which contains a mirror of a third-party product,
5dd126
               which must be signed-off by local IT */
5dd126
            "hostname:5000/vendor/product": [
5dd126
                { /* Require the image to be signed by the original vendor, using the vendor's repository location. */
5dd126
                    "type": "signedBy",
5dd126
                    "keyType": "GPGKeys",
5dd126
                    "keyPath": "/path/to/vendor-pubkey.gpg",
5dd126
                    "signedIdentity": {
5dd126
                        "type": "exactRepository",
5dd126
                        "dockerRepository": "vendor-hostname/product/repository"
5dd126
                    }
5dd126
                },
5dd126
                { /* Require the image to _also_ be signed by a local reviewer. */
5dd126
                    "type": "signedBy",
5dd126
                    "keyType": "GPGKeys",
5dd126
                    "keyPath": "/path/to/reviewer-pubkey.gpg"
5dd126
                }
5dd126
            ],
5dd126
            /* A way to mirror many repositories from a single vendor */
5dd126
            "private-mirror:5000/vendor-mirror": [
5dd126
                { /* Require the image to be signed by the original vendor, using the vendor's repository location.
5dd126
                     For example, private-mirror:5000/vendor-mirror/productA/image1:latest needs to be signed as
5dd126
                     vendor.example/productA/image1:latest . */
5dd126
                    "type": "signedBy",
5dd126
                    "keyType": "GPGKeys",
5dd126
                    "keyPath": "/path/to/vendor-pubkey.gpg",
5dd126
                    "signedIdentity": {
5dd126
                        "type": "remapIdentity",
5dd126
                        "prefix": "private-mirror:5000/vendor-mirror",
169ddb
                        "signedPrefix": "vendor.example.com"
5dd126
                    }
5dd126
                }
5dd126
            ]
5dd126
        }
5dd126
    }
5dd126
}
5dd126
```
5dd126
5dd126
### Completely disable security, allow all images, do not trust any signatures
5dd126
5dd126
```json
5dd126
{
5dd126
    "default": [{"type": "insecureAcceptAnything"}]
5dd126
}
5dd126
```
5dd126
## SEE ALSO
5dd126
  atomic(1)
5dd126
5dd126
## HISTORY
5dd126
August 2018, Rename to containers-policy.json(5) by Valentin Rothberg <vrothberg@suse.com>
5dd126
5dd126
September 2016, Originally compiled by Miloslav Trmač <mitr@redhat.com>