dwww Home | Manual pages | Find package

CONTAINERS-POLICY.JSON(5)             Page            CONTAINERS-POLICY.JSON(5)

Miloslav Trmač September 2016

NAME
       containers-policy.json  -  syntax  for the signature verification policy
       file

DESCRIPTION
       Signature verification policy files are used  to  specify  policy,  e.g.
       trusted  keys,  applicable  when deciding whether to accept an image, or
       individual signatures of that image, as valid.

       By  default,  the  policy  is  read  from  $HOME/.config/containers/pol-
       icy.json, if it exists, otherwise from /etc/containers/policy.json;  ap-
       plications  performing  verification  may allow using a different policy
       instead.

FORMAT
       The signature verification policy file, usually called policy.json, uses
       a JSON format.  Unlike some other JSON  files,  its  parsing  is  fairly
       strict:  unrecognized,  duplicated or otherwise invalid fields cause the
       entire file, and usually the entire operation, to be rejected.

       The purpose of the policy file is to define a set of policy requirements
       for a container image, usually depending on its location  (where  it  is
       being pulled from) or otherwise defined identity.

       Policy requirements can be defined for:

              • An  individual  scope in a transport.  The transport values are
                the same as the transport prefixes when pushing/pulling  images
                (e.g.  docker:,  atomic:), and scope values are defined by each
                transport; see below for more details.

       Usually, a scope can be defined to match a  single  image,  and  various
       prefixes of
         such a most specific scope define namespaces of matching images.

              • A  default  policy  for  a single transport, expressed using an
                empty string as a scope

              • A global default policy.

       If multiple policy requirements match a given image, only  the  require-
       ments  from  the  most specific match apply, the more general policy re-
       quirements definitions are ignored.

       This is expressed in JSON using the top-level syntax

       {
           "default": [/* policy requirements: global default */]
           "transports": {
               transport_name: {
                   "": [/* policy requirements: default for transport $transport_name */],
                   scope_1: [/* policy requirements: default for $scope_1 in $transport_name */],
                   scope_2: [/*…*/]
                   /*…*/
               },
               transport_name_2: {/*…*/}
               /*…*/
           }
       }

       The global default set of policy requirements is mandatory; all  of  the
       other  fields (transports itself, any specific transport, the transport-
       specific default, etc.) are optional.

Supported transports and their scopes
       See containers-transports(5) for general documentation about the  trans-
       ports and their reference syntax.

   atomic:
       The deprecated atomic: transport refers to images in an Atomic Registry.

       Supported  scopes  use  the form hostname[:port][/namespace[/imagestream
       [:tag]]], i.e. either specifying a complete name of a tagged  image,  or
       prefix  denoting  a host/namespace/image stream, or a wildcarded expres-
       sion starting with *. for matching all subdomains. For wildcarded subdo-
       main matching, *.example.com is a valid case, but example*.*.com is not.

       Note: The hostname and port refer to the  container  registry  host  and
       port  (the one used e.g. for docker pull), not to the OpenShift API host
       and port.

   containers-storage:
       Supported scopes have the form [storage-specifier]image-scope.

       [storage-specifier]  is  usually  [graph-driver-name@graph-root],   e.g.
       [overlay@/var/lib/containers/storage].

       image-scope  matching the individual image is - a named Docker reference
       in the fully expanded form, either using a tag or digest.  For  example,
       docker.io/library/busybox:latest  (not busybox:latest) - and/or (depend-
       ing on which one the user’s input provides) @image-id

       More general scopes are prefixes of individual-image scopes, and specify
       a less-precisely-specified image, or a repository (by omitting first the
       image ID, if any; then the digest, if any; and finally a tag, if any), a
       repository namespace, or a registry host (by only  specifying  the  host
       name and possibly a port number).

       Finally,  two full-store specifiers matching all images in the store are
       valid scopes: - [graph-driver-name@graph-root] and - [graph-root]

       Note that some tools like Podman and Buildah hard-code overrides of  the
       signature  verification policy for “push” operations, allowing these op-
       erations regardless of configuration in policy.json.

   dir:
       The dir: transport refers to images stored in local directories.

       Supported scopes are paths of directories (either  containing  a  single
       image or subdirectories possibly containing images).

       Note:  -  The paths must be absolute and contain no symlinks. Paths vio-
       lating these requirements may be  silently  ignored.   -  The  top-level
       scope "/" is forbidden; use the transport default scope "",
         for consistency with other transports.

   docker:
       The  docker:  transport  refers to images in a registry implementing the
       "Docker Registry HTTP API V2".

       Scopes matching individual images are named  Docker  references  in  the
       fully  expanded  form,  either  using  a  tag  or  digest.  For example,
       docker.io/library/busybox:latest (not busybox:latest).

       More general scopes are prefixes of individual-image scopes, and specify
       a repository (by omitting the tag or digest), a repository namespace, or
       a registry host (by only specifying the host name and  possibly  a  port
       number)  or  a  wildcarded expression starting with *., for matching all
       subdomains (not including  a  port  number).  For  wildcarded  subdomain
       matching, *.example.com is a valid case, but example*.*.com is not.

   docker-archive:
       Only the default "" scope is supported.

   docker-daemon:
       For  references using the algo:digest format (referring to an image ID),
       only the default "" scope is used.

       For images using a named reference, scopes  matching  individual  images
       are  in the fully expanded form, either using a tag or digest. For exam-
       ple, docker.io/library/busybox:latest (not busybox:latest).

       More general named scopes are prefixes of individual-image  scopes,  and
       specify a repository (by omitting the tag or digest), a repository name-
       space, or a registry host (by only specifying the host name and possibly
       a port number) or a wildcarded expression starting with *., for matching
       all  subdomains  (not including a port number). For wildcarded subdomain
       matching, *.example.com is a valid case, but example*.*.com is not.

   oci:
       The oci: transport refers to images in directories compliant with  "Open
       Container Image Layout Specification".

       Supported scopes are paths to directories (either containing an OCI lay-
       out, or subdirectories possibly containing OCI layout directories).  The
       reference annotation value, if any, is not used.

       Note:  -  The paths must be absolute and contain no symlinks. Paths vio-
       lating these requirements may be  silently  ignored.   -  The  top-level
       scope "/" is forbidden; use the transport default scope "",
         for consistency with other transports.

   oci-archive:
       Supported scopes are paths to OCI archives, and their parent directories
       (either containing a single archive, or subdirectories possibly contain-
       ing archives).  The reference annotation value, if any, is not used.

       Note:  -  The paths must be absolute and contain no symlinks. Paths vio-
       lating these requirements may be  silently  ignored.   -  The  top-level
       scope "/" is forbidden; use the transport default scope "",
         for consistency with other transports.

   ostree:
       Supported  scopes  have the form repo-path:image-scope; _repopath is the
       path to the OSTree repository.

       image-scope is the _dockerreference part of the reference, with  with  a
       :latest  tag  implied if no tag is present, and parent namespaces of the
       _dockerreference value (by omitting the tag, or a  prefix  specifying  a
       higher-level namespace).

       Note:  -  The  _repopath must be absolute and contain no symlinks. Paths
       violating these requirements may be silently ignored.

   sif:
       Supported scopes are paths to Singularity images, and their  parent  di-
       rectories (either containing images, or subdirectories possibly contain-
       ing images).

       Note:  -  The paths must be absolute and contain no symlinks. Paths vio-
       lating these requirements may be  silently  ignored.   -  The  top-level
       scope "/" is forbidden; use the transport default scope "",
         for consistency with other transports.

   tarball:
       The  tarball: transport is an implementation detail of some import work-
       flows. Only the default "" scope is supported.

Policy Requirements
       Using the mechanisms above, a set of policy requirements is  looked  up.
       The  policy  requirements  are represented as a JSON array of individual
       requirement objects.  For an image to be accepted, all of  the  require-
       ments must be satisfied simultaneously.

       The policy requirements can also be used to decide whether an individual
       signature  is  accepted  (= is signed by a recognized key of a known au-
       thor); in that case some requirements may apply only to some signatures,
       but each signature must be accepted by at least one requirement object.

       The following requirement objects are supported:

   insecureAcceptAnything
       A simple requirement with the following syntax

       {"type":"insecureAcceptAnything"}

       This requirement accepts any image (but note that other requirements  in
       the array still apply).

       When  deciding  to accept an individual signature, this requirement does
       not have any effect; it does not cause the  signature  to  be  accepted,
       though.

       This  is useful primarily for policy scopes where no signature verifica-
       tion is required; because the array of policy requirements must  not  be
       empty,  this  requirement  is used to represent the lack of requirements
       explicitly.

   reject
       A simple requirement with the following syntax:

       {"type":"reject"}

       This requirement rejects every image, and every signature.

   signedBy
       This requirement requires an image to be signed using  “simple  signing”
       with  an expected identity, or accepts a signature if it is using an ex-
       pected identity and key.

       {
           "type":    "signedBy",
           "keyType": "GPGKeys", /* The only currently supported value */
           "keyPath": "/path/to/local/keyring/file",
           "keyPaths": ["/path/to/local/keyring/file1","/path/to/local/keyring/file2"…],
           "keyData": "base64-encoded-keyring-data",
           "signedIdentity": identity_requirement
       }

       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.

       The signedIdentity field, a JSON object, specifies what  image  identity
       the signature claims about the image.  One of the following alternatives
       are supported:

              • 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.

         {"type":"matchExact"}

              • If the image identity carries a tag, the identity in the signa-
                ture must exactly match; 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).

       (Note that with images identified using digest  references,  the  digest
       from  the  reference  is  validated  even  before signature verification
       starts.)

         {"type":"matchRepoDigestOrExact"}

              • 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.

         {"type":"matchRepository"}

              • The  identity  in  the signature must exactly match a specified
                identity.  This is useful e.g. when  locally  mirroring  images
                signed using their public identity.

         {
             "type": "exactReference",
             "dockerReference": docker_reference_value
         }

              • The identity in the signature must be in the same repository as
                a   specified   identity.   This  combines  the  properties  of
                matchRepository and exactReference.

         {
             "type": "exactRepository",
             "dockerRepository": docker_repository_value
         }

              • Prefix remapping:

       If the image identity matches the specified prefix, that prefix  is  re-
       placed by the specified “signed prefix”
         (otherwise it is used as unchanged and no remapping takes place);
         matching  then follows the matchRepoDigestOrExact semantics documented
       above
         (i.e. if the image identity carries a tag, the identity in the  signa-
       ture must exactly match,
         if it uses a digest reference, the repository must match).

       The prefix and signedPrefix values can be either host[:port] values
         (matching exactly the same host[:port], string),
         repository  namespaces,  or  repositories  (i.e. they must not contain
       tags/digests),
         and match as prefixes of the fully expanded form.
         For example, docker.io/library/busybox (not busybox) to  specify  that
       single repository,
         or docker.io/library (not an empty string) to specify the parent name-
       space of docker.io/library/busybox==busybox).

       The  prefix value is usually the same as the scope containing the parent
       signedBy requirement.

         {
             "type": "remapIdentity",
             "prefix": prefix,
             "signedPrefix": prefix,
         }

       If the signedIdentity field is missing, it is treated as  matchRepoDige-
       stOrExact.

       Note: matchExact, matchRepoDigestOrExact and matchRepository can be only
       used  if  a Docker-like image identity is provided by the transport.  In
       particular, the dir: and oci: transports can be only used with exactRef-
       erence or exactRepository.

   sigstoreSigned
       This requirement requires an image to be signed using a sigstore  signa-
       ture with an expected identity and key.

       {
           "type":    "sigstoreSigned",
           "keyPath": "/path/to/local/public/key/file",
           "keyPaths": ["/path/to/first/public/key/one", "/path/to/first/public/key/two"],
           "keyData": "base64-encoded-public-key-data",
           "keyDatas": ["base64-encoded-public-key-one-data", "base64-encoded-public-key-two-data"]
           "fulcio": {
               "caPath": "/path/to/local/CA/file",
               "caData": "base64-encoded-CA-data",
               "oidcIssuer": "https://expected.OIDC.issuer/",
               "subjectEmail", "expected-signing-user@example.com",
           },
           "pki": {
               "caRootsPath": "/path/to/local/CARoots/file",
               "caRootsData": "base64-encoded-CARoots-data",
               "caIntermediatesPath": "/path/to/local/CAIntermediates/file",
               "caIntermediatesData": "base64-encoded-CAIntermediates-data",
               "subjectHostname": "expected-signing-hostname.example.com",
               "subjectEmail": "expected-signing-user@example.com"
           },
           "rekorPublicKeyPath": "/path/to/local/public/key/file",
           "rekorPublicKeyPaths": ["/path/to/local/public/key/one","/path/to/local/public/key/two"],
           "rekorPublicKeyData": "base64-encoded-public-key-data",
           "rekorPublicKeyDatas": ["base64-encoded-public-key-one-data","base64-encoded-public-key-two-data"],
           "signedIdentity": identity_requirement
       }

       Exactly one of keyPath, keyPaths, keyData, keyDatas, fulcio and pki must
       be present.

       If  keyPath  or  keyData  is present, it contains a sigstore public key.
       Only signatures made by this key are accepted.

       If keyPaths or keyDatas is present, it contains  sigstore  public  keys.
       Only signatures made by any key in the list are accepted.

       If  fulcio  is  present,  the signature must be based on a Fulcio-issued
       certificate.  One of caPath and caData must be specified, containing the
       public key of the Fulcio instance.  Both oidcIssuer and subjectEmail are
       mandatory, exactly specifying the expected identity  provider,  and  the
       identity of the user obtaining the Fulcio certificate.

       If  pki  is  present,  the signature must be based on a non-Fulcio X.509
       certificate.  One of caRootsPath and caRootsData must be specified, con-
       taining certificates of the CAs.  Only one  of  caIntermediatesPath  and
       caIntermediatesData  can  be present, containing certificates of the in-
       termediate CAs.  One of subjectEmail and subjectHostname must be  speci-
       fied,  exactly specifying the expected identity to which the certificate
       was issued.

       At most one of rekorPublicKeyPath, rekorPublicKeyPaths,  rekorPublicKey-
       Data  and  rekorPublicKeyDatas can be present; it is mandatory if fulcio
       is specified.  If a Rekor public key is specified,  the  signature  must
       have  been  uploaded to a Rekor server and the signature must contain an
       (offline-verifiable) “signed entry timestamp” proving the  existence  of
       the Rekor log record, signed by one of the provided public keys.

       The  signedIdentity  field has the same semantics as in the signedBy re-
       quirement described above.  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).

       To use this with images hosted on image registries, the use-sigstore-at-
       tachments option needs to be enabled for the relevant registry or repos-
       itory in the client's containers-registries.d(5).

Examples
       It is strongly recommended to set the default policy to reject, and then
       selectively allow individual transports and scopes as desired.

   A reasonably locked-down system
       (Note  that  the  /*…*/  comments are not valid in JSON, and must not be
       used in real policies.)

       {
           "default": [{"type": "reject"}], /* Reject anything not explicitly allowed */
           "transports": {
               "docker": {
                   /* Allow installing images from a specific repository namespace, without cryptographic verification.
                      This namespace includes images like openshift/hello-openshift and openshift/origin. */
                   "docker.io/openshift": [{"type": "insecureAcceptAnything"}],
                   /* Similarly, allow installing the “official” busybox images.  Note how the fully expanded
                      form, with the explicit /library/, must be used. */
                   "docker.io/library/busybox": [{"type": "insecureAcceptAnything"}],
                   /* Allow installing images from all subdomains */
                   "*.temporary-project.example.com": [{"type": "insecureAcceptAnything"}],
                   /* A sigstore-signed repository */
                   "hostname:5000/myns/sigstore-signed-with-full-references": [
                       {
                           "type": "sigstoreSigned",
                           "keyPath": "/path/to/sigstore-pubkey.pub"
                       }
                   ],
                   /* A sigstore-signed repository using the community Fulcio+Rekor servers.

                      The community servers’ public keys can be obtained from
                      https://github.com/sigstore/sigstore/tree/main/pkg/tuf/repository/targets .  */
                   "hostname:5000/myns/sigstore-signed-fulcio-rekor": [
                       {
                           "type": "sigstoreSigned",
                           "fulcio": {
                               "caPath": "/path/to/fulcio_v1.crt.pem",
                               "oidcIssuer": "https://github.com/login/oauth",
                               "subjectEmail": "test-user@example.com"
                           },
                           "rekorPublicKeyPath": "/path/to/rekor.pub",
                       }
                   ],
                   /* A Sigstore-signed repository using a certificate generated by a custom public-key infrastructure.*/
                   "hostname:5000/myns/sigstore-signed-byopki": [
                       {
                           "type": "sigstoreSigned",
                           "pki": {
                               "caRootsPath": "/path/to/pki_root_crts.pem",
                               "caIntermediatesPath": "/path/to/pki_intermediate_crts.pem",
                               "subjectHostname": "test-user.example.com"
                               "subjectEmail": "test-user@example.com"
                           }
                       }
                   ],
                   /* A sigstore-signed repository, accepts signatures by /usr/bin/cosign */
                   "hostname:5000/myns/sigstore-signed-allows-malicious-tag-substitution": [
                       {
                           "type": "sigstoreSigned",
                           "keyPath": "/path/to/sigstore-pubkey.pub",
                           "signedIdentity": {"type": "matchRepository"}
                       }
                   ],
                   /* A sigstore-signed repository using the community Fulcio+Rekor servers,
                      accepts signatures by /usr/bin/cosign.

                      The community servers’ public keys can be obtained from
                      https://github.com/sigstore/sigstore/tree/main/pkg/tuf/repository/targets .  */
                   "hostname:5000/myns/sigstore-signed-fulcio-rekor- allows-malicious-tag-substitution": [
                       {
                           "type": "sigstoreSigned",
                           "fulcio": {
                               "caPath": "/path/to/fulcio_v1.crt.pem",
                               "oidcIssuer": "https://github.com/login/oauth",
                               "subjectEmail": "test-user@example.com"
                           },
                           "rekorPublicKeyPath": "/path/to/rekor.pub",
                           "signedIdentity": { "type": "matchRepository" }
                       }
                   ]
                     /* Other docker: images use the global default policy and are rejected */
               },
               "dir": {
                   "": [{"type": "insecureAcceptAnything"}] /* Allow any images originating in local directories */
               },
               "atomic": {
                   /* The common case: using a known key for a repository or set of repositories */
                   "hostname:5000/myns/official": [
                       {
                           "type": "signedBy",
                           "keyType": "GPGKeys",
                           "keyPath": "/path/to/official-pubkey.gpg"
                       }
                   ],
                   /* A more complex example, for a repository which contains a mirror of a third-party product,
                      which must be signed-off by local IT */
                   "hostname:5000/vendor/product": [
                       { /* Require the image to be signed by the original vendor, using the vendor's repository location. */
                           "type": "signedBy",
                           "keyType": "GPGKeys",
                           "keyPath": "/path/to/vendor-pubkey.gpg",
                           "signedIdentity": {
                               "type": "exactRepository",
                               "dockerRepository": "vendor-hostname/product/repository"
                           }
                       },
                       { /* Require the image to _also_ be signed by a local reviewer. */
                           "type": "signedBy",
                           "keyType": "GPGKeys",
                           "keyPath": "/path/to/reviewer-pubkey.gpg"
                       }
                   ],
                   /* A way to mirror many repositories from a single vendor */
                   "private-mirror:5000/vendor-mirror": [
                       { /* Require the image to be signed by the original vendor, using the vendor's repository location.
                            For example, private-mirror:5000/vendor-mirror/productA/image1:latest needs to be signed as
                            vendor.example/productA/image1:latest . */
                           "type": "signedBy",
                           "keyType": "GPGKeys",
                           "keyPath": "/path/to/vendor-pubkey.gpg",
                           "signedIdentity": {
                               "type": "remapIdentity",
                               "prefix": "private-mirror:5000/vendor-mirror",
                               "signedPrefix": "vendor.example.com"
                           }
                       }
                   ]
               }
           }
       }

   Completely disable security, allow all images, do not trust any signatures
       {
           "default": [{"type": "insecureAcceptAnything"}]
       }

SEE ALSO
       atomic(1)

HISTORY
       August 2018, Rename to containers-policy.json(5)  by  Valentin  Rothberg
       vrothberg@suse.com ⟨mailto:vrothberg@suse.com⟩

       September  2016,  Originally  compiled by Miloslav Trmač mitr@redhat.com
       ⟨mailto:mitr@redhat.com⟩

Man                               policy.json         CONTAINERS-POLICY.JSON(5)

Generated by dwww version 1.16 on Tue Dec 16 06:38:18 CET 2025.