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