From 8826f09cf4908160a8be73c3f0c405b328ace410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Mon, 8 Aug 2016 21:39:02 +0200 Subject: [PATCH 1/4] Vendor after merging mtrmac/image:default-policy --- .../image/docker/docker_transport.go | 2 +- .../containers/image/oci/oci_transport.go | 2 +- .../image/openshift/openshift_transport.go | 2 +- .../image/signature/policy_config.go | 27 +++++++++++++++++++ .../containers/image/types/types.go | 9 +++++++ vendor/github.com/davecgh/go-spew/LICENSE | 2 ++ 6 files changed, 41 insertions(+), 3 deletions(-) diff --git a/vendor/github.com/containers/image/docker/docker_transport.go b/vendor/github.com/containers/image/docker/docker_transport.go index e2166636..68cb0060 100644 --- a/vendor/github.com/containers/image/docker/docker_transport.go +++ b/vendor/github.com/containers/image/docker/docker_transport.go @@ -9,7 +9,7 @@ import ( "github.com/docker/docker/reference" ) -// Transport is an ImageTransport for Docker references. +// Transport is an ImageTransport for Docker registry-hosted images. var Transport = dockerTransport{} type dockerTransport struct{} diff --git a/vendor/github.com/containers/image/oci/oci_transport.go b/vendor/github.com/containers/image/oci/oci_transport.go index f3afd221..be96a85e 100644 --- a/vendor/github.com/containers/image/oci/oci_transport.go +++ b/vendor/github.com/containers/image/oci/oci_transport.go @@ -12,7 +12,7 @@ import ( "github.com/docker/docker/reference" ) -// Transport is an ImageTransport for Docker references. +// Transport is an ImageTransport for OCI directories. var Transport = ociTransport{} type ociTransport struct{} diff --git a/vendor/github.com/containers/image/openshift/openshift_transport.go b/vendor/github.com/containers/image/openshift/openshift_transport.go index 13f99c6b..96b5f085 100644 --- a/vendor/github.com/containers/image/openshift/openshift_transport.go +++ b/vendor/github.com/containers/image/openshift/openshift_transport.go @@ -12,7 +12,7 @@ import ( "github.com/docker/docker/reference" ) -// Transport is an ImageTransport for directory paths. +// Transport is an ImageTransport for OpenShift registry-hosted images. var Transport = openshiftTransport{} type openshiftTransport struct{} diff --git a/vendor/github.com/containers/image/signature/policy_config.go b/vendor/github.com/containers/image/signature/policy_config.go index 1f74e19d..20821a35 100644 --- a/vendor/github.com/containers/image/signature/policy_config.go +++ b/vendor/github.com/containers/image/signature/policy_config.go @@ -24,6 +24,15 @@ import ( "github.com/docker/docker/reference" ) +// systemDefaultPolicyPath is the policy path used for DefaultPolicy(). +// You can override this at build time with +// -ldflags '-X github.com/containers/image/signature.systemDefaultPolicyPath=$your_path' +var systemDefaultPolicyPath = builtinDefaultPolicyPath + +// builtinDefaultPolicyPath is the policy pat used for DefaultPolicy(). +// DO NOT change this, instead see systemDefaultPolicyPath above. +const builtinDefaultPolicyPath = "/etc/containers/policy.json" + // InvalidPolicyFormatError is returned when parsing an invalid policy configuration. type InvalidPolicyFormatError string @@ -33,6 +42,24 @@ func (err InvalidPolicyFormatError) Error() string { // FIXME: NewDefaultPolicy, from default file (or environment if trusted?) +// DefaultPolicy returns the default policy of the system. +// Most applications should be using this method to get the policy configured +// by the system administrator. +// ctx should usually be nil, can be set to override the default. +// NOTE: When this function returns an error, report it to the user and abort. +// DO NOT hard-code fallback policies in your application. +func DefaultPolicy(ctx *types.SystemContext) (*Policy, error) { + return NewPolicyFromFile(defaultPolicyPath(ctx)) +} + +// defaultPolicyPath returns a path to the default policy of the system. +func defaultPolicyPath(ctx *types.SystemContext) string { + if ctx != nil && ctx.SignaturePolicyPath != "" { + return ctx.SignaturePolicyPath + } + return systemDefaultPolicyPath +} + // NewPolicyFromFile returns a policy configured in the specified file. func NewPolicyFromFile(fileName string) (*Policy, error) { contents, err := ioutil.ReadFile(fileName) diff --git a/vendor/github.com/containers/image/types/types.go b/vendor/github.com/containers/image/types/types.go index b67e6b30..c5eb5ab6 100644 --- a/vendor/github.com/containers/image/types/types.go +++ b/vendor/github.com/containers/image/types/types.go @@ -147,3 +147,12 @@ type ImageInspectInfo struct { Os string Layers []string } + +// SystemContext allows parametrizing access to implicitly-accessed resources, +// like configuration files in /etc and users' login state in their home directory. +// Various components can share the same field only if their semantics is exactly +// the same; if in doubt, add a new field. +// It is always OK to pass nil instead of a SystemContext. +type SystemContext struct { + SignaturePolicyPath string // If not "", overrides the system's default path for signature.Policy configuration. +} diff --git a/vendor/github.com/davecgh/go-spew/LICENSE b/vendor/github.com/davecgh/go-spew/LICENSE index 2a7cfd2b..bb673323 100644 --- a/vendor/github.com/davecgh/go-spew/LICENSE +++ b/vendor/github.com/davecgh/go-spew/LICENSE @@ -1,3 +1,5 @@ +ISC License + Copyright (c) 2012-2013 Dave Collins Permission to use, copy, modify, and distribute this software for any From d5d6bc28f7f44853695c80462d942ab6c996a36d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Mon, 6 Jun 2016 16:48:57 +0200 Subject: [PATCH 2/4] Add a new --policy flag. This ordinarily uses the compiled-in default, but allows per-command override. No users yet. Note that this adds an URL to policy documentation within containers/image, and that URL does not exist at the moment. --- cmd/skopeo/main.go | 22 ++++++++++++++++++++++ docs/skopeo.1.md | 8 ++++++++ 2 files changed, 30 insertions(+) diff --git a/cmd/skopeo/main.go b/cmd/skopeo/main.go index 3c791076..28b26229 100644 --- a/cmd/skopeo/main.go +++ b/cmd/skopeo/main.go @@ -5,6 +5,7 @@ import ( "os" "github.com/Sirupsen/logrus" + "github.com/containers/image/signature" "github.com/projectatomic/skopeo/version" "github.com/urfave/cli" ) @@ -50,6 +51,11 @@ func createApp() *cli.App { Name: "tls-verify", Usage: "verify certificates", }, + cli.StringFlag{ + Name: "policy", + Value: "", + Usage: "Path to a signature verification policy file", + }, } app.Before = func(c *cli.Context) error { if c.GlobalBool("debug") { @@ -75,3 +81,19 @@ func main() { logrus.Fatal(err) } } + +// getPolicyContext handles the global "policy" flag. +func getPolicyContext(c *cli.Context) (*signature.PolicyContext, error) { + policyPath := c.GlobalString("policy") + var policy *signature.Policy // This could be cached across calls, if we had an application context. + var err error + if policyPath == "" { + policy, err = signature.DefaultPolicy(nil) + } else { + policy, err = signature.NewPolicyFromFile(policyPath) + } + if err != nil { + return nil, err + } + return signature.NewPolicyContext(policy) +} diff --git a/docs/skopeo.1.md b/docs/skopeo.1.md index 90852d6f..957f4211 100644 --- a/docs/skopeo.1.md +++ b/docs/skopeo.1.md @@ -43,6 +43,9 @@ Most commands refer to container images, using a _transport_`:`_details_ format. **--cert-path** _path_ Use certificates at _path_ (cert.pem, key.pem) to connect to the registry + **--policy** _path-to-policy_ Path to a policy.json file to use for verifying signatures and + deciding whether an image is accepted, instead of the default policy. + **--tls-verify** _bool-value_ Verify certificates **--help**|**-h** Show help @@ -128,6 +131,11 @@ Verify a signature using local files, digest will be printed on success. ## skopeo help show help for `skopeo` +# FILES + **/etc/containers/policy.json** + Default signature verification policy file, if **--policy** is not specified. + The policy format is documented in https://github.com/containers/image/blob/master/docs/policy.json.md . + # EXAMPLES ## skopeo copy From d4462330a596315f13951e0cf593c823cdedf7dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Mon, 8 Aug 2016 22:07:35 +0200 Subject: [PATCH 3/4] Add a default policy file, install it in (make install) and integration tests (skopeo copy) will soon ALWAYS require a present policy file. So, install one by (make install), and ensure that integration tests do so as well. Also simplifies the usage of install(1) a bit. --- Makefile | 8 ++++---- default-policy.json | 7 +++++++ hack/make/test-integration | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 default-policy.json diff --git a/Makefile b/Makefile index 19bd3962..17d1198f 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ export GO15VENDOREXPERIMENT=1 PREFIX ?= ${DESTDIR}/usr INSTALLDIR=${PREFIX}/bin MANINSTALLDIR=${PREFIX}/share/man +CONTAINERSSYSCONFIGDIR=${DESTDIR}/etc/containers BASHINSTALLDIR=${PREFIX}/share/bash-completion/completions GO_MD2MAN ?= /usr/bin/go-md2man @@ -60,14 +61,13 @@ clean: rm -f skopeo docs/*.1 install: install-binary install-docs install-completions + install -D -m 644 default-policy.json ${CONTAINERSSYSCONFIGDIR}/policy.json install-binary: ./skopeo - install -d -m 0755 ${INSTALLDIR} - install -m 755 skopeo ${INSTALLDIR} + install -D -m 755 skopeo ${INSTALLDIR}/skopeo install-docs: docs/skopeo.1 - install -d -m 0755 ${MANINSTALLDIR}/man1 - install -m 644 docs/skopeo.1 ${MANINSTALLDIR}/man1/ + install -D -m 644 docs/skopeo.1 ${MANINSTALLDIR}/man1/skopeo.1 install-completions: install -m 644 -T hack/make/bash_autocomplete ${BASHINSTALLDIR}/skopeo diff --git a/default-policy.json b/default-policy.json new file mode 100644 index 00000000..a4c2e1f9 --- /dev/null +++ b/default-policy.json @@ -0,0 +1,7 @@ +{ + "default": [ + { + "type": "insecureAcceptAnything" + } + ] +} \ No newline at end of file diff --git a/hack/make/test-integration b/hack/make/test-integration index ac9704d4..564438f1 100755 --- a/hack/make/test-integration +++ b/hack/make/test-integration @@ -9,7 +9,7 @@ bundle_test_integration() { # subshell so that we can export PATH without breaking other things ( make binary-local - make install-binary + make install export GO15VENDOREXPERIMENT=1 bundle_test_integration ) 2>&1 From 76a14985d6f571083d98152f78f4c73ed2b7276f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Thu, 2 Jun 2016 16:26:01 +0200 Subject: [PATCH 4/4] Implement policy enforcement in (skopeo copy) Finally, load and enforce the policy. NOTE that this breaks a simple ./skopeo from a built directory if you don't have /etc/atomic/policy.json installed for other reasons; use (./skopeo --policy default-policy.json) instead. --- cmd/skopeo/copy.go | 21 ++++++++++++++++----- docs/skopeo.1.md | 2 ++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/cmd/skopeo/copy.go b/cmd/skopeo/copy.go index 14e3577a..e2104826 100644 --- a/cmd/skopeo/copy.go +++ b/cmd/skopeo/copy.go @@ -80,6 +80,12 @@ func copyHandler(context *cli.Context) error { return errors.New("Usage: copy source destination") } + policyContext, err := getPolicyContext(context) + if err != nil { + return fmt.Errorf("Error loading verification policy: %v", err) + } + defer policyContext.Destroy() + dest, err := parseImageDestination(context, context.Args()[1]) if err != nil { return fmt.Errorf("Error initializing %s: %v", context.Args()[1], err) @@ -93,11 +99,21 @@ func copyHandler(context *cli.Context) error { signBy := context.String("sign-by") + // Please keep this policy check BEFORE reading any other information about the image. + if allowed, err := policyContext.IsRunningImageAllowed(src); !allowed || err != nil { // Be paranoid and fail if either return value indicates so. + return fmt.Errorf("Source image rejected: %v", err) + } + manifest, _, err := src.Manifest() if err != nil { return fmt.Errorf("Error reading manifest: %v", err) } + sigs, err := src.Signatures() + if err != nil { + return fmt.Errorf("Error reading signatures: %v", err) + } + blobDigests, err := src.BlobDigests() if err != nil { return fmt.Errorf("Error parsing manifest: %v", err) @@ -128,11 +144,6 @@ func copyHandler(context *cli.Context) error { } } - sigs, err := src.Signatures() - if err != nil { - return fmt.Errorf("Error reading signatures: %v", err) - } - if signBy != "" { mech, err := signature.NewGPGSigningMechanism() if err != nil { diff --git a/docs/skopeo.1.md b/docs/skopeo.1.md index 957f4211..a761f2cb 100644 --- a/docs/skopeo.1.md +++ b/docs/skopeo.1.md @@ -59,6 +59,8 @@ Most commands refer to container images, using a _transport_`:`_details_ format. Copy an image (manifest, filesystem layers, signatures) from one location to another. +Uses the system's signature verification policy to validate images, refuses to copy images rejected by the policy. + _source-image_ use the "image name" format described above _destination-image_ use the "image name" format described above