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