1CONTAINERS-POLICY.JSON(5) Page CONTAINERS-POLICY.JSON(5)
2
3
4
5Miloslav Trmač September 2016
6
7
9 containers-policy.json - syntax for the signature verification policy
10 file
11
12
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
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
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
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
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
635 atomic(1)
636
637
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)