1CONTAINERS-POLICY.JSON(5)            Page            CONTAINERS-POLICY.JSON(5)
2
3
4
5Miloslav Trmač September 2016
6
7

NAME

9       containers-policy.json  -  syntax for the signature verification policy
10       file
11
12

DESCRIPTION

14       Signature verification policy files are used to  specify  policy,  e.g.
15       trusted  keys,  applicable when deciding whether to accept an image, or
16       individual signatures of that image, as valid.
17
18
19       By default,  the  policy  is  read  from  $HOME/.config/containers/pol‐
20       icy.json,  if  it  exists,  otherwise from /etc/containers/policy.json;
21       applications performing verification may allow using a different policy
22       instead.
23
24

FORMAT

26       The  signature  verification  policy  file, usually called policy.json,
27       uses a JSON format.  Unlike some  other  JSON  files,  its  parsing  is
28       fairly  strict:  unrecognized,  duplicated  or otherwise invalid fields
29       cause the entire file, and usually the  entire  operation,  to  be  re‐
30       jected.
31
32
33       The  purpose  of  the policy file is to define a set of policy require‐
34       ments for a container image, usually depending on its  location  (where
35       it is being pulled from) or otherwise defined identity.
36
37
38       Policy requirements can be defined for:
39
40
41              • An  individual scope in a transport.  The transport values are
42                the same as the transport prefixes when pushing/pulling images
43                (e.g.  docker:, atomic:), and scope values are defined by each
44                transport; see below for more details.
45
46
47
48       Usually, a scope can be defined to match a single  image,  and  various
49       prefixes of
50         such a most specific scope define namespaces of matching images.
51
52
53              • A  default  policy  for a single transport, expressed using an
54                empty string as a scope
55
56              • A global default policy.
57
58
59
60       If multiple policy requirements match a given image, only the  require‐
61       ments  from  the most specific match apply, the more general policy re‐
62       quirements definitions are ignored.
63
64
65       This is expressed in JSON using the top-level syntax
66
67
68              {
69                  "default": [/* policy requirements: global default */]
70                  "transports": {
71                      transport_name: {
72                          "": [/* policy requirements: default for transport $transport_name */],
73                          scope_1: [/* policy requirements: default for $scope_1 in $transport_name */],
74                          scope_2: [/*…*/]
75                          /*…*/
76                      },
77                      transport_name_2: {/*…*/}
78                      /*…*/
79                  }
80              }
81
82
83
84       The global default set of policy requirements is mandatory; all of  the
85       other fields (transports itself, any specific transport, the transport-
86       specific default, etc.) are optional.
87
88

Supported transports and their scopes

90       See containers-transports(5) for general documentation about the trans‐
91       ports and their reference syntax.
92
93
94   atomic:
95       The  deprecated  atomic:  transport  refers to images in an Atomic Reg‐
96       istry.
97
98
99       Supported scopes use the  form  hostname[:port][/namespace[/imagestream
100       [:tag]]],  i.e. either specifying a complete name of a tagged image, or
101       prefix denoting a host/namespace/image stream, or a wildcarded  expres‐
102       sion  starting with *. for matching all subdomains. For wildcarded sub‐
103       domain matching, *.example.com is a valid case, but  example*.*.com  is
104       not.
105
106
107       Note:  The  hostname  and port refer to the container registry host and
108       port (the one used e.g. for docker pull), not to the OpenShift API host
109       and port.
110
111
112   containers-storage:
113       Supported scopes have the form [storage-specifier]image-scope.
114
115
116       [storage-specifier]  is  usually  [graph-driver-name@graph-root],  e.g.
117       [overlay@/var/lib/containers/storage].
118
119
120       image-scope matching the individual image is - a named Docker reference
121       in  the fully expanded form, either using a tag or digest. For example,
122       docker.io/library/busybox:latest (not busybox:latest) - and/or (depend‐
123       ing on which one the user’s input provides) @image-id
124
125
126       More  general scopes are prefixes of individual-image scopes, and spec‐
127       ify a less-precisely-specified image,  or  a  repository  (by  omitting
128       first the image ID, if any; then the digest, if any; and finally a tag,
129       if any), a repository namespace, or a registry host (by only specifying
130       the host name and possibly a port number).
131
132
133       Finally, two full-store specifiers matching all images in the store are
134       valid scopes: - [graph-driver-name@graph-root] and - [graph-root]
135
136
137       Note that some tools like Podman and Buildah hard-code overrides of the
138       signature  verification  policy  for  “push” operations, allowing these
139       oprations regardless of configuration in policy.json.
140
141
142   dir:
143       The dir: transport refers to images stored in local directories.
144
145
146       Supported scopes are paths of directories (either containing  a  single
147       image or subdirectories possibly containing images).
148
149
150       Note:  - The paths must be absolute and contain no symlinks. Paths vio‐
151       lating these requirements may be silently  ignored.   -  The  top-level
152       scope "/" is forbidden; use the transport default scope "",
153         for consistency with other transports.
154
155
156   docker:
157       The  docker:  transport refers to images in a registry implementing the
158       "Docker Registry HTTP API V2".
159
160
161       Scopes matching individual images are named Docker  references  in  the
162       fully  expanded  form,  either  using  a  tag  or  digest. For example,
163       docker.io/library/busybox:latest (not busybox:latest).
164
165
166       More general scopes are prefixes of individual-image scopes, and  spec‐
167       ify  a  repository  (by omitting the tag or digest), a repository name‐
168       space, or a registry host (by only specifying the host name and  possi‐
169       bly  a  port  number)  or a wildcarded expression starting with *., for
170       matching all subdomains (not including a port number).  For  wildcarded
171       subdomain  matching,  *.example.com is a valid case, but example*.*.com
172       is not.
173
174
175   docker-archive:
176       Only the default "" scope is supported.
177
178
179   docker-daemon:
180       For references using the algo:digest format (referring to an image ID),
181       only the default "" scope is used.
182
183
184       For  images  using a named reference, scopes matching individual images
185       are in the fully expanded form, either using a tag or digest. For exam‐
186       ple, docker.io/library/busybox:latest (not busybox:latest).
187
188
189       More  general named scopes are prefixes of individual-image scopes, and
190       specify a repository (by omitting the  tag  or  digest),  a  repository
191       namespace,  or  a  registry  host (by only specifying the host name and
192       possibly a port number) or a wildcarded expression  starting  with  *.,
193       for  matching  all  subdomains (not including a port number). For wild‐
194       carded subdomain matching, *.example.com is a  valid  case,  but  exam‐
195       ple*.*.com is not.
196
197
198   oci:
199       The oci: transport refers to images in directories compliant with "Open
200       Container Image Layout Specification".
201
202
203       Supported scopes are paths to directories  (either  containing  an  OCI
204       layout,  or subdirectories possibly containing OCI layout directories).
205       The reference annotation value, if any, is not used.
206
207
208       Note: - The paths must be absolute and contain no symlinks. Paths  vio‐
209       lating  these  requirements  may  be silently ignored.  - The top-level
210       scope "/" is forbidden; use the transport default scope "",
211         for consistency with other transports.
212
213
214   oci-archive:
215       Supported scopes are paths to OCI archives, and their  parent  directo‐
216       ries  (either  containing  a single archive, or subdirectories possibly
217       containing archives).  The reference annotation value, if any,  is  not
218       used.
219
220
221       Note:  - The paths must be absolute and contain no symlinks. Paths vio‐
222       lating these requirements may be silently  ignored.   -  The  top-level
223       scope "/" is forbidden; use the transport default scope "",
224         for consistency with other transports.
225
226
227   ostree:
228       Supported  scopes have the form repo-path:image-scope; _repopath is the
229       path to the OSTree repository.
230
231
232       image-scope is the _dockerreference part of the reference, with with  a
233       :latest  tag implied if no tag is present, and parent namespaces of the
234       _dockerreference value (by omitting the tag, or a prefix  speciyfing  a
235       higher-level namespace).
236
237
238       Note:  -  The _repopath must be absolute and contain no symlinks. Paths
239       violating these requirements may be silently ignored.
240
241
242   sif:
243       Supported scopes are paths to Singularity images, and their parent  di‐
244       rectories  (either  containing  images, or subdirectories possibly con‐
245       taining images).
246
247
248       Note: - The paths must be absolute and contain no symlinks. Paths  vio‐
249       lating  these  requirements  may  be silently ignored.  - The top-level
250       scope "/" is forbidden; use the transport default scope "",
251         for consistency with other transports.
252
253
254   tarball:
255       The tarball: transport is an implementation detail of some import work‐
256       flows. Only the default "" scope is supported.
257
258

Policy Requirements

260       Using  the mechanisms above, a set of policy requirements is looked up.
261       The policy requirements are represented as a JSON array  of  individual
262       requirement  objects.  For an image to be accepted, all of the require‐
263       ments must be satisfied simultaneously.
264
265
266       The policy requirements can also be used to decide whether an  individ‐
267       ual  signature  is accepted (= is signed by a recognized key of a known
268       author); in that case some requirements may apply only to  some  signa‐
269       tures,  but each signature must be accepted by at least one requirement
270       object.
271
272
273       The following requirement objects are supported:
274
275
276   insecureAcceptAnything
277       A simple requirement with the following syntax
278
279
280              {"type":"insecureAcceptAnything"}
281
282
283
284       This requirement accepts any image (but note that other requirements in
285       the array still apply).
286
287
288       When  deciding to accept an individual signature, this requirement does
289       not have any effect; it does not cause the signature  to  be  accepted,
290       though.
291
292
293       This is useful primarily for policy scopes where no signature verifica‐
294       tion is required; because the array of policy requirements must not  be
295       empty,  this  requirement is used to represent the lack of requirements
296       explicitly.
297
298
299   reject
300       A simple requirement with the following syntax:
301
302
303              {"type":"reject"}
304
305
306
307       This requirement rejects every image, and every signature.
308
309
310   signedBy
311       This requirement requires an image to be signed using “simple  signing”
312       with an expected identity, or accepts a signature if it is using an ex‐
313       pected identity and key.
314
315
316              {
317                  "type":    "signedBy",
318                  "keyType": "GPGKeys", /* The only currently supported value */
319                  "keyPath": "/path/to/local/keyring/file",
320                  "keyPaths": ["/path/to/local/keyring/file1","/path/to/local/keyring/file2"…],
321                  "keyData": "base64-encoded-keyring-data",
322                  "signedIdentity": identity_requirement
323              }
324
325
326
327       Exactly one of keyPath, keyPaths and keyData must be present,  contain‐
328       ing  a GPG keyring of one or more public keys.  Only signatures made by
329       these keys are accepted.
330
331
332       The signedIdentity field, a JSON object, specifies what image  identity
333       the  signature  claims  about the image.  One of the following alterna‐
334       tives are supported:
335
336
337              • The identity in the signature must  exactly  match  the  image
338                identity.  Note that with this, referencing an image by digest
339                (with a signature claiming  a  repository:tag  identity)  will
340                fail.
341
342
343
344                {"type":"matchExact"}
345
346
347
348              • If  the image identity carries a tag, the identity in the sig‐
349                nature must exactly match; if the image identity uses a digest
350                reference,  the  identity in the signature must be in the same
351                repository as the image identity (using any tag).
352
353
354
355       (Note that with images identified using digest references,  the  digest
356       from  the  reference  is  validated  even before signature verification
357       starts.)
358
359
360                {"type":"matchRepoDigestOrExact"}
361
362
363
364              • The identity in the signature must be in the  same  repository
365                as  the  image identity.  This is useful e.g. to pull an image
366                using the :latest tag when the image  is  signed  with  a  tag
367                specifying an exact image version.
368
369
370
371                {"type":"matchRepository"}
372
373
374
375              • The  identity  in the signature must exactly match a specified
376                identity.  This is useful e.g. when locally  mirroring  images
377                signed using their public identity.
378
379
380
381                {
382                    "type": "exactReference",
383                    "dockerReference": docker_reference_value
384                }
385
386
387
388              • The  identity  in the signature must be in the same repository
389                as a specified identity.   This  combines  the  properties  of
390                matchRepository and exactReference.
391
392
393
394                {
395                    "type": "exactRepository",
396                    "dockerRepository": docker_repository_value
397                }
398
399
400
401              • Prefix remapping:
402
403
404
405       If  the image identity matches the specified prefix, that prefix is re‐
406       placed by the specified “signed prefix”
407         (otherwise it is used as unchanged and no remapping takes place);
408         matching then follows the matchRepoDigestOrExact semantics documented
409       above
410         (i.e. if the image identity carries a tag, the identity in the signa‐
411       ture must exactly match,
412         if it uses a digest reference, the repository must match).
413
414
415       The prefix and signedPrefix values can be either host[:port] values
416         (matching exactly the same host[:port], string),
417         repository namespaces, or repositories (i.e. they  must  not  contain
418       tags/digests),
419         and match as prefixes of the fully expanded form.
420         For  example, docker.io/library/busybox (not busybox) to specify that
421       single repository,
422         or docker.io/library (not an empty  string)  to  specify  the  parent
423       namespace of docker.io/library/busybox==busybox).
424
425
426       The prefix value is usually the same as the scope containing the parent
427       signedBy requirement.
428
429
430                {
431                    "type": "remapIdentity",
432                    "prefix": prefix,
433                    "signedPrefix": prefix,
434                }
435
436
437
438       If the signedIdentity field is missing, it is treated as matchRepoDige‐
439       stOrExact.
440
441
442       Note:  matchExact,  matchRepoDigestOrExact  and  matchRepository can be
443       only used if a Docker-like image identity is provided by the transport.
444       In particular, the dir: and oci: transports can be only used with exac‐
445       tReference or exactRepository.
446
447
448   sigstoreSigned
449       This requirement requires an image to be signed using a sigstore signa‐
450       ture with an expected identity and key.
451
452
453              {
454                  "type":    "sigstoreSigned",
455                  "keyPath": "/path/to/local/public/key/file",
456                  "keyData": "base64-encoded-public-key-data",
457                  "fulcio": {
458                      "caPath": "/path/to/local/CA/file",
459                      "caData": "base64-encoded-CA-data",
460                      "oidcIssuer": "https://expected.OIDC.issuer/",
461                      "subjectEmail", "expected-signing-user@example.com",
462                  },
463                  "rekorPublicKeyPath": "/path/to/local/public/key/file",
464                  "rekorPublicKeyData": "base64-encoded-public-key-data",
465                  "signedIdentity": identity_requirement
466              }
467
468
469
470       Exactly one of keyPath, keyData and fulcio must be present.
471
472
473       If  keyPath  or  keyData is present, it contains a sigstore public key.
474       Only signatures made by this key are accepted.
475
476
477       If fulcio is present, the signature must be based  on  a  Fulcio-issued
478       certificate.   One  of  caPath and caData must be specified, containing
479       the public key of  the  Fulcio  instance.   Both  oidcIssuer  and  sub‐
480       jectEmail  are  mandatory,  exactly  specifying  the  expected identity
481       provider, and the identity of the user obtaining  the  Fulcio  certifi‐
482       cate.
483
484
485       At  most  one  of  rekorPublicKeyPath  and  rekorPublicKeyData  can  be
486       present; it is mandatory if fulcio is specified.  If a Rekor public key
487       is  specified,  the signature must have been uploaded to a Rekor server
488       and the signature must contain an  (offline-verifiable)  “signed  entry
489       timestamp” proving the existence of the Rekor log record, signed by the
490       provided public key.
491
492
493       The signedIdentity field has the same semantics as in the signedBy  re‐
494       quirement  described  above.   Note that cosign-created signatures only
495       contain a repository, so only matchRepository and  exactRepository  can
496       be  used to accept them (and that does not protect against substitution
497       of a signed image with an unexpected tag).
498
499
500       To use this with images hosted on image registries,  the  use-sigstore-
501       attachments  option  needs  to  be enabled for the relevant registry or
502       repository in the client's containers-registries.d(5).
503
504

Examples

506       It is strongly recommended to set the default  policy  to  reject,  and
507       then selectively allow individual transports and scopes as desired.
508
509
510   A reasonably locked-down system
511       (Note  that  the  /**/ comments are not valid in JSON, and must not be
512       used in real policies.)
513
514
515              {
516                  "default": [{"type": "reject"}], /* Reject anything not explicitly allowed */
517                  "transports": {
518                      "docker": {
519                          /* Allow installing images from a specific repository namespace, without cryptographic verification.
520                             This namespace includes images like openshift/hello-openshift and openshift/origin. */
521                          "docker.io/openshift": [{"type": "insecureAcceptAnything"}],
522                          /* Similarly, allow installing the “official” busybox images.  Note how the fully expanded
523                             form, with the explicit /library/, must be used. */
524                          "docker.io/library/busybox": [{"type": "insecureAcceptAnything"}],
525                          /* Allow installing images from all subdomains */
526                          "*.temporary-project.example.com": [{"type": "insecureAcceptAnything"}],
527                          /* A sigstore-signed repository */
528                          "hostname:5000/myns/sigstore-signed-with-full-references": [
529                              {
530                                  "type": "sigstoreSigned",
531                                  "keyPath": "/path/to/sigstore-pubkey.pub"
532                              }
533                          ],
534                          /* A sigstore-signed repository using the community Fulcio+Rekor servers.
535
536                             The community servers’ public keys can be obtained from
537                             https://github.com/sigstore/sigstore/tree/main/pkg/tuf/repository/targets .  */
538                          "hostname:5000/myns/sigstore-signed-fulcio-rekor": [
539                              {
540                                  "type": "sigstoreSigned",
541                                  "fulcio": {
542                                      "caPath": "/path/to/fulcio_v1.crt.pem",
543                                      "oidcIssuer": "https://github.com/login/oauth",
544                                      "subjectEmail": "test-user@example.com"
545                                  },
546                                  "rekorPublicKeyPath": "/path/to/rekor.pub",
547                              }
548                          ],
549                          /* A sigstore-signed repository, accepts signatures by /usr/bin/cosign */
550                          "hostname:5000/myns/sigstore-signed-allows-malicious-tag-substitution": [
551                              {
552                                  "type": "sigstoreSigned",
553                                  "keyPath": "/path/to/sigstore-pubkey.pub",
554                                  "signedIdentity": {"type": "matchRepository"}
555                              }
556                          ],
557                          /* A sigstore-signed repository using the community Fulcio+Rekor servers,
558                             accepts signatures by /usr/bin/cosign.
559
560                             The community servers’ public keys can be obtained from
561                             https://github.com/sigstore/sigstore/tree/main/pkg/tuf/repository/targets .  */
562                          "hostname:5000/myns/sigstore-signed-fulcio-rekor- allows-malicious-tag-substitution": [
563                              {
564                                  "type": "sigstoreSigned",
565                                  "fulcio": {
566                                      "caPath": "/path/to/fulcio_v1.crt.pem",
567                                      "oidcIssuer": "https://github.com/login/oauth",
568                                      "subjectEmail": "test-user@example.com"
569                                  },
570                                  "rekorPublicKeyPath": "/path/to/rekor.pub",
571                                  "signedIdentity": { "type": "matchRepository" }
572                              }
573                          ]
574                            /* Other docker: images use the global default policy and are rejected */
575                      },
576                      "dir": {
577                          "": [{"type": "insecureAcceptAnything"}] /* Allow any images originating in local directories */
578                      },
579                      "atomic": {
580                          /* The common case: using a known key for a repository or set of repositories */
581                          "hostname:5000/myns/official": [
582                              {
583                                  "type": "signedBy",
584                                  "keyType": "GPGKeys",
585                                  "keyPath": "/path/to/official-pubkey.gpg"
586                              }
587                          ],
588                          /* A more complex example, for a repository which contains a mirror of a third-party product,
589                             which must be signed-off by local IT */
590                          "hostname:5000/vendor/product": [
591                              { /* Require the image to be signed by the original vendor, using the vendor's repository location. */
592                                  "type": "signedBy",
593                                  "keyType": "GPGKeys",
594                                  "keyPath": "/path/to/vendor-pubkey.gpg",
595                                  "signedIdentity": {
596                                      "type": "exactRepository",
597                                      "dockerRepository": "vendor-hostname/product/repository"
598                                  }
599                              },
600                              { /* Require the image to _also_ be signed by a local reviewer. */
601                                  "type": "signedBy",
602                                  "keyType": "GPGKeys",
603                                  "keyPath": "/path/to/reviewer-pubkey.gpg"
604                              }
605                          ],
606                          /* A way to mirror many repositories from a single vendor */
607                          "private-mirror:5000/vendor-mirror": [
608                              { /* Require the image to be signed by the original vendor, using the vendor's repository location.
609                                   For example, private-mirror:5000/vendor-mirror/productA/image1:latest needs to be signed as
610                                   vendor.example/productA/image1:latest . */
611                                  "type": "signedBy",
612                                  "keyType": "GPGKeys",
613                                  "keyPath": "/path/to/vendor-pubkey.gpg",
614                                  "signedIdentity": {
615                                      "type": "remapIdentity",
616                                      "prefix": "private-mirror:5000/vendor-mirror",
617                                      "signedPrefix": "vendor.example.com"
618                                  }
619                              }
620                          ]
621                      }
622                  }
623              }
624
625
626
627   Completely disable security, allow all images, do not trust any signatures
628              {
629                  "default": [{"type": "insecureAcceptAnything"}]
630              }
631
632
633

SEE ALSO

635       atomic(1)
636
637

HISTORY

639       August 2018, Rename to containers-policy.json(5) by  Valentin  Rothberg
640       vrothberg@suse.com ⟨mailto:vrothberg@suse.com⟩
641
642
643       September  2016,  Originally compiled by Miloslav Trmač mitr@redhat.com
644       ⟨mailto:mitr@redhat.com⟩
645
646
647
648Man                               policy.json        CONTAINERS-POLICY.JSON(5)
Impressum