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 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
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
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
536 atomic(1)
537
538
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)