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   atomic:
91       The atomic: transport refers to images in an Atomic Registry.
92
93
94       Supported scopes use the  form  hostname[:port][/namespace[/imagestream
95       [:tag]]],  i.e. either specifying a complete name of a tagged image, or
96       prefix denoting a host/namespace/image stream or a  wildcarded  expres‐
97       sion  for  matching  all subdomains. For wildcarded subdomain matching,
98       *.example.com is a valid case, but example*.*.com is not.
99
100
101       Note: The hostname and port refer to the container  registry  host  and
102       port (the one used e.g. for docker pull), not to the OpenShift API host
103       and port.
104
105
106   dir:
107       The dir: transport refers to images stored in local directories.
108
109
110       Supported scopes are paths of directories (either containing  a  single
111       image or subdirectories possibly containing images).
112
113
114       Note: The paths must be absolute and contain no symlinks. Paths violat‐
115       ing these requirements may be silently ignored.
116
117
118       The top-level scope "/" is forbidden; use the transport  default  scope
119       "", for consistency with other transports.
120
121
122   docker:
123       The  docker:  transport refers to images in a registry implementing the
124       "Docker Registry HTTP API V2".
125
126
127       Scopes matching individual images are named Docker  references  in  the
128       fully  expanded  form,  either  using  a  tag  or  digest. For example,
129       docker.io/library/busybox:latest (not busybox:latest).
130
131
132       More general scopes are prefixes of individual-image scopes, and  spec‐
133       ify  a  repository  (by omitting the tag or digest), a repository name‐
134       space, or a registry host (by only specifying the host name) or a wild‐
135       carded expression for matching all subdomains. For wildcarded subdomain
136       matching, *.example.com is a valid case, but example*.*.com is not.
137
138
139   oci:
140       The oci: transport refers to images in directories compliant with "Open
141       Container Image Layout Specification".
142
143
144       Supported scopes use the form directory:tag, and directory referring to
145       a directory containing one or more tags, or any of the parent  directo‐
146       ries.
147
148
149       Note:  See  dir:  above for semantics and restrictions on the directory
150       paths, they apply to oci: equivalently.
151
152
153   tarball:
154       The tarball: transport refers to tarred up container root filesystems.
155
156
157       Scopes are ignored.
158
159

Policy Requirements

161       Using the mechanisms above, a set of policy requirements is looked  up.
162       The  policy  requirements are represented as a JSON array of individual
163       requirement objects.  For an image to be accepted, all of the  require‐
164       ments must be satisfied simultaneously.
165
166
167       The  policy requirements can also be used to decide whether an individ‐
168       ual signature is accepted (= is signed by a recognized key of  a  known
169       author);  in  that case some requirements may apply only to some signa‐
170       tures, but each signature must be accepted by at least one  requirement
171       object.
172
173
174       The following requirement objects are supported:
175
176
177   insecureAcceptAnything
178       A simple requirement with the following syntax
179
180
181              {"type":"insecureAcceptAnything"}
182
183
184
185       This requirement accepts any image (but note that other requirements in
186       the array still apply).
187
188
189       When deciding to accept an individual signature, this requirement  does
190       not  have  any  effect; it does not cause the signature to be accepted,
191       though.
192
193
194       This is useful primarily for policy scopes where no signature verifica‐
195       tion  is required; because the array of policy requirements must not be
196       empty, this requirement is used to represent the lack  of  requirements
197       explicitly.
198
199
200   reject
201       A simple requirement with the following syntax:
202
203
204              {"type":"reject"}
205
206
207
208       This requirement rejects every image, and every signature.
209
210
211   signedBy
212       This  requirement requires an image to be signed using “simple signing”
213       with an expected identity, or accepts a signature if it is using an ex‐
214       pected identity and key.
215
216
217              {
218                  "type":    "signedBy",
219                  "keyType": "GPGKeys", /* The only currently supported value */
220                  "keyPath": "/path/to/local/keyring/file",
221                  "keyPaths": ["/path/to/local/keyring/file1","/path/to/local/keyring/file2"…],
222                  "keyData": "base64-encoded-keyring-data",
223                  "signedIdentity": identity_requirement
224              }
225
226
227
228       Exactly  one of keyPath, keyPaths and keyData must be present, contain‐
229       ing a GPG keyring of one or more public keys.  Only signatures made  by
230       these keys are accepted.
231
232
233       The  signedIdentity field, a JSON object, specifies what image identity
234       the signature claims about the image.  One of  the  following  alterna‐
235       tives are supported:
236
237
238              • The  identity  in  the  signature must exactly match the image
239                identity.  Note that with this, referencing an image by digest
240                (with  a  signature  claiming  a repository:tag identity) will
241                fail.
242
243
244
245                {"type":"matchExact"}
246
247
248
249              • If the image identity carries a tag, the identity in the  sig‐
250                nature must exactly match; if the image identity uses a digest
251                reference, the identity in the signature must be in  the  same
252                repository as the image identity (using any tag).
253
254
255
256       (Note  that  with images identified using digest references, the digest
257       from the reference is  validated  even  before  signature  verification
258       starts.)
259
260
261                {"type":"matchRepoDigestOrExact"}
262
263
264
265              • The  identity  in the signature must be in the same repository
266                as the image identity.  This is useful e.g. to pull  an  image
267                using  the  :latest  tag  when  the image is signed with a tag
268                specifying an exact image version.
269
270
271
272                {"type":"matchRepository"}
273
274
275
276              • The identity in the signature must exactly match  a  specified
277                identity.   This  is useful e.g. when locally mirroring images
278                signed using their public identity.
279
280
281
282                {
283                    "type": "exactReference",
284                    "dockerReference": docker_reference_value
285                }
286
287
288
289              • The identity in the signature must be in the  same  repository
290                as  a  specified  identity.   This  combines the properties of
291                matchRepository and exactReference.
292
293
294
295                {
296                    "type": "exactRepository",
297                    "dockerRepository": docker_repository_value
298                }
299
300
301
302              • Prefix remapping:
303
304
305
306       If the image identity matches the specified prefix, that prefix is  re‐
307       placed by the specified “signed prefix”
308         (otherwise it is used as unchanged and no remapping takes place);
309         matching then follows the matchRepoDigestOrExact semantics documented
310       above
311         (i.e. if the image identity carries a tag, the identity in the signa‐
312       ture must exactly match,
313         if it uses a digest reference, the repository must match).
314
315
316       The prefix and signedPrefix values can be either host[:port] values
317         (matching exactly the same host[:port], string),
318         repository  namespaces,  or  repositories (i.e. they must not contain
319       tags/digests),
320         and match as prefixes of the fully expanded form.
321         For example, docker.io/library/busybox (not busybox) to specify  that
322       single repository,
323         or  docker.io/library  (not  an  empty  string) to specify the parent
324       namespace of docker.io/library/busybox==busybox).
325
326
327       The prefix value is usually the same as the scope containing the parent
328       signedBy requirement.
329
330
331                {
332                    "type": "remapIdentity",
333                    "prefix": prefix,
334                    "signedPrefix": prefix,
335                }
336
337
338
339       If the signedIdentity field is missing, it is treated as matchRepoDige‐
340       stOrExact.
341
342
343       Note: matchExact, matchRepoDigestOrExact  and  matchRepository  can  be
344       only used if a Docker-like image identity is provided by the transport.
345       In particular, the dir: and oci: transports can be only used with exac‐
346       tReference or exactRepository.
347
348
349   sigstoreSigned
350       This requirement requires an image to be signed using a sigstore signa‐
351       ture with an expected identity and key.
352
353
354              {
355                  "type":    "sigstoreSigned",
356                  "keyPath": "/path/to/local/public/key/file",
357                  "keyData": "base64-encoded-public-key-data",
358                  "fulcio": {
359                      "caPath": "/path/to/local/CA/file",
360                      "caData": "base64-encoded-CA-data",
361                      "oidcIssuer": "https://expected.OIDC.issuer/",
362                      "subjectEmail", "expected-signing-user@example.com",
363                  },
364                  "rekorPublicKeyPath": "/path/to/local/public/key/file",
365                  "rekorPublicKeyData": "base64-encoded-public-key-data",
366                  "signedIdentity": identity_requirement
367              }
368
369
370
371       Exactly one of keyPath, keyData and fulcio must be present.
372
373
374       If keyPath or keyData is present, it contains a  sigstore  public  key.
375       Only signatures made by this key are accepted.
376
377
378       If  fulcio  is  present, the signature must be based on a Fulcio-issued
379       certificate.  One of caPath and caData must  be  specified,  containing
380       the  public  key  of  the  Fulcio  instance.   Both oidcIssuer and sub‐
381       jectEmail are  mandatory,  exactly  specifying  the  expected  identity
382       provider,  and  the  identity of the user obtaining the Fulcio certifi‐
383       cate.
384
385
386       At  most  one  of  rekorPublicKeyPath  and  rekorPublicKeyData  can  be
387       present; it is mandatory if fulcio is specified.  If a Rekor public key
388       is specified, the signature must have been uploaded to a  Rekor  server
389       and  the  signature  must contain an (offline-verifiable) “signed entry
390       timestamp” proving the existence of the Rekor log record, signed by the
391       provided public key.
392
393
394       The  signedIdentity field has the same semantics as in the signedBy re‐
395       quirement described above.  Note that  cosign-created  signatures  only
396       contain  a  repository, so only matchRepository and exactRepository can
397       be used to accept them (and that does not protect against  substitution
398       of a signed image with an unexpected tag).
399
400
401       To  use  this with images hosted on image registries, the relevant reg‐
402       istry or repository must have the use-sigstore-attachments  option  en‐
403       abled in containers-registries.d(5).
404
405

Examples

407       It  is  strongly  recommended  to set the default policy to reject, and
408       then selectively allow individual transports and scopes as desired.
409
410
411   A reasonably locked-down system
412       (Note that the /**/ comments are not valid in JSON, and  must  not  be
413       used in real policies.)
414
415
416              {
417                  "default": [{"type": "reject"}], /* Reject anything not explicitly allowed */
418                  "transports": {
419                      "docker": {
420                          /* Allow installing images from a specific repository namespace, without cryptographic verification.
421                             This namespace includes images like openshift/hello-openshift and openshift/origin. */
422                          "docker.io/openshift": [{"type": "insecureAcceptAnything"}],
423                          /* Similarly, allow installing the “official” busybox images.  Note how the fully expanded
424                             form, with the explicit /library/, must be used. */
425                          "docker.io/library/busybox": [{"type": "insecureAcceptAnything"}],
426                          /* Allow installing images from all subdomains */
427                          "*.temporary-project.example.com": [{"type": "insecureAcceptAnything"}],
428                          /* A sigstore-signed repository */
429                          "hostname:5000/myns/sigstore-signed-with-full-references": [
430                              {
431                                  "type": "sigstoreSigned",
432                                  "keyPath": "/path/to/sigstore-pubkey.pub"
433                              }
434                          ],
435                          /* A sigstore-signed repository using the community Fulcio+Rekor servers.
436
437                             The community servers’ public keys can be obtained from
438                             https://github.com/sigstore/sigstore/tree/main/pkg/tuf/repository/targets .  */
439                          "hostname:5000/myns/sigstore-signed-fulcio-rekor": [
440                              {
441                                  "type": "sigstoreSigned",
442                                  "fulcio": {
443                                      "caPath": "/path/to/fulcio_v1.crt.pem",
444                                      "oidcIssuer": "https://github.com/login/oauth",
445                                      "subjectEmail": "test-user@example.com"
446                                  },
447                                  "rekorPublicKeyPath": "/path/to/rekor.pub",
448                              }
449                          ],
450                          /* A sigstore-signed repository, accepts signatures by /usr/bin/cosign */
451                          "hostname:5000/myns/sigstore-signed-allows-malicious-tag-substitution": [
452                              {
453                                  "type": "sigstoreSigned",
454                                  "keyPath": "/path/to/sigstore-pubkey.pub",
455                                  "signedIdentity": {"type": "matchRepository"}
456                              }
457                          ],
458                          /* A sigstore-signed repository using the community Fulcio+Rekor servers,
459                             accepts signatures by /usr/bin/cosign.
460
461                             The community servers’ public keys can be obtained from
462                             https://github.com/sigstore/sigstore/tree/main/pkg/tuf/repository/targets .  */
463                          "hostname:5000/myns/sigstore-signed-fulcio-rekor- allows-malicious-tag-substitution": [
464                              {
465                                  "type": "sigstoreSigned",
466                                  "fulcio": {
467                                      "caPath": "/path/to/fulcio_v1.crt.pem",
468                                      "oidcIssuer": "https://github.com/login/oauth",
469                                      "subjectEmail": "test-user@example.com"
470                                  },
471                                  "rekorPublicKeyPath": "/path/to/rekor.pub",
472                                  "signedIdentity": { "type": "matchRepository" }
473                              }
474                          ]
475                            /* Other docker: images use the global default policy and are rejected */
476                      },
477                      "dir": {
478                          "": [{"type": "insecureAcceptAnything"}] /* Allow any images originating in local directories */
479                      },
480                      "atomic": {
481                          /* The common case: using a known key for a repository or set of repositories */
482                          "hostname:5000/myns/official": [
483                              {
484                                  "type": "signedBy",
485                                  "keyType": "GPGKeys",
486                                  "keyPath": "/path/to/official-pubkey.gpg"
487                              }
488                          ],
489                          /* A more complex example, for a repository which contains a mirror of a third-party product,
490                             which must be signed-off by local IT */
491                          "hostname:5000/vendor/product": [
492                              { /* Require the image to be signed by the original vendor, using the vendor's repository location. */
493                                  "type": "signedBy",
494                                  "keyType": "GPGKeys",
495                                  "keyPath": "/path/to/vendor-pubkey.gpg",
496                                  "signedIdentity": {
497                                      "type": "exactRepository",
498                                      "dockerRepository": "vendor-hostname/product/repository"
499                                  }
500                              },
501                              { /* Require the image to _also_ be signed by a local reviewer. */
502                                  "type": "signedBy",
503                                  "keyType": "GPGKeys",
504                                  "keyPath": "/path/to/reviewer-pubkey.gpg"
505                              }
506                          ],
507                          /* A way to mirror many repositories from a single vendor */
508                          "private-mirror:5000/vendor-mirror": [
509                              { /* Require the image to be signed by the original vendor, using the vendor's repository location.
510                                   For example, private-mirror:5000/vendor-mirror/productA/image1:latest needs to be signed as
511                                   vendor.example/productA/image1:latest . */
512                                  "type": "signedBy",
513                                  "keyType": "GPGKeys",
514                                  "keyPath": "/path/to/vendor-pubkey.gpg",
515                                  "signedIdentity": {
516                                      "type": "remapIdentity",
517                                      "prefix": "private-mirror:5000/vendor-mirror",
518                                      "signedPrefix": "vendor.example.com"
519                                  }
520                              }
521                          ]
522                      }
523                  }
524              }
525
526
527
528   Completely disable security, allow all images, do not trust any signatures
529              {
530                  "default": [{"type": "insecureAcceptAnything"}]
531              }
532
533
534

SEE ALSO

536       atomic(1)
537
538

HISTORY

540       August  2018,  Rename to containers-policy.json(5) by Valentin Rothberg
541       vrothberg@suse.com ⟨mailto:vrothberg@suse.com⟩
542
543
544       September 2016, Originally compiled by Miloslav  Trmač  mitr@redhat.com
545       ⟨mailto:mitr@redhat.com⟩
546
547
548
549Man                               policy.json        CONTAINERS-POLICY.JSON(5)
Impressum