From efe151ddf6a7fd3848fea340cab7553d0a7d295b Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Fri, 31 Jul 2020 13:36:04 +0800 Subject: [PATCH 01/69] Initial prototype This is a joint commit of - Shiwei Zhang - Steve Lasker - Aviral Takkar Signed-off-by: Shiwei Zhang --- README.md | 110 +++++++- cmd/nv2/common.go | 20 ++ cmd/nv2/main.go | 29 +++ cmd/nv2/manifest.go | 68 +++++ cmd/nv2/sign.go | 137 ++++++++++ cmd/nv2/verify.go | 122 +++++++++ docs/artifact/README.md | 22 ++ docs/artifact/examples/manifest.json | 9 + docs/nv2/README.md | 293 ++++++++++++++++++++++ docs/signature/README.md | 225 +++++++++++++++++ docs/signature/examples/x509_kid.nv2.json | 1 + docs/signature/examples/x509_x5c.nv2.json | 1 + docs/signature/schema.json | 78 ++++++ go.mod | 11 + go.sum | 26 ++ internal/crypto/x509.go | 51 ++++ media/acme-rockets-cert.png | Bin 0 -> 17157 bytes media/example-cert.png | Bin 0 -> 18030 bytes media/notary-e2e-scenarios.png | Bin 0 -> 54561 bytes media/nv2-client-components.png | Bin 0 -> 26127 bytes pkg/registry/client.go | 32 +++ pkg/registry/docker.go | 7 + pkg/registry/manifest.go | 113 +++++++++ pkg/registry/transport.go | 110 ++++++++ pkg/signature/errors.go | 10 + pkg/signature/interface.go | 12 + pkg/signature/scheme.go | 90 +++++++ pkg/signature/signature.go | 35 +++ pkg/signature/util.go | 17 ++ pkg/signature/x509/signer.go | 92 +++++++ pkg/signature/x509/type.go | 4 + pkg/signature/x509/verifier.go | 146 +++++++++++ 32 files changed, 1870 insertions(+), 1 deletion(-) create mode 100644 cmd/nv2/common.go create mode 100644 cmd/nv2/main.go create mode 100644 cmd/nv2/manifest.go create mode 100644 cmd/nv2/sign.go create mode 100644 cmd/nv2/verify.go create mode 100644 docs/artifact/README.md create mode 100644 docs/artifact/examples/manifest.json create mode 100644 docs/nv2/README.md create mode 100644 docs/signature/README.md create mode 100644 docs/signature/examples/x509_kid.nv2.json create mode 100644 docs/signature/examples/x509_x5c.nv2.json create mode 100644 docs/signature/schema.json create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/crypto/x509.go create mode 100644 media/acme-rockets-cert.png create mode 100644 media/example-cert.png create mode 100644 media/notary-e2e-scenarios.png create mode 100644 media/nv2-client-components.png create mode 100644 pkg/registry/client.go create mode 100644 pkg/registry/docker.go create mode 100644 pkg/registry/manifest.go create mode 100644 pkg/registry/transport.go create mode 100644 pkg/signature/errors.go create mode 100644 pkg/signature/interface.go create mode 100644 pkg/signature/scheme.go create mode 100644 pkg/signature/signature.go create mode 100644 pkg/signature/util.go create mode 100644 pkg/signature/x509/signer.go create mode 100644 pkg/signature/x509/type.go create mode 100644 pkg/signature/x509/verifier.go diff --git a/README.md b/README.md index 996158e49..1eb1b9ddc 100644 --- a/README.md +++ b/README.md @@ -1 +1,109 @@ -# nv2 \ No newline at end of file +# Notary V2 (nv2) - Prototype + +nv2 is an incubation and prototype for the [Notary v2][notary-v2] efforts, securing artifacts stored in [distribution-spec][distribution-spec] based registries. +The `nv2` prototype covers the scenarios outlined in [notaryproject/requirements](https://github.com/notaryproject/requirements/blob/master/scenarios.md#scenarios). It also follows the [prototyping approach described here](https://github.com/stevelasker/nv2#prototyping-approach). + +![nv2-components](media/notary-e2e-scenarios.png) + +To enable the above workflow: + +- The nv2 client (1) will sign any OCI artifact type (2) (including a Docker Image, Helm Chart, OPA, SBoM or any OCI Artifact type), generating a Notary v2 signature (3) +- The [ORAS][oras] client (4) can then push the artifact (2) and the Notary v2 signature (3) to an OCI Artifacts supported registry (5) +- In a subsequent prototype, signatures may be retrieved from the OCI Artifacts supported registry (5) + +![nv2-components](media/nv2-client-components.png) + +## Table of Contents + +1. [Scenarios](#scenarios) +1. [nv2 signature spec](./docs/signature/README.md) +1. [nv2 signing and verification docs](docs/nv2/README.md) +1. [OCI Artifact schema for storing signatures](docs/artifact/README.md) +1. [nv2 prototype scope](#prototype-scope) + +## Scenarios + +The current implementation focuses on x509 cert based signatures. Using this approach, the digest and references block are signed, with the cert Common Name required to match the registry references. This enables both the public registry and private registry scenarios. + +### Public Registry + +Public registries generally have two cateogires of content: + +1. Public, certified content. This content is scanned, certified and signed by the registry that wishes to claim the content is "certified". It may be additionaly signed by the originating vendor. +2. Public, community driven content. Community content is a choice for the consumer to trust (downloading their key), or accept as un-trusted. + +#### End to End Experience + +The user works for ACME Rockets. They build `FROM` and use certified content from docker hub. +Their environemt is configured to only trust content from `docker.io` and `acme-rockets.io` + +#### Public Certified Content + +1. The user discovers some certified content they wish to acquire +1. The user copies the URI for the content, passing it to the docker cli + - `docker run docker.io/hello-world:latest` +1. The user already has the `docker.io` certificate, enabling all certified content from docker hub +1. The image runs, as verification passes + +#### Public non-certified content + +1. The user discovers some community content they wish to acquire, such as a new network-monitor project +1. The user copies the URI for the content, passing it to the docker cli + - `docker run docker.io/wabbit-networks/net-monitor:latest` +1. The image fails to run as the user has `trust-required` enabled, and doesn't have the wabbit-networks key.The docker cli produces an error with a url for acquiring the wabbit-networks key. + - The user can disable `trust-requried`, or acquire the required key. +1. The user acquires the wabbit-networks key, saves it in their local store +1. The user again runs: + - `docker run docker.io/wabbit-networks/net-monitor:latest` + and the image is sucessfully run + +### Key acquisition + +*TBD by the key-management working group* + +### Private Registry + +Private registries serve the follwing scenarios: + +- Host public content, ceritifed for use within an orgnization +- Host privately built content, containing the intellectual property of the orgnization. + + +![acme-rockets cert](./media/acme-rockets-cert.png) + +```json +{ + "signed": { + "exp": 1626938793, + "nbf": 1595402793, + "iat": 1595402793, + "digest": "sha256:3351c53952446db17d21b86cfe5829ae70f823aff5d410fbf09dff820a39ab55", + "size": 528, + "references": [ + "registry.acme-rockets.io/hello-world:latest", + "registry.acme-rockets.io/hello-world:v1.0" + ] + }, + "signature": { + "typ": "x509", + ... +``` + +## Prototype Scope + +- Client + - CLI experience + - Signing + - Verification + - Binaries plug-in + - Actual pull / push should be done by external binaries +- Server + - Access control + - HTTP API changes + - Registry storage changes + +Key management is offloaded to the underlying signing tools. + +[distribution-spec]: https://github.com/opencontainers/distribution-spec +[notary-v2]: http://github.com/notaryproject/ +[oras]: https://github.com/deislabs/oras diff --git a/cmd/nv2/common.go b/cmd/nv2/common.go new file mode 100644 index 000000000..f6752a827 --- /dev/null +++ b/cmd/nv2/common.go @@ -0,0 +1,20 @@ +package main + +import "github.com/urfave/cli/v2" + +var ( + usernameFlag = &cli.StringFlag{ + Name: "username", + Aliases: []string{"u"}, + Usage: "username for generic remote access", + } + passwordFlag = &cli.StringFlag{ + Name: "password", + Aliases: []string{"p"}, + Usage: "password for generic remote access", + } + insecureFlag = &cli.BoolFlag{ + Name: "insecure", + Usage: "enable insecure remote access", + } +) diff --git a/cmd/nv2/main.go b/cmd/nv2/main.go new file mode 100644 index 000000000..828faca52 --- /dev/null +++ b/cmd/nv2/main.go @@ -0,0 +1,29 @@ +package main + +import ( + "log" + "os" + + "github.com/urfave/cli/v2" +) + +func main() { + app := &cli.App{ + Name: "nv2", + Usage: "Notary V2 - Prototype", + Version: "0.1.2", + Authors: []*cli.Author{ + { + Name: "Shiwei Zhang", + Email: "shizh@microsoft.com", + }, + }, + Commands: []*cli.Command{ + signCommand, + verifyCommand, + }, + } + if err := app.Run(os.Args); err != nil { + log.Fatal(err) + } +} diff --git a/cmd/nv2/manifest.go b/cmd/nv2/manifest.go new file mode 100644 index 000000000..9bd837c2f --- /dev/null +++ b/cmd/nv2/manifest.go @@ -0,0 +1,68 @@ +package main + +import ( + "fmt" + "io" + "math" + "net/url" + "os" + "strings" + + "github.com/notaryproject/nv2/pkg/registry" + "github.com/notaryproject/nv2/pkg/signature" + "github.com/opencontainers/go-digest" + "github.com/urfave/cli/v2" +) + +func getManifestFromContext(ctx *cli.Context) (signature.Manifest, error) { + if uri := ctx.Args().First(); uri != "" { + return getManfestsFromURI(ctx, uri) + } + return getManifestFromReader(os.Stdin) +} + +func getManifestFromReader(r io.Reader) (signature.Manifest, error) { + lr := &io.LimitedReader{ + R: r, + N: math.MaxInt64, + } + digest, err := digest.SHA256.FromReader(lr) + if err != nil { + return signature.Manifest{}, err + } + return signature.Manifest{ + Digest: digest.String(), + Size: math.MaxInt64 - lr.N, + }, nil +} + +func getManfestsFromURI(ctx *cli.Context, uri string) (signature.Manifest, error) { + parsed, err := url.Parse(uri) + if err != nil { + return signature.Manifest{}, err + } + var r io.Reader + switch strings.ToLower(parsed.Scheme) { + case "file": + path := parsed.Path + if parsed.Opaque != "" { + path = parsed.Opaque + } + file, err := os.Open(path) + if err != nil { + return signature.Manifest{}, err + } + defer file.Close() + r = file + case "docker", "oci": + remote := registry.NewClient(nil, ®istry.ClientOptions{ + Username: ctx.String("username"), + Password: ctx.String("password"), + Insecure: ctx.Bool("insecure"), + }) + return remote.GetManifestMetadata(parsed) + default: + return signature.Manifest{}, fmt.Errorf("unsupported URI scheme: %s", parsed.Scheme) + } + return getManifestFromReader(r) +} diff --git a/cmd/nv2/sign.go b/cmd/nv2/sign.go new file mode 100644 index 000000000..9a04ffde2 --- /dev/null +++ b/cmd/nv2/sign.go @@ -0,0 +1,137 @@ +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "strings" + "time" + + "github.com/notaryproject/nv2/pkg/signature" + "github.com/notaryproject/nv2/pkg/signature/x509" + "github.com/urfave/cli/v2" +) + +const signerID = "nv2" + +var signCommand = &cli.Command{ + Name: "sign", + Usage: "signs artifacts or images", + ArgsUsage: "[]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "method", + Aliases: []string{"m"}, + Usage: "signing method", + Required: true, + }, + &cli.StringFlag{ + Name: "key", + Aliases: []string{"k"}, + Usage: "signing key file [x509]", + TakesFile: true, + }, + &cli.StringFlag{ + Name: "cert", + Aliases: []string{"c"}, + Usage: "signing cert [x509]", + TakesFile: true, + }, + &cli.DurationFlag{ + Name: "expiry", + Aliases: []string{"e"}, + Usage: "expire duration", + }, + &cli.StringSliceFlag{ + Name: "reference", + Aliases: []string{"r"}, + Usage: "original references", + }, + &cli.StringFlag{ + Name: "output", + Aliases: []string{"o"}, + Usage: "write signature to a specific path", + }, + usernameFlag, + passwordFlag, + insecureFlag, + }, + Action: runSign, +} + +func runSign(ctx *cli.Context) error { + // initialize + scheme, err := getSchemeForSigning(ctx) + if err != nil { + return err + } + + // core process + content, err := prepareContentForSigning(ctx) + if err != nil { + return err + } + sig, err := scheme.Sign(signerID, content) + if err != nil { + return err + } + sigma, err := signature.Pack(content, sig) + if err != nil { + return err + } + + // write out + sigmaJSON, err := json.Marshal(sigma) + if err != nil { + return err + } + path := ctx.String("output") + if path == "" { + path = strings.Split(content.Manifest.Digest, ":")[1] + ".nv2" + } + if err := ioutil.WriteFile(path, sigmaJSON, 0666); err != nil { + return err + } + + fmt.Println(content.Manifest.Digest) + return nil +} + +func prepareContentForSigning(ctx *cli.Context) (signature.Content, error) { + manifest, err := getManifestFromContext(ctx) + if err != nil { + return signature.Content{}, err + } + manifest.References = ctx.StringSlice("reference") + now := time.Now() + nowUnix := now.Unix() + content := signature.Content{ + Manifest: manifest, + IssuedAt: nowUnix, + } + if expiry := ctx.Duration("expiry"); expiry != 0 { + content.NotBefore = nowUnix + content.Expiration = now.Add(expiry).Unix() + } + + return content, nil +} + +func getSchemeForSigning(ctx *cli.Context) (*signature.Scheme, error) { + var ( + signer signature.Signer + err error + ) + switch method := ctx.String("method"); method { + case "x509": + signer, err = x509.NewSignerFromFiles(ctx.String("key"), ctx.String("cert")) + default: + return nil, fmt.Errorf("unsupported signing method: %s", method) + } + scheme := signature.NewScheme() + if err != nil { + return nil, err + } + scheme.RegisterSigner(signerID, signer) + return scheme, nil +} diff --git a/cmd/nv2/verify.go b/cmd/nv2/verify.go new file mode 100644 index 000000000..d2bcf4eca --- /dev/null +++ b/cmd/nv2/verify.go @@ -0,0 +1,122 @@ +package main + +import ( + "crypto/x509" + "encoding/json" + "fmt" + "os" + + "github.com/notaryproject/nv2/internal/crypto" + "github.com/notaryproject/nv2/pkg/signature" + x509nv2 "github.com/notaryproject/nv2/pkg/signature/x509" + "github.com/urfave/cli/v2" +) + +var verifyCommand = &cli.Command{ + Name: "verify", + Usage: "verifies artifacts or images", + ArgsUsage: "[]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "signature", + Aliases: []string{"s", "f"}, + Usage: "signature file", + Required: true, + TakesFile: true, + }, + &cli.StringSliceFlag{ + Name: "cert", + Aliases: []string{"c"}, + Usage: "certs for verification [x509]", + TakesFile: true, + }, + &cli.StringSliceFlag{ + Name: "ca-cert", + Usage: "CA certs for verification [x509]", + TakesFile: true, + }, + usernameFlag, + passwordFlag, + insecureFlag, + }, + Action: runVerify, +} + +func runVerify(ctx *cli.Context) error { + // initialize + scheme, err := getSchemeForVerification(ctx) + if err != nil { + return err + } + sigma, err := readSignatrueFile(ctx.String("signature")) + if err != nil { + return err + } + + // core process + content, _, err := scheme.Verify(sigma) + if err != nil { + return fmt.Errorf("verification failure: %v", err) + } + manifest, err := getManifestFromContext(ctx) + if err != nil { + return err + } + if content.Manifest.Digest != manifest.Digest || content.Manifest.Size != manifest.Size { + return fmt.Errorf("verification failure: manifest is not signed: %s", manifest.Digest) + } + + // write out + fmt.Println(manifest.Digest) + return nil +} + +func readSignatrueFile(path string) (sig signature.Signed, err error) { + file, err := os.Open(path) + if err != nil { + return sig, err + } + defer file.Close() + err = json.NewDecoder(file).Decode(&sig) + return sig, err +} + +func getSchemeForVerification(ctx *cli.Context) (*signature.Scheme, error) { + scheme := signature.NewScheme() + + // add x509 verifier + verifier, err := getX509Verifier(ctx) + if err != nil { + return nil, err + } + scheme.RegisterVerifier(verifier) + + return scheme, nil +} + +func getX509Verifier(ctx *cli.Context) (signature.Verifier, error) { + roots := x509.NewCertPool() + + var certs []*x509.Certificate + for _, path := range ctx.StringSlice("cert") { + bundledCerts, err := crypto.ReadCertificateFile(path) + if err != nil { + return nil, err + } + certs = append(certs, bundledCerts...) + for _, cert := range bundledCerts { + roots.AddCert(cert) + } + } + for _, path := range ctx.StringSlice("ca-cert") { + bundledCerts, err := crypto.ReadCertificateFile(path) + if err != nil { + return nil, err + } + for _, cert := range bundledCerts { + roots.AddCert(cert) + } + } + + return x509nv2.NewVerifier(certs, roots) +} diff --git a/docs/artifact/README.md b/docs/artifact/README.md new file mode 100644 index 000000000..0e5df5c05 --- /dev/null +++ b/docs/artifact/README.md @@ -0,0 +1,22 @@ +# Notary V2 Artifact +[Notary v2 signatures](../signature/README.md) can be stored as [OCI artifacts](https://github.com/opencontainers/artifacts). Precisely, it is a [OCI manifest](https://github.com/opencontainers/image-spec/blob/master/manifest.md) with a config of type + +- `application/vnd.cncf.notary.config.v2+json` + +and no layers. + +## Example Artifact + +Example showing the manifest ([examples/manifest.json](examples/manifest.json)) of an artifact. + +```json +{ + "schemaVersion": 2, + "config": { + "mediaType": "application/vnd.cncf.notary.config.v2+json", + "size": 1906, + "digest": "sha256:c7848182f2c817415f0de63206f9e4220012cbb0bdb750c2ecf8020350239814" + }, + "layers": [] +} +``` diff --git a/docs/artifact/examples/manifest.json b/docs/artifact/examples/manifest.json new file mode 100644 index 000000000..5e57feda6 --- /dev/null +++ b/docs/artifact/examples/manifest.json @@ -0,0 +1,9 @@ +{ + "schemaVersion": 2, + "config": { + "mediaType": "application/vnd.cncf.notary.config.v2+json", + "size": 1906, + "digest": "sha256:c7848182f2c817415f0de63206f9e4220012cbb0bdb750c2ecf8020350239814" + }, + "layers": [] +} \ No newline at end of file diff --git a/docs/nv2/README.md b/docs/nv2/README.md new file mode 100644 index 000000000..6ee30200e --- /dev/null +++ b/docs/nv2/README.md @@ -0,0 +1,293 @@ +# Notary V2 (nv2) - Prototype + +`nv2` is a command line tool for signing and verifying [OCI Artifacts]. This implementation supports `x509` signing mechanisms. + +## Table of Contents + +- [Prerequisites](#prerequisites) +- [CLI Overview](#cli-overview) +- [Offline signing & verification](#offline-signing-and-verification) + +## Prerequisites + +### Build and Install + +This plugin requires [golang](https://golang.org/dl/) with version `>= 1.14`. + +To build and install, run + +```shell +go install github.com/notaryproject/nv2/cmd/nv2 +``` + +To build and install to an optional path, run + +```shell +go build -o nv2 ./cmd/nv2 +``` + +Next, install optional components: + +- Install [docker-generate](https://github.com/shizhMSFT/docker-generate) for local Docker manifest generation and local signing. +- Install [OpenSSL](https://www.openssl.org/) for key generation. + +### Self-signed certificate key generation + +To generate a `x509` self-signed certificate key pair `example.key` and `example.crt`, run + +``` shell +openssl req \ + -x509 \ + -sha256 \ + -nodes \ + -newkey rsa:2048 \ + -days 365 \ + -subj "/CN=registry.example.com/O=example inc/C=US/ST=Washington/L=Seattle" \ + -keyout example.key \ + -out example.crt +``` + +When generating the certificate, make sure that the Common Name (`CN`) is set properly in the `Subject` field. The Common Name will be verified against the registry name within the signature. + +## Offline Signing + +Offline signing is accomplished with the `nv2 sign` command. + +### nv2 sign options + +```shell +NAME: + nv2 sign - signs OCI Artifacts + +USAGE: + nv2 sign [command options] [] + +OPTIONS: + --method value, -m value signing method + --key value, -k value signing key file [x509] + --cert value, -c value signing cert [x509] + --expiry value, -e value expire duration (default: 0s) + --reference value, -r value original references + --output value, -o value write signature to a specific path + --username value, -u value username for generic remote access + --password value, -p value password for generic remote access + --insecure enable insecure remote access (default: false) + --help, -h show help (default: false) +``` + +Signing and verification are based on [OCI manifests](https://github.com/opencontainers/image-spec/blob/master/manifest.md), [docker-generate](https://github.com/shizhMSFT/docker-generate) is used to generate the manifest, which is exactly the same manifest as the `docker push` produces. + +### Generating a manifest + +Notary v2 signing is accomplished by signing the OCI manifest representing the artifact. When building docker images, the manifest is not generated until the image is pushed to a registry. To accomplish offline/local signing, the manifest must first exist. + +- Build the hello-world image + + ``` shell + docker build \ + -f Dockerfile.build \ + -t registry.acme-rockets.io/hello-world:v1 \ + https://github.com/docker-library/hello-world.git + ``` + +- Generate a manifest, saving it as `hello-world_v1-manifest.json` + + ``` shell + docker generate manifest registry.acme-rockets.io/hello-world:v1 > hello-world_v1-manifest.json + ``` + +### Signing using `x509` + +To sign the manifest `hello-world_v1-manifest.json` using the key `key.pem` from the `x509` certificate `cert.pem` with the Common Name `registry.acme-rockets.io`, run + +```shell +nv2 sign --method x509 \ + -k key.key \ + -c cert.crt \ + -r registry.acme-rockets.io/hello-world:v1 \ + -o hello-world.signature.config.json \ + file:hello-world_v1-manifest.json +``` + +The formatted x509 signature: `hello-world.signature.config.json` is: + +``` json +{ + "signed": { + "digest": "sha256:5de47f48e0be1a9d41176a980728449a696fd4fcc37e9d99b8d26618c0f5bf51", + "size": 3056, + "references": [ + "registry.acme-rockets.io/hello-world:v1" + ], + "iat": 1596020554 + }, + "signature": { + "typ": "x509", + "sig": "vUNmuwrdHmcMyvG//eZQLjmIz2gnOUFNaL5Y5Jc3x1oaYu3nFnJxBEkB8232l0zBmV30sVUX2vjao0IDgLMv0Q7VWT2hiTutocgf+oRq88Jz/xKGvByGUWmVyYx9sMW6R+JHK/LlzthCLgDoYTjFD9qDTHf+AWnmRNPLv5nSYNQrVSxNH22jiO3CV/bNEQD8xoR7kZOdov6QzNw3rAP+XvlKxdf/D7vcYdR0D5T9G5xGa72aQSZmzXL/Zd2V7JQnxyJmw6PL3moU1i/8t8RK7LbsU6slvTScLUokFLZxzqCz8TcjujtaThyyxPF47ekx/HVsKW0mYXidpgCOfl+nqw==", + "alg": "RS256", + "x5c": [ + "MIIDJzCCAg+gAwIBAgIUMwVg7bpx8QmWaFzRcgpRFBN6JoQwDQYJKoZIhvcNAQELBQAwIzEhMB8GA1UEAwwYcmVnaXN0cnkuYWNtZS1yb2NrZXRzLmlvMB4XDTIwMDcyOTExMDIzMloXDTIxMDcyOTExMDIzMlowIzEhMB8GA1UEAwwYcmVnaXN0cnkuYWNtZS1yb2NrZXRzLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2mXqcXqkllwxj7S12WhVDsIu6y4ebZ/CwVwwime44yDcd0bcpdJExqIH/Qy6axQd/1zmLCHPeOXGFq48Ul0oS4Bawj1GEeLvB7VFvqB0KaBeAdxrZAvdKXCXIDH5qyFSGnOmvkja1BuR8XrH7tts5u56i+U3KEDBZg5tfx4cQuKKt0DfXZAL+4RZkNh1LoO77X0ThaBThFoRsg6aZA/cEpttoWmvnO6uUkK73oZEVgZNKGGIZZKzhUjnydRSTphp9GmZzbqUHlOiMvbzdtsQYC0qeQeNqua38HN93Ur3p+oH7oSrBWxX1Xlx933oVb+4G6h5oz0aZvMQ0G6gCLzjwIDAQABo1MwUTAdBgNVHQ4EFgQU8l2F7avSjFZ9TvnpHackunxSFcswHwYDVR0jBBgwFoAU8l2F7avSjFZ9TvnpHackunxSFcswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAwECYhttcbCbqyi7DvOTHw5bixmxplbgD0AmMvE6Ci4P/MrooBququlkri/Jcp58GBaMjxItE4qVsaWwFCEvZEfP2xN4DAbr+rdrIFy9VYuwEIBs5l0ZLRH2H2N3HlqBzhYOjVzNlYfIqnqHUDip2VsUKqhcVFkCmb3cpJ1VNAgjQU2N60JUW28L0XrGyBctBIiicLvdP4NMhHP/hhN2vr2VGIyyo5XtP+QHFi/Uwa48BJ+c9bbVpXeghOMOPMeSJmJ2b/qlp95e/YHlSCfxDXyxZ70N2vBGecrc8ly4tD9KGLb9y3Q7RBgsagOFe7cGQ2db/t60AwTIxP0a9bIyJMg==" + ] + } +} +``` + +If the embedded cert chain `x5c` is not desired, it can be replaced by a key ID `kid` by omitting the `-c` option. + +```shell +nv2 sign -m x509 \ + -k key.key \ + -r registry.acme-rockets.io/hello-world:v1 \ + -o hello-world.signature.config.json \ + file:hello-world_v1-manifest.json +``` + +The formatted x509, without the `x5c` chain signature: `hello-world.signature.config.json` is: + + +```json +{ + "signed": { + "digest": "sha256:5de47f48e0be1a9d41176a980728449a696fd4fcc37e9d99b8d26618c0f5bf51", + "size": 3056, + "references": [ + "registry.acme-rockets.io/hello-world:v1" + ], + "iat": 1596020616 + }, + "signature": { + "typ": "x509", + "sig": "OyRPlwwsO5mYDxKkiNeTQlSl4WV8SOiQMCJv4i1+sx7uv6Pe8dHDaPt1SE5s64HzFvo6s26PrfiPYp4RphQOd/KvW2Hh03nS8ZByE4NWFOE6VLQcfNpScba6Q9vAzc3TnZrg1c9t992MGuec1oZB9pR77Ms7Jv/+gZd1qr6VPpA0A6+UucEbN6+pKRTiPRx5WkFXTkN0a4jmlJnev6MyBY3VI0EzjLI4nbCu9P05e4SK1dO0hXtD7aQCf2CCVKdYNHAMX4pNPTLxS3a5p4CFjV3oCbZO6cYT/5ZxgQrVV7vaGEI1MGCOEXS2KSI14zO6KlU1awtOQq3g04e03O+SVQ==", + "alg": "RS256", + "kid": "RQGT:OPJI:IABT:DFXB:52VS:FNOJ:4XBS:H4KY:WHGM:HQMC:WSMN:LKXM" + } +} +``` + +The detailed signature specification is [available](../signature/README.md). + +### Offline Verification + +Notary v2 verification can be accomplished with the `nv2 verify` command. + +```shell +NAME: + nv2 verify - verifies OCI Artifacts + +USAGE: + nv2 verify [command options] [] + +OPTIONS: + --signature value, -s value, -f value signature file + --cert value, -c value certs for verification [x509] + --ca-cert value CA certs for verification [x509] + --username value, -u value username for generic remote access + --password value, -p value password for generic remote access + --insecure enable insecure remote access (default: false) + --help, -h show help (default: false) +``` + +To verify a manifest `example.json` with a signature file `example.nv2`, run + +Since the manifest was signed by a self-signed certificate, that certificate `cert.pem` is required to be provided to `nv2`. + +```shell +nv2 verify \ + -f hello-world.signature.config.json \ + -c cert.crt \ + file:hello-world_v1-manifest.json +``` + +If the cert isn't self-signed, you can omit the `-c` parameter. + +``` shell +nv2 verify \ + -f hello-world.signature.config.json \ + file:hello-world_v1-manifest.json + +sha256:3351c53952446db17d21b86cfe5829ae70f823aff5d410fbf09dff820a39ab55 +``` + +On successful verification, the `sha256` digest of the manifest is printed. Otherwise, `nv2` prints error messages and returns non-zero values. + +The command `nv2 verify` takes care of all signing methods. + +## Remote Manifests + +With `nv2`, it is also possible to sign and verify a manifest or a manifest list in a remote registry where the registry can be a docker registry or an OCI registry. + +### Docker Registry + +Here is an example to sign and verify the image `hello-world` in DockerHub, i.e. `docker.io/library/hello-world:latest`, using `x509`. + +``` shell +nv2 sign -m x509 \ + -k key.key \ + -o hello-world_latest.signature.config.json \ + docker://docker.io/library/hello-world:latest + +sha256:49a1c8800c94df04e9658809b006fd8a686cab8028d33cfba2cc049724254202 + +nv2 verify \ + -c cert.crt \ + -f hello-world_latest.signature.config.json \ + docker://docker.io/library/hello-world:latest +sha256:49a1c8800c94df04e9658809b006fd8a686cab8028d33cfba2cc049724254202 +``` + +It is possible to use `digest` in the reference. For instance: + +``` shell +docker.io/library/hello-world@sha256:49a1c8800c94df04e9658809b006fd8a686cab8028d33cfba2cc049724254202 +``` + +If neither `tag` nor `digest` is specified, the default tag `latest` is used. + +### OCI Registry + +OCI registry works the same as Docker but with the scheme `oci`. + + +``` shell +nv2 sign -m x509 \ + -k key.key \ + -o hello-world_latest.signature.config.json \ + oci://docker.io/library/hello-world:latest + +sha256:0ebe6f409b373c8baf39879fccee6cae5e718003ec3167ded7d54cb2b5da2946 + +nv2 verify \ + -c cert.crt \ + -f hello-world_latest.signature.config.json \ + oci://docker.io/library/hello-world:latest + +sha256:0ebe6f409b373c8baf39879fccee6cae5e718003ec3167ded7d54cb2b5da2946 +``` + +**Note** The digest of the OCI manifest is different from the Docker manifest for the same image since their format is different. Therefore, the signer should be careful with the manifest type when signing. + +### Insecure Registries + +To sign and verify images from insecure registries accessed via `HTTP`, such as `localhost`, the option `--insecure` is required. + +``` shell +docker tag example localhost:5000/example +docker push localhost:5000/example +The push refers to repository [localhost:5000/example] +50644c29ef5a: Pushed +latest: digest: sha256:3351c53952446db17d21b86cfe5829ae70f823aff5d410fbf09dff820a39ab55 size: 528 +nv2 verify -f example.nv2 --insecure docker://localhost:5000/example + +sha256:3351c53952446db17d21b86cfe5829ae70f823aff5d410fbf09dff820a39ab55 +``` + +### Secure Image Pulling + +Since the tag might be changed during the verification process, it is required to pull by digest after verification. + +```shell +digest=$(nv2 verify -f hello-world_latest.signature.config.json -c cert.crt docker://docker.io/library/hello-world:latest) +if [ $? -eq 0 ]; then + docker pull docker.io/library/hello-world@$digest +fi +``` diff --git a/docs/signature/README.md b/docs/signature/README.md new file mode 100644 index 000000000..d3b49d7fd --- /dev/null +++ b/docs/signature/README.md @@ -0,0 +1,225 @@ +# Notary V2 Signature Specification + +This section defines the signature file, which is in JSON format with no whitespaces. Its JSON schema is available at [schema.json](schema.json). + +## Signature Goals + +- Offline signature creation +- Persistance within an [OCI Artifact][oci-artifacts] enabled, [distribution-spec][distribution-spec] based registry +- Artifact and signature copying within and across [OCI Artifact][oci-artifacts] enabled, [distribution-spec][distribution-spec] based registries +- Support public registry acquisition of content - where the public registry may host certified content as well as public, non-certified content +- Support private registries, where public content may be copied to, and new content originated within +- Air-gapped environments, where the originating registry of content is not accessable +- Multiple signatures per artifact, enabling the originating vendor signature, public registry certification and user/environment signatures +- Maintain the original artifact digest and collection of associated tags, supporting dev/ops deployment definitions + +## Signature + +A Notary v2 signature is clear-signed signature of manifest metadata, including but not limited to + +- [OCI Image Index](https://github.com/opencontainers/image-spec/blob/master/image-index.md) +- [OCI Image Manifest](https://github.com/opencontainers/image-spec/blob/master/manifest.md) +- [Docker Image Manifest List](https://docs.docker.com/registry/spec/manifest-v2-2/#manifest-list) +- [Docker Image Manifest](https://docs.docker.com/registry/spec/manifest-v2-2/#image-manifest) + +### Signing an Artifact Manifest + +For any [OCI Artifact][oci-artifacts] submitted to a registry, an [OCI Manifest][oci-manifest] and an optional [OCI Manifest List/Index][oci-manifest-list] is required. + +The nv2 prototype signs a combination of: + +- Key properties +- The target artifact manifest digest +- *optional:* list of associated tags + +#### Generating a self-signed x509 cert + +``` shell +openssl req \ + -x509 \ + -sha256 \ + -nodes \ + -newkey rsa:2048 \ + -days 365 \ + -subj "/CN=registry.example.com/O=example inc/C=US/ST=Washington/L=Seattle" \ + -keyout example.key \ + -out example.crt +``` + +An nv2 client would generate the following content to be signed: + +``` JSON +{ + "signed": { + "digest": "sha256:c4516b8a311e85f1f2a60573abf4c6b740ca3ade4127e29b05616848de487d34", + "size": 528, + "references": [ + "registry.example.com/example:latest", + "registry.example.com/example:v1.0" + ], + "exp": 1627555319, + "nbf": 1596019319, + "iat": 1596019319 + } +} +``` + +The signature of the above would be represented as: + +``` JSON +{ + "signature": { + "typ": "x509", + "sig": "UFqN24K2fLj7/h2slM68PLTfF9CDhrEVGuMQ8m3kkQJ4SKusj9fNxYV78tTiedqB+E8SqVH66mZbdlTrVQFJAd7aL2c3NZFfo92pE9SaHnqEDqnnGWXGRVjtBRM13YyRDm2wD8aRyuL5jEDUkTw7jBLY0+LfKHMDuYCsOOzvedof7aiaFc3qA+qKiW53jn2uEGCFfAs0LmsNafGfAtVmdGSO4zX4fdnQFAGT8sbUmL71uXl9W1B6tGeLfx5nBoQUvtplQipHly/yMQvWw7qMXsaAsf/BbGDmivN06CRahSb7VOwNq6K7Py4zYeiW40hEFVz9L7/5xT5XI1unKPZDuw==", + "alg": "RS256", + "x5c": [ + "MIIDszCCApugAwIBAgIUL1anEU/yJy67VJTbHkNX0bBNAnEwDQYJKoZIhvcNAQELBQAwaTEdMBsGA1UEAwwUcmVnaXN0cnkuZXhhbXBsZS5jb20xFDASBgNVBAoMC2V4YW1wbGUgaW5jMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTAeFw0yMDA3MjcxNDQzNDZaFw0yMTA3MjcxNDQzNDZaMGkxHTAbBgNVBAMMFHJlZ2lzdHJ5LmV4YW1wbGUuY29tMRQwEgYDVQQKDAtleGFtcGxlIGluYzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkKwAcV44psjN8nno1eZ3zv1ZKUhJAoxwBOIGfIxIe+iHtpXLvFFVwk5Jbxu+Pkig2N4B3Ilrj/Vryi0hxp4mag02M733bXLRENSOFONRkslpO8zHUN5pYdnhTSwYTLap1+1bgcFSuUXLWieqZB6qc7kiv3bj3SPaf42+s48V49t/OpXxLtgiWL9XkuDTZctpJJA4vHHk6Ou0bcg7iGm+L1xwIfb8Ml4oWvT0SF35fgW08bbLXZ2v1XCLRsrWUgbq4U+KxtEpG3XIYcYhKx1rIrUhfEJkuHzgPglM11gG5W+Cyfg+wfOJig5q6axIKWzIf6C8m8lmy6bM+N5EsD9SvAgMBAAGjUzBRMB0GA1UdDgQWBBTf1hM6/ibGF+u/SVAK88FUMjzRoTAfBgNVHSMEGDAWgBTf1hM6/ibGF+u/SVAK88FUMjzRoTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBgvVau5+2wAuCsmOyyG28h1zyC4IPmMmpRZTDOp/pLdwXeHjJr8kEC3l92qJEvc+WAboJ1RoucHycUe7RWh2C6ZF/WPCBLyWGwnlyqGyRM9/j86UJ1OgiuZl7kl9zxwWoaxPBCmHa0RHowdQB7AVlpqg1c7FhKjhUCBmGT4Ve8tV0hdZtrZoQV+6xHPbUd37KV1B1Bmfo3o4ekoJKhUu99Eo03OpE3JLtM13A1HxABEuQGHTI0tycDBBdRn3b03HoIhU0VnqjvpV1KPvsrgYi/0VStLNezZPgGe0fG3Xgy8yekdB9NMUn+zZLATI4+z8j4QH5Wj5ZPaUkyoAD2oUJO" + ] + } +} +``` + +### Signature Persisted within an OCI Artifact Enabled Registry + +Both values are persisted in a `signature.json` file. The file would be submitted to a registry as an Artifact with null layers. +The `signature.json` would be persisted within the `manifest.config` object + +``` SHELL +oras push \ + registry.example.com/hello-world:v1.0 \ + --manifest-config signature.json:application/vnd.cncf.notary.config.v2+json +``` + +Would push the following manifest: + +``` JSON +{ + "schemaVersion": 2, + "config": { + "mediaType": "application/vnd.cncf.notary.config.v2+json", + "size": 1906, + "digest": "sha256:c7848182f2c817415f0de63206f9e4220012cbb0bdb750c2ecf8020350239814" + }, + "layers": [] +} +``` + +## *Signature* Property Descriptions + +- **`signed`** *object* + + This REQUIRED property provides the signed content. + + - **`iat`** *integer* + + This OPTIONAL property identities the time at which the manifests were presented to the notary. This field is based on [RFC 7519 Section 4.1.6](https://tools.ietf.org/html/rfc7519#section-4.1.6). When used, it does not imply the issue time of any signature in the `signatures` property. + + - **`nbf`** *integer* + + This OPTIONAL property identifies the time before which the signed content MUST NOT be accepted for processing. This field is based on [RFC 7519 Section 4.1.5](https://tools.ietf.org/html/rfc7519#section-4.1.5). + + - **`exp`** *integer* + + This OPTIONAL property identifies the expiration time on or after which the signed content MUST NOT be accepted for processing. This field is based on [RFC 7519 Section 4.1.4](https://tools.ietf.org/html/rfc7519#section-4.1.4). + + - **`digest`** *string* + + This REQUIRED property is the *digest* of the target manifest, conforming to the requirements outlined in [Digests](https://github.com/opencontainers/image-spec/blob/master/descriptor.md#digests). If the actual content is fetched according to the *digest*, implementations MUST verify the content against the *digest*. + + - **`size`** *integer* + + This REQUIRED property is the *size* of the target manifest. If the actual content is fetched according the *digest*, implementations MUST verify the content against the *size*. + + - **`references`** *array of strings* + + This OPTIONAL property claims the manifest references of its origin. The format of the value MUST matches the [*reference* grammar](https://github.com/docker/distribution/blob/master/reference/reference.go). With used, the `x509` signatures are valid only if the domain names of all references match the Common Name (`CN`) in the `Subject` field of the certificate. + +- **`signature`** *string* + + This REQUIRED property provides the signature of the signed content. The entire signature file is valid if any signature is valid. The `signature` object is influenced by JSON Web Signature (JWS) at [RFC 7515](https://tools.ietf.org/html/rfc7515). + + - **`typ`** *string* + + This REQUIRED property identifies the signature type. Implementations MUST support at least the following types + + - `x509`: X.509 public key certificates. Implementations MUST verify that the certificate of the signing key has the `digitalSignature` `Key Usage` extension ([RFC 5280 Section 4.2.1.3](https://tools.ietf.org/html/rfc5280#section-4.2.1.3)). + + Implementations MAY support the following types + + - `tuf`: [The update framework](https://theupdateframework.io/). + + - **`sig`** *string* + + This REQUIRED property provides the base64-encoded signature binary of the specified signature type. + + - **`alg`** *string* + + This REQUIRED property for the `x509` type identifies the cryptographic algorithm used to sign the content. This field is based on [RFC 7515 Section 4.1.1](https://tools.ietf.org/html/rfc7515#section-4.1.1). + + - **`x5c`** *array of strings* + + This OPTIONAL property for the `x509` type contains the X.509 public key certificate or certificate chain corresponding to the key used to digitally sign the content. The certificates are encoded in base64. This field is based on [RFC 7515 Section 4.1.6](https://tools.ietf.org/html/rfc7515#section-4.1.6). + + - **`kid`** *string* + + This OPTIONAL property for the `x509` type is a hint (key ID) indicating which key was used to sign the content. This field is based on [RFC 7515 Section 4.1.4](https://tools.ietf.org/html/rfc7515#section-4.1.4). + +## Example Signatures + +### x509 Signature + +Example showing a formatted `x509` signature file [examples/x509_x5c.nv2.json](examples/x509_x5c.nv2.json) with certificates provided by `x5c`: + +```json +{ + "signed": { + "digest": "sha256:c4516b8a311e85f1f2a60573abf4c6b740ca3ade4127e29b05616848de487d34", + "size": 528, + "references": [ + "registry.example.com/example:latest", + "registry.example.com/example:v1.0" + ], + "exp": 1627555319, + "nbf": 1596019319, + "iat": 1596019319 + }, + "signature": { + "typ": "x509", + "sig": "UFqN24K2fLj7/h2slM68PLTfF9CDhrEVGuMQ8m3kkQJ4SKusj9fNxYV78tTiedqB+E8SqVH66mZbdlTrVQFJAd7aL2c3NZFfo92pE9SaHnqEDqnnGWXGRVjtBRM13YyRDm2wD8aRyuL5jEDUkTw7jBLY0+LfKHMDuYCsOOzvedof7aiaFc3qA+qKiW53jn2uEGCFfAs0LmsNafGfAtVmdGSO4zX4fdnQFAGT8sbUmL71uXl9W1B6tGeLfx5nBoQUvtplQipHly/yMQvWw7qMXsaAsf/BbGDmivN06CRahSb7VOwNq6K7Py4zYeiW40hEFVz9L7/5xT5XI1unKPZDuw==", + "alg": "RS256", + "x5c": [ + "MIIDszCCApugAwIBAgIUL1anEU/yJy67VJTbHkNX0bBNAnEwDQYJKoZIhvcNAQELBQAwaTEdMBsGA1UEAwwUcmVnaXN0cnkuZXhhbXBsZS5jb20xFDASBgNVBAoMC2V4YW1wbGUgaW5jMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTAeFw0yMDA3MjcxNDQzNDZaFw0yMTA3MjcxNDQzNDZaMGkxHTAbBgNVBAMMFHJlZ2lzdHJ5LmV4YW1wbGUuY29tMRQwEgYDVQQKDAtleGFtcGxlIGluYzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkKwAcV44psjN8nno1eZ3zv1ZKUhJAoxwBOIGfIxIe+iHtpXLvFFVwk5Jbxu+Pkig2N4B3Ilrj/Vryi0hxp4mag02M733bXLRENSOFONRkslpO8zHUN5pYdnhTSwYTLap1+1bgcFSuUXLWieqZB6qc7kiv3bj3SPaf42+s48V49t/OpXxLtgiWL9XkuDTZctpJJA4vHHk6Ou0bcg7iGm+L1xwIfb8Ml4oWvT0SF35fgW08bbLXZ2v1XCLRsrWUgbq4U+KxtEpG3XIYcYhKx1rIrUhfEJkuHzgPglM11gG5W+Cyfg+wfOJig5q6axIKWzIf6C8m8lmy6bM+N5EsD9SvAgMBAAGjUzBRMB0GA1UdDgQWBBTf1hM6/ibGF+u/SVAK88FUMjzRoTAfBgNVHSMEGDAWgBTf1hM6/ibGF+u/SVAK88FUMjzRoTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBgvVau5+2wAuCsmOyyG28h1zyC4IPmMmpRZTDOp/pLdwXeHjJr8kEC3l92qJEvc+WAboJ1RoucHycUe7RWh2C6ZF/WPCBLyWGwnlyqGyRM9/j86UJ1OgiuZl7kl9zxwWoaxPBCmHa0RHowdQB7AVlpqg1c7FhKjhUCBmGT4Ve8tV0hdZtrZoQV+6xHPbUd37KV1B1Bmfo3o4ekoJKhUu99Eo03OpE3JLtM13A1HxABEuQGHTI0tycDBBdRn3b03HoIhU0VnqjvpV1KPvsrgYi/0VStLNezZPgGe0fG3Xgy8yekdB9NMUn+zZLATI4+z8j4QH5Wj5ZPaUkyoAD2oUJO" + ] + } +} +``` + +Example showing a formatted `x509` signature file [examples/x509_kid.nv2.json](examples/x509_kid.nv2.json) with certificates referenced by `kid`: + +```json +{ + "signed": { + "digest": "sha256:c4516b8a311e85f1f2a60573abf4c6b740ca3ade4127e29b05616848de487d34", + "size": 528, + "references": [ + "registry.example.com/example:latest", + "registry.example.com/example:v1.0" + ], + "exp": 1627554920, + "nbf": 1596018920, + "iat": 1596018920 + }, + "signature": { + "typ": "x509", + "sig": "emzP9ygJD3y2ZWMYGO/wyqOhaSxrhd4ZdmjC9Zd+Ba7gGmGzBylsY1CskyZw389Hz2Z0xA6AQLhaNBbbqyxuAxVXtataMRsqCl/cgyNbyYU1URB2aTUZY/3V4iJzH1O/QfwSkpQa3aN1OCL8uMBNCtM6Rde9+SX8Q8XNMByDbuXtyPDvnKunZxpofEn2ibLe2Cm3o+MTK4pgxacEWeld85gTb06NicARf7mcVj7bflLyUIgel4qvmdqT6896Gtd2ES1KawvyjoEyskdlVlneSTdEKGRYxfchwIUK4E7p3EtTnmj+FuD9MpCtP0M4CQiOr19j0NtQe2bHuTo4bwtjuw==", + "alg": "RS256", + "kid": "XP5O:Y7W2:PRB6:O355:56CC:P3A6:CBDV:EDMN:QZCK:W5PO:QMV3:T2LX" + } +} +``` + +[distribution-spec]: https://github.com/opencontainers/distribution-spec +[oci-artifacts]: https://github.com/opencontainers/artifacts +[oci-manifest]: https://github.com/opencontainers/image-spec/blob/master/manifest.md +[oci-manifest-list]: https://github.com/opencontainers/image-spec/blob/master/image-index.md + diff --git a/docs/signature/examples/x509_kid.nv2.json b/docs/signature/examples/x509_kid.nv2.json new file mode 100644 index 000000000..dc30f0a6e --- /dev/null +++ b/docs/signature/examples/x509_kid.nv2.json @@ -0,0 +1 @@ +{"signed":{"digest":"sha256:c4516b8a311e85f1f2a60573abf4c6b740ca3ade4127e29b05616848de487d34","size":528,"references":["registry.example.com/example:latest","registry.example.com/example:v1.0"],"exp":1627554920,"nbf":1596018920,"iat":1596018920},"signature":{"typ":"x509","sig":"emzP9ygJD3y2ZWMYGO/wyqOhaSxrhd4ZdmjC9Zd+Ba7gGmGzBylsY1CskyZw389Hz2Z0xA6AQLhaNBbbqyxuAxVXtataMRsqCl/cgyNbyYU1URB2aTUZY/3V4iJzH1O/QfwSkpQa3aN1OCL8uMBNCtM6Rde9+SX8Q8XNMByDbuXtyPDvnKunZxpofEn2ibLe2Cm3o+MTK4pgxacEWeld85gTb06NicARf7mcVj7bflLyUIgel4qvmdqT6896Gtd2ES1KawvyjoEyskdlVlneSTdEKGRYxfchwIUK4E7p3EtTnmj+FuD9MpCtP0M4CQiOr19j0NtQe2bHuTo4bwtjuw==","alg":"RS256","kid":"XP5O:Y7W2:PRB6:O355:56CC:P3A6:CBDV:EDMN:QZCK:W5PO:QMV3:T2LX"}} \ No newline at end of file diff --git a/docs/signature/examples/x509_x5c.nv2.json b/docs/signature/examples/x509_x5c.nv2.json new file mode 100644 index 000000000..2c621e223 --- /dev/null +++ b/docs/signature/examples/x509_x5c.nv2.json @@ -0,0 +1 @@ +{"signed":{"digest":"sha256:c4516b8a311e85f1f2a60573abf4c6b740ca3ade4127e29b05616848de487d34","size":528,"references":["registry.example.com/example:latest","registry.example.com/example:v1.0"],"exp":1627555319,"nbf":1596019319,"iat":1596019319},"signature":{"typ":"x509","sig":"UFqN24K2fLj7/h2slM68PLTfF9CDhrEVGuMQ8m3kkQJ4SKusj9fNxYV78tTiedqB+E8SqVH66mZbdlTrVQFJAd7aL2c3NZFfo92pE9SaHnqEDqnnGWXGRVjtBRM13YyRDm2wD8aRyuL5jEDUkTw7jBLY0+LfKHMDuYCsOOzvedof7aiaFc3qA+qKiW53jn2uEGCFfAs0LmsNafGfAtVmdGSO4zX4fdnQFAGT8sbUmL71uXl9W1B6tGeLfx5nBoQUvtplQipHly/yMQvWw7qMXsaAsf/BbGDmivN06CRahSb7VOwNq6K7Py4zYeiW40hEFVz9L7/5xT5XI1unKPZDuw==","alg":"RS256","x5c":["MIIDszCCApugAwIBAgIUL1anEU/yJy67VJTbHkNX0bBNAnEwDQYJKoZIhvcNAQELBQAwaTEdMBsGA1UEAwwUcmVnaXN0cnkuZXhhbXBsZS5jb20xFDASBgNVBAoMC2V4YW1wbGUgaW5jMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTAeFw0yMDA3MjcxNDQzNDZaFw0yMTA3MjcxNDQzNDZaMGkxHTAbBgNVBAMMFHJlZ2lzdHJ5LmV4YW1wbGUuY29tMRQwEgYDVQQKDAtleGFtcGxlIGluYzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkKwAcV44psjN8nno1eZ3zv1ZKUhJAoxwBOIGfIxIe+iHtpXLvFFVwk5Jbxu+Pkig2N4B3Ilrj/Vryi0hxp4mag02M733bXLRENSOFONRkslpO8zHUN5pYdnhTSwYTLap1+1bgcFSuUXLWieqZB6qc7kiv3bj3SPaf42+s48V49t/OpXxLtgiWL9XkuDTZctpJJA4vHHk6Ou0bcg7iGm+L1xwIfb8Ml4oWvT0SF35fgW08bbLXZ2v1XCLRsrWUgbq4U+KxtEpG3XIYcYhKx1rIrUhfEJkuHzgPglM11gG5W+Cyfg+wfOJig5q6axIKWzIf6C8m8lmy6bM+N5EsD9SvAgMBAAGjUzBRMB0GA1UdDgQWBBTf1hM6/ibGF+u/SVAK88FUMjzRoTAfBgNVHSMEGDAWgBTf1hM6/ibGF+u/SVAK88FUMjzRoTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBgvVau5+2wAuCsmOyyG28h1zyC4IPmMmpRZTDOp/pLdwXeHjJr8kEC3l92qJEvc+WAboJ1RoucHycUe7RWh2C6ZF/WPCBLyWGwnlyqGyRM9/j86UJ1OgiuZl7kl9zxwWoaxPBCmHa0RHowdQB7AVlpqg1c7FhKjhUCBmGT4Ve8tV0hdZtrZoQV+6xHPbUd37KV1B1Bmfo3o4ekoJKhUu99Eo03OpE3JLtM13A1HxABEuQGHTI0tycDBBdRn3b03HoIhU0VnqjvpV1KPvsrgYi/0VStLNezZPgGe0fG3Xgy8yekdB9NMUn+zZLATI4+z8j4QH5Wj5ZPaUkyoAD2oUJO"]}} \ No newline at end of file diff --git a/docs/signature/schema.json b/docs/signature/schema.json new file mode 100644 index 000000000..a66e843c7 --- /dev/null +++ b/docs/signature/schema.json @@ -0,0 +1,78 @@ +{ + "description": "Notary V2 Signature Config Specification", + "$schema": "http://json-schema.org/draft-04/schema#", + "id": "https://localhost:5000/schema/signature/config", + "type": "object", + "properties": { + "signed": { + "type": "object", + "properties": { + "exp": { + "type": "integer", + "description": "Expiration time. Ref RFC7519." + }, + "nbf": { + "type": "integer", + "description": "Not before time. Ref RFC7519." + }, + "iat": { + "type": "integer", + "description": "Issued at time. Ref RFC7519." + }, + "digest": { + "description": "The cryptographic checksum digest of the object, in the pattern ':'", + "$ref": "defs-descriptor.json#/definitions/digest" + }, + "size": { + "description": "The size in bytes of the referenced object.", + "$ref": "defs.json#/definitions/int64" + }, + "references": { + "type": "array", + "description": "Each element in this array represents a fully qualified tag reference to the object.", + "minItems": 1, + "items": { + "type": "string", + "description": "Example: localhost:5000/hello-world:latest" + } + } + } + }, + "signature": { + "type": "object", + "properties": { + "typ": { + "type": "string", + "description": "Media type. Ref RFC7519.", + "enum": [ + "x509" + ] + }, + "sig": { + "type": "string", + "description": "The signature blob." + }, + "alg": { + "type": "string", + "description": "Signing algorithm. Ref RFC7515." + }, + "x5c": { + "type": "string", + "description": "X509 public key certificate or certificate chain. Ref RFC7515." + }, + "kid": { + "type": "string", + "description": "Signing key hint. Ref RFC7515." + } + }, + "required": [ + "typ", + "sig" + ] + } + }, + "required": [ + "signed", + "signatures" + ] +} \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 000000000..9bad1ee32 --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module github.com/notaryproject/nv2 + +go 1.14 + +require ( + github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 + github.com/opencontainers/go-digest v1.0.0 + github.com/opencontainers/image-spec v1.0.1 + github.com/urfave/cli/v2 v2.2.0 + golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 +) diff --git a/go.sum b/go.sum new file mode 100644 index 000000000..64123900c --- /dev/null +++ b/go.sum @@ -0,0 +1,26 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4= +github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4= +github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg= +golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/crypto/x509.go b/internal/crypto/x509.go new file mode 100644 index 000000000..e53173d06 --- /dev/null +++ b/internal/crypto/x509.go @@ -0,0 +1,51 @@ +package crypto + +import ( + "crypto/x509" + "encoding/pem" + "errors" + "io/ioutil" + + "github.com/docker/libtrust" +) + +// ReadPrivateKeyFile reads a key PEM file as a libtrust key +func ReadPrivateKeyFile(path string) (libtrust.PrivateKey, error) { + raw, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + block, _ := pem.Decode(raw) + if block == nil { + return nil, errors.New("no PEM data found") + } + switch block.Type { + case "PRIVATE KEY": + key, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return nil, err + } + return libtrust.FromCryptoPrivateKey(key) + default: + return libtrust.UnmarshalPrivateKeyPEM(raw) + } +} + +// ReadCertificateFile reads a certificate PEM file +func ReadCertificateFile(path string) ([]*x509.Certificate, error) { + raw, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + var certs []*x509.Certificate + block, rest := pem.Decode(raw) + for block != nil { + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, err + } + certs = append(certs, cert) + block, rest = pem.Decode(rest) + } + return certs, nil +} diff --git a/media/acme-rockets-cert.png b/media/acme-rockets-cert.png new file mode 100644 index 0000000000000000000000000000000000000000..0c3e8cd3df8179b5e6bf25a2a92fe7411ed443c4 GIT binary patch literal 17157 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 literal 0 HcmV?d00001 diff --git a/media/example-cert.png b/media/example-cert.png new file mode 100644 index 0000000000000000000000000000000000000000..3f84aa20dbea5dbf1c6d4cc2e4850417e3d00175 GIT binary patch literal 18030 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 S1^HPO6nPmH>2k@BU;Zy!4&}7~ literal 0 HcmV?d00001 diff --git a/media/notary-e2e-scenarios.png b/media/notary-e2e-scenarios.png new file mode 100644 index 0000000000000000000000000000000000000000..2669f3fd447a8bf92873dddc415f09484256f03d GIT binary patch literal 54561 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%0DNEEB07lzZwGE$5@hY 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 literal 0 HcmV?d00001 diff --git a/pkg/registry/client.go b/pkg/registry/client.go new file mode 100644 index 000000000..8bfd056ae --- /dev/null +++ b/pkg/registry/client.go @@ -0,0 +1,32 @@ +package registry + +import ( + "net/http" +) + +// Client is a customized registry client +type Client struct { + base http.RoundTripper + insecure bool +} + +// ClientOptions configures the client +type ClientOptions struct { + Username string + Password string + Insecure bool +} + +// NewClient creates a new registry client +func NewClient(base http.RoundTripper, opts *ClientOptions) *Client { + if base == nil { + base = http.DefaultTransport + } + if opts == nil { + opts = &ClientOptions{} + } + return &Client{ + base: newV2transport(base, opts.Username, opts.Password), + insecure: opts.Insecure, + } +} diff --git a/pkg/registry/docker.go b/pkg/registry/docker.go new file mode 100644 index 000000000..d6351dcfd --- /dev/null +++ b/pkg/registry/docker.go @@ -0,0 +1,7 @@ +package registry + +// docker media types +const ( + MediaTypeManifestList = "application/vnd.docker.distribution.manifest.list.v2+json" + MediaTypeManifest = "application/vnd.docker.distribution.manifest.v2+json" +) diff --git a/pkg/registry/manifest.go b/pkg/registry/manifest.go new file mode 100644 index 000000000..2d5b38ff9 --- /dev/null +++ b/pkg/registry/manifest.go @@ -0,0 +1,113 @@ +package registry + +import ( + "fmt" + "net/http" + "net/url" + "strconv" + "strings" + + "github.com/notaryproject/nv2/pkg/signature" + v1 "github.com/opencontainers/image-spec/specs-go/v1" +) + +// GetManifestMetadata returns signature manifest information by URI scheme +func (c *Client) GetManifestMetadata(uri *url.URL) (signature.Manifest, error) { + switch scheme := strings.ToLower(uri.Scheme); scheme { + case "docker": + return c.GetDockerManifestMetadata(uri) + case "oci": + return c.GetOCIManifestMetadata(uri) + default: + return signature.Manifest{}, fmt.Errorf("unsupported scheme: %s", scheme) + } +} + +// GetDockerManifestMetadata returns signature manifest information +// from a remote Docker manifest +func (c *Client) GetDockerManifestMetadata(uri *url.URL) (signature.Manifest, error) { + return c.getManifestMetadata(uri, + MediaTypeManifestList, + MediaTypeManifest, + ) +} + +// GetOCIManifestMetadata returns signature manifest information +// from a remote OCI manifest +func (c *Client) GetOCIManifestMetadata(uri *url.URL) (signature.Manifest, error) { + return c.getManifestMetadata(uri, + v1.MediaTypeImageIndex, + v1.MediaTypeImageManifest, + ) +} + +// GetManifestMetadata returns signature manifest information +func (c *Client) getManifestMetadata(uri *url.URL, mediaTypes ...string) (signature.Manifest, error) { + host := uri.Host + if host == "docker.io" { + host = "registry-1.docker.io" + } + var repository string + var reference string + path := strings.TrimPrefix(uri.Path, "/") + if index := strings.Index(path, "@"); index != -1 { + repository = path[:index] + reference = path[index+1:] + } else if index := strings.Index(path, ":"); index != -1 { + repository = path[:index] + reference = path[index+1:] + } else { + repository = path + reference = "latest" + } + scheme := "https" + if c.insecure { + scheme = "http" + } + url := fmt.Sprintf("%s://%s/v2/%s/manifests/%s", + scheme, + host, + repository, + reference, + ) + req, err := http.NewRequest(http.MethodHead, url, nil) + if err != nil { + return signature.Manifest{}, fmt.Errorf("invalid uri: %v", uri) + } + req.Header.Set("Connection", "close") + for _, mediaType := range mediaTypes { + req.Header.Add("Accept", mediaType) + } + + resp, err := c.base.RoundTrip(req) + if err != nil { + return signature.Manifest{}, fmt.Errorf("%v: %v", url, err) + } + resp.Body.Close() + switch resp.StatusCode { + case http.StatusOK: + // no op + case http.StatusUnauthorized, http.StatusNotFound: + return signature.Manifest{}, fmt.Errorf("%v: %s", uri, resp.Status) + default: + return signature.Manifest{}, fmt.Errorf("%v: %s", url, resp.Status) + } + + header := resp.Header + digest := header.Get("Docker-Content-Digest") + if digest == "" { + return signature.Manifest{}, fmt.Errorf("%v: missing Docker-Content-Digest", url) + } + length := header.Get("Content-Length") + if length == "" { + return signature.Manifest{}, fmt.Errorf("%v: missing Content-Length", url) + } + size, err := strconv.ParseInt(length, 10, 64) + if err != nil { + return signature.Manifest{}, fmt.Errorf("%v: invalid Content-Length", url) + } + return signature.Manifest{ + Digest: digest, + Size: size, + }, nil +} diff --git a/pkg/registry/transport.go b/pkg/registry/transport.go new file mode 100644 index 000000000..a4ff6eb21 --- /dev/null +++ b/pkg/registry/transport.go @@ -0,0 +1,110 @@ +package registry + +import ( + "encoding/json" + "net/http" + "net/url" + "regexp" + "strings" +) + +var authHeaderRegex = regexp.MustCompile(`(realm|service|scope)="([^"]*)`) + +type v2Transport struct { + base http.RoundTripper + username string + password string +} + +func newV2transport(base http.RoundTripper, username, password string) http.RoundTripper { + return &v2Transport{ + base: base, + username: username, + password: password, + } +} + +func (t *v2Transport) RoundTrip(originalReq *http.Request) (*http.Response, error) { + req := originalReq.Clone(originalReq.Context()) + if t.username != "" { + req.SetBasicAuth(t.username, t.password) + } + + resp, err := t.base.RoundTrip(req) + if err != nil { + return nil, err + } + if resp.StatusCode != http.StatusUnauthorized { + return resp, nil + } + + scheme, params := parseAuthHeader(resp.Header.Get("Www-Authenticate")) + if scheme != "bearer" { + return resp, nil + } + resp.Body.Close() + + token, resp, err := t.fetchToken(params) + if err != nil { + if resp != nil { + return resp, nil + } + return nil, err + } + + req = originalReq.Clone(originalReq.Context()) + req.Header.Set("Authorization", "Bearer "+token) + return t.base.RoundTrip(req) +} + +func (t *v2Transport) fetchToken(params map[string]string) (string, *http.Response, error) { + req, err := http.NewRequest(http.MethodGet, params["realm"], nil) + if err != nil { + return "", nil, err + } + if t.username != "" { + req.SetBasicAuth(t.username, t.password) + } + + query := url.Values{} + if service, ok := params["service"]; ok { + query.Set("service", service) + } + if scope, ok := params["scope"]; ok { + query.Set("scope", scope) + } + req.URL.RawQuery = query.Encode() + + resp, err := t.base.RoundTrip(req) + if err != nil { + return "", nil, err + } + if resp.StatusCode != http.StatusOK { + return "", resp, nil + } + defer resp.Body.Close() + + var result struct { + AccessToken string `json:"access_token"` + } + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + return "", nil, err + } + return result.AccessToken, nil, nil +} + +func parseAuthHeader(header string) (string, map[string]string) { + parts := strings.SplitN(header, " ", 2) + scheme := strings.ToLower(parts[0]) + if len(parts) < 2 { + return scheme, nil + } + + params := make(map[string]string) + result := authHeaderRegex.FindAllStringSubmatch(parts[1], -1) + for _, match := range result { + params[strings.ToLower(match[1])] = match[2] + } + + return scheme, params +} diff --git a/pkg/signature/errors.go b/pkg/signature/errors.go new file mode 100644 index 000000000..6c939d883 --- /dev/null +++ b/pkg/signature/errors.go @@ -0,0 +1,10 @@ +package signature + +import "errors" + +// common errors +var ( + ErrInvalidSignatureType = errors.New("invalid signature type") + ErrUnknownSignatureType = errors.New("unknown signature type") + ErrUnknownSigner = errors.New("unknown signer") +) diff --git a/pkg/signature/interface.go b/pkg/signature/interface.go new file mode 100644 index 000000000..e1127e10f --- /dev/null +++ b/pkg/signature/interface.go @@ -0,0 +1,12 @@ +package signature + +// Signer signs content +type Signer interface { + Sign(content []byte) (Signature, error) +} + +// Verifier verifies content +type Verifier interface { + Type() string + Verify(content []byte, signature Signature) error +} diff --git a/pkg/signature/scheme.go b/pkg/signature/scheme.go new file mode 100644 index 000000000..30b9337b8 --- /dev/null +++ b/pkg/signature/scheme.go @@ -0,0 +1,90 @@ +package signature + +import ( + "encoding/json" + "fmt" + "time" +) + +// Scheme is a signature scheme +type Scheme struct { + signers map[string]Signer + verifiers map[string]Verifier +} + +// NewScheme creates a new scheme +func NewScheme() *Scheme { + return &Scheme{ + signers: make(map[string]Signer), + verifiers: make(map[string]Verifier), + } +} + +// RegisterSigner registers signer with a name +func (s *Scheme) RegisterSigner(signerID string, signer Signer) { + s.signers[signerID] = signer +} + +// RegisterVerifier registers verifier +func (s *Scheme) RegisterVerifier(verifier Verifier) { + s.verifiers[verifier.Type()] = verifier +} + +// Sign signs content by a signer +func (s *Scheme) Sign(signerID string, content Content) (Signature, error) { + bytes, err := json.Marshal(content) + if err != nil { + return Signature{}, err + } + return s.SignRaw(signerID, bytes) +} + +// SignRaw signs raw content by a signer +func (s *Scheme) SignRaw(signerID string, content []byte) (Signature, error) { + signer, found := s.signers[signerID] + if !found { + return Signature{}, ErrUnknownSigner + } + return signer.Sign(content) +} + +// Verify verifies signed data +func (s *Scheme) Verify(signed Signed) (Content, Signature, error) { + sig, err := s.verifySignature(signed) + if err != nil { + return Content{}, sig, err + } + + var content Content + if err := json.Unmarshal(signed.Signed, &content); err != nil { + return Content{}, sig, err + } + + return content, sig, s.verifyContent(content) +} + +func (s *Scheme) verifySignature(signed Signed) (Signature, error) { + sig := signed.Signature + verifier, found := s.verifiers[sig.Type] + if !found { + return Signature{}, ErrUnknownSignatureType + } + + content := []byte(signed.Signed) + if err := verifier.Verify(content, sig); err != nil { + return Signature{}, err + } + + return sig, nil +} + +func (s *Scheme) verifyContent(content Content) error { + now := time.Now().Unix() + if content.Expiration != 0 && now > content.Expiration { + return fmt.Errorf("content expired: %d: current: %d", content.Expiration, now) + } + if content.NotBefore != 0 && now < content.NotBefore { + return fmt.Errorf("content is not available yet: %d: current: %d", content.NotBefore, now) + } + return nil +} diff --git a/pkg/signature/signature.go b/pkg/signature/signature.go new file mode 100644 index 000000000..f116d9450 --- /dev/null +++ b/pkg/signature/signature.go @@ -0,0 +1,35 @@ +package signature + +import ( + "encoding/json" +) + +// Signed is the high level, partially deserialized metadata object +type Signed struct { + Signed json.RawMessage `json:"signed"` + Signature Signature `json:"signature"` +} + +// Content contains the contents to be signed +type Content struct { + Manifest + Expiration int64 `json:"exp,omitempty"` + NotBefore int64 `json:"nbf,omitempty"` + IssuedAt int64 `json:"iat,omitempty"` +} + +// Manifest to be signed +type Manifest struct { + Digest string `json:"digest"` + Size int64 `json:"size"` + References []string `json:"references,omitempty"` +} + +// Signature to verify the content +type Signature struct { + Type string `json:"typ"` + Signature []byte `json:"sig"` + Algorithm string `json:"alg,omitempty"` + KeyID string `json:"kid,omitempty"` + X5c [][]byte `json:"x5c,omitempty"` +} diff --git a/pkg/signature/util.go b/pkg/signature/util.go new file mode 100644 index 000000000..0a62bfd06 --- /dev/null +++ b/pkg/signature/util.go @@ -0,0 +1,17 @@ +package signature + +import ( + "encoding/json" +) + +// Pack packs content with its signature +func Pack(content Content, signature Signature) (Signed, error) { + signed, err := json.Marshal(content) + if err != nil { + return Signed{}, err + } + return Signed{ + Signed: signed, + Signature: signature, + }, nil +} diff --git a/pkg/signature/x509/signer.go b/pkg/signature/x509/signer.go new file mode 100644 index 000000000..f5e8de755 --- /dev/null +++ b/pkg/signature/x509/signer.go @@ -0,0 +1,92 @@ +package x509 + +import ( + "bytes" + "crypto" + "crypto/x509" + "errors" + + "github.com/docker/libtrust" + cryptoutil "github.com/notaryproject/nv2/internal/crypto" + "github.com/notaryproject/nv2/pkg/signature" +) + +type signer struct { + key libtrust.PrivateKey + keyID string + cert *x509.Certificate + rawCerts [][]byte + hash crypto.Hash +} + +// NewSignerFromFiles creates a signer from files +func NewSignerFromFiles(keyPath, certPath string) (signature.Signer, error) { + key, err := cryptoutil.ReadPrivateKeyFile(keyPath) + if err != nil { + return nil, err + } + if certPath == "" { + return NewSigner(key, nil) + } + + certs, err := cryptoutil.ReadCertificateFile(certPath) + if err != nil { + return nil, err + } + return NewSigner(key, certs) +} + +// NewSigner creates a signer +func NewSigner(key libtrust.PrivateKey, certs []*x509.Certificate) (signature.Signer, error) { + s := &signer{ + key: key, + keyID: key.KeyID(), + hash: crypto.SHA256, + } + if len(certs) == 0 { + return s, nil + } + + cert := certs[0] + publicKey, err := libtrust.FromCryptoPublicKey(crypto.PublicKey(cert.PublicKey)) + if err != nil { + return nil, err + } + if s.keyID != publicKey.KeyID() { + return nil, errors.New("key and certificate mismatch") + } + s.cert = cert + + rawCerts := make([][]byte, 0, len(certs)) + for _, cert := range certs { + rawCerts = append(rawCerts, cert.Raw) + } + s.rawCerts = rawCerts + + return s, nil +} + +func (s *signer) Sign(raw []byte) (signature.Signature, error) { + if s.cert != nil { + if err := verifyReferences(raw, s.cert); err != nil { + return signature.Signature{}, err + } + } + + sig, alg, err := s.key.Sign(bytes.NewReader(raw), s.hash) + if err != nil { + return signature.Signature{}, err + } + sigma := signature.Signature{ + Type: Type, + Algorithm: alg, + Signature: sig, + } + + if s.cert != nil { + sigma.X5c = s.rawCerts + } else { + sigma.KeyID = s.keyID + } + return sigma, nil +} diff --git a/pkg/signature/x509/type.go b/pkg/signature/x509/type.go new file mode 100644 index 000000000..82dd54370 --- /dev/null +++ b/pkg/signature/x509/type.go @@ -0,0 +1,4 @@ +package x509 + +// Type indicates the signature type +const Type = "x509" diff --git a/pkg/signature/x509/verifier.go b/pkg/signature/x509/verifier.go new file mode 100644 index 000000000..e906e896c --- /dev/null +++ b/pkg/signature/x509/verifier.go @@ -0,0 +1,146 @@ +package x509 + +import ( + "bytes" + "crypto" + "crypto/x509" + "encoding/json" + "errors" + "strings" + + "github.com/docker/libtrust" + "github.com/notaryproject/nv2/pkg/signature" +) + +type verifier struct { + keys map[string]libtrust.PublicKey + certs map[string]*x509.Certificate + roots *x509.CertPool +} + +// NewVerifier creates a verifier +func NewVerifier(certs []*x509.Certificate, roots *x509.CertPool) (signature.Verifier, error) { + if roots == nil { + if certs == nil { + pool, err := x509.SystemCertPool() + if err != nil { + return nil, err + } + roots = pool + } else { + roots = x509.NewCertPool() + } + for _, cert := range certs { + roots.AddCert(cert) + } + } + + keys := make(map[string]libtrust.PublicKey, len(certs)) + keyedCerts := make(map[string]*x509.Certificate, len(certs)) + for _, cert := range certs { + key, err := libtrust.FromCryptoPublicKey(crypto.PublicKey(cert.PublicKey)) + if err != nil { + return nil, err + } + keyID := key.KeyID() + keys[keyID] = key + keyedCerts[keyID] = cert + } + + return &verifier{ + keys: keys, + certs: keyedCerts, + roots: roots, + }, nil +} + +func (v *verifier) Type() string { + return Type +} + +func (v *verifier) Verify(content []byte, sig signature.Signature) error { + if sig.Type != Type { + return signature.ErrInvalidSignatureType + } + + key, cert, err := v.getVerificationKeyPair(sig) + if err != nil { + return err + } + if err := key.Verify(bytes.NewReader(content), sig.Algorithm, sig.Signature); err != nil { + return err + } + return verifyReferences(content, cert) +} + +func (v *verifier) getVerificationKeyPair(sig signature.Signature) (libtrust.PublicKey, *x509.Certificate, error) { + switch { + case len(sig.X5c) > 0: + return v.getVerificationKeyPairFromX5c(sig.X5c) + case sig.KeyID != "": + return v.getVerificationKeyPairFromKeyID(sig.KeyID) + default: + return nil, nil, errors.New("missing verification key") + } +} + +func (v *verifier) getVerificationKeyPairFromKeyID(keyID string) (libtrust.PublicKey, *x509.Certificate, error) { + key, found := v.keys[keyID] + if !found { + return nil, nil, errors.New("key not found: " + keyID) + } + cert, found := v.certs[keyID] + if !found { + return nil, nil, errors.New("cert not found: " + keyID) + } + return key, cert, nil +} + +func (v *verifier) getVerificationKeyPairFromX5c(x5c [][]byte) (libtrust.PublicKey, *x509.Certificate, error) { + certs := make([]*x509.Certificate, 0, len(x5c)) + for _, certBytes := range x5c { + cert, err := x509.ParseCertificate(certBytes) + if err != nil { + return nil, nil, err + } + certs = append(certs, cert) + } + + intermediates := x509.NewCertPool() + for _, cert := range certs[1:] { + intermediates.AddCert(cert) + } + + cert := certs[0] + if _, err := cert.Verify(x509.VerifyOptions{ + Intermediates: intermediates, + Roots: v.roots, + KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, + }); err != nil { + return nil, nil, err + } + + key, err := libtrust.FromCryptoPublicKey(crypto.PublicKey(cert.PublicKey)) + if err != nil { + return nil, nil, err + } + return key, cert, nil +} + +func verifyReferences(raw []byte, cert *x509.Certificate) error { + var content signature.Content + if err := json.Unmarshal(raw, &content); err != nil { + return err + } + roots := x509.NewCertPool() + roots.AddCert(cert) + for _, reference := range content.Manifest.References { + if _, err := cert.Verify(x509.VerifyOptions{ + DNSName: strings.SplitN(reference, "/", 2)[0], + Roots: roots, + }); err != nil { + return err + } + } + return nil +} From f49491405325883cdf8fd03b2a0bc91e55bd6957 Mon Sep 17 00:00:00 2001 From: Steve Lasker Date: Fri, 14 Aug 2020 18:11:41 -0700 Subject: [PATCH 02/69] Distribution api proposal Signed-off-by: Steve Lasker --- docs/distribution/README.md | 528 ++++++++++++++++++++++ media/signature-as-index.png | Bin 0 -> 30953 bytes media/signature-as-manifest-via-index.png | Bin 0 -> 50411 bytes media/signature-as-manifest.png | Bin 0 -> 32479 bytes 4 files changed, 528 insertions(+) create mode 100644 docs/distribution/README.md create mode 100644 media/signature-as-index.png create mode 100644 media/signature-as-manifest-via-index.png create mode 100644 media/signature-as-manifest.png diff --git a/docs/distribution/README.md b/docs/distribution/README.md new file mode 100644 index 000000000..b1c6eb4ed --- /dev/null +++ b/docs/distribution/README.md @@ -0,0 +1,528 @@ +# OCI Distribution - Notary v2 Signature Support + +To support [Notary v2 goals][notaryv2-goals], upload, persistance and discovery of signatures must be supported. + +To minimize the complexity of registry operators and projects to adopt Notary v2, a balance between leveraging what already exists and new patterns to support secure discovery are explored. + +## Table of Contents + +* [Signature Persistance](#signature-persistance) +* [Signature Push](#signature-push) +* [Signature Discovery](#signature-discovery) +* [Signature Pull](#signature-pull) +* [Example Artifacts](#example-artifacts) + +## Signature Persistance + +Several options for how to persist a signature were explored. We measure these options against the [goals of Notary v2][notaryv2-goals], specifically: + +* Maintain the original artifact digest and collection of associated tags, supporting existing dev through deployment workflows +* Multiple signatures per artifact, enabling the originating vendor signature, public registry certification and user/environment signatures +* Native persistance within an OCI Artifact enabled, distribution*spec based registry +* Artifact and signature copying within and across OCI Artifact enabled, distribution*spec based registries +* Support multi-tenant registries enabling cloud providers and enterprises to support managed services at scale +* Support private registries, where public content may be copied to, and new content originated within +* Air-gapped environments, where the originating registry of content is not accessible + +To support the above requirements, signatures are stored as separate [OCI Artifacts][oci-artifacts]. They are maintained as any other artifact in a registry, supporting standard operations such as listing, deleting, garbage collection and any other content addressable operations within a registry. + +Following the [OCI Artifacts][oci-artifacts] design, signatures are identified with: `config.mediaType: "application/vnd.cncf.notary.config.v2+jwt"`. +The config object contains the signature and signed content. See [nv2-signature-spec][nv2-signature-spec] for details. + +Storing a signature as a separate artifact enables the above goals, most importantly the ability to maintain the existing tag and and digest for a given artifact. + +### Persistance as Manifest or Index + +A typical signing workflow would involve: + +1. An artifact (`net-monitor:v1` container image) is pushed to a registry +1. Signature artifacts are pushed to the same registry using a set of new [OCI distribution][oci-distribution] capabilities + +It's presumed artifact clients like docker, oras, buildkit would support these new workflows. The question is what oci schema they are pushed with: + +* [Option 1: oci-manifest](#signature-persistance---option-1-oci-manifest) +* [Option 2: oci-index](#signature-persistance---option-2-oci-index) +* [Option 3: oci-manifest-linked through index](#signature-persistance---option-3-oci-manifest-linked-through-oci-index) + +### Signature Persistance - Option 1: oci-manifest + +The challenge with using oci-manifest is how the registry tracks the linkage between the signature and the original artifact. + + + +Example **manifest** for a Notary v2 signature + +```json +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v2+json", + "config": { + "mediaType": "application/vnd.cncf.notary.config.v2+jwt", + "digest": "sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042", + "size": 1906 + }, + "layers": [] +} +``` + +**Pros with this approach:** + +* OCI Artifacts already supports manifest based artifacts, through the `manifest.config.mediaType` + +**Cons with this approach:** + +* Manifests have no means to reference other artifacts. +* An alternative is required to link a target artifact with it's signature. Either through parsing the signature `manifest.config` object, or [a separate API for linking objects](#linking-signatures-to-artifacts). + +### Signature Persistance - Option 2: oci-index + +This option is similar to using oci-manifest. However, instead of parsing the signature object to determine the linkage between an artifact and signature, the `index.manifests` collection is utilized. + + + +Example **index** for a Notary v2 signature + +``` json +{ + "schemaVersion": 2.1, + "mediaType": "application/vnd.oci.image.index.v2+json", + "config": { + "mediaType": "application/vnd.cncf.notary.config.v2+jwt", + "digest": "sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042", + "size": 1906 + }, + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:2235d2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49cc77c", + "size": 7023, + "platform": { + "architecture": "ppc64le", + "os": "linux" + } + } + ] +} +``` + +**Pros with this approach:** + +* Utilize the existing `index.manifests` collection for linking artifacts +* Registries that support oci index already have infrastructure for tracking `index.manifests`, including delete operations and garbage collection +* Existing distribution-spec upload APIs are utilized +* Unlike the manifest proposal, no additional artifact handler would be required to parse the config object for linking artifacts +* Based on the artifact type: `manifest.config.mediaType: "application/vnd.cncf.notary.config.v2+jwt"`, role check may be done to confirm the identity has a signer role +* As registry operators may offer role checking for different artifact types, Notary v2 Signatures are just one of many types they may want to authorize + +**Cons with this approach:** + +* OCI index does not yet support the [OCI config descriptor][oci-descriptor]. This would require a schema change to oci-index, with a version bump. + * This has been a [desired item for OCI Artifacts][oci-artifacts-index] to support other artifact types which would base on Index. +* An additional role check is performed, based on the artifact type. Also noted as a pro as registry operators may want to utilize this for other artifact types, making it a consistent model. + +> **Note:** this is our working/preferred method: See OCI image-spec issue: [Add Index Support for Artifact Type #806](https://github.com/opencontainers/image-spec/issues/) + +### Signature Persistance - Option 3: oci-manifest linked through oci-index + +This model is a hybrid of the 1 & 2, but moves the persistance of the signature from the config object to a layer of an additional manifest. + + + +**Pros with this approach:** + +* Conforms to norms of indexes as collections of manifests with no config data + +**Cons with this approach:** + +* An additional indirection between the original artifact being signed and the individual signatures. +* An `index.config.mediaType` is still required to identify the type of index being something other than a multi-arch index. + +The implied benefit is the signature is moved from the `index.config` to a layer within a manifest. However, config objects are [oci descriptors][oci-descriptor] pointing to blobs. Whether the signature is stored within a config or a layer is little difference. Since we'll need an `index.config.mediaType` to differentiate a signature index from a multi-arch index, are we justifying additional round trips to get a list of signatures? + +## Linking Signatures to Artifacts + +A signature is only interesting if it's linked to the object it's signing. The question is how. + +If manifest is used, we must choose between options 1-3. +If index is used, option 4 defers the linking to existing Index linking capabilities + +1. [Option 1: Parse the config object](#linking-signatures---option-1-parse-the-config-object) +1. [Option 2: Distinct Linking API](#linking-signatures---option-2-distinct-linking-api) +1. [Option 3: Signature Upload API](#linking-signatures---option-3-signature-upload-api) +1. [Option 4: Utilize OCI Index PUT](#linking-signatures---option-4-utilize-oci-index-put) + +### Linking Signatures - Option 1: Parse the config object + +Upon [manifest put][oci-dist-spec-manifest-put], perform the following steps: + +* The [nv2 signature specification][nv2-signature-spec] identifies the referenced artifact by its digest and optional tags. +* As the registry receives artifacts, the artifact type is parsed, evaluating the `manifest.config.mediaType` of `"application/vnd.cncf.notary.config.v2+jwt"` +* A role check is performed, confirming the identity of the PUT has **signer** rights +* The registry uses the config objects reference to link the signature with signed digest. This would enable registry tracking for garbage collection + +Partial config object, referring to the digest and tag of the `net-monitor:v1` container image: + +```json +{ + "signed": { + "mediaType": "application/vnd.oci.image.manifest.v2+json", + "digest": "sha256:2235d2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49cc77c", + "size": 528, + "references": [ + "registry.acme-rockets.com/net-monitor:v1" + ], +``` + +**Pros with this approach:** + +* Existing [distribution-spec manifest put APIs][oci-dist-spec-manifest-put] are utilized for the manifest PUT +* Rather than add a new linking API, an artifact handler would be added to registries. Many already parse the config objects to understand which platform and architectures they support. + +**Cons with this approach:** + +* An artifact handler is required that must parse the signature object for the linked artifact +* New code for tracking dependency linking is required through a config object handler +* Based on the unique artifact type: `manifest.config.mediaType: "application/vnd.cncf.notary.config.v2+jwt"`, a role check may be done to confirm the identity has a signer role. + +### Linking Signatures - Option 2: Distinct Linking API + +Similar to the manifest or index options, the client pushes the artifact and signatures through standard oci-distribution PUT apis. +However, no linkage is made between the signature object and the signed artifact. Rather a signature linking api is added: + +1. Push all artifacts to the registry: + * Push `net-monitor:v1` container image: `sha256:2235d2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49cc77c` + * Push **acme-rockets** signature artifact `sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b` +1. Link **acme-rockets** signature to the `net-monitor:v1` container image + +``` REST +PUT https://localhost:6000/v2/net-monitor/manifests/sha256:2235d2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49cc77c/signatures/sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b +``` + +**Pros with this approach:** + +* Using a unique API enables RBAC to the API, without having to parse the content to determine the role check. + +**Cons with this approach:** + +* A new linking api, unique to signatures +* The client must make two calls to achieve a single operation of uploading a signature object, which by definition has the linking information +* If the signature linking API fails, additional garbage collection of a signature manifest must be cleaned up + +### Linking Signatures - Option 3: Signature Upload API + +In this option the signature artifact (manifest or index) is uploaded through a new signature API. + +**Pros with this approach:** + +* The signature artifact upload and role check are coupled to a signature API + +**Cons with this approach:** + +* Signature upload, which is just another artifact type, is uploaded differently than other artifacts. + +### Linking Signatures - Option 4: Utilize OCI Index PUT + +Utilizing the OCI Index, the manifest list is used to track dependencies. + +**Pros with this approach:** + +* Existing Index parsing logic is used to track despondencies +* No additional distribution-spec APIs are required + +**Cons with this approach:** + +* OCI Index would need to support a config object: [Add Index Support for Artifact Type #806](https://github.com/opencontainers/image-spec/issues/) + +## Signature Discovery + +Once a signature artifact is in a registry and linked to its target artifact, how is it retrieved? + +The following options are offered: + +1. [Option 1: Signature Listing API](#signature-discovery---option-1-rest-api-standard-paging) +1. [Option 2: Generic Reference Listing API](#signature-discovery---option-2-generic-reference-listing-api) + +### Signature Discovery - Option 1: Signature Listing API + +Similar to the [_tags api][tags-api], a new signatures API is proposed. The signatures API uses the digest as the path to find all signatures related to said digest. +In the below example, the `net-monitor:v1` tag has a digest of: `sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042` + +```HTTP +GET /v2//manifests/sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042/signatures/ +``` + +The response will be in the following format: + +```HTTP +200 OK +Content-Type: application/json +{ + "digest": "sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042", + "signatures": [ + { + "digest": "sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042", + "mediaType": "application/vnd.oci.image.index.v1+json", + "size": "1024", + "signature-typ": "x509" + }, + { + "digest": "sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b", + "mediaType": "application/vnd.oci.image.index.v1+json", + "size": "1025", + "signature-typ": "x509" + } + ] +} +``` + +### Signature Discovery - Option 2: Generic Reference Listing API + +A slight alternative to the signatures API is to provide a generic reference listing API, where a paged collection of references are returned. + +In the below example, the `net-monitor:v1` tag has a digest of: `sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042` + +```HTTP +GET /v2//manifests/sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042/references/ +``` + +The response will be in the following format: + +```HTTP +200 OK +Content-Type: application/json +{ + "digest": "sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042", + "references": [ + { + "digest": "sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042", + "mediaType": "application/vnd.oci.image.index.v1+json", + "size": "1024", + "config-mediaType": "application/vnd.cncf.notary.config.v2+jwt" + }, + { + "digest": "sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b", + "mediaType": "application/vnd.oci.image.index.v1+json", + "size": "1025", + "config-mediaType": "application/vnd.cncf.notary.config.v2+jwt" + }, + { + "digest": "sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b", + "mediaType": "application/vnd.oci.image.index.v1+json", + "size": "1025", + "config-mediaType": "application/vnd.oci.image.index.v1+json" + } + ] +} +``` + +### Paging Results + +There are three identified patterns for paging results: + +1. [OCI distribution-spec Tag Listing](#distribution-spec---tags-listing-api) +1. [Google API Design Guidelines](#dis) +1. [Microsoft API Design Guidelines](https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md#98-pagination) + +#### Distribution Spec - Tags Listing API + +The [OCI distribution-spec][distribution-spec-paging] identifies paging with `n` and `last` parameters: +[tags-api] + +Get a list of paginated signatures from the registry. The response will include an opaque URL that can be followed to obtain the next page of results. + +Paginated tag results can be retrieved by adding an `n` parameter to the request URL, declaring that the response SHOULD be limited to `n` results. Starting a paginated flow MAY begin as follows: + +```HTTP +GET /v2//manifests/sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042/references/list?n= +``` + +The above specifies that a tags response SHOULD be returned, from the start of the result set, ordered lexically, limiting the number of results to `n`. The response to such a request would look as follows: + +```HTTP +200 OK +Content-Type: application/json +Link: <?n=&last=>; rel="next" +{ + "digest": "sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042", + "@nextLink": "{opaqueUrl}", + "references": [ + { + "digest": "sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042", + "mediaType": "application/vnd.oci.image.index.v1+json", + "size": "1024", + "config-mediaType": "application/vnd.cncf.notary.config.v2+jwt" + }, + { + "digest": "sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b", + "mediaType": "application/vnd.oci.image.index.v1+json", + "size": "1025", + "config-mediaType": "application/vnd.cncf.notary.config.v2+jwt" + }, + { + "digest": "sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b", + "mediaType": "application/vnd.oci.image.index.v1+json", + "size": "1025", + "config-mediaType": "application/vnd.oci.image.index.v1+json" + } + ] +} +``` + +To get the _next_ `n` entries, one can create a URL where the argument `last` has the value from `references[len(tags)-1]`. +If there are indeed more results, the URL for the next block is encoded in an [RFC5988](https://tools.ietf.org/html/rfc5988) `Link` header, as a "next" relation. + +The presence of the `Link` header communicates to the client that the entire result set has not been returned and another request MAY be issued. +If the header is not present, the client can assume that all results have been received. + +> __NOTE:__ In the request template above, note that the brackets are required. For example, if the url is `http://example.com//manifests/sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042/references/list?n=20&last=b`, the value of the header would be `http://example.com//manifests/sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042/references/list?n=20&last=b>; rel="next"`. +> Please see [RFC5988](https://tools.ietf.org/html/rfc5988) for details. + +Compliant client implementations SHOULD always use the `Link` header value when proceeding through results linearly. The client MAY construct URLs to skip forward in the list of tags. + +To get the next result set, a client would issue the request as follows, using the URL encoded in the described `Link` header: + +``` HTTP +GET /v2//manifests/sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042/references/list?n=&last= +``` + +The above process should then be repeated until the `Link` header is no longer set in the response. + +The tag list result set is represented abstractly as a lexically sorted list, where the position in that list can be specified by the query term `last`. The entries in the response start _after_ the term specified by `last`, up to `n` +entries. + +#### Google Paging API + +From [Google API Design Guides][google-paging-api] + +To support pagination (returning list results in pages) in a List method, the API shall: + +* define `a string` field `page_token` in the `List` method's request message. The client uses this field to request a specific page of the list results. +* define an `int32` field `page_size` in the `List` method's request message. Clients use this field to specify the maximum number of results to be returned by the server. The server **may** further constrain the maximum number of results returned in a single page. If the `page_size` is `0`, the server will decide the number of results to be returned. +* define a `string` field `next_page_token` in the `List` method's response message. This field represents the pagination token to retrieve the next page of results. If the value is `""`, it means no further results for the request. +To retrieve the next page of results, client **shall** pass the value of response's `next_page_token` in the subsequent `List` method call (in the request message's `page_token` field): + +``` HTTP +GET /v2//manifests/sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042/references/list?page_token=1&page_size=10&next_page_token= +``` + +The above specifies that a tags response SHOULD be returned, from the start of the result set, ordered lexically, limiting the number of results to `n`. The response to such a request would look as follows: + +```json +{ + "digest": "sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042", + "@next_page_token": "{opaqueUrl}", + "references": [ + { + "digest": "sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042", + "mediaType": "application/vnd.oci.image.index.v1+json", + "size": "1024", + "config-mediaType": "application/vnd.cncf.notary.config.v2+jwt" + }, + { + "digest": "sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b", + "mediaType": "application/vnd.oci.image.index.v1+json", + "size": "1025", + "config-mediaType": "application/vnd.cncf.notary.config.v2+jwt" + }, + { + "digest": "sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b", + "mediaType": "application/vnd.oci.image.index.v1+json", + "size": "1025", + "config-mediaType": "application/vnd.oci.image.index.v1+json" + } + ] +} +``` + +## Signature Pull + +Using one of the options from the [Signature Discovery](#signature-discovery) section, a specific digest is resolved. A signature shall be pulled using the distribution spec [GET Manifest][distribution-spec-get-manifest] API. + +## Example Artifacts + +The following are references used in the examples below. + +These assume: + +* The original net-monitors image was sourced from `registry.wabbit-networks.com/net-monitor:v1`. +* Wabbit Networks signed the original image +* ACME Rockets imported the net-monitor image into `registry.acme-rockets.com/net-monitor:v1` +* The Wabbit Networks signature was copied into `registry.acme-rockets.com/net-monitor:v1` +* ACME Rockets added a verification signature. +* Signature objects do NOT have tags. However, they are placed in the same repo as the artifact they reference. +* Per the design options, a signature object may be persisted as an OCI Manifest or OCI Index. + +|Artifact |`config.mediaType` | Digest | +|-------------------------|-------------------------------------------|-------------------------------------------------------------------------| +|`net-monitor:v1` image |`application/vnd.oci.image.config.v1+json` |`sha256:2235d2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49cc77c`| +|wabbit-networks signature|`application/vnd.cncf.notary.config.v2+jwt`|`sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042`| +|acme-rockets signature |`application/vnd.cncf.notary.config.v2+jwt`|`sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b`| + +### Example manifest for the **container image**: `registry.acme-rockets.com/net-monitor:v1` + +```json +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v2+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:2235d2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49cc77c", + "size": 1906 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0", + "size": 32654 + }, + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736", + "size": 73109 + } + ] +} +``` + +### Example **config object** for the **Notary v2 signature artifact** + +See [nv2 signature spec][nv2-signature-spec] for more details. + +```json +{ + "signed": { + "digest": "sha256:2235d2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49cc77c", + "size": 528, + "references": [ + "registry.acme-rockets.com/net-monitor:v1" + ], + "exp": 1627555319, + "nbf": 1596019319, + "iat": 1596019319 + }, + "signature": { + "typ": "x509", + "sig": "UFqN24K2fLj7/h2slM68PLTfF9CDhrEVGuMQ8m3kkQJ4SKusj9fNxYV78tTiedqB+E8SqVH66mZbdlTrVQFJAd7aL2c3NZFfo92pE9SaHnqEDqnnGWXGRVjtBRM13YyRDm2wD8aRyuL5jEDUkTw7jBLY0+LfKHMDuYCsOOzvedof7aiaFc3qA+qKiW53jn2uEGCFfAs0LmsNafGfAtVmdGSO4zX4fdnQFAGT8sbUmL71uXl9W1B6tGeLfx5nBoQUvtplQipHly/yMQvWw7qMXsaAsf/BbGDmivN06CRahSb7VOwNq6K7Py4zYeiW40hEFVz9L7/5xT5XI1unKPZDuw==", + "alg": "RS256", + "x5c": [ + "MIIDszCCApugAwIBAgIUL1anEU/yJy67VJTbHkNX0bBNAnEwDQYJKoZIhvcNAQELBQAwaTEdMBsGA1UEAwwUcmVnaXN0cnkuZXhhbXBsZS5jb20xFDASBgNVBAoMC2V4YW1wbGUgaW5jMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTAeFw0yMDA3MjcxNDQzNDZaFw0yMTA3MjcxNDQzNDZaMGkxHTAbBgNVBAMMFHJlZ2lzdHJ5LmV4YW1wbGUuY29tMRQwEgYDVQQKDAtleGFtcGxlIGluYzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkKwAcV44psjN8nno1eZ3zv1ZKUhJAoxwBOIGfIxIe+iHtpXLvFFVwk5Jbxu+Pkig2N4B3Ilrj/Vryi0hxp4mag02M733bXLRENSOFONRkslpO8zHUN5pYdnhTSwYTLap1+1bgcFSuUXLWieqZB6qc7kiv3bj3SPaf42+s48V49t/OpXxLtgiWL9XkuDTZctpJJA4vHHk6Ou0bcg7iGm+L1xwIfb8Ml4oWvT0SF35fgW08bbLXZ2v1XCLRsrWUgbq4U+KxtEpG3XIYcYhKx1rIrUhfEJkuHzgPglM11gG5W+Cyfg+wfOJig5q6axIKWzIf6C8m8lmy6bM+N5EsD9SvAgMBAAGjUzBRMB0GA1UdDgQWBBTf1hM6/ibGF+u/SVAK88FUMjzRoTAfBgNVHSMEGDAWgBTf1hM6/ibGF+u/SVAK88FUMjzRoTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBgvVau5+2wAuCsmOyyG28h1zyC4IPmMmpRZTDOp/pLdwXeHjJr8kEC3l92qJEvc+WAboJ1RoucHycUe7RWh2C6ZF/WPCBLyWGwnlyqGyRM9/j86UJ1OgiuZl7kl9zxwWoaxPBCmHa0RHowdQB7AVlpqg1c7FhKjhUCBmGT4Ve8tV0hdZtrZoQV+6xHPbUd37KV1B1Bmfo3o4ekoJKhUu99Eo03OpE3JLtM13A1HxABEuQGHTI0tycDBBdRn3b03HoIhU0VnqjvpV1KPvsrgYi/0VStLNezZPgGe0fG3Xgy8yekdB9NMUn+zZLATI4+z8j4QH5Wj5ZPaUkyoAD2oUJO" + ] + } +} +``` + +[cnab]: https://cnab.io +[distribution-spec-paging]: https://github.com/opencontainers/distribution-spec/blob/master/spec.md#listing-image-tags +[distribution-spec-get-manifest]: https://github.com/opencontainers/distribution-spec/blob/master/spec.md#get-manifest +[google-paging-api]: https://cloud.google.com/apis/design/design_patterns#list_pagination +[notaryv2-goals]: https://github.com/notaryproject/requirements/blob/52c1ba2f5696a98b317aff84288d3564b4041ad5/README.md#goals +[nv2-signature-spec]: https://github.com/notaryproject/nv2/blob/efe151ddf6a7fd3848fea340cab7553d0a7d295b/docs/signature/README.md +[oci-artifacts]: https://github.com/opencontainers/artifacts +[oci-artifacts-index]: https://github.com/opencontainers/artifacts/issues/25 +[oci-index]: https://github.com/opencontainers/image-spec/blob/master/image-index.md +[oci-descriptor]: https://github.com/opencontainers/image-spec/blob/master/descriptor.md +[oci-distribution]: https://github.com/opencontainers/distribution-spec +[oci-manifest]: https://github.com/opencontainers/image-spec/blob/master/manifest.md +[oras]: https://github.com/deislabs/oras +[oci-dist-spec-manifest-put]: https://github.com/opencontainers/distribution-spec/blob/master/spec.md#put-manifest +[tags-api]: https://github.com/opencontainers/distribution-spec diff --git a/media/signature-as-index.png b/media/signature-as-index.png new file mode 100644 index 0000000000000000000000000000000000000000..76f521991916e4f93492767ae9dd8e01cb8bcfd0 GIT binary patch literal 30953 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 literal 0 HcmV?d00001 diff --git a/media/signature-as-manifest.png b/media/signature-as-manifest.png new file mode 100644 index 0000000000000000000000000000000000000000..e8e1e72f310fb47170abb89143dad96165072677 GIT binary patch literal 32479 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 PJA_fwx=^TcIp}`@XYN{y literal 0 HcmV?d00001 From 230940df1d072d1d8be557ad75aa3b83f59d92a3 Mon Sep 17 00:00:00 2001 From: Steve Lasker Date: Fri, 14 Aug 2020 18:15:50 -0700 Subject: [PATCH 03/69] Formating fix Signed-off-by: Steve Lasker --- docs/distribution/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/distribution/README.md b/docs/distribution/README.md index b1c6eb4ed..150b95168 100644 --- a/docs/distribution/README.md +++ b/docs/distribution/README.md @@ -170,7 +170,7 @@ Partial config object, referring to the digest and tag of the `net-monitor:v1` c "size": 528, "references": [ "registry.acme-rockets.com/net-monitor:v1" - ], + ] ``` **Pros with this approach:** From 945c02c92f5d66d08d186ad8b870527e11ca746c Mon Sep 17 00:00:00 2001 From: Steve Lasker Date: Fri, 14 Aug 2020 18:18:13 -0700 Subject: [PATCH 04/69] Formating fix Signed-off-by: Steve Lasker --- docs/distribution/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/distribution/README.md b/docs/distribution/README.md index 150b95168..3411758fe 100644 --- a/docs/distribution/README.md +++ b/docs/distribution/README.md @@ -194,7 +194,7 @@ However, no linkage is made between the signature object and the signed artifact * Push **acme-rockets** signature artifact `sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b` 1. Link **acme-rockets** signature to the `net-monitor:v1` container image -``` REST +```HTTP PUT https://localhost:6000/v2/net-monitor/manifests/sha256:2235d2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49cc77c/signatures/sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b ``` @@ -381,7 +381,7 @@ Compliant client implementations SHOULD always use the `Link` header value when To get the next result set, a client would issue the request as follows, using the URL encoded in the described `Link` header: -``` HTTP +```HTTP GET /v2//manifests/sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042/references/list?n=&last= ``` @@ -401,7 +401,7 @@ To support pagination (returning list results in pages) in a List method, the AP * define a `string` field `next_page_token` in the `List` method's response message. This field represents the pagination token to retrieve the next page of results. If the value is `""`, it means no further results for the request. To retrieve the next page of results, client **shall** pass the value of response's `next_page_token` in the subsequent `List` method call (in the request message's `page_token` field): -``` HTTP +```HTTP GET /v2//manifests/sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042/references/list?page_token=1&page_size=10&next_page_token= ``` From a42acd8ade7dbb63f718f955aac488cea557e032 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Wed, 19 Aug 2020 11:25:13 +0800 Subject: [PATCH 05/69] JWT based system (#16) Signed-off-by: Shiwei Zhang --- cmd/nv2/common.go | 5 + cmd/nv2/main.go | 2 +- cmd/nv2/manifest.go | 19 +- cmd/nv2/sign.go | 34 ++-- cmd/nv2/verify.go | 24 ++- docs/artifact/README.md | 22 --- docs/artifact/examples/manifest.json | 9 - docs/nv2/README.md | 85 +++++---- docs/signature/README.md | 212 ++++++++++++---------- docs/signature/examples/x509_kid.nv2.json | 1 - docs/signature/examples/x509_kid.nv2.jwt | 1 + docs/signature/examples/x509_x5c.nv2.json | 1 - docs/signature/examples/x509_x5c.nv2.jwt | 1 + docs/signature/schema.json | 78 -------- go.mod | 1 - go.sum | 7 - pkg/registry/manifest.go | 11 +- pkg/signature/encoding.go | 30 +++ pkg/signature/errors.go | 4 + pkg/signature/interface.go | 4 +- pkg/signature/model.go | 28 +++ pkg/signature/scheme.go | 85 ++++++--- pkg/signature/signature.go | 35 ---- pkg/signature/util.go | 17 -- pkg/signature/x509/header.go | 18 ++ pkg/signature/x509/signer.go | 49 +++-- pkg/signature/x509/verifier.go | 39 ++-- 27 files changed, 403 insertions(+), 419 deletions(-) delete mode 100644 docs/artifact/README.md delete mode 100644 docs/artifact/examples/manifest.json delete mode 100644 docs/signature/examples/x509_kid.nv2.json create mode 100644 docs/signature/examples/x509_kid.nv2.jwt delete mode 100644 docs/signature/examples/x509_x5c.nv2.json create mode 100644 docs/signature/examples/x509_x5c.nv2.jwt delete mode 100644 docs/signature/schema.json create mode 100644 pkg/signature/encoding.go create mode 100644 pkg/signature/model.go delete mode 100644 pkg/signature/signature.go delete mode 100644 pkg/signature/util.go create mode 100644 pkg/signature/x509/header.go diff --git a/cmd/nv2/common.go b/cmd/nv2/common.go index f6752a827..981b36788 100644 --- a/cmd/nv2/common.go +++ b/cmd/nv2/common.go @@ -17,4 +17,9 @@ var ( Name: "insecure", Usage: "enable insecure remote access", } + mediaTypeFlag = &cli.StringFlag{ + Name: "media-type", + Usage: "specify the media type of the manifest read from file or stdin", + Value: "application/vnd.docker.distribution.manifest.v2+json", + } ) diff --git a/cmd/nv2/main.go b/cmd/nv2/main.go index 828faca52..93c82436d 100644 --- a/cmd/nv2/main.go +++ b/cmd/nv2/main.go @@ -11,7 +11,7 @@ func main() { app := &cli.App{ Name: "nv2", Usage: "Notary V2 - Prototype", - Version: "0.1.2", + Version: "0.2.0", Authors: []*cli.Author{ { Name: "Shiwei Zhang", diff --git a/cmd/nv2/manifest.go b/cmd/nv2/manifest.go index 9bd837c2f..588e696a2 100644 --- a/cmd/nv2/manifest.go +++ b/cmd/nv2/manifest.go @@ -18,10 +18,10 @@ func getManifestFromContext(ctx *cli.Context) (signature.Manifest, error) { if uri := ctx.Args().First(); uri != "" { return getManfestsFromURI(ctx, uri) } - return getManifestFromReader(os.Stdin) + return getManifestFromReader(os.Stdin, ctx.String(mediaTypeFlag.Name)) } -func getManifestFromReader(r io.Reader) (signature.Manifest, error) { +func getManifestFromReader(r io.Reader, mediaType string) (signature.Manifest, error) { lr := &io.LimitedReader{ R: r, N: math.MaxInt64, @@ -31,8 +31,11 @@ func getManifestFromReader(r io.Reader) (signature.Manifest, error) { return signature.Manifest{}, err } return signature.Manifest{ - Digest: digest.String(), - Size: math.MaxInt64 - lr.N, + Descriptor: signature.Descriptor{ + MediaType: mediaType, + Digest: digest.String(), + Size: math.MaxInt64 - lr.N, + }, }, nil } @@ -56,13 +59,13 @@ func getManfestsFromURI(ctx *cli.Context, uri string) (signature.Manifest, error r = file case "docker", "oci": remote := registry.NewClient(nil, ®istry.ClientOptions{ - Username: ctx.String("username"), - Password: ctx.String("password"), - Insecure: ctx.Bool("insecure"), + Username: ctx.String(usernameFlag.Name), + Password: ctx.String(passwordFlag.Name), + Insecure: ctx.Bool(insecureFlag.Name), }) return remote.GetManifestMetadata(parsed) default: return signature.Manifest{}, fmt.Errorf("unsupported URI scheme: %s", parsed.Scheme) } - return getManifestFromReader(r) + return getManifestFromReader(r, ctx.String(mediaTypeFlag.Name)) } diff --git a/cmd/nv2/sign.go b/cmd/nv2/sign.go index 9a04ffde2..df79d2af4 100644 --- a/cmd/nv2/sign.go +++ b/cmd/nv2/sign.go @@ -1,7 +1,6 @@ package main import ( - "encoding/json" "fmt" "io/ioutil" "strings" @@ -16,7 +15,7 @@ const signerID = "nv2" var signCommand = &cli.Command{ Name: "sign", - Usage: "signs artifacts or images", + Usage: "signs OCI Artifacts", ArgsUsage: "[]", Flags: []cli.Flag{ &cli.StringFlag{ @@ -55,6 +54,7 @@ var signCommand = &cli.Command{ usernameFlag, passwordFlag, insecureFlag, + mediaTypeFlag, }, Action: runSign, } @@ -67,54 +67,46 @@ func runSign(ctx *cli.Context) error { } // core process - content, err := prepareContentForSigning(ctx) + claims, err := prepareClaimsForSigning(ctx) if err != nil { return err } - sig, err := scheme.Sign(signerID, content) - if err != nil { - return err - } - sigma, err := signature.Pack(content, sig) + sig, err := scheme.Sign(signerID, claims) if err != nil { return err } // write out - sigmaJSON, err := json.Marshal(sigma) - if err != nil { - return err - } path := ctx.String("output") if path == "" { - path = strings.Split(content.Manifest.Digest, ":")[1] + ".nv2" + path = strings.Split(claims.Manifest.Digest, ":")[1] + ".nv2" } - if err := ioutil.WriteFile(path, sigmaJSON, 0666); err != nil { + if err := ioutil.WriteFile(path, []byte(sig), 0666); err != nil { return err } - fmt.Println(content.Manifest.Digest) + fmt.Println(claims.Manifest.Digest) return nil } -func prepareContentForSigning(ctx *cli.Context) (signature.Content, error) { +func prepareClaimsForSigning(ctx *cli.Context) (signature.Claims, error) { manifest, err := getManifestFromContext(ctx) if err != nil { - return signature.Content{}, err + return signature.Claims{}, err } manifest.References = ctx.StringSlice("reference") now := time.Now() nowUnix := now.Unix() - content := signature.Content{ + claims := signature.Claims{ Manifest: manifest, IssuedAt: nowUnix, } if expiry := ctx.Duration("expiry"); expiry != 0 { - content.NotBefore = nowUnix - content.Expiration = now.Add(expiry).Unix() + claims.NotBefore = nowUnix + claims.Expiration = now.Add(expiry).Unix() } - return content, nil + return claims, nil } func getSchemeForSigning(ctx *cli.Context) (*signature.Scheme, error) { diff --git a/cmd/nv2/verify.go b/cmd/nv2/verify.go index d2bcf4eca..2db1652a7 100644 --- a/cmd/nv2/verify.go +++ b/cmd/nv2/verify.go @@ -2,9 +2,8 @@ package main import ( "crypto/x509" - "encoding/json" "fmt" - "os" + "io/ioutil" "github.com/notaryproject/nv2/internal/crypto" "github.com/notaryproject/nv2/pkg/signature" @@ -14,7 +13,7 @@ import ( var verifyCommand = &cli.Command{ Name: "verify", - Usage: "verifies artifacts or images", + Usage: "verifies OCI Artifacts", ArgsUsage: "[]", Flags: []cli.Flag{ &cli.StringFlag{ @@ -38,6 +37,7 @@ var verifyCommand = &cli.Command{ usernameFlag, passwordFlag, insecureFlag, + mediaTypeFlag, }, Action: runVerify, } @@ -48,13 +48,13 @@ func runVerify(ctx *cli.Context) error { if err != nil { return err } - sigma, err := readSignatrueFile(ctx.String("signature")) + sig, err := readSignatrueFile(ctx.String("signature")) if err != nil { return err } // core process - content, _, err := scheme.Verify(sigma) + claims, err := scheme.Verify(sig) if err != nil { return fmt.Errorf("verification failure: %v", err) } @@ -62,8 +62,8 @@ func runVerify(ctx *cli.Context) error { if err != nil { return err } - if content.Manifest.Digest != manifest.Digest || content.Manifest.Size != manifest.Size { - return fmt.Errorf("verification failure: manifest is not signed: %s", manifest.Digest) + if manifest.Descriptor != claims.Manifest.Descriptor { + return fmt.Errorf("verification failure: %s: ", manifest.Digest) } // write out @@ -71,14 +71,12 @@ func runVerify(ctx *cli.Context) error { return nil } -func readSignatrueFile(path string) (sig signature.Signed, err error) { - file, err := os.Open(path) +func readSignatrueFile(path string) (string, error) { + bytes, err := ioutil.ReadFile(path) if err != nil { - return sig, err + return "", err } - defer file.Close() - err = json.NewDecoder(file).Decode(&sig) - return sig, err + return string(bytes), nil } func getSchemeForVerification(ctx *cli.Context) (*signature.Scheme, error) { diff --git a/docs/artifact/README.md b/docs/artifact/README.md deleted file mode 100644 index 0e5df5c05..000000000 --- a/docs/artifact/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# Notary V2 Artifact -[Notary v2 signatures](../signature/README.md) can be stored as [OCI artifacts](https://github.com/opencontainers/artifacts). Precisely, it is a [OCI manifest](https://github.com/opencontainers/image-spec/blob/master/manifest.md) with a config of type - -- `application/vnd.cncf.notary.config.v2+json` - -and no layers. - -## Example Artifact - -Example showing the manifest ([examples/manifest.json](examples/manifest.json)) of an artifact. - -```json -{ - "schemaVersion": 2, - "config": { - "mediaType": "application/vnd.cncf.notary.config.v2+json", - "size": 1906, - "digest": "sha256:c7848182f2c817415f0de63206f9e4220012cbb0bdb750c2ecf8020350239814" - }, - "layers": [] -} -``` diff --git a/docs/artifact/examples/manifest.json b/docs/artifact/examples/manifest.json deleted file mode 100644 index 5e57feda6..000000000 --- a/docs/artifact/examples/manifest.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "schemaVersion": 2, - "config": { - "mediaType": "application/vnd.cncf.notary.config.v2+json", - "size": 1906, - "digest": "sha256:c7848182f2c817415f0de63206f9e4220012cbb0bdb750c2ecf8020350239814" - }, - "layers": [] -} \ No newline at end of file diff --git a/docs/nv2/README.md b/docs/nv2/README.md index 6ee30200e..319cfbfcd 100644 --- a/docs/nv2/README.md +++ b/docs/nv2/README.md @@ -72,6 +72,7 @@ OPTIONS: --username value, -u value username for generic remote access --password value, -p value password for generic remote access --insecure enable insecure remote access (default: false) + --media-type value specify the media type of the manifest read from file or stdin (default: "application/vnd.docker.distribution.manifest.v2+json") --help, -h show help (default: false) ``` @@ -98,38 +99,35 @@ Notary v2 signing is accomplished by signing the OCI manifest representing the a ### Signing using `x509` -To sign the manifest `hello-world_v1-manifest.json` using the key `key.pem` from the `x509` certificate `cert.pem` with the Common Name `registry.acme-rockets.io`, run +To sign the manifest `hello-world_v1-manifest.json` using the key `key.key` from the `x509` certificate `cert.crt` with the Common Name `registry.acme-rockets.io`, run ```shell nv2 sign --method x509 \ -k key.key \ -c cert.crt \ -r registry.acme-rockets.io/hello-world:v1 \ - -o hello-world.signature.config.json \ + -o hello-world.signature.config.jwt \ file:hello-world_v1-manifest.json ``` -The formatted x509 signature: `hello-world.signature.config.json` is: +The formatted x509 signature: `hello-world.signature.config.jwt` is: ``` json { - "signed": { - "digest": "sha256:5de47f48e0be1a9d41176a980728449a696fd4fcc37e9d99b8d26618c0f5bf51", - "size": 3056, - "references": [ - "registry.acme-rockets.io/hello-world:v1" - ], - "iat": 1596020554 - }, - "signature": { - "typ": "x509", - "sig": "vUNmuwrdHmcMyvG//eZQLjmIz2gnOUFNaL5Y5Jc3x1oaYu3nFnJxBEkB8232l0zBmV30sVUX2vjao0IDgLMv0Q7VWT2hiTutocgf+oRq88Jz/xKGvByGUWmVyYx9sMW6R+JHK/LlzthCLgDoYTjFD9qDTHf+AWnmRNPLv5nSYNQrVSxNH22jiO3CV/bNEQD8xoR7kZOdov6QzNw3rAP+XvlKxdf/D7vcYdR0D5T9G5xGa72aQSZmzXL/Zd2V7JQnxyJmw6PL3moU1i/8t8RK7LbsU6slvTScLUokFLZxzqCz8TcjujtaThyyxPF47ekx/HVsKW0mYXidpgCOfl+nqw==", - "alg": "RS256", - "x5c": [ - "MIIDJzCCAg+gAwIBAgIUMwVg7bpx8QmWaFzRcgpRFBN6JoQwDQYJKoZIhvcNAQELBQAwIzEhMB8GA1UEAwwYcmVnaXN0cnkuYWNtZS1yb2NrZXRzLmlvMB4XDTIwMDcyOTExMDIzMloXDTIxMDcyOTExMDIzMlowIzEhMB8GA1UEAwwYcmVnaXN0cnkuYWNtZS1yb2NrZXRzLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2mXqcXqkllwxj7S12WhVDsIu6y4ebZ/CwVwwime44yDcd0bcpdJExqIH/Qy6axQd/1zmLCHPeOXGFq48Ul0oS4Bawj1GEeLvB7VFvqB0KaBeAdxrZAvdKXCXIDH5qyFSGnOmvkja1BuR8XrH7tts5u56i+U3KEDBZg5tfx4cQuKKt0DfXZAL+4RZkNh1LoO77X0ThaBThFoRsg6aZA/cEpttoWmvnO6uUkK73oZEVgZNKGGIZZKzhUjnydRSTphp9GmZzbqUHlOiMvbzdtsQYC0qeQeNqua38HN93Ur3p+oH7oSrBWxX1Xlx933oVb+4G6h5oz0aZvMQ0G6gCLzjwIDAQABo1MwUTAdBgNVHQ4EFgQU8l2F7avSjFZ9TvnpHackunxSFcswHwYDVR0jBBgwFoAU8l2F7avSjFZ9TvnpHackunxSFcswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAwECYhttcbCbqyi7DvOTHw5bixmxplbgD0AmMvE6Ci4P/MrooBququlkri/Jcp58GBaMjxItE4qVsaWwFCEvZEfP2xN4DAbr+rdrIFy9VYuwEIBs5l0ZLRH2H2N3HlqBzhYOjVzNlYfIqnqHUDip2VsUKqhcVFkCmb3cpJ1VNAgjQU2N60JUW28L0XrGyBctBIiicLvdP4NMhHP/hhN2vr2VGIyyo5XtP+QHFi/Uwa48BJ+c9bbVpXeghOMOPMeSJmJ2b/qlp95e/YHlSCfxDXyxZ70N2vBGecrc8ly4tD9KGLb9y3Q7RBgsagOFe7cGQ2db/t60AwTIxP0a9bIyJMg==" - ] - } -} + "typ": "x509", + "alg": "RS256", + "x5c": [ + "MIIDJzCCAg+gAwIBAgIUMwVg7bpx8QmWaFzRcgpRFBN6JoQwDQYJKoZIhvcNAQELBQAwIzEhMB8GA1UEAwwYcmVnaXN0cnkuYWNtZS1yb2NrZXRzLmlvMB4XDTIwMDcyOTExMDIzMloXDTIxMDcyOTExMDIzMlowIzEhMB8GA1UEAwwYcmVnaXN0cnkuYWNtZS1yb2NrZXRzLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2mXqcXqkllwxj7S12WhVDsIu6y4ebZ/CwVwwime44yDcd0bcpdJExqIH/Qy6axQd/1zmLCHPeOXGFq48Ul0oS4Bawj1GEeLvB7VFvqB0KaBeAdxrZAvdKXCXIDH5qyFSGnOmvkja1BuR8XrH7tts5u56i+U3KEDBZg5tfx4cQuKKt0DfXZAL+4RZkNh1LoO77X0ThaBThFoRsg6aZA/cEpttoWmvnO6uUkK73oZEVgZNKGGIZZKzhUjnydRSTphp9GmZzbqUHlOiMvbzdtsQYC0qeQeNqua38HN93Ur3p+oH7oSrBWxX1Xlx933oVb+4G6h5oz0aZvMQ0G6gCLzjwIDAQABo1MwUTAdBgNVHQ4EFgQU8l2F7avSjFZ9TvnpHackunxSFcswHwYDVR0jBBgwFoAU8l2F7avSjFZ9TvnpHackunxSFcswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAwECYhttcbCbqyi7DvOTHw5bixmxplbgD0AmMvE6Ci4P/MrooBququlkri/Jcp58GBaMjxItE4qVsaWwFCEvZEfP2xN4DAbr+rdrIFy9VYuwEIBs5l0ZLRH2H2N3HlqBzhYOjVzNlYfIqnqHUDip2VsUKqhcVFkCmb3cpJ1VNAgjQU2N60JUW28L0XrGyBctBIiicLvdP4NMhHP/hhN2vr2VGIyyo5XtP+QHFi/Uwa48BJ+c9bbVpXeghOMOPMeSJmJ2b/qlp95e/YHlSCfxDXyxZ70N2vBGecrc8ly4tD9KGLb9y3Q7RBgsagOFe7cGQ2db/t60AwTIxP0a9bIyJMg==" + ] +}.{ + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "digest": "sha256:24a74900a4e749ef31295e5aabde7093e3244b119582bd6e64b1a88c71c410d0", + "size": 3056, + "references": [ + "registry.acme-rockets.io/hello-world:v1" + ], + "iat": 1597053936 +}.[Signature] ``` If the embedded cert chain `x5c` is not desired, it can be replaced by a key ID `kid` by omitting the `-c` option. @@ -138,30 +136,27 @@ If the embedded cert chain `x5c` is not desired, it can be replaced by a key ID nv2 sign -m x509 \ -k key.key \ -r registry.acme-rockets.io/hello-world:v1 \ - -o hello-world.signature.config.json \ + -o hello-world.signature.config.jwt \ file:hello-world_v1-manifest.json ``` -The formatted x509, without the `x5c` chain signature: `hello-world.signature.config.json` is: +The formatted x509, without the `x5c` chain signature: `hello-world.signature.config.jwt` is: ```json { - "signed": { - "digest": "sha256:5de47f48e0be1a9d41176a980728449a696fd4fcc37e9d99b8d26618c0f5bf51", - "size": 3056, - "references": [ - "registry.acme-rockets.io/hello-world:v1" - ], - "iat": 1596020616 - }, - "signature": { - "typ": "x509", - "sig": "OyRPlwwsO5mYDxKkiNeTQlSl4WV8SOiQMCJv4i1+sx7uv6Pe8dHDaPt1SE5s64HzFvo6s26PrfiPYp4RphQOd/KvW2Hh03nS8ZByE4NWFOE6VLQcfNpScba6Q9vAzc3TnZrg1c9t992MGuec1oZB9pR77Ms7Jv/+gZd1qr6VPpA0A6+UucEbN6+pKRTiPRx5WkFXTkN0a4jmlJnev6MyBY3VI0EzjLI4nbCu9P05e4SK1dO0hXtD7aQCf2CCVKdYNHAMX4pNPTLxS3a5p4CFjV3oCbZO6cYT/5ZxgQrVV7vaGEI1MGCOEXS2KSI14zO6KlU1awtOQq3g04e03O+SVQ==", - "alg": "RS256", - "kid": "RQGT:OPJI:IABT:DFXB:52VS:FNOJ:4XBS:H4KY:WHGM:HQMC:WSMN:LKXM" - } -} + "typ": "x509", + "alg": "RS256", + "kid": "RQGT:OPJI:IABT:DFXB:52VS:FNOJ:4XBS:H4KY:WHGM:HQMC:WSMN:LKXM" +}.{ + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "digest": "sha256:24a74900a4e749ef31295e5aabde7093e3244b119582bd6e64b1a88c71c410d0", + "size": 3056, + "references": [ + "registry.acme-rockets.io/hello-world:v1" + ], + "iat": 1597053992 +}.[Signature] ``` The detailed signature specification is [available](../signature/README.md). @@ -184,6 +179,7 @@ OPTIONS: --username value, -u value username for generic remote access --password value, -p value password for generic remote access --insecure enable insecure remote access (default: false) + --media-type value specify the media type of the manifest read from file or stdin (default: "application/vnd.docker.distribution.manifest.v2+json") --help, -h show help (default: false) ``` @@ -193,7 +189,7 @@ Since the manifest was signed by a self-signed certificate, that certificate `ce ```shell nv2 verify \ - -f hello-world.signature.config.json \ + -f hello-world.signature.config.jwt \ -c cert.crt \ file:hello-world_v1-manifest.json ``` @@ -202,7 +198,7 @@ If the cert isn't self-signed, you can omit the `-c` parameter. ``` shell nv2 verify \ - -f hello-world.signature.config.json \ + -f hello-world.signature.config.jwt \ file:hello-world_v1-manifest.json sha256:3351c53952446db17d21b86cfe5829ae70f823aff5d410fbf09dff820a39ab55 @@ -223,15 +219,16 @@ Here is an example to sign and verify the image `hello-world` in DockerHub, i.e. ``` shell nv2 sign -m x509 \ -k key.key \ - -o hello-world_latest.signature.config.json \ + -o hello-world_latest.signature.config.jwt \ docker://docker.io/library/hello-world:latest sha256:49a1c8800c94df04e9658809b006fd8a686cab8028d33cfba2cc049724254202 nv2 verify \ -c cert.crt \ - -f hello-world_latest.signature.config.json \ + -f hello-world_latest.signature.config.jwt \ docker://docker.io/library/hello-world:latest + sha256:49a1c8800c94df04e9658809b006fd8a686cab8028d33cfba2cc049724254202 ``` @@ -251,14 +248,14 @@ OCI registry works the same as Docker but with the scheme `oci`. ``` shell nv2 sign -m x509 \ -k key.key \ - -o hello-world_latest.signature.config.json \ + -o hello-world_latest.signature.config.jwt \ oci://docker.io/library/hello-world:latest sha256:0ebe6f409b373c8baf39879fccee6cae5e718003ec3167ded7d54cb2b5da2946 nv2 verify \ -c cert.crt \ - -f hello-world_latest.signature.config.json \ + -f hello-world_latest.signature.config.jwt \ oci://docker.io/library/hello-world:latest sha256:0ebe6f409b373c8baf39879fccee6cae5e718003ec3167ded7d54cb2b5da2946 @@ -286,7 +283,7 @@ sha256:3351c53952446db17d21b86cfe5829ae70f823aff5d410fbf09dff820a39ab55 Since the tag might be changed during the verification process, it is required to pull by digest after verification. ```shell -digest=$(nv2 verify -f hello-world_latest.signature.config.json -c cert.crt docker://docker.io/library/hello-world:latest) +digest=$(nv2 verify -f hello-world_latest.signature.config.jwt -c cert.crt docker://docker.io/library/hello-world:latest) if [ $? -eq 0 ]; then docker pull docker.io/library/hello-world@$digest fi diff --git a/docs/signature/README.md b/docs/signature/README.md index d3b49d7fd..76bca766a 100644 --- a/docs/signature/README.md +++ b/docs/signature/README.md @@ -1,15 +1,15 @@ # Notary V2 Signature Specification -This section defines the signature file, which is in JSON format with no whitespaces. Its JSON schema is available at [schema.json](schema.json). +This section defines the signature file, which is a [JWT](https://tools.ietf.org/html/rfc7519) variant. ## Signature Goals - Offline signature creation -- Persistance within an [OCI Artifact][oci-artifacts] enabled, [distribution-spec][distribution-spec] based registry +- Persistence within an [OCI Artifact][oci-artifacts] enabled, [distribution-spec][distribution-spec] based registry - Artifact and signature copying within and across [OCI Artifact][oci-artifacts] enabled, [distribution-spec][distribution-spec] based registries - Support public registry acquisition of content - where the public registry may host certified content as well as public, non-certified content - Support private registries, where public content may be copied to, and new content originated within -- Air-gapped environments, where the originating registry of content is not accessable +- Air-gapped environments, where the originating registry of content is not accessible - Multiple signatures per artifact, enabling the originating vendor signature, public registry certification and user/environment signatures - Maintain the original artifact digest and collection of associated tags, supporting dev/ops deployment definitions @@ -46,48 +46,70 @@ openssl req \ -out example.crt ``` -An nv2 client would generate the following content to be signed: +An nv2 client would generate the following header and claims to be signed. -``` JSON +The header would be a base64 URL encoded string without paddings: + +``` +eyJ0eXAiOiJ4NTA5IiwiYWxnIjoiUlMyNTYiLCJ4NWMiOlsiTUlJRHN6Q0NBcHVnQXdJQkFnSVVMMWFuRVUveUp5NjdWSlRiSGtOWDBiQk5BbkV3RFFZSktvWklodmNOQVFFTEJRQXdhVEVkTUJzR0ExVUVBd3dVY21WbmFYTjBjbmt1WlhoaGJYQnNaUzVqYjIweEZEQVNCZ05WQkFvTUMyVjRZVzF3YkdVZ2FXNWpNUXN3Q1FZRFZRUUdFd0pWVXpFVE1CRUdBMVVFQ0F3S1YyRnphR2x1WjNSdmJqRVFNQTRHQTFVRUJ3d0hVMlZoZEhSc1pUQWVGdzB5TURBM01qY3hORFF6TkRaYUZ3MHlNVEEzTWpjeE5EUXpORFphTUdreEhUQWJCZ05WQkFNTUZISmxaMmx6ZEhKNUxtVjRZVzF3YkdVdVkyOXRNUlF3RWdZRFZRUUtEQXRsZUdGdGNHeGxJR2x1WXpFTE1Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBZ01DbGRoYzJocGJtZDBiMjR4RURBT0JnTlZCQWNNQjFObFlYUjBiR1V3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRRGtLd0FjVjQ0cHNqTjhubm8xZVozenYxWktVaEpBb3h3Qk9JR2ZJeEllK2lIdHBYTHZGRlZ3azVKYnh1K1BraWcyTjRCM0lscmovVnJ5aTBoeHA0bWFnMDJNNzMzYlhMUkVOU09GT05Sa3NscE84ekhVTjVwWWRuaFRTd1lUTGFwMSsxYmdjRlN1VVhMV2llcVpCNnFjN2tpdjNiajNTUGFmNDIrczQ4VjQ5dC9PcFh4THRnaVdMOVhrdURUWmN0cEpKQTR2SEhrNk91MGJjZzdpR20rTDF4d0lmYjhNbDRvV3ZUMFNGMzVmZ1cwOGJiTFhaMnYxWENMUnNyV1VnYnE0VStLeHRFcEczWElZY1loS3gxcklyVWhmRUprdUh6Z1BnbE0xMWdHNVcrQ3lmZyt3Zk9KaWc1cTZheElLV3pJZjZDOG04bG15NmJNK041RXNEOVN2QWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJUZjFoTTYvaWJHRit1L1NWQUs4OEZVTWp6Um9UQWZCZ05WSFNNRUdEQVdnQlRmMWhNNi9pYkdGK3UvU1ZBSzg4RlVNanpSb1RBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFCZ3ZWYXU1KzJ3QXVDc21PeXlHMjhoMXp5QzRJUG1NbXBSWlRET3AvcExkd1hlSGpKcjhrRUMzbDkycUpFdmMrV0Fib0oxUm91Y0h5Y1VlN1JXaDJDNlpGL1dQQ0JMeVdHd25seXFHeVJNOS9qODZVSjFPZ2l1Wmw3a2w5enh3V29heFBCQ21IYTBSSG93ZFFCN0FWbHBxZzFjN0ZoS2poVUNCbUdUNFZlOHRWMGhkWnRyWm9RVis2eEhQYlVkMzdLVjFCMUJtZm8zbzRla29KS2hVdTk5RW8wM09wRTNKTHRNMTNBMUh4QUJFdVFHSFRJMHR5Y0RCQmRSbjNiMDNIb0loVTBWbnFqdnBWMUtQdnNyZ1lpLzBWU3RMTmV6WlBnR2UwZkczWGd5OHlla2RCOU5NVW4relpMQVRJNCt6OGo0UUg1V2o1WlBhVWt5b0FEMm9VSk8iXX0 +``` + +The parsed and formatted header would be: + +```json { - "signed": { - "digest": "sha256:c4516b8a311e85f1f2a60573abf4c6b740ca3ade4127e29b05616848de487d34", - "size": 528, - "references": [ - "registry.example.com/example:latest", - "registry.example.com/example:v1.0" - ], - "exp": 1627555319, - "nbf": 1596019319, - "iat": 1596019319 - } + "typ": "x509", + "alg": "RS256", + "x5c": [ + "MIIDszCCApugAwIBAgIUL1anEU/yJy67VJTbHkNX0bBNAnEwDQYJKoZIhvcNAQELBQAwaTEdMBsGA1UEAwwUcmVnaXN0cnkuZXhhbXBsZS5jb20xFDASBgNVBAoMC2V4YW1wbGUgaW5jMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTAeFw0yMDA3MjcxNDQzNDZaFw0yMTA3MjcxNDQzNDZaMGkxHTAbBgNVBAMMFHJlZ2lzdHJ5LmV4YW1wbGUuY29tMRQwEgYDVQQKDAtleGFtcGxlIGluYzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkKwAcV44psjN8nno1eZ3zv1ZKUhJAoxwBOIGfIxIe+iHtpXLvFFVwk5Jbxu+Pkig2N4B3Ilrj/Vryi0hxp4mag02M733bXLRENSOFONRkslpO8zHUN5pYdnhTSwYTLap1+1bgcFSuUXLWieqZB6qc7kiv3bj3SPaf42+s48V49t/OpXxLtgiWL9XkuDTZctpJJA4vHHk6Ou0bcg7iGm+L1xwIfb8Ml4oWvT0SF35fgW08bbLXZ2v1XCLRsrWUgbq4U+KxtEpG3XIYcYhKx1rIrUhfEJkuHzgPglM11gG5W+Cyfg+wfOJig5q6axIKWzIf6C8m8lmy6bM+N5EsD9SvAgMBAAGjUzBRMB0GA1UdDgQWBBTf1hM6/ibGF+u/SVAK88FUMjzRoTAfBgNVHSMEGDAWgBTf1hM6/ibGF+u/SVAK88FUMjzRoTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBgvVau5+2wAuCsmOyyG28h1zyC4IPmMmpRZTDOp/pLdwXeHjJr8kEC3l92qJEvc+WAboJ1RoucHycUe7RWh2C6ZF/WPCBLyWGwnlyqGyRM9/j86UJ1OgiuZl7kl9zxwWoaxPBCmHa0RHowdQB7AVlpqg1c7FhKjhUCBmGT4Ve8tV0hdZtrZoQV+6xHPbUd37KV1B1Bmfo3o4ekoJKhUu99Eo03OpE3JLtM13A1HxABEuQGHTI0tycDBBdRn3b03HoIhU0VnqjvpV1KPvsrgYi/0VStLNezZPgGe0fG3Xgy8yekdB9NMUn+zZLATI4+z8j4QH5Wj5ZPaUkyoAD2oUJO" + ] } ``` -The signature of the above would be represented as: +The claims would be a base64 URL encoded string without paddings: + +``` +eyJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiZGlnZXN0Ijoic2hhMjU2OmM0NTE2YjhhMzExZTg1ZjFmMmE2MDU3M2FiZjRjNmI3NDBjYTNhZGU0MTI3ZTI5YjA1NjE2ODQ4ZGU0ODdkMzQiLCJzaXplIjo1MjgsInJlZmVyZW5jZXMiOlsicmVnaXN0cnkuZXhhbXBsZS5jb20vZXhhbXBsZTpsYXRlc3QiLCJyZWdpc3RyeS5leGFtcGxlLmNvbS9leGFtcGxlOnYxLjAiXSwiZXhwIjoxNjI4NTg3MTE5LCJpYXQiOjE1OTcwNTExMTksIm5iZiI6MTU5NzA1MTExOX0 +``` + +The parsed and formatted claims would be: ``` JSON { - "signature": { - "typ": "x509", - "sig": "UFqN24K2fLj7/h2slM68PLTfF9CDhrEVGuMQ8m3kkQJ4SKusj9fNxYV78tTiedqB+E8SqVH66mZbdlTrVQFJAd7aL2c3NZFfo92pE9SaHnqEDqnnGWXGRVjtBRM13YyRDm2wD8aRyuL5jEDUkTw7jBLY0+LfKHMDuYCsOOzvedof7aiaFc3qA+qKiW53jn2uEGCFfAs0LmsNafGfAtVmdGSO4zX4fdnQFAGT8sbUmL71uXl9W1B6tGeLfx5nBoQUvtplQipHly/yMQvWw7qMXsaAsf/BbGDmivN06CRahSb7VOwNq6K7Py4zYeiW40hEFVz9L7/5xT5XI1unKPZDuw==", - "alg": "RS256", - "x5c": [ - "MIIDszCCApugAwIBAgIUL1anEU/yJy67VJTbHkNX0bBNAnEwDQYJKoZIhvcNAQELBQAwaTEdMBsGA1UEAwwUcmVnaXN0cnkuZXhhbXBsZS5jb20xFDASBgNVBAoMC2V4YW1wbGUgaW5jMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTAeFw0yMDA3MjcxNDQzNDZaFw0yMTA3MjcxNDQzNDZaMGkxHTAbBgNVBAMMFHJlZ2lzdHJ5LmV4YW1wbGUuY29tMRQwEgYDVQQKDAtleGFtcGxlIGluYzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkKwAcV44psjN8nno1eZ3zv1ZKUhJAoxwBOIGfIxIe+iHtpXLvFFVwk5Jbxu+Pkig2N4B3Ilrj/Vryi0hxp4mag02M733bXLRENSOFONRkslpO8zHUN5pYdnhTSwYTLap1+1bgcFSuUXLWieqZB6qc7kiv3bj3SPaf42+s48V49t/OpXxLtgiWL9XkuDTZctpJJA4vHHk6Ou0bcg7iGm+L1xwIfb8Ml4oWvT0SF35fgW08bbLXZ2v1XCLRsrWUgbq4U+KxtEpG3XIYcYhKx1rIrUhfEJkuHzgPglM11gG5W+Cyfg+wfOJig5q6axIKWzIf6C8m8lmy6bM+N5EsD9SvAgMBAAGjUzBRMB0GA1UdDgQWBBTf1hM6/ibGF+u/SVAK88FUMjzRoTAfBgNVHSMEGDAWgBTf1hM6/ibGF+u/SVAK88FUMjzRoTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBgvVau5+2wAuCsmOyyG28h1zyC4IPmMmpRZTDOp/pLdwXeHjJr8kEC3l92qJEvc+WAboJ1RoucHycUe7RWh2C6ZF/WPCBLyWGwnlyqGyRM9/j86UJ1OgiuZl7kl9zxwWoaxPBCmHa0RHowdQB7AVlpqg1c7FhKjhUCBmGT4Ve8tV0hdZtrZoQV+6xHPbUd37KV1B1Bmfo3o4ekoJKhUu99Eo03OpE3JLtM13A1HxABEuQGHTI0tycDBBdRn3b03HoIhU0VnqjvpV1KPvsrgYi/0VStLNezZPgGe0fG3Xgy8yekdB9NMUn+zZLATI4+z8j4QH5Wj5ZPaUkyoAD2oUJO" - ] - } + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "digest": "sha256:c4516b8a311e85f1f2a60573abf4c6b740ca3ade4127e29b05616848de487d34", + "size": 528, + "references": [ + "registry.example.com/example:latest", + "registry.example.com/example:v1.0" + ], + "exp": 1628587119, + "iat": 1597051119, + "nbf": 1597051119 } ``` +The signature of the above would be represented as a base64 URL encoded string without paddings: + +``` +MtQBOL2FERM2fMSikruHOMQdHuEXAE1wf6J6TfDY2W_7PfQQllBKbJJE0HqJ5ENAbuqNYHNZeIeKUCYFrNx2XgtrKuTe7WCa1ZZKDtp5bmANp484ekdl6lW23YB8r_SRtseJuibqjI3HuiMyELj9uYV1CdRYaD2BIZ_qxraYH1fMpjDWjehU4RYLI37hsSuDQ90o09BwaNfzbQXYPsGmkSUSmej7rOFPDnuwhNy4WcUed3kRKYEW8eIjO9OUBGQq3PWvhDjxZi3QF4QFDoiKBOXL70AjaiVIveQRkJI9-xHZSYwje9OFEMioeNWB5ceZR-r4L7VzDcU-Fxqjxn79Fw +``` + +Putting everything together: + +``` +eyJ0eXAiOiJ4NTA5IiwiYWxnIjoiUlMyNTYiLCJ4NWMiOlsiTUlJRHN6Q0NBcHVnQXdJQkFnSVVMMWFuRVUveUp5NjdWSlRiSGtOWDBiQk5BbkV3RFFZSktvWklodmNOQVFFTEJRQXdhVEVkTUJzR0ExVUVBd3dVY21WbmFYTjBjbmt1WlhoaGJYQnNaUzVqYjIweEZEQVNCZ05WQkFvTUMyVjRZVzF3YkdVZ2FXNWpNUXN3Q1FZRFZRUUdFd0pWVXpFVE1CRUdBMVVFQ0F3S1YyRnphR2x1WjNSdmJqRVFNQTRHQTFVRUJ3d0hVMlZoZEhSc1pUQWVGdzB5TURBM01qY3hORFF6TkRaYUZ3MHlNVEEzTWpjeE5EUXpORFphTUdreEhUQWJCZ05WQkFNTUZISmxaMmx6ZEhKNUxtVjRZVzF3YkdVdVkyOXRNUlF3RWdZRFZRUUtEQXRsZUdGdGNHeGxJR2x1WXpFTE1Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBZ01DbGRoYzJocGJtZDBiMjR4RURBT0JnTlZCQWNNQjFObFlYUjBiR1V3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRRGtLd0FjVjQ0cHNqTjhubm8xZVozenYxWktVaEpBb3h3Qk9JR2ZJeEllK2lIdHBYTHZGRlZ3azVKYnh1K1BraWcyTjRCM0lscmovVnJ5aTBoeHA0bWFnMDJNNzMzYlhMUkVOU09GT05Sa3NscE84ekhVTjVwWWRuaFRTd1lUTGFwMSsxYmdjRlN1VVhMV2llcVpCNnFjN2tpdjNiajNTUGFmNDIrczQ4VjQ5dC9PcFh4THRnaVdMOVhrdURUWmN0cEpKQTR2SEhrNk91MGJjZzdpR20rTDF4d0lmYjhNbDRvV3ZUMFNGMzVmZ1cwOGJiTFhaMnYxWENMUnNyV1VnYnE0VStLeHRFcEczWElZY1loS3gxcklyVWhmRUprdUh6Z1BnbE0xMWdHNVcrQ3lmZyt3Zk9KaWc1cTZheElLV3pJZjZDOG04bG15NmJNK041RXNEOVN2QWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJUZjFoTTYvaWJHRit1L1NWQUs4OEZVTWp6Um9UQWZCZ05WSFNNRUdEQVdnQlRmMWhNNi9pYkdGK3UvU1ZBSzg4RlVNanpSb1RBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFCZ3ZWYXU1KzJ3QXVDc21PeXlHMjhoMXp5QzRJUG1NbXBSWlRET3AvcExkd1hlSGpKcjhrRUMzbDkycUpFdmMrV0Fib0oxUm91Y0h5Y1VlN1JXaDJDNlpGL1dQQ0JMeVdHd25seXFHeVJNOS9qODZVSjFPZ2l1Wmw3a2w5enh3V29heFBCQ21IYTBSSG93ZFFCN0FWbHBxZzFjN0ZoS2poVUNCbUdUNFZlOHRWMGhkWnRyWm9RVis2eEhQYlVkMzdLVjFCMUJtZm8zbzRla29KS2hVdTk5RW8wM09wRTNKTHRNMTNBMUh4QUJFdVFHSFRJMHR5Y0RCQmRSbjNiMDNIb0loVTBWbnFqdnBWMUtQdnNyZ1lpLzBWU3RMTmV6WlBnR2UwZkczWGd5OHlla2RCOU5NVW4relpMQVRJNCt6OGo0UUg1V2o1WlBhVWt5b0FEMm9VSk8iXX0.eyJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiZGlnZXN0Ijoic2hhMjU2OmM0NTE2YjhhMzExZTg1ZjFmMmE2MDU3M2FiZjRjNmI3NDBjYTNhZGU0MTI3ZTI5YjA1NjE2ODQ4ZGU0ODdkMzQiLCJzaXplIjo1MjgsInJlZmVyZW5jZXMiOlsicmVnaXN0cnkuZXhhbXBsZS5jb20vZXhhbXBsZTpsYXRlc3QiLCJyZWdpc3RyeS5leGFtcGxlLmNvbS9leGFtcGxlOnYxLjAiXSwiZXhwIjoxNjI4NTg3MTE5LCJpYXQiOjE1OTcwNTExMTksIm5iZiI6MTU5NzA1MTExOX0.MtQBOL2FERM2fMSikruHOMQdHuEXAE1wf6J6TfDY2W_7PfQQllBKbJJE0HqJ5ENAbuqNYHNZeIeKUCYFrNx2XgtrKuTe7WCa1ZZKDtp5bmANp484ekdl6lW23YB8r_SRtseJuibqjI3HuiMyELj9uYV1CdRYaD2BIZ_qxraYH1fMpjDWjehU4RYLI37hsSuDQ90o09BwaNfzbQXYPsGmkSUSmej7rOFPDnuwhNy4WcUed3kRKYEW8eIjO9OUBGQq3PWvhDjxZi3QF4QFDoiKBOXL70AjaiVIveQRkJI9-xHZSYwje9OFEMioeNWB5ceZR-r4L7VzDcU-Fxqjxn79Fw +``` + ### Signature Persisted within an OCI Artifact Enabled Registry -Both values are persisted in a `signature.json` file. The file would be submitted to a registry as an Artifact with null layers. -The `signature.json` would be persisted within the `manifest.config` object +All values are persisted in a `signature.jwt` file. The file would be submitted to a registry as an Artifact with null layers. +The `signature.jwt` would be persisted within the `manifest.config` object ``` SHELL oras push \ registry.example.com/hello-world:v1.0 \ - --manifest-config signature.json:application/vnd.cncf.notary.config.v2+json + --manifest-config signature.json:application/vnd.cncf.notary.config.v2+jwt ``` Would push the following manifest: @@ -96,7 +118,7 @@ Would push the following manifest: { "schemaVersion": 2, "config": { - "mediaType": "application/vnd.cncf.notary.config.v2+json", + "mediaType": "application/vnd.cncf.notary.config.v2+jwt", "size": 1906, "digest": "sha256:c7848182f2c817415f0de63206f9e4220012cbb0bdb750c2ecf8020350239814" }, @@ -106,116 +128,108 @@ Would push the following manifest: ## *Signature* Property Descriptions -- **`signed`** *object* - - This REQUIRED property provides the signed content. +### Header - - **`iat`** *integer* +- **`typ`** *string* - This OPTIONAL property identities the time at which the manifests were presented to the notary. This field is based on [RFC 7519 Section 4.1.6](https://tools.ietf.org/html/rfc7519#section-4.1.6). When used, it does not imply the issue time of any signature in the `signatures` property. + This REQUIRED property identifies the signature type. Implementations MUST support at least the following types - - **`nbf`** *integer* + - `x509`: X.509 public key certificates. Implementations MUST verify that the certificate of the signing key has the `digitalSignature` `Key Usage` extension ([RFC 5280 Section 4.2.1.3](https://tools.ietf.org/html/rfc5280#section-4.2.1.3)). - This OPTIONAL property identifies the time before which the signed content MUST NOT be accepted for processing. This field is based on [RFC 7519 Section 4.1.5](https://tools.ietf.org/html/rfc7519#section-4.1.5). + Implementations MAY support the following types - - **`exp`** *integer* + - `tuf`: [The update framework](https://theupdateframework.io/). - This OPTIONAL property identifies the expiration time on or after which the signed content MUST NOT be accepted for processing. This field is based on [RFC 7519 Section 4.1.4](https://tools.ietf.org/html/rfc7519#section-4.1.4). + Although the signature file is a JWT, type `JWT` is not used as it is not an authentication or authorization token. - - **`digest`** *string* +- **`alg`** *string* - This REQUIRED property is the *digest* of the target manifest, conforming to the requirements outlined in [Digests](https://github.com/opencontainers/image-spec/blob/master/descriptor.md#digests). If the actual content is fetched according to the *digest*, implementations MUST verify the content against the *digest*. + This REQUIRED property for the `x509` type identifies the cryptographic algorithm used to sign the content. This field is based on [RFC 7515 Section 4.1.1](https://tools.ietf.org/html/rfc7515#section-4.1.1). - - **`size`** *integer* +- **`x5c`** *array of strings* - This REQUIRED property is the *size* of the target manifest. If the actual content is fetched according the *digest*, implementations MUST verify the content against the *size*. + This OPTIONAL property for the `x509` type contains the X.509 public key certificate or certificate chain corresponding to the key used to digitally sign the content. The certificates are encoded in base64. This field is based on [RFC 7515 Section 4.1.6](https://tools.ietf.org/html/rfc7515#section-4.1.6). - - **`references`** *array of strings* +- **`kid`** *string* - This OPTIONAL property claims the manifest references of its origin. The format of the value MUST matches the [*reference* grammar](https://github.com/docker/distribution/blob/master/reference/reference.go). With used, the `x509` signatures are valid only if the domain names of all references match the Common Name (`CN`) in the `Subject` field of the certificate. + This OPTIONAL property for the `x509` type is a hint (key ID) indicating which key was used to sign the content. This field is based on [RFC 7515 Section 4.1.4](https://tools.ietf.org/html/rfc7515#section-4.1.4). -- **`signature`** *string* +### Claims - This REQUIRED property provides the signature of the signed content. The entire signature file is valid if any signature is valid. The `signature` object is influenced by JSON Web Signature (JWS) at [RFC 7515](https://tools.ietf.org/html/rfc7515). +- **`iat`** *integer* - - **`typ`** *string* + This OPTIONAL property identities the time at which the manifests were presented to the notary. This field is based on [RFC 7519 Section 4.1.6](https://tools.ietf.org/html/rfc7519#section-4.1.6). When used, it does not imply the issue time of any signature in the `signatures` property. - This REQUIRED property identifies the signature type. Implementations MUST support at least the following types +- **`nbf`** *integer* - - `x509`: X.509 public key certificates. Implementations MUST verify that the certificate of the signing key has the `digitalSignature` `Key Usage` extension ([RFC 5280 Section 4.2.1.3](https://tools.ietf.org/html/rfc5280#section-4.2.1.3)). + This OPTIONAL property identifies the time before which the signed content MUST NOT be accepted for processing. This field is based on [RFC 7519 Section 4.1.5](https://tools.ietf.org/html/rfc7519#section-4.1.5). - Implementations MAY support the following types +- **`exp`** *integer* - - `tuf`: [The update framework](https://theupdateframework.io/). + This OPTIONAL property identifies the expiration time on or after which the signed content MUST NOT be accepted for processing. This field is based on [RFC 7519 Section 4.1.4](https://tools.ietf.org/html/rfc7519#section-4.1.4). - - **`sig`** *string* +- **`mediaType`** *string* - This REQUIRED property provides the base64-encoded signature binary of the specified signature type. + This REQUIRED property contains the media type of the referenced content. Values MUST comply with [RFC 6838][rfc6838], including the [naming requirements in its section 4.2][rfc6838-s4.2]. - - **`alg`** *string* +- **`digest`** *string* - This REQUIRED property for the `x509` type identifies the cryptographic algorithm used to sign the content. This field is based on [RFC 7515 Section 4.1.1](https://tools.ietf.org/html/rfc7515#section-4.1.1). + This REQUIRED property is the *digest* of the target manifest, conforming to the requirements outlined in [Digests](https://github.com/opencontainers/image-spec/blob/master/descriptor.md#digests). If the actual content is fetched according to the *digest*, implementations MUST verify the content against the *digest*. - - **`x5c`** *array of strings* +- **`size`** *integer* - This OPTIONAL property for the `x509` type contains the X.509 public key certificate or certificate chain corresponding to the key used to digitally sign the content. The certificates are encoded in base64. This field is based on [RFC 7515 Section 4.1.6](https://tools.ietf.org/html/rfc7515#section-4.1.6). + This REQUIRED property is the *size* of the target manifest. If the actual content is fetched according the *digest*, implementations MUST verify the content against the *size*. - - **`kid`** *string* +- **`references`** *array of strings* - This OPTIONAL property for the `x509` type is a hint (key ID) indicating which key was used to sign the content. This field is based on [RFC 7515 Section 4.1.4](https://tools.ietf.org/html/rfc7515#section-4.1.4). + This OPTIONAL property claims the manifest references of its origin. The format of the value MUST matches the [*reference* grammar](https://github.com/docker/distribution/blob/master/reference/reference.go). With used, the `x509` signatures are valid only if the domain names of all references match the Common Name (`CN`) in the `Subject` field of the certificate. ## Example Signatures ### x509 Signature -Example showing a formatted `x509` signature file [examples/x509_x5c.nv2.json](examples/x509_x5c.nv2.json) with certificates provided by `x5c`: +Example showing a formatted `x509` signature file [examples/x509_x5c.nv2.jwt](examples/x509_x5c.nv2.jwt) with certificates provided by `x5c`: ```json { - "signed": { - "digest": "sha256:c4516b8a311e85f1f2a60573abf4c6b740ca3ade4127e29b05616848de487d34", - "size": 528, - "references": [ - "registry.example.com/example:latest", - "registry.example.com/example:v1.0" - ], - "exp": 1627555319, - "nbf": 1596019319, - "iat": 1596019319 - }, - "signature": { - "typ": "x509", - "sig": "UFqN24K2fLj7/h2slM68PLTfF9CDhrEVGuMQ8m3kkQJ4SKusj9fNxYV78tTiedqB+E8SqVH66mZbdlTrVQFJAd7aL2c3NZFfo92pE9SaHnqEDqnnGWXGRVjtBRM13YyRDm2wD8aRyuL5jEDUkTw7jBLY0+LfKHMDuYCsOOzvedof7aiaFc3qA+qKiW53jn2uEGCFfAs0LmsNafGfAtVmdGSO4zX4fdnQFAGT8sbUmL71uXl9W1B6tGeLfx5nBoQUvtplQipHly/yMQvWw7qMXsaAsf/BbGDmivN06CRahSb7VOwNq6K7Py4zYeiW40hEFVz9L7/5xT5XI1unKPZDuw==", - "alg": "RS256", - "x5c": [ - "MIIDszCCApugAwIBAgIUL1anEU/yJy67VJTbHkNX0bBNAnEwDQYJKoZIhvcNAQELBQAwaTEdMBsGA1UEAwwUcmVnaXN0cnkuZXhhbXBsZS5jb20xFDASBgNVBAoMC2V4YW1wbGUgaW5jMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTAeFw0yMDA3MjcxNDQzNDZaFw0yMTA3MjcxNDQzNDZaMGkxHTAbBgNVBAMMFHJlZ2lzdHJ5LmV4YW1wbGUuY29tMRQwEgYDVQQKDAtleGFtcGxlIGluYzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkKwAcV44psjN8nno1eZ3zv1ZKUhJAoxwBOIGfIxIe+iHtpXLvFFVwk5Jbxu+Pkig2N4B3Ilrj/Vryi0hxp4mag02M733bXLRENSOFONRkslpO8zHUN5pYdnhTSwYTLap1+1bgcFSuUXLWieqZB6qc7kiv3bj3SPaf42+s48V49t/OpXxLtgiWL9XkuDTZctpJJA4vHHk6Ou0bcg7iGm+L1xwIfb8Ml4oWvT0SF35fgW08bbLXZ2v1XCLRsrWUgbq4U+KxtEpG3XIYcYhKx1rIrUhfEJkuHzgPglM11gG5W+Cyfg+wfOJig5q6axIKWzIf6C8m8lmy6bM+N5EsD9SvAgMBAAGjUzBRMB0GA1UdDgQWBBTf1hM6/ibGF+u/SVAK88FUMjzRoTAfBgNVHSMEGDAWgBTf1hM6/ibGF+u/SVAK88FUMjzRoTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBgvVau5+2wAuCsmOyyG28h1zyC4IPmMmpRZTDOp/pLdwXeHjJr8kEC3l92qJEvc+WAboJ1RoucHycUe7RWh2C6ZF/WPCBLyWGwnlyqGyRM9/j86UJ1OgiuZl7kl9zxwWoaxPBCmHa0RHowdQB7AVlpqg1c7FhKjhUCBmGT4Ve8tV0hdZtrZoQV+6xHPbUd37KV1B1Bmfo3o4ekoJKhUu99Eo03OpE3JLtM13A1HxABEuQGHTI0tycDBBdRn3b03HoIhU0VnqjvpV1KPvsrgYi/0VStLNezZPgGe0fG3Xgy8yekdB9NMUn+zZLATI4+z8j4QH5Wj5ZPaUkyoAD2oUJO" - ] - } -} + "typ": "x509", + "alg": "RS256", + "x5c": [ + "MIIDszCCApugAwIBAgIUL1anEU/yJy67VJTbHkNX0bBNAnEwDQYJKoZIhvcNAQELBQAwaTEdMBsGA1UEAwwUcmVnaXN0cnkuZXhhbXBsZS5jb20xFDASBgNVBAoMC2V4YW1wbGUgaW5jMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTAeFw0yMDA3MjcxNDQzNDZaFw0yMTA3MjcxNDQzNDZaMGkxHTAbBgNVBAMMFHJlZ2lzdHJ5LmV4YW1wbGUuY29tMRQwEgYDVQQKDAtleGFtcGxlIGluYzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkKwAcV44psjN8nno1eZ3zv1ZKUhJAoxwBOIGfIxIe+iHtpXLvFFVwk5Jbxu+Pkig2N4B3Ilrj/Vryi0hxp4mag02M733bXLRENSOFONRkslpO8zHUN5pYdnhTSwYTLap1+1bgcFSuUXLWieqZB6qc7kiv3bj3SPaf42+s48V49t/OpXxLtgiWL9XkuDTZctpJJA4vHHk6Ou0bcg7iGm+L1xwIfb8Ml4oWvT0SF35fgW08bbLXZ2v1XCLRsrWUgbq4U+KxtEpG3XIYcYhKx1rIrUhfEJkuHzgPglM11gG5W+Cyfg+wfOJig5q6axIKWzIf6C8m8lmy6bM+N5EsD9SvAgMBAAGjUzBRMB0GA1UdDgQWBBTf1hM6/ibGF+u/SVAK88FUMjzRoTAfBgNVHSMEGDAWgBTf1hM6/ibGF+u/SVAK88FUMjzRoTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBgvVau5+2wAuCsmOyyG28h1zyC4IPmMmpRZTDOp/pLdwXeHjJr8kEC3l92qJEvc+WAboJ1RoucHycUe7RWh2C6ZF/WPCBLyWGwnlyqGyRM9/j86UJ1OgiuZl7kl9zxwWoaxPBCmHa0RHowdQB7AVlpqg1c7FhKjhUCBmGT4Ve8tV0hdZtrZoQV+6xHPbUd37KV1B1Bmfo3o4ekoJKhUu99Eo03OpE3JLtM13A1HxABEuQGHTI0tycDBBdRn3b03HoIhU0VnqjvpV1KPvsrgYi/0VStLNezZPgGe0fG3Xgy8yekdB9NMUn+zZLATI4+z8j4QH5Wj5ZPaUkyoAD2oUJO" + ] +}.{ + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "digest": "sha256:c4516b8a311e85f1f2a60573abf4c6b740ca3ade4127e29b05616848de487d34", + "size": 528, + "references": [ + "registry.example.com/example:latest", + "registry.example.com/example:v1.0" + ], + "exp": 1628587119, + "iat": 1597051119, + "nbf": 1597051119 +}.[Signature] ``` -Example showing a formatted `x509` signature file [examples/x509_kid.nv2.json](examples/x509_kid.nv2.json) with certificates referenced by `kid`: +Example showing a formatted `x509` signature file [examples/x509_kid.nv2.jwt](examples/x509_kid.nv2.jwt) with certificates referenced by `kid`: ```json { - "signed": { - "digest": "sha256:c4516b8a311e85f1f2a60573abf4c6b740ca3ade4127e29b05616848de487d34", - "size": 528, - "references": [ - "registry.example.com/example:latest", - "registry.example.com/example:v1.0" - ], - "exp": 1627554920, - "nbf": 1596018920, - "iat": 1596018920 - }, - "signature": { - "typ": "x509", - "sig": "emzP9ygJD3y2ZWMYGO/wyqOhaSxrhd4ZdmjC9Zd+Ba7gGmGzBylsY1CskyZw389Hz2Z0xA6AQLhaNBbbqyxuAxVXtataMRsqCl/cgyNbyYU1URB2aTUZY/3V4iJzH1O/QfwSkpQa3aN1OCL8uMBNCtM6Rde9+SX8Q8XNMByDbuXtyPDvnKunZxpofEn2ibLe2Cm3o+MTK4pgxacEWeld85gTb06NicARf7mcVj7bflLyUIgel4qvmdqT6896Gtd2ES1KawvyjoEyskdlVlneSTdEKGRYxfchwIUK4E7p3EtTnmj+FuD9MpCtP0M4CQiOr19j0NtQe2bHuTo4bwtjuw==", - "alg": "RS256", - "kid": "XP5O:Y7W2:PRB6:O355:56CC:P3A6:CBDV:EDMN:QZCK:W5PO:QMV3:T2LX" - } -} + "typ": "x509", + "alg": "RS256", + "kid": "XP5O:Y7W2:PRB6:O355:56CC:P3A6:CBDV:EDMN:QZCK:W5PO:QMV3:T2LX" +}.{ + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "digest": "sha256:c4516b8a311e85f1f2a60573abf4c6b740ca3ade4127e29b05616848de487d34", + "size": 528, + "references": [ + "registry.example.com/example:latest", + "registry.example.com/example:v1.0" + ], + "exp": 1628587341, + "iat": 1597051341, + "nbf": 1597051341 +}.[Signature] ``` [distribution-spec]: https://github.com/opencontainers/distribution-spec diff --git a/docs/signature/examples/x509_kid.nv2.json b/docs/signature/examples/x509_kid.nv2.json deleted file mode 100644 index dc30f0a6e..000000000 --- a/docs/signature/examples/x509_kid.nv2.json +++ /dev/null @@ -1 +0,0 @@ -{"signed":{"digest":"sha256:c4516b8a311e85f1f2a60573abf4c6b740ca3ade4127e29b05616848de487d34","size":528,"references":["registry.example.com/example:latest","registry.example.com/example:v1.0"],"exp":1627554920,"nbf":1596018920,"iat":1596018920},"signature":{"typ":"x509","sig":"emzP9ygJD3y2ZWMYGO/wyqOhaSxrhd4ZdmjC9Zd+Ba7gGmGzBylsY1CskyZw389Hz2Z0xA6AQLhaNBbbqyxuAxVXtataMRsqCl/cgyNbyYU1URB2aTUZY/3V4iJzH1O/QfwSkpQa3aN1OCL8uMBNCtM6Rde9+SX8Q8XNMByDbuXtyPDvnKunZxpofEn2ibLe2Cm3o+MTK4pgxacEWeld85gTb06NicARf7mcVj7bflLyUIgel4qvmdqT6896Gtd2ES1KawvyjoEyskdlVlneSTdEKGRYxfchwIUK4E7p3EtTnmj+FuD9MpCtP0M4CQiOr19j0NtQe2bHuTo4bwtjuw==","alg":"RS256","kid":"XP5O:Y7W2:PRB6:O355:56CC:P3A6:CBDV:EDMN:QZCK:W5PO:QMV3:T2LX"}} \ No newline at end of file diff --git a/docs/signature/examples/x509_kid.nv2.jwt b/docs/signature/examples/x509_kid.nv2.jwt new file mode 100644 index 000000000..444cd2790 --- /dev/null +++ b/docs/signature/examples/x509_kid.nv2.jwt @@ -0,0 +1 @@ +eyJ0eXAiOiJ4NTA5IiwiYWxnIjoiUlMyNTYiLCJraWQiOiJYUDVPOlk3VzI6UFJCNjpPMzU1OjU2Q0M6UDNBNjpDQkRWOkVETU46UVpDSzpXNVBPOlFNVjM6VDJMWCJ9.eyJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiZGlnZXN0Ijoic2hhMjU2OmM0NTE2YjhhMzExZTg1ZjFmMmE2MDU3M2FiZjRjNmI3NDBjYTNhZGU0MTI3ZTI5YjA1NjE2ODQ4ZGU0ODdkMzQiLCJzaXplIjo1MjgsInJlZmVyZW5jZXMiOlsicmVnaXN0cnkuZXhhbXBsZS5jb20vZXhhbXBsZTpsYXRlc3QiLCJyZWdpc3RyeS5leGFtcGxlLmNvbS9leGFtcGxlOnYxLjAiXSwiZXhwIjoxNjI4NTg3MzQxLCJpYXQiOjE1OTcwNTEzNDEsIm5iZiI6MTU5NzA1MTM0MX0.cr9C_Py-IJcgIUXtHAQ9dFmZO4JBEOedPdg67Fm-Av8vMQBHrs7kHZOqZhF33OYR7tuG94v760RlrCrBl1OhUpk5umLjeCOk1-RBqSWUhM7GxwfeIWEIC10gzmolHVI55nb27QQxq0pTqhAC9Nof6QljFG8kyqYqjn0cr3X1zt23ppyJ1CYkcdXdDL0QD8-1EnngHAYcssun8A9dKveld-O-dMq94wk2FkSuKz6WSOM1I5E-thbq6NltB7dzLuZAkU4LXAqODCJ7fTQgUvtapzyEMvV6cQwAG1sUV1yEST0A6t6U_0Tt-X32_kciptVuzbtRLYuOW8Wzv7E41ryU6w \ No newline at end of file diff --git a/docs/signature/examples/x509_x5c.nv2.json b/docs/signature/examples/x509_x5c.nv2.json deleted file mode 100644 index 2c621e223..000000000 --- a/docs/signature/examples/x509_x5c.nv2.json +++ /dev/null @@ -1 +0,0 @@ -{"signed":{"digest":"sha256:c4516b8a311e85f1f2a60573abf4c6b740ca3ade4127e29b05616848de487d34","size":528,"references":["registry.example.com/example:latest","registry.example.com/example:v1.0"],"exp":1627555319,"nbf":1596019319,"iat":1596019319},"signature":{"typ":"x509","sig":"UFqN24K2fLj7/h2slM68PLTfF9CDhrEVGuMQ8m3kkQJ4SKusj9fNxYV78tTiedqB+E8SqVH66mZbdlTrVQFJAd7aL2c3NZFfo92pE9SaHnqEDqnnGWXGRVjtBRM13YyRDm2wD8aRyuL5jEDUkTw7jBLY0+LfKHMDuYCsOOzvedof7aiaFc3qA+qKiW53jn2uEGCFfAs0LmsNafGfAtVmdGSO4zX4fdnQFAGT8sbUmL71uXl9W1B6tGeLfx5nBoQUvtplQipHly/yMQvWw7qMXsaAsf/BbGDmivN06CRahSb7VOwNq6K7Py4zYeiW40hEFVz9L7/5xT5XI1unKPZDuw==","alg":"RS256","x5c":["MIIDszCCApugAwIBAgIUL1anEU/yJy67VJTbHkNX0bBNAnEwDQYJKoZIhvcNAQELBQAwaTEdMBsGA1UEAwwUcmVnaXN0cnkuZXhhbXBsZS5jb20xFDASBgNVBAoMC2V4YW1wbGUgaW5jMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTAeFw0yMDA3MjcxNDQzNDZaFw0yMTA3MjcxNDQzNDZaMGkxHTAbBgNVBAMMFHJlZ2lzdHJ5LmV4YW1wbGUuY29tMRQwEgYDVQQKDAtleGFtcGxlIGluYzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkKwAcV44psjN8nno1eZ3zv1ZKUhJAoxwBOIGfIxIe+iHtpXLvFFVwk5Jbxu+Pkig2N4B3Ilrj/Vryi0hxp4mag02M733bXLRENSOFONRkslpO8zHUN5pYdnhTSwYTLap1+1bgcFSuUXLWieqZB6qc7kiv3bj3SPaf42+s48V49t/OpXxLtgiWL9XkuDTZctpJJA4vHHk6Ou0bcg7iGm+L1xwIfb8Ml4oWvT0SF35fgW08bbLXZ2v1XCLRsrWUgbq4U+KxtEpG3XIYcYhKx1rIrUhfEJkuHzgPglM11gG5W+Cyfg+wfOJig5q6axIKWzIf6C8m8lmy6bM+N5EsD9SvAgMBAAGjUzBRMB0GA1UdDgQWBBTf1hM6/ibGF+u/SVAK88FUMjzRoTAfBgNVHSMEGDAWgBTf1hM6/ibGF+u/SVAK88FUMjzRoTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBgvVau5+2wAuCsmOyyG28h1zyC4IPmMmpRZTDOp/pLdwXeHjJr8kEC3l92qJEvc+WAboJ1RoucHycUe7RWh2C6ZF/WPCBLyWGwnlyqGyRM9/j86UJ1OgiuZl7kl9zxwWoaxPBCmHa0RHowdQB7AVlpqg1c7FhKjhUCBmGT4Ve8tV0hdZtrZoQV+6xHPbUd37KV1B1Bmfo3o4ekoJKhUu99Eo03OpE3JLtM13A1HxABEuQGHTI0tycDBBdRn3b03HoIhU0VnqjvpV1KPvsrgYi/0VStLNezZPgGe0fG3Xgy8yekdB9NMUn+zZLATI4+z8j4QH5Wj5ZPaUkyoAD2oUJO"]}} \ No newline at end of file diff --git a/docs/signature/examples/x509_x5c.nv2.jwt b/docs/signature/examples/x509_x5c.nv2.jwt new file mode 100644 index 000000000..78ff07e12 --- /dev/null +++ b/docs/signature/examples/x509_x5c.nv2.jwt @@ -0,0 +1 @@ +eyJ0eXAiOiJ4NTA5IiwiYWxnIjoiUlMyNTYiLCJ4NWMiOlsiTUlJRHN6Q0NBcHVnQXdJQkFnSVVMMWFuRVUveUp5NjdWSlRiSGtOWDBiQk5BbkV3RFFZSktvWklodmNOQVFFTEJRQXdhVEVkTUJzR0ExVUVBd3dVY21WbmFYTjBjbmt1WlhoaGJYQnNaUzVqYjIweEZEQVNCZ05WQkFvTUMyVjRZVzF3YkdVZ2FXNWpNUXN3Q1FZRFZRUUdFd0pWVXpFVE1CRUdBMVVFQ0F3S1YyRnphR2x1WjNSdmJqRVFNQTRHQTFVRUJ3d0hVMlZoZEhSc1pUQWVGdzB5TURBM01qY3hORFF6TkRaYUZ3MHlNVEEzTWpjeE5EUXpORFphTUdreEhUQWJCZ05WQkFNTUZISmxaMmx6ZEhKNUxtVjRZVzF3YkdVdVkyOXRNUlF3RWdZRFZRUUtEQXRsZUdGdGNHeGxJR2x1WXpFTE1Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBZ01DbGRoYzJocGJtZDBiMjR4RURBT0JnTlZCQWNNQjFObFlYUjBiR1V3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRRGtLd0FjVjQ0cHNqTjhubm8xZVozenYxWktVaEpBb3h3Qk9JR2ZJeEllK2lIdHBYTHZGRlZ3azVKYnh1K1BraWcyTjRCM0lscmovVnJ5aTBoeHA0bWFnMDJNNzMzYlhMUkVOU09GT05Sa3NscE84ekhVTjVwWWRuaFRTd1lUTGFwMSsxYmdjRlN1VVhMV2llcVpCNnFjN2tpdjNiajNTUGFmNDIrczQ4VjQ5dC9PcFh4THRnaVdMOVhrdURUWmN0cEpKQTR2SEhrNk91MGJjZzdpR20rTDF4d0lmYjhNbDRvV3ZUMFNGMzVmZ1cwOGJiTFhaMnYxWENMUnNyV1VnYnE0VStLeHRFcEczWElZY1loS3gxcklyVWhmRUprdUh6Z1BnbE0xMWdHNVcrQ3lmZyt3Zk9KaWc1cTZheElLV3pJZjZDOG04bG15NmJNK041RXNEOVN2QWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJUZjFoTTYvaWJHRit1L1NWQUs4OEZVTWp6Um9UQWZCZ05WSFNNRUdEQVdnQlRmMWhNNi9pYkdGK3UvU1ZBSzg4RlVNanpSb1RBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFCZ3ZWYXU1KzJ3QXVDc21PeXlHMjhoMXp5QzRJUG1NbXBSWlRET3AvcExkd1hlSGpKcjhrRUMzbDkycUpFdmMrV0Fib0oxUm91Y0h5Y1VlN1JXaDJDNlpGL1dQQ0JMeVdHd25seXFHeVJNOS9qODZVSjFPZ2l1Wmw3a2w5enh3V29heFBCQ21IYTBSSG93ZFFCN0FWbHBxZzFjN0ZoS2poVUNCbUdUNFZlOHRWMGhkWnRyWm9RVis2eEhQYlVkMzdLVjFCMUJtZm8zbzRla29KS2hVdTk5RW8wM09wRTNKTHRNMTNBMUh4QUJFdVFHSFRJMHR5Y0RCQmRSbjNiMDNIb0loVTBWbnFqdnBWMUtQdnNyZ1lpLzBWU3RMTmV6WlBnR2UwZkczWGd5OHlla2RCOU5NVW4relpMQVRJNCt6OGo0UUg1V2o1WlBhVWt5b0FEMm9VSk8iXX0.eyJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiZGlnZXN0Ijoic2hhMjU2OmM0NTE2YjhhMzExZTg1ZjFmMmE2MDU3M2FiZjRjNmI3NDBjYTNhZGU0MTI3ZTI5YjA1NjE2ODQ4ZGU0ODdkMzQiLCJzaXplIjo1MjgsInJlZmVyZW5jZXMiOlsicmVnaXN0cnkuZXhhbXBsZS5jb20vZXhhbXBsZTpsYXRlc3QiLCJyZWdpc3RyeS5leGFtcGxlLmNvbS9leGFtcGxlOnYxLjAiXSwiZXhwIjoxNjI4NTg3MTE5LCJpYXQiOjE1OTcwNTExMTksIm5iZiI6MTU5NzA1MTExOX0.MtQBOL2FERM2fMSikruHOMQdHuEXAE1wf6J6TfDY2W_7PfQQllBKbJJE0HqJ5ENAbuqNYHNZeIeKUCYFrNx2XgtrKuTe7WCa1ZZKDtp5bmANp484ekdl6lW23YB8r_SRtseJuibqjI3HuiMyELj9uYV1CdRYaD2BIZ_qxraYH1fMpjDWjehU4RYLI37hsSuDQ90o09BwaNfzbQXYPsGmkSUSmej7rOFPDnuwhNy4WcUed3kRKYEW8eIjO9OUBGQq3PWvhDjxZi3QF4QFDoiKBOXL70AjaiVIveQRkJI9-xHZSYwje9OFEMioeNWB5ceZR-r4L7VzDcU-Fxqjxn79Fw \ No newline at end of file diff --git a/docs/signature/schema.json b/docs/signature/schema.json deleted file mode 100644 index a66e843c7..000000000 --- a/docs/signature/schema.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "description": "Notary V2 Signature Config Specification", - "$schema": "http://json-schema.org/draft-04/schema#", - "id": "https://localhost:5000/schema/signature/config", - "type": "object", - "properties": { - "signed": { - "type": "object", - "properties": { - "exp": { - "type": "integer", - "description": "Expiration time. Ref RFC7519." - }, - "nbf": { - "type": "integer", - "description": "Not before time. Ref RFC7519." - }, - "iat": { - "type": "integer", - "description": "Issued at time. Ref RFC7519." - }, - "digest": { - "description": "The cryptographic checksum digest of the object, in the pattern ':'", - "$ref": "defs-descriptor.json#/definitions/digest" - }, - "size": { - "description": "The size in bytes of the referenced object.", - "$ref": "defs.json#/definitions/int64" - }, - "references": { - "type": "array", - "description": "Each element in this array represents a fully qualified tag reference to the object.", - "minItems": 1, - "items": { - "type": "string", - "description": "Example: localhost:5000/hello-world:latest" - } - } - } - }, - "signature": { - "type": "object", - "properties": { - "typ": { - "type": "string", - "description": "Media type. Ref RFC7519.", - "enum": [ - "x509" - ] - }, - "sig": { - "type": "string", - "description": "The signature blob." - }, - "alg": { - "type": "string", - "description": "Signing algorithm. Ref RFC7515." - }, - "x5c": { - "type": "string", - "description": "X509 public key certificate or certificate chain. Ref RFC7515." - }, - "kid": { - "type": "string", - "description": "Signing key hint. Ref RFC7515." - } - }, - "required": [ - "typ", - "sig" - ] - } - }, - "required": [ - "signed", - "signatures" - ] -} \ No newline at end of file diff --git a/go.mod b/go.mod index 9bad1ee32..745083dc8 100644 --- a/go.mod +++ b/go.mod @@ -7,5 +7,4 @@ require ( github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.1 github.com/urfave/cli/v2 v2.2.0 - golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 ) diff --git a/go.sum b/go.sum index 64123900c..83b110164 100644 --- a/go.sum +++ b/go.sum @@ -15,12 +15,5 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5I github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4= github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg= -golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/pkg/registry/manifest.go b/pkg/registry/manifest.go index 2d5b38ff9..694d73f1f 100644 --- a/pkg/registry/manifest.go +++ b/pkg/registry/manifest.go @@ -94,6 +94,10 @@ func (c *Client) getManifestMetadata(uri *url.URL, mediaTypes ...string) (signat } header := resp.Header + mediaType := header.Get("Content-Type") + if mediaType == "" { + return signature.Manifest{}, fmt.Errorf("%v: missing Content-Type", url) + } digest := header.Get("Docker-Content-Digest") if digest == "" { return signature.Manifest{}, fmt.Errorf("%v: missing Docker-Content-Digest", url) @@ -107,7 +111,10 @@ func (c *Client) getManifestMetadata(uri *url.URL, mediaTypes ...string) (signat return signature.Manifest{}, fmt.Errorf("%v: invalid Content-Length", url) } return signature.Manifest{ - Digest: digest, - Size: size, + Descriptor: signature.Descriptor{ + MediaType: mediaType, + Digest: digest, + Size: size, + }, }, nil } diff --git a/pkg/signature/encoding.go b/pkg/signature/encoding.go new file mode 100644 index 000000000..325e8ad55 --- /dev/null +++ b/pkg/signature/encoding.go @@ -0,0 +1,30 @@ +package signature + +import ( + "encoding/base64" + "encoding/json" + "fmt" +) + +// EncodeSegment JWT specific base64url encoding with padding stripped +func EncodeSegment(seg []byte) string { + return base64.RawURLEncoding.EncodeToString(seg) +} + +// DecodeSegment JWT specific base64url encoding with padding stripped +func DecodeSegment(seg string) ([]byte, error) { + return base64.RawURLEncoding.DecodeString(seg) +} + +// DecodeClaims JWT specific base64url encoding with padding stripped as Claims +func DecodeClaims(seg string) (Claims, error) { + bytes, err := DecodeSegment(seg) + if err != nil { + return Claims{}, fmt.Errorf("invalid base64 encoded claims: %v", err) + } + var claims Claims + if err := json.Unmarshal(bytes, &claims); err != nil { + return Claims{}, fmt.Errorf("invalid JSON encoded claims: %v", err) + } + return claims, nil +} diff --git a/pkg/signature/errors.go b/pkg/signature/errors.go index 6c939d883..9387af88a 100644 --- a/pkg/signature/errors.go +++ b/pkg/signature/errors.go @@ -4,7 +4,11 @@ import "errors" // common errors var ( + ErrInvalidToken = errors.New("invalid token") ErrInvalidSignatureType = errors.New("invalid signature type") ErrUnknownSignatureType = errors.New("unknown signature type") ErrUnknownSigner = errors.New("unknown signer") + ErrDigestMismatch = errors.New("digest mismatch") + ErrSizeMismatch = errors.New("size mismatch") + ErrMediaTypeMismatch = errors.New("media type mismatch") ) diff --git a/pkg/signature/interface.go b/pkg/signature/interface.go index e1127e10f..0cc0d14d4 100644 --- a/pkg/signature/interface.go +++ b/pkg/signature/interface.go @@ -2,11 +2,11 @@ package signature // Signer signs content type Signer interface { - Sign(content []byte) (Signature, error) + Sign(claims string) (string, []byte, error) } // Verifier verifies content type Verifier interface { Type() string - Verify(content []byte, signature Signature) error + Verify(header Header, signed string, sig []byte) error } diff --git a/pkg/signature/model.go b/pkg/signature/model.go new file mode 100644 index 000000000..282c48ea7 --- /dev/null +++ b/pkg/signature/model.go @@ -0,0 +1,28 @@ +package signature + +// Header defines the signature header +type Header struct { + Raw []byte `json:"-"` + Type string `json:"typ"` +} + +// Claims contains the claims to be signed +type Claims struct { + Manifest + Expiration int64 `json:"exp,omitempty"` + IssuedAt int64 `json:"iat,omitempty"` + NotBefore int64 `json:"nbf,omitempty"` +} + +// Manifest to be signed +type Manifest struct { + Descriptor + References []string `json:"references,omitempty"` +} + +// Descriptor describes the basic information of the target content +type Descriptor struct { + MediaType string `json:"mediaType,omitempty"` + Digest string `json:"digest"` + Size int64 `json:"size"` +} diff --git a/pkg/signature/scheme.go b/pkg/signature/scheme.go index 30b9337b8..d531be54f 100644 --- a/pkg/signature/scheme.go +++ b/pkg/signature/scheme.go @@ -3,6 +3,7 @@ package signature import ( "encoding/json" "fmt" + "strings" "time" ) @@ -30,61 +31,87 @@ func (s *Scheme) RegisterVerifier(verifier Verifier) { s.verifiers[verifier.Type()] = verifier } -// Sign signs content by a signer -func (s *Scheme) Sign(signerID string, content Content) (Signature, error) { - bytes, err := json.Marshal(content) +// Sign signs claims by a signer +func (s *Scheme) Sign(signerID string, claims Claims) (string, error) { + bytes, err := json.Marshal(claims) if err != nil { - return Signature{}, err + return "", err } return s.SignRaw(signerID, bytes) } // SignRaw signs raw content by a signer -func (s *Scheme) SignRaw(signerID string, content []byte) (Signature, error) { +func (s *Scheme) SignRaw(signerID string, content []byte) (string, error) { signer, found := s.signers[signerID] if !found { - return Signature{}, ErrUnknownSigner + return "", ErrUnknownSigner } - return signer.Sign(content) -} -// Verify verifies signed data -func (s *Scheme) Verify(signed Signed) (Content, Signature, error) { - sig, err := s.verifySignature(signed) + signed, sig, err := signer.Sign(EncodeSegment(content)) if err != nil { - return Content{}, sig, err + return "", nil } - var content Content - if err := json.Unmarshal(signed.Signed, &content); err != nil { - return Content{}, sig, err + return strings.Join([]string{ + signed, + EncodeSegment(sig), + }, "."), nil +} + +// Verify verifies the JWT-like token +func (s *Scheme) Verify(token string) (Claims, error) { + parts := strings.Split(token, ".") + if len(parts) != 3 { + return Claims{}, ErrInvalidToken } - return content, sig, s.verifyContent(content) + if err := s.verifySignature(parts); err != nil { + return Claims{}, err + } + + claims, err := DecodeClaims(parts[1]) + if err != nil { + return Claims{}, err + } + + return claims, s.verifyClaims(claims) } -func (s *Scheme) verifySignature(signed Signed) (Signature, error) { - sig := signed.Signature - verifier, found := s.verifiers[sig.Type] +func (s *Scheme) verifySignature(parts []string) error { + rawHeader, err := DecodeSegment(parts[0]) + if err != nil { + return ErrInvalidToken + } + var header Header + if json.Unmarshal(rawHeader, &header); err != nil { + return ErrInvalidToken + } + header.Raw = rawHeader + + verifier, found := s.verifiers[header.Type] if !found { - return Signature{}, ErrUnknownSignatureType + return ErrUnknownSignatureType } - content := []byte(signed.Signed) - if err := verifier.Verify(content, sig); err != nil { - return Signature{}, err + sig, err := DecodeSegment(parts[2]) + if err != nil { + return ErrInvalidToken } - return sig, nil + return verifier.Verify( + header, + strings.Join(parts[:2], "."), + sig, + ) } -func (s *Scheme) verifyContent(content Content) error { +func (s *Scheme) verifyClaims(claims Claims) error { now := time.Now().Unix() - if content.Expiration != 0 && now > content.Expiration { - return fmt.Errorf("content expired: %d: current: %d", content.Expiration, now) + if claims.Expiration != 0 && now > claims.Expiration { + return fmt.Errorf("content expired: %d: current: %d", claims.Expiration, now) } - if content.NotBefore != 0 && now < content.NotBefore { - return fmt.Errorf("content is not available yet: %d: current: %d", content.NotBefore, now) + if claims.NotBefore != 0 && now < claims.NotBefore { + return fmt.Errorf("content is not available yet: %d: current: %d", claims.NotBefore, now) } return nil } diff --git a/pkg/signature/signature.go b/pkg/signature/signature.go deleted file mode 100644 index f116d9450..000000000 --- a/pkg/signature/signature.go +++ /dev/null @@ -1,35 +0,0 @@ -package signature - -import ( - "encoding/json" -) - -// Signed is the high level, partially deserialized metadata object -type Signed struct { - Signed json.RawMessage `json:"signed"` - Signature Signature `json:"signature"` -} - -// Content contains the contents to be signed -type Content struct { - Manifest - Expiration int64 `json:"exp,omitempty"` - NotBefore int64 `json:"nbf,omitempty"` - IssuedAt int64 `json:"iat,omitempty"` -} - -// Manifest to be signed -type Manifest struct { - Digest string `json:"digest"` - Size int64 `json:"size"` - References []string `json:"references,omitempty"` -} - -// Signature to verify the content -type Signature struct { - Type string `json:"typ"` - Signature []byte `json:"sig"` - Algorithm string `json:"alg,omitempty"` - KeyID string `json:"kid,omitempty"` - X5c [][]byte `json:"x5c,omitempty"` -} diff --git a/pkg/signature/util.go b/pkg/signature/util.go deleted file mode 100644 index 0a62bfd06..000000000 --- a/pkg/signature/util.go +++ /dev/null @@ -1,17 +0,0 @@ -package signature - -import ( - "encoding/json" -) - -// Pack packs content with its signature -func Pack(content Content, signature Signature) (Signed, error) { - signed, err := json.Marshal(content) - if err != nil { - return Signed{}, err - } - return Signed{ - Signed: signed, - Signature: signature, - }, nil -} diff --git a/pkg/signature/x509/header.go b/pkg/signature/x509/header.go new file mode 100644 index 000000000..fb5ebdddf --- /dev/null +++ b/pkg/signature/x509/header.go @@ -0,0 +1,18 @@ +package x509 + +import ( + "github.com/notaryproject/nv2/pkg/signature" +) + +// Header defines the signature header +type Header struct { + signature.Header + Parameters +} + +// Parameters defines the signature parameters +type Parameters struct { + Algorithm string `json:"alg,omitempty"` + KeyID string `json:"kid,omitempty"` + X5c [][]byte `json:"x5c,omitempty"` +} diff --git a/pkg/signature/x509/signer.go b/pkg/signature/x509/signer.go index f5e8de755..eb39882d0 100644 --- a/pkg/signature/x509/signer.go +++ b/pkg/signature/x509/signer.go @@ -1,10 +1,12 @@ package x509 import ( - "bytes" "crypto" "crypto/x509" + "encoding/json" "errors" + "io" + "strings" "github.com/docker/libtrust" cryptoutil "github.com/notaryproject/nv2/internal/crypto" @@ -66,27 +68,46 @@ func NewSigner(key libtrust.PrivateKey, certs []*x509.Certificate) (signature.Si return s, nil } -func (s *signer) Sign(raw []byte) (signature.Signature, error) { +func (s *signer) Sign(claims string) (string, []byte, error) { if s.cert != nil { - if err := verifyReferences(raw, s.cert); err != nil { - return signature.Signature{}, err + if err := verifyReferences(claims, s.cert); err != nil { + return "", nil, err } } - sig, alg, err := s.key.Sign(bytes.NewReader(raw), s.hash) + // Generate header + // We have to sign an empty string for the proper algorithm string first. + _, alg, err := s.key.Sign(io.MultiReader(), s.hash) if err != nil { - return signature.Signature{}, err + return "", nil, err } - sigma := signature.Signature{ - Type: Type, - Algorithm: alg, - Signature: sig, + header := Header{ + Header: signature.Header{ + Type: Type, + }, + Parameters: Parameters{ + Algorithm: alg, + }, } - if s.cert != nil { - sigma.X5c = s.rawCerts + header.X5c = s.rawCerts } else { - sigma.KeyID = s.keyID + header.KeyID = s.keyID + } + headerJSON, err := json.Marshal(header) + if err != nil { + return "", nil, err + } + + // Generate signature + signed := strings.Join([]string{ + signature.EncodeSegment(headerJSON), + claims, + }, ".") + + sig, _, err := s.key.Sign(strings.NewReader(signed), s.hash) + if err != nil { + return "", nil, err } - return sigma, nil + return signed, sig, nil } diff --git a/pkg/signature/x509/verifier.go b/pkg/signature/x509/verifier.go index e906e896c..97eb17c99 100644 --- a/pkg/signature/x509/verifier.go +++ b/pkg/signature/x509/verifier.go @@ -1,7 +1,6 @@ package x509 import ( - "bytes" "crypto" "crypto/x509" "encoding/json" @@ -58,27 +57,37 @@ func (v *verifier) Type() string { return Type } -func (v *verifier) Verify(content []byte, sig signature.Signature) error { - if sig.Type != Type { +func (v *verifier) Verify(header signature.Header, signed string, sig []byte) error { + if header.Type != Type { return signature.ErrInvalidSignatureType } + var params Parameters + if err := json.Unmarshal(header.Raw, ¶ms); err != nil { + return err + } - key, cert, err := v.getVerificationKeyPair(sig) + key, cert, err := v.getVerificationKeyPair(params) if err != nil { return err } - if err := key.Verify(bytes.NewReader(content), sig.Algorithm, sig.Signature); err != nil { + if err := key.Verify(strings.NewReader(signed), params.Algorithm, sig); err != nil { return err } - return verifyReferences(content, cert) + + parts := strings.Split(signed, ".") + if len(parts) != 2 { + return errors.New("invalid signed content") + } + + return verifyReferences(parts[1], cert) } -func (v *verifier) getVerificationKeyPair(sig signature.Signature) (libtrust.PublicKey, *x509.Certificate, error) { +func (v *verifier) getVerificationKeyPair(params Parameters) (libtrust.PublicKey, *x509.Certificate, error) { switch { - case len(sig.X5c) > 0: - return v.getVerificationKeyPairFromX5c(sig.X5c) - case sig.KeyID != "": - return v.getVerificationKeyPairFromKeyID(sig.KeyID) + case len(params.X5c) > 0: + return v.getVerificationKeyPairFromX5c(params.X5c) + case params.KeyID != "": + return v.getVerificationKeyPairFromKeyID(params.KeyID) default: return nil, nil, errors.New("missing verification key") } @@ -127,14 +136,14 @@ func (v *verifier) getVerificationKeyPairFromX5c(x5c [][]byte) (libtrust.PublicK return key, cert, nil } -func verifyReferences(raw []byte, cert *x509.Certificate) error { - var content signature.Content - if err := json.Unmarshal(raw, &content); err != nil { +func verifyReferences(seg string, cert *x509.Certificate) error { + claims, err := signature.DecodeClaims(seg) + if err != nil { return err } roots := x509.NewCertPool() roots.AddCert(cert) - for _, reference := range content.Manifest.References { + for _, reference := range claims.Manifest.References { if _, err := cert.Verify(x509.VerifyOptions{ DNSName: strings.SplitN(reference, "/", 2)[0], Roots: roots, From 02723c724f98f9351b983e2260ee80a781d4c98e Mon Sep 17 00:00:00 2001 From: Steve Lasker Date: Mon, 24 Aug 2020 16:27:27 -0700 Subject: [PATCH 06/69] Update examples Signed-off-by: Steve Lasker --- docs/distribution/README.md | 304 ++++++++++++++++++---- media/signature-as-index.png | Bin 30953 -> 40096 bytes media/signature-as-manifest-via-index.png | Bin 50411 -> 72895 bytes media/signature-as-manifest.png | Bin 32479 -> 40394 bytes 4 files changed, 258 insertions(+), 46 deletions(-) diff --git a/docs/distribution/README.md b/docs/distribution/README.md index 3411758fe..3f5223343 100644 --- a/docs/distribution/README.md +++ b/docs/distribution/README.md @@ -19,7 +19,7 @@ Several options for how to persist a signature were explored. We measure these o * Maintain the original artifact digest and collection of associated tags, supporting existing dev through deployment workflows * Multiple signatures per artifact, enabling the originating vendor signature, public registry certification and user/environment signatures * Native persistance within an OCI Artifact enabled, distribution*spec based registry -* Artifact and signature copying within and across OCI Artifact enabled, distribution*spec based registries +* Artifact and signature copying within and across OCI Artifact enabled, distribution spec based registries * Support multi-tenant registries enabling cloud providers and enterprises to support managed services at scale * Support private registries, where public content may be copied to, and new content originated within * Air-gapped environments, where the originating registry of content is not accessible @@ -50,20 +50,58 @@ The challenge with using oci-manifest is how the registry tracks the linkage bet -Example **manifest** for a Notary v2 signature +Example **manifests** for a container image (`net-monitor:v1`) and two signatures (**wabbit-networks**, **acme-rockets**): -```json -{ - "schemaVersion": 2, - "mediaType": "application/vnd.oci.image.manifest.v2+json", - "config": { - "mediaType": "application/vnd.cncf.notary.config.v2+jwt", - "digest": "sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042", - "size": 1906 - }, - "layers": [] -} -``` +1. **manifest digest for the `net-monitor:v1` image:** `sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m"` + ```JSON + { + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v2+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:111ca3788f3464fd9a06386c4d7a8e3018b525278ac4b9da872943d4cfea111c", + "size": 1906 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0", + "size": 32654 + }, + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736", + "size": 73109 + } + ] + } + ``` +2. **manifest digest for the wabbit-networks signature** `sha256:222mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222m` + ```json + { + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v2+json", + "config": { + "mediaType": "application/vnd.cncf.notary.config.v2+jwt", + "digest": "sha256:222cb130c152895905abe66279dd9feaa68091ba55619f5b900f2ebed38b222c", + "size": 1906 + }, + "layers": [] + } + ``` +3. **manifest digest for the acme-rockets signature** `sha256:333mc0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333m` + ```json + { + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v2+json", + "config": { + "mediaType": "application/vnd.cncf.notary.config.v2+jwt", + "digest": "sha256:333cc44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b785c333c", + "size": 1906 + }, + "layers": [] + } + ``` **Pros with this approach:** @@ -78,32 +116,80 @@ Example **manifest** for a Notary v2 signature This option is similar to using oci-manifest. However, instead of parsing the signature object to determine the linkage between an artifact and signature, the `index.manifests` collection is utilized. - + -Example **index** for a Notary v2 signature +Example **manifests** for a container image (`net-monitor:v1`) and two signatures (**wabbit-networks**, **acme-rockets**). The signatures are persisted as OCI Indexes, with a new `index.config` object: -``` json -{ - "schemaVersion": 2.1, - "mediaType": "application/vnd.oci.image.index.v2+json", - "config": { - "mediaType": "application/vnd.cncf.notary.config.v2+jwt", - "digest": "sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042", - "size": 1906 - }, - "manifests": [ +1. **manifest digest for the `net-monitor:v1` image:** `sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m"` + ```JSON { - "mediaType": "application/vnd.oci.image.manifest.v1+json", - "digest": "sha256:2235d2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49cc77c", - "size": 7023, - "platform": { - "architecture": "ppc64le", - "os": "linux" - } + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v2+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:111ca3788f3464fd9a06386c4d7a8e3018b525278ac4b9da872943d4cfea111c", + "size": 1906 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0", + "size": 32654 + }, + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736", + "size": 73109 + } + ] } - ] -} -``` + ``` +2. **index digest for the wabbit-networks signature** `sha256:222ibbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222i` + ```json + { + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.index.v2+json", + "config": { + "mediaType": "application/vnd.cncf.notary.config.v2+jwt", + "digest": "sha256:222cb130c152895905abe66279dd9feaa68091ba55619f5b900f2ebed38b222c", + "size": 1906 + }, + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", + "size": 7023, + "platform": { + "architecture": "ppc64le", + "os": "linux" + } + } + ] + } + ``` +3. **index digest for the acme-rockets signature** `sha256:333ic0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333i` + ```json + { + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.index.v2+json", + "config": { + "mediaType": "application/vnd.cncf.notary.config.v2+jwt", + "digest": "sha256:333cc44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b785c333c", + "size": 1906 + }, + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", + "size": 7023, + "platform": { + "architecture": "ppc64le", + "os": "linux" + } + } + ] + } + ``` **Pros with this approach:** @@ -120,13 +206,123 @@ Example **index** for a Notary v2 signature * This has been a [desired item for OCI Artifacts][oci-artifacts-index] to support other artifact types which would base on Index. * An additional role check is performed, based on the artifact type. Also noted as a pro as registry operators may want to utilize this for other artifact types, making it a consistent model. -> **Note:** this is our working/preferred method: See OCI image-spec issue: [Add Index Support for Artifact Type #806](https://github.com/opencontainers/image-spec/issues/) +> **Note:** this is our working/preferred method: See OCI image-spec issue: [Add Index Support for Artifact Type #806](https://github.com/opencontainers/image-spec/issues/806) ### Signature Persistance - Option 3: oci-manifest linked through oci-index This model is a hybrid of the 1 & 2, but moves the persistance of the signature from the config object to a layer of an additional manifest. - + + +1. **manifest digest for the `net-monitor:v1` image:** `sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m"` + ```JSON + { + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v2+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:111ca3788f3464fd9a06386c4d7a8e3018b525278ac4b9da872943d4cfea111c", + "size": 1906 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0", + "size": 32654 + }, + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736", + "size": 73109 + } + ] + } + ``` +2. **index digest for the wabbit-networks signature** `sha256:222ibbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222i` + ```json + { + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.index.v2+json", + "config": { + "mediaType": "application/vnd.cncf.notary.config.v2+jwt", + "digest": "sha256:222cb130c152895905abe66279dd9feaa68091ba55619f5b900f2ebed38b222c", + "size": 1906 + }, + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", + "size": 7023, + "platform": { + "architecture": "ppc64le", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:222mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222m", + "size": 7023, + "config_mediaType": "application/vnd.cncf.notary.config.v2+jwt" + } + } + ] + } + ``` +3. **manifest digest for the wabbit-networks signature** `sha256:222mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222m` + ```json + { + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v2+json", + "config": { + "mediaType": "application/vnd.cncf.notary.config.v2+jwt", + "digest": "sha256:222cb130c152895905abe66279dd9feaa68091ba55619f5b900f2ebed38b222c", + "size": 1906 + }, + "layers": [] + } + ``` +4. **index digest for the acme-rockets signature** `sha256:333ic0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333i` + ```json + { + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.index.v2+json", + "config": { + "mediaType": "application/vnd.cncf.notary.config.v2+jwt", + "digest": "sha256:333cc44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b785c333c", + "size": 1906 + }, + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", + "size": 7023, + "platform": { + "architecture": "ppc64le", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:333mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb333m", + "size": 7023, + "config_mediaType": "application/vnd.cncf.notary.config.v2+jwt" + } + } + ] + } +5. **manifest digest for the acme-rockets signature** `sha256:333mc0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333m` + ```json + { + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v2+json", + "config": { + "mediaType": "application/vnd.cncf.notary.config.v2+jwt", + "digest": "sha256:333cc44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b785c333c", + "size": 1906 + }, + "layers": [] + } + ``` **Pros with this approach:** @@ -155,7 +351,7 @@ If index is used, option 4 defers the linking to existing Index linking capabili Upon [manifest put][oci-dist-spec-manifest-put], perform the following steps: -* The [nv2 signature specification][nv2-signature-spec] identifies the referenced artifact by its digest and optional tags. +* The [proposed nv2 signature specification][nv2-signature-spec] identifies the referenced artifact by its digest and optional tags. * As the registry receives artifacts, the artifact type is parsed, evaluating the `manifest.config.mediaType` of `"application/vnd.cncf.notary.config.v2+jwt"` * A role check is performed, confirming the identity of the PUT has **signer** rights * The registry uses the config objects reference to link the signature with signed digest. This would enable registry tracking for garbage collection @@ -320,7 +516,7 @@ Content-Type: application/json There are three identified patterns for paging results: 1. [OCI distribution-spec Tag Listing](#distribution-spec---tags-listing-api) -1. [Google API Design Guidelines](#dis) +1. [Google API Design Guidelines](#google-paging-api) 1. [Microsoft API Design Guidelines](https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md#98-pagination) #### Distribution Spec - Tags Listing API @@ -452,11 +648,27 @@ These assume: * Signature objects do NOT have tags. However, they are placed in the same repo as the artifact they reference. * Per the design options, a signature object may be persisted as an OCI Manifest or OCI Index. -|Artifact |`config.mediaType` | Digest | -|-------------------------|-------------------------------------------|-------------------------------------------------------------------------| -|`net-monitor:v1` image |`application/vnd.oci.image.config.v1+json` |`sha256:2235d2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49cc77c`| -|wabbit-networks signature|`application/vnd.cncf.notary.config.v2+jwt`|`sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042`| -|acme-rockets signature |`application/vnd.cncf.notary.config.v2+jwt`|`sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b`| +### Artifacts submitted to a registry + +The following are artifacts that represent a container image, or signature artifact. Depending on the example above, the signatures are represented as an oci manifest or oci index. +|Artifact |`config.mediaType` | Digest | +|----------------------------------|-------------------------------------------|-------------------------------------------------------------------------| +|`net-monitor:v1` image **manifest** |`application/vnd.oci.image.config.v1+json` |`sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m`| +|`net-monitor:v1` multi-arch **index** |`application/vnd.oci.image.config.v1+json` |`sha256:111ia2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111i`| +|wabbit-networks signature **manifest**|`application/vnd.cncf.notary.config.v2+jwt`|`sha256:222mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222m`| +|wabbit-networks signature **index** |`application/vnd.cncf.notary.config.v2+jwt`|`sha256:222ibbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222i`| +|acme-rockets signature **manifest** |`application/vnd.cncf.notary.config.v2+jwt`|`sha256:333mc0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333m`| +|acme-rockets signature **index** |`application/vnd.cncf.notary.config.v2+jwt`|`sha256:333ic0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333i`| + +### Config Objects - referenced by manifests + +The following are descriptors, representing config objects within a manifest and/or index + +| Config Object | Config Digest | +|-|-| +|net-monitor image |`sha256:111ca3788f3464fd9a06386c4d7a8e3018b525278ac4b9da872943d4cfea111c`| +|wabbit-networks signature |`sha256:222cb130c152895905abe66279dd9feaa68091ba55619f5b900f2ebed38b222c`| +|acme-rockets signature |`sha256:333cc44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b785c333c`| ### Example manifest for the **container image**: `registry.acme-rockets.com/net-monitor:v1` @@ -466,7 +678,7 @@ These assume: "mediaType": "application/vnd.oci.image.manifest.v2+json", "config": { "mediaType": "application/vnd.oci.image.config.v1+json", - "digest": "sha256:2235d2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49cc77c", + "digest": "sha256:1101a3788f3464fd9a06386c4d7a8e3018b525278ac4b9da872943d4cfe97fe8", "size": 1906 }, "layers": [ diff --git a/media/signature-as-index.png b/media/signature-as-index.png index 76f521991916e4f93492767ae9dd8e01cb8bcfd0..ba1ca81d85c4c740342a068d7c74014c0dc4d147 100644 GIT binary patch literal 40096 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 z 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 RmqLe6TG<}2IC}Aq{{yk@vO)j= literal 50411 zcmbSz2RzjO|M;~&N`<7zOkGx?L1bM4FVlh z1%dXD9{vOP#EMVw9`MgTCv9Z~P(d5#Ebz-gOL+}>5ax=P*j20j2Wex zp4hN$`WuEc#Q*J>KbS^=eWY5lJk%dt4c_Jcs8FPWU&UcnUsWa~?fYsyA%Hbp9LP<6 zo~^NR2*u#pYC*ftRwk}^DAo4v;Vyl8B}aeo{cs=QNbl3zdcWO@`M}%UTLyJ*Safpodzu9=eu|ey@g~jn9VhU_Xx|JLpgo;#PTu4+%eZOX6-pRtLHY+q=4a6K=M#q67%*WN+=vY)K8?IH7hsk z#D}3wNP%kmpvr~w;^>p|kwIs#ELoLb8>f;Cc){;nu|W)~-nK%*cvF28jn$xT8mn7* z!4G~Ug7oc^AJ1tb6unASwg@LG`|LyUId&>3Am#2kO;(6>12K03Z_np*HfQxBqstwl z)xi3((+ld>lrGAI)W{p5Y4>plg2(bVME2rhFppl>ng(ywY90Q$+F&|n%j#`V^cJozwQclHKy%&<=19!@0sj2Z` zJ3orQ-nF`tG{9}#Qt66|%GBnkgliYxWAD3#B@gTmDgh-4R$J-BqHU>Nu!OFa5ynGT zVkJbeADE*v#}br@64uhUo7OQp*6!PizZnH9ud1D4LQcM)?V?qat-x_y3V_rBwfIfN zeK!X^SW;#fLfLM=&9F17T8YmTgUj&QM*6UP<@s_?@KR^pV`8}p16L~gUuYyciS&Gs ztLIsJ$#W|h_9W~4NH5^|=ue1MHbn}>UIkklDs!}Q)G=2oUlF+Rxc|bxNS=J2lRSLn z0>i20pjUH?0bNVi4Y-hQrbSq?(;c;Ltux3OH*WRhNI%s2JoBE`N9_0>Rl6&B9cvon z&T}u784j#ecX}D8F*U#>>VLXiaaPf0|1;e|#~&z%Bd~I&F!iNI(gzZw{il> zc`M#p*nn4g7L_)WD#@N{-9u>4cEXplsxdO@*^j$ODmi4D^fuh*Rozs1wcZx%MG;hB zCQw{th}Ehnak&w)wnsb5ZR;}xO=g1B;ETKhv`}OeNi@fRrrW;OyS^+eC8?S>P>sv3 zQvU|$y<+(L+gvcZ3qk=GVj&D6?Xq9y!t2}d9j;IMh2SV^FUE_Kt$<{c%wDOSTDzXT z9IjO7RUsQ6IL&ju%MH=JM)A1xcV`nZQ!~qd8gKio*76PS z%~ZL%F0$G2qwAASMP9~q&fC6JTbIksrQNW~$?np8Q?bfM{S93pKx{|oQXXvf&Yhw$$;=Q4L_2Zg?`rYi0|IbW#Mzz5{g)x{;~NW~ ztU^I|qIrhij&bkfBjB|E!b%WuZjlN|#CARZ;?|7mmm6yEEh5AO^^@DyPa(WS`z-Q2 zxaP(0Q3p7ke)eBJJAu4}IcjOi<9@}Zq8pQ#OLxlJOLka!PCkbF?;hL{IQdEu=>x6Y zjsLkjhP?mIxKHd}O0g5;aYj`?XUnnMa3AY8q!I}qQ-{Qdt>R$vN`HTxsf@IzNN;Xg zOX?P7$g-^sjZR2g{_^P)O0~|;ql{7z4truu+1e1l)a%q+e_RZmu(pB2;8(n?f27Xh zE|P5EaD~Be^pkjY*I5RZ)`+=o>-VLVhEc2832Dec_}R$l%8RW=TFeN)rYdBk!Qhvx zza&u8_auy0mFrl&FK=HigW8<$r1sY&bM{2EkpGXPTxxSS6^ZbhsBVKGu!i11$rI?2 zmKI#E2eXC_oFz+lWaL1Tc_}*bHvyICI~`MnR=}p~FES`~t(A`|?DGpuN1=6;^oC_q zP}XjwW5^XM6K}Idz!ev>F>`v6k?gSqiGuT$-sdX4btgztahSme0X(q<-c%)7G`$-b zj-R+|t0p9vuKjtUNF)CWveUov{y$-%ta9}O9ctLky@k|K%u$L{q`CeiIvPP$7XUVGS(9>7OJ&F} zwuBfMJ{v6ohm1tGhQxqV_6KRFDix5W5ORNMLe;dB==-WQCoPO$M@rkRRTi4L?uc~v zV7vm7DQqY|Bs|SeinU+oFrfZB$X1`ApHx)6@KlW?n#DT4lM7pVP~@aETW@o7Bdz`u2ri zMIYcc$0x3X!fIT2L1skBGy5ktN_A$}=6Uo`>@2m+3P^^zc{43uvClO5+aJLMfP7mg z9vyzI#rwj$9a;e8V)`$K@XrB7+|UN(oXfxyn|A~3KASEYrvJrsv#Cngwl4V_zy`Jx z{|6JFOgm23n;T#R=-&aKsrFF)8~Ig5CLdNXPk~egbi4i+mculQKMI^Z557@A`|{71 zI0aDkl*847jcXJdp#HhuS|EiqxB*!Fwcnl$qvfnUMo1d4;0tb%*2LG1;D%JdKB9mF{(bp zZuOVL7Kdg{E>x`}d}hr6LI-4>w?i$vx3F9BYbIE#v3|S27#VCZ>ykYZJ$E$QYdG0M zu6H6^Y%AO*J3*C{uA8uJk_7*!Yw0=<4k(^LGNbnK_? zirqV*9kylj8yY>-tYbn!=piBpNc?Lm;4E{%M+9nAvlcbIipHA*4*CHDwB;wYnIyl#cM zqWo>|rk9Hhgy9SHf@-k0^}b55c%@iqOYdj4mu?gh-sZP|hcejmQIB5jVaJI~1Y>?H86wB|ItwVor35++ zL`6p)oD53zSbH6nydS`;&;Dx9q3_w-P9MeKi{SnNLg)4tdHiDw;azQzjU5C4rF>Cm~y@mmB0mgqA5T72_u7wWTng9>VS2 zo<`!->>^H}%84ruj7TmqWn~o@tR-{?q=+z2Y%gV(LEj@5AnNH0WQ!eN0rX_bDeWMG zCI#MGE^AHRz8|DD30j93lRfS~J!Y*fc(Z@>fCYvbIa7fQVkNXif88+l@K)>gSV?4K z*Qem*pokLQWf}TgG8)G;G?O1^10Bvh@%P7yss7;B5__-BDwxo4RDRc*(-GBY8C|O~ zhLwhr3V;LtGRP=c07*CRHR0K4$`T6T@4a)rqin+C`sufM7r@q1K2cMILN|2h-3ZTNAyhnJOhaR_s zznCz}bvN16E}4XqS?%VkK019!IC0?JndL7ZZKU(8^=uBS#ul}9>r0tVRlsvHY-IwY zkASNG40XTS0)(U;Mxs2!i%rH&V+Yb205GSE5qJ)2!*#^9+9iLU}*UDN@WIPwe4#e3s!Lk6}B2p zmQNB@07SFD)ag|z zuQ2DOG&Q!fJ1`#x4}hwlymr63@=>qsN5_$&?Fqd3n;_h$3b}qeJSq82|ixSgr>(6T4 z>koDD??j&x&2AMv)j*NNhwr70#a1~xEF7)V_I)@~BGP0@@2yq!1@N{0V1KZB(&cm9 zi1mA{vgg6C%MBQfeLg2Vvga-8|K>R{YGO;}efEiHKRmtdway!>?4rl3x|PW3`d#M2 zR{Q>V8@RW1+3mR&8aXu9uY4r7<%z0{2Lx%YYw)|9Jeqx&1UBts^6DJZboKu5Hi(5m z!&yE$WS@T>U8jv+^h87p20PX9aWZCM?TTRQ#975b_q;BtTM#<-XhuYZtw~rri}S^* zlIfYMv@85O*q+$V(b!Z8-5((~U(ys%cC9ZF9||ixMlJmD?$vZyNr|K;##v5RJYX(` zJWg&TI^Upca8Z&&h{Z$HiR+M4%T%W0HgTElfs+IL&WfY)5Lf_4c15L1dsf0kzraQrap0s zEl7(JY*U(bf==Wj8==8WFeZ2xce!Y_K_cB>io)W;=GfG93l`p!+BQe`WwCJ~lET^~q&Y>5ZaGH~!pEuM12&dPf-IJ(+>y657=k zNIXDB=$>bLfLtHd)jK9Y&*)frtxx&cc-eIpzJp~QxtlAK-cov`70rrS8u zl8nk+3l50hpBiP(To)c>1rur~-fG&S^LVY?9R@4m=+R|4H&0o3_n`-~n#U^jf2uX{ zN297*lOH!<8BFAfxZ+msMaT<{tiS!`dKV?eH7 ziAmlz#w%jDJv~Z~pO@Qsl;NCkmx;;mgv*@EvtXENQKxh4h`FyCN}Z>UAZ8-xJ$_RT zQo7E-n4emY`#S5D4kx(@V`>80(=Qk%w!7za5eS>N+MtRBQ2J%zw*$NU`MUQ+UiXN(YOI%n#`p#hs&=lnz^UpeC^ zs!i(UDV|-f0vdWWyM@H54PL9CZU8a_z)v#o)iqk4(eE2Nf!Th$GJD5E&SeSSRFh2!1aBn@FcMv@AYLs`w>Xb$ zCE7^I-9v9(2MlkAmjy*ng>?pdSI^3I7R72pPNE-6k31ZzAME?NerIeN2*uu7e&6p}dt>QX+4z zs%reFj>`kg{Vk}FZ5>7rCFRx-Z=RiPB)#WUr5!WH+c1rfgRadA-FuLbe%l+ z;$tlb_Td%L8uT7AD7C>f>t$bg8I6M3bvH`JlR<1jQ)c_>bW_?z;apriI3@9jomTgX z+@H3+u3n9++5n399B8rIMnobUNA{Fkt0j9vBnG!_`F3j&gVe3u>!lM-HkW+9+GGuq z!1*~$Q{!4xD7~TBd*6dcN1gb9tfPUJmb2384VXTPUO{qv>3Miss+9DP2$#Ddw^V?R z3ooi*ecDewc2OZa!Pc=>+0{4L!Q?RLhm2-m_4<}PkORx=R?^dty#z|%-3N7P5AyXZ zLSeltXEBt;w`}2QcplGK`-4Y+tAJ3nOKaxzx|qX0A6Avh`Q#^?{AmEF7_Cn7EVEzq z2@9U5x??x&WQ-^RjD<|btouRN5wwinM5T+D^Gy24)lomQBfB+Fg!iC*zr!(CY zkE^tPM!d&yiRD*G#Isp~B~+Ddl<=FbH?WD^dEgI@28wHw9>zzN&aX)h?>&%e)M$rQ zo}q8bc7-y(@ErCt+8*_U5be3I-nqB;&;tDZpQr+ep4LYlkD1&ll(L1AXhOW~o4H6` z7^#^1wfAR{gP^C}v|>4W>!5v5;bakq8puoGzzC)R4f^y(Sl;>zL(UTuW(x9}kCfh0W)12mA(KG##k; z0S!7NY<`4SRoTV0kRSK{bS?|>(mnuGR-&|{v~*kVhiCMV9Lw1GpbMeh<6;1=mEB`s zr-456?POKiC(em-(w?6%`FLE7dc&`>c!O3&;&oB<^#2FiS&ai=8oZa$aoA^3MQHf3 zww8998F(}Oy}AzdMBkUARx5B>x9nf6@DZhTvNfmrYesknvfd+icI5D|AWK6cXOL{Uj&OK{hsnI}btoETX3-@W6}v65?`4nO21YLAEWbr~D#v2KM_G;O?ME zXMbeOdTVy4p@I~UU6Q>b>ncE3^q#MFD8{w^ans#fxPnZwima82(-%NZM!$Xk`AE`L zWtpPOqyCdh)fPI$h*FOvmb_IXin)U$r}SdRW`hQJgq2&KrNTQ`t+7SVY=c(GhB?_* z(v^6PQ){VWawzeRhN9J*- zZsmTaV#qKT-|WV)M{PwYPbn}HqdvP|*-G|sZRuHK&w%$x)h+SM4Arr4TK}jnGND88 zfsWXg@2xL5s?7`xpn27mFVv{uqE`E<0 zPZ7|Q?SD4N<*x(`dJ>>5#IkP86}czp2MYX}m_WYb92<|aI+9kdL>nJd6&v9>(`n#R z;6x8{&b(FOnX+(R>;l8-WwQ(|mGLkiEK^Fm7h&-jR}1q(d2IwUS89d>!@~+MVdbXc z`s5HShn*ItT(=_BWF#?Tt$!L+S6(8(U+ z&jB0G2l}X|I-9Ind?y+I?6r}d(Zjdu15C`GFqM5I)|+gJED8h%MMa=bDC#;vSgy*1k6%;e)J?;~h#8L|Io3Ebj8~OS-(ywPMumB`M!Zki_R->W_br{9Wh6D* zq{V_mz7IHvk7mxEb^Y9X&tSSjFy^ix(_K)KqZJZXaEjUL#)k>i-9|35B2ahbervG3 zXU!hKOPG+F8clJw^a~W9b>t6T?Qc?OYDs=R)w^~D>~KHTUB=kl54sUkZ&833zccZ0 zG-V>&<$5KAGG|fXULh5@h9jWaL z;HAI4!tbL~d3X4hBbL-G=PE%*fBYi@I+tF!?BHp3SF0PdHaaTfKkvL+) zsH2FMVL(#-E;=WHWTujGnXfH#AxAk>ey|vJ%%Otvwn)b+xAgw|M9}w<7=A@MPWo#M zE@8t*+NFmUzrz+lo;QL%pNG=RRlL@=Hcjag`>fwyC-)JOANKN6Ge$fOE0> zHSJe8pE}<-9W-KhNI0i}hwv_>3NRf~RUTAh^nLgvT*EDaKhL|&@o4;%me*|$D3{Lx zhE2op*L;Ed(MF04mzo&G;Ki|@qXMO8egv>v-=B8Lz-ZOG^kMO}r@Ec9q1l-sJg9z- z0$>iOm!#bqlZNM7nqPEnc8}9@*tngvFks7}sgsCwrMD%W4k4cO?FYn|Wd_iwXfSdzZ?Yo&LUY;Vo= z9&9_JS^_op-+yuWA@vGZfEX$1!;EoyEoe@sOEWotz>^?~l2ZzL1)myJTZR zi4Ed~DK6Dh)? zL(-1g=?p4ci$Pl|zFBy@*2?TELAZykBoL1WfG-4ue9S+^np~|`;f9}(M9qz%NTYjH zKYjG;dZ0X^Kh>j(h=(3JHYYZXdpcKC8USXWYWo<4L!?c%tV)S50%#C77+4l`(t;A6 zd~WoF6l-+Rg-V)x+-eOD@A$o( zn^9B;ujrNVs-$%GetXT)?4n`2e1Jn<6THD&WnY;{u^6vj6FuvppikvZl7A?cw8r8Z6Q?`OU>HRB*ftr-(~QehX+sTnQaPd;Z@ z8|wG0-CuW;zJJfUd^s`x2H7aPD1N#(_sIK`$YTu<3sB*qBKHG1pWehPm=%7ZaG7q1 zY`?z8a*LGTdTcfdS}a6>3niXVK2-WKdDoZQNBH$HS8n59>Euh;RQGNB1;+x=DgLz#K&pO5>Z z`5+QIvl(NcY=Nu)+hu+LX7;p+{3x=yU1O)oFGEW`i+2M;a>wocKbUveSOc(ecO2C` zInB3I3f-o`H2NQ40zFBf)jzgtyMYQEN6gf%h=1r>(n$wYj{O9T5_Sz>4>wKS0e34<^afPof8FjTP)q0>J|;pNj~ZVke+i~l zZ9E#l90vD4fLx2#1`5OB|K(&Nt%Tvp{U2`McA^Of_8&O(H-Up`0?+&(1TOcUHqA8u zk1(Ug&>IC+t2G-~YBC+Zd@Im{$-WnwIH$pig)XCYP1Vv@sV&(fZ=R_BrIobNqi4>4 zxVkA2%(ES=HB{*|-F7c>W4dZN7v@8buIe(3lT~ig(mM%t{E5$lN^=DhvoJDrg(EAtrLJh(T_2vF>znd~K<{&j9)hMN@KE9Cn zee&YL>oY+#8EEY$Z&z6cR6s@waS};DTi}SiyhS`S(zqB{GG!csQS%3aK0_E~?WtoP zVrBR4CWn;`a=`Iz5#@;XeD6U%O-C+zg*fiffB z+kDr^^v{n|%mDGs>X)k0JjL(&rqERO;jrq|LX8cECuBq6X4fE2`^z=dU2v6!(!?qI z&%#13A1!VoVVe`14kIN$^Wznff@|;@7Ya3QmyiRrQWO}ao&<8~-&_ROynmaE#R=qh ztl}Eh?fOE~0@fW%8YXFxUNa|Xbp;$ab_h%_7Q3!_(4{1m?PJmKndGwe&wgrY0+cQ2=ydoZZ-K=q?F%Q5*$w+Hj2Yq-8!RXPk#9Jog+7XI8R z8AO)=B~F{)v!*(5X}~f(*|G5_F{jiwn5})vo<>{6yb$4GjGQ8Qrjcc2P#Fu0wJkBb zOrWDlbM_zn&4c@Q^KSTqH(lZuSzgVIR$h%tjUsr*!I?BtA8x^COp)m3L(rqb(_3 zmf^OpL;Mwi&NaC|Vzs)TaK*N5%ugUuI;XHr=%P!#kN8Y^3*~*J0Gr!l{0Ea)P^QU0 zDs}6k1cA3eZ?*vG!8}hi`D5-fEO}N8UU8ttRyVrv{M@xfMfymo4F_(YV_#26Z`s1W zSlw_}Nh%kuc<)wvXOL2S4AFvLSz7YqfpZeapoqrl7DqQ`MCBSv{bp}bn}zj*oZT3- z1q0;TCqa@MxWU_e*XsPfr$=l@e1Y`?e*B&2SK*J&IG3snME{zejwf6Q1YfBLU%!&n z6@P*|I*37|0zo)0V~ba2SkP}C(!la=edg{-*GTRnbjRU3-*COIger)*f;wZq`vBakI zc9qaUiR&A4Umgp}u)BEZ+#87FghN?wJ>#oT2Cg7h zZlr~$lxj{3zk7PA`aV2OX+eF2@NB&N>bUYfnM;B6CZBC_ zUDg<}1az9Mv5sUCV#=yY)(&cL2Dy@c7rYg~0dIwTR8-kNnuMo?pzWf6@UQbd*H7^_ zU!4zP!H^QoEooEE4a3OVh$k5*tcD$AuQ95P6J^xeYhFIQ%an*8qkA=n%2*kD>@r)_ z~s2Xjql(CD6j z2QJ0cSW?_H*wDFGw#PN72CgD~*B+j|#so_s6^CZ(@XNf~r%+J`&b)liwL?}bTGP{5 zS#|KUw&Y!Ug?S-G=Iv~3mn&(EbQ@|pJ66&pkZ++IfnxfRw5>sll z6A$1cScaQhSYucC2siONoWH zH+QW6kYAG`CMAKNSpZm+goC$pFPFtN@;vzRDqN{axvuy)S&~cHR!1h#P?I}r{k$$Y z9y~HFGbt4nl^(n6m85A6VC8>s&GWFBmRl+xIqA=jdp97;X3p@M4^?`MQtC)xzoW^m zLx>MjBMfx9WvTL9_SpU;?acDo^Ec+IH`*~dMVDIfmv5#M-ULmX-we(mtX#02P$W#GGsBDf=Ne=xy35BE1ZBx-y*)Xa_g3)Vt~FAO?ngeSww+3@B3d#Fcr}BZei<)e+#!^jux~xCw8YO zP%pwYlHnq-117p*BLO>gzbDnzC&K_1UXQ3bMxFNHDO>%~U2e-p=;yCK6|*^1Pn%Nk z(45CVWqY4+)g?WGyv7m=}h9NVVFRk?qF!;k9$YR^a1<)DhP@kB-u>$0Qi9wp63c>4F9Hrvw! zJ1v^G{HJ;*&&lYL0@C&?_i|Zo2HlrFSZ2L17{2|Z+yDHJmwSwzC1wG+>|P`7Z*|km z=yhQ7;#wb6(fBRV;+&_?$Qm%LiIV$vAn(VX7LB|GGV8>Ds47lM*J=RFBT(AdAS==5c@HAo)bNn11Syo4U?Z z{2-9Ez3o|`uM+9`Zx>3?qOF#}zen3s>J#^>G5cy(V=szC>biETt56-7 z0aU)O7Xm2x59nNc3V7que!)&5NCZ?5tx>I#8#~q=P(&hKq6Xx!!bm{hb(W|gn zu{0X|Ogaz8vLVy(r#$9EodoBzG6}2m!u)}}(C9QgM4NHri$_QJU!uU%d@lAM3W1YS zA46%cYhZ_!tEheh?C7 zv4my$nI2Y6(7AlC{nJ|KJH?hxoR?RG7`j^u*dpN%%Awbsvn^Pp59Yl^L9aV-v_{Vz zv9o|%zQPM-_vvU&kaPzpW{bl-)-@`lRw^;3!=cv-_l#0DhE}mA?Il2YA3}S871$fc zJ>??T$nb2?(-!u@iibEvRO#fwTcl>w%poakM(EXTDd4vQoPva0c*F}u(#^G!TXUw`yCW=_S<0o~JqFKM$Bz$CipHS8!?=F$$?o zNauH>bQXj~E74*;a;S83a^i(B7eR3LpY(ImS~Ap=*sg^z93r+&F*{|+8m+xB zg00}`rn%w1zS}~D8;&_Lg-&iM(yAFrBr9pq_m+Wyii>&x%Uo0nfg#7N3hZqUR(}O# zAnTLn-JcaJ!iDql9-7dE=cEFYo0)KQ;=Cp^3c!R5&L5nqUObplIONA0oCdtMD*ApZ ze^I6LdQWOlhONM}ru#ccZ0pm)@x)(@iM+n7kzJIi1Fvu7!R@;&YGh61y9ZqV;C^8* zAhBB7x=9(1kh`@UnjyTY$7!q*?@lGfR3_czIeG8y(rgGK%=!2w!{}5D*{xG-)`f(5 zsIAw2suQDY()U32Y;l2lJ6N^&s8(%7FBkWgz#Z9PkscMS&9Eo1iy5TXJ?kRU%CS}{ zB{(eH^^ST@c5!F7-;+StHntKOL6pPOMfu}-k44BvV4i_Agay0H13lohZvSj*ayWL|7m6zbZ+O9_y^Tqr8deOwW0(V;E;DOoB2 zjBH#eIWO##hZy)eIi0c7{<_QChd*kBWli#`4k`z4I;2)oIcoM|p|?6s{@r`>?l4=7S|?TdUMZSZ9Y6kzL2+|(c`xUe?EG1$9^KW>vAj@=MA|86hTSG}P* zIg`D7eRlBn6T?HCH|Xfo+k6sTtjc6Ytqd~{1j)z<3a1K!38t0JerGzH9xgw=u_*xm z&M(D+eA`E7=0%}iq&|BH3aB;%mRa`aRfmkdyFfv6%S7!_OD&_7bokue#u7lTcK6gi ze@U?5Fu9|IA>fbLCOt#%ZYeHF=XYq}8ZM4lxo1HaO{3)K)66MuuNyC_2zJWE7J$8b zvR00r22FJ0q1|{s%`}9{v3n@@R)b-^$VTDhxw?HI6OG+2FWz(~Axrjfaa}db@mUxj zbf9(1((O31t%)E7PJtPlf+7YuxT$?#^F>o{>zHFFkZ$FJLRC1$n%kRhZx$alL%dT- zHpamjB;^2I!_($RE+5|>F&}YD1U+q@wB-)H1iUE{Nn@Tx&Ng4~_VwN@V73&vqjKrh zDZnro@j(DAD4SNSKEtaxqN+Wxs91C-KeI@V(Jr-63FmS@?dLwWXm1Py_1X9wL2lm< zWb>d5`vWt#GM!0j9jcX3z_~41olx%ZuQY#3v)Aj42h+4v9IXbt$m!-+l~l&ZGG)%! z!y=UoedO|j7jpz{Ief=vVfi>bUjYODq_6P1iq_OOhcq##U)570viTe|Rj#sB!Az_N zw9Om@)?eb5hB?TJ&l^v&P*3T+b z49^HZ$mptjobvgjE7Nx;QE6o?uQtm}*KpoHaaCJ5yw`+;w*{x%gPZ4QLkYqLCNe|# z&}p~=^C7yem%$0G$?lv&R&LQ9ih=a1o0s(?7X>=Sgdk>m&jYMC)Ve31BO0wgH{v|8 z+2ihFm1xYC&AS}7taZ1ys~pvY70>kAieFqBEo6ID@%~$tgx(Dna;nb?VuV^vCuhIb zmv00^nO1RUz7sq91{g{wuglJ>bw^1pqKUkJ&`&X)?HWEq&rsogh>reh(YzN~1NW3d ztW2LB1l~bjwUQQ(kIpTZId?pS(bnZKvW2H@ZsFe9RJ^P)uKOynT<>$lLAD^Dwaa!D zTA-3g%hwUNPk+vX2{7Yw4lv&U?D!Q{8T4cSK*i%x`2NBR5vA^8AFG3tRW50qoT^0n zD$(>~e2p1Y;(Oih%r8AEnMu~gM$S#%1@{^6--DwC`tibK5FJJF!&AT4k}5z#D6;( zY^=r2bF;PfAHyFB_uBJn(2l=am_X8Anfkxu2%TYS4bNuH!(#SwoXsT-RX$#!&0ii7Y-w*9=e6xvbjc*E4i_*9NIwWhiW~!^B~K&v zGS3 z%>(EG|H7s+QTbz!uM&;5&6oQ+ZkHX9aiudz_C**#(_MJxVkB%)FJih@a&!cH?p|Kb znCor0?j|jEXJUCY)z*_G%J|k@?SUxm{^YgV-jxJ1*-fbE>E9TZ1Te#H{diR}k*E^I zxhwZGjqC#|FyE&6(Ya?Q@+Z`@IWG%vzN}H@KJ8X6180RI)L_V!ccn*%lT*&tw;%ZXeeHIvn9H{fV1xI*x?uQBEv(r2o$27@g8uAAmn-)G9qN;H#j0R|GCnh^ zpCxC8;gs+-G~NSI#;vF^O>+LZaFP1-0hU_rMV2)Nx&$?swk*e9eU4uk5P>ypJQt4J zoK7^Ad@7$g{pQiWW>0NleVSpNY2+OI>K3Gsy?pc(&c4 zPPQM>n8u;;H%1e)cUsmD;}euWX8fgXQ$KD~&U2Sp1#`KYyq-CCzDmGB*(Ckw30Sx| zO7zd=5G7G{Sm=7nEz`=y0@%6rhabe?Ln6^7%DB*t$BUyjapMhg!>TFp z9*>Gk8aRto^8vKmiD}EU`U#=3m>#c@#?5spXMz_rW7Vj8D*08Q=L2#>PKo@Wm&%}L z=j7e2E*Rvpj|W5#NKLNB2=*nHe77}%vU3j_UDV*nRcf)OcLsLx*`DBfxIH|JjXQ0Q z^P~u`tcGPTNX}9vS>CR**XT)!@(>daY@K;W>&5cv%OWO2?Yt}|h$?+ME_GKVDkdG) zaXk+fYrCUG?0Y`+N*+3F;v&me)ZJThGDT-&uxbA};%g1#zd@fOJ>SL_~TwUPoLoJkr zTPj{WPwVne3&;6@N^dzapTvm?ivgA#&QClskjl)QJ>oiUWI0C%;8g^Qt2FB3+#Y25 ze>Yh-9(Bq9^iKv6uh60!dTW~14rU$a@?Bgmq5WLqHL;QICYIih#L}F3w>Kp&IB#SbT7NS_Y&zc zsFW*$#+Smqb*xR&$udwexve0Dii@dfEmEA?Z`%gt7&IohVmIJ~GBsY+h>|tVj`qMO zSAlvz<}RRW-0+oq+w-~lr~Z=L(4dOR=*)P1yqTUiA?GOXaSXK3J?CAZD)V76a?# zpMqwjK~Q*teAjLD6yBmLbq4_hpN07dHqz4Dd4DRvjp#~qB}N&h?0de`T_23 zJ6m)m0sd+OlVSb9WWBZ&S7D+U`8y3O!bG6iu>~<8B z3+$zgOb1pR7^#n+?^=PDs&Ayvs&`YorWRg3m!Ez1>V1hx3#P~+(a|t0I=yT87WU#D zq2em`#RW`>r?m5XaX5FLTe%*A`f_^Si(?}%mF4OBW-^(I#RL@WKIIDPf3eJiy|45C`(x?g|UUomVHf@N}ZV`WM4-qOJbyuJ$n?B zvc(vcWh!Nv!IZHN27@sM!`PnB(0QHbbzSH0d7k_J^FHoB&ht1reCPZ9tndB(dOdB- z5R6^8-a~CwyC{er!2W#iyQ#PQuEWG|6Ev>;0x6Gqj*9nQ%#xp(A9wD(CTSrAVAe4rIKu)sbYQJEhJ z8b!i;Jr1w^I@H4!iKR@HxT3$!6VDGb*w3+r-k?49`5V87pE!wM+ppmLWEA-eRneUO zpuj~v`7_TN%A%n3hl|F!RBs)FrOW{XQufX!0mWepe{|rUZu6t*`Ob2DvW3+TrEnA5 zMt;zGKqZ#^3O8zvQ;kZv};VzsQ@8oY0iMn!!x>Q_8EBNdJoWuNms87=FajLML(e_3wPttN{b_7bXkh3B;B_5s#NMQTFPSoPMeb`2}7X8wn;$ZB3&>f+<3aOF_<1buqgJ2KfMX8Y4hqDjY;8Du^YkY3L+>UA_vyQwC&Bg7 zuC8FKU2Yeam$TZN-*t)nfVJFG!<{K2!bA?TFm4g$lver|1ehw*jKV>!=BZdK4pc+e z;fT26(q(*$_Krj7X_HpQIUB-jJ-z!E`n(nv##ALZSM1X{j;?Wg z7U1dPhc#fUm)Dbo$4r3&Jyc6Sv~s$*>pa_-kBz+{@Go;**OhB~=?Sj~+2!EvdwGv@ zitrfgk;BGM1gOtcYhotwX)Z3LGsh-xk-RtdGKgD&Ra{3nKJ*O{yzO>yi_s3{=NE2vdPEFjlZ7=6(*{8KPoR3wR zraU|j38<9f6%89b5zvQ8U5*hzJ~>bDO)YQnx%g_v?-D8Jrqp49s?#)-#JDrJLa8)p zDb2J{8AN9G33w9;1xam>E!I`?2XwQtD?l(^Zwg|c-($@P9@ir zqEJivNY(=z?DbjI$bRY#MMPK4uAo!~2*5nU3izU+RkC(`xYpBhB4L;mEVWI}{mS(@ zB};>)ULU9nL7^x+M_TM_;+4XMbdJG{=&$uKoyRtgE;7GWBlnunrjG|sV1I~;A#&u- z`E0K@eEWH)*K>Us&gqJ_nYgt^B*&ikJc2*;?(En?H4mr&MJpfCTe`}n=cygZv~%z} z!Q;h(3O;cck910zdz#_*K)zgXoS zXhlAbWpa3wFPvqA(pZL{<^4GJrwb)v^h**c*1>POSUI-jlOsjPNvCe5t)nn}6TqFNG7z3kAv3N6F~d~<#+Cy~K0{&lD0KVI4)i98m+?v({p zCl?|DIwWNc(C`kbDJX8QJlwU_H9QQFny2)LS&di=!+WRB+LyJdNg2~;4McSNm_iH+ z({;n~b7DYJWj0)xUC}dqY4`fPUdEJhZ1pO26o>QjW9-tgQNBK*Q(|MMUHPlDF5C}E zgz49nBGE=(k0pC~C&N+CI?0Y`GIQ8muy}WFB$J5C;)@evq&u#z`v|~Y{@X&o$uvpN zGLsn>N`yB|J*V6ct9WhHI&d>h&|E0X<=(lMc%~NTDKiX=M@o;{8tjy+cEBvlkxEZ5 z=Zn)}4?CY}z_vSpum9IBog`ko3^iMEMK0?+gqP)3b6n52h4wEz;rc<~Q*^qV+zGXh zhc^XfC=9$6p~(eQS9#~G(D#7eWg#K9_tmZdpcoF>Xa^d3E+@|`V_|BIJjaqf?ZOlD z$2{0ZR@pAW{F{ZdL1sGmoH140^5QMW|6013=y#jr1Z;=meJ=G#ws7z!h7G6P^odCs zr<>dPr5TVq%0wrdS4yC+uGNK+F`>!}TxQo1FB;zp?V9lGgrqvLA~)Z0sEzt|Ae z%;%fMIEHn1-w&$c`@BfZiJmiqD6`Sm#5A9eDV5LcK&UiPpOih9@L+p5f7daCeH>x< z9zLb;6Fd;TQj`rUF&7bZNB$CtLcZ2z=^9lox>cyFQ{}3Yzj~?d58Ckgpw0nD;cx^? zv6i@x#x(<4nvMc}b{svD2(Ma7@JzR|j3r1VuPiJe*s4dsU{L@bkeD^BQC_mU$T*4QTPG zbz|#iQvWqz!}@I}h>IzWfTJ+F@(=SZGqJq&3wkvXPF(EazXzfVeqDuM3({`>pm{kh zT_XJ~w+~l3Y5U?qMcM0erWPjSGxmb1s4RKT~#OQZP~y(`aPqmE!Rv~D^9?)@>x;yTPzd0z0fJ5`Q21p1oaCof{xRX zSMy#itFh}Wa?c%3|JK4V9uvS-tIEp=U!gB$PDT9g27GH@(HC!_Wx;YFf!iNre9le(N;kB~&OdQ97w@mVafFHo`x?{4$hz z%)Kj9DFjhC+FEkEi>XG9EgwtieCoVYH)dTN_ie<0{w9t`eo9bfHb3G#`Nh~b6J`Az zo`ZWR#&xLu>Ac-G(B5N1^{(8r3*-x+;qVTw`-52O5*|A&B*+btlw-}@HQUtwFrY>D z)dqr|H{Qy7cEoGBj$Tes6GBV)?zlJ4`YM3$yD6k2^9P4p)q3QQTkt02%Dey8HBQfe z+baLQpD#_e{uOlmOWKECJoqtTU9tb)mwWv$EX$A+(X?i4kaS_uS_&FPv_dB%`s90- z0ODxEjVD0ycWy*-|FS5wm+nbPdmuEvG775hD2VKMYwHMfSNXAZo%`1=D0T6hN=hhs zYBzQRlsKxw#guJVoi~h#-y4hh5H3ccEl!xtRpj?~djf3ex50mDL5<&r&=1x1fPKIf z(i{LJo6?$l>F9R1Dm-?Jwfe>#zY602f1Zhiy>XQ>-1;o65n4ajtzW-D1^t;*^-YJ+ z*`eO2dawq1U`eS8VVPAKLma-9>Le(geg4xU7-k%iqRH*zoN7rWXotq^(3N+vO~9gX zngpi>(T>+m7}vbvv9fZ`kJHQ5To9Z-Kfss%>yroKD*eNb2K9+=+dN)>9O8?V;@o@E z+U@6V$?jIUaQ@_$O`lE|2pio@?`t{RR_e}DsW*mX4y0Q)5&ba}I-4%qqVqf6<_%MX z;uNRpCDY!{N&t=0Fokil?c^D0?K*Qv7>>rzHtawd!?i!R!B5AuCb;ERMzVg*N=-(P zpX<`Qae;){pbUAJf;t#TTy5i`%j^t4_O9Re^HnHz&h|PU@Im&APUD zmNm5>LTIC9aY14dW!`QF8HV4RTy#{dfZ9yTSf02-wTlAVH#L3ymGO2Hu0tSMrYElw z!$>={I(q5Na`B!=GX8d5Jaqr+FfsePhGg@RxyJr_SXtZI%`XgBmv%r_#y(5gI{_HA z=-&e2imuK*?IpT_QSj8Rxx2$Lei?i`3o+b5Kk6Qse#s0uM@Udp+ozs<1Z3)rNS4^p zx`D=ak;ny^{e4g~)~j71^!Q-)O)oRXHy^ik``c>?p*C|S@gFRMgPX^V6|d)GjJTAR zG0_47&oyIww>{45a7K2Etyvpn#Mb-732~hrDx4DAgFNx&e(bz*@SW`+<@IVaAgxAT znfqk`JbBDT_DVQ0E_O~6U8=%Fy~mf#xrAq8wFnY?t#09hQb90S;qArcr<60C`~B_w zkLl{FA={ZrV!5bq@~XZTKCMob5B4D2kJW~5{kSk&oxeGRY{73ku=z>skQ3WU0IfDR zF6-bGgi6f%@?}JHue>tGi;K}&`_-POqvF&R8bl0)3m3?;g~cL~dQGV01X*EeT=Ek3BkQ)4>auD?}1u|i{ZjVJ1Ie?iZA6f?>|sKl}$`mSG$tUcduSq#}->H z#w*BrC^m?iaq`P`iMsX>OY{_+LYzqp^E(9gj>odJ#wMoXiinQc)oi*{(ffLz##az- zRG%y)UsUWMH{0Kdbm>JG)LuU~mbyHVfjSN_+xN!ttMX za&D4(#BHBoe?<*BG(1$gE8Qp;QMzo}pZQYE@by@!E02VpkMDUNT~M|#mnLF=OY(3D ze)VFv?&c@@wGL7cMPU&5XUn8VntLkzkjFcasay>Ch7VtT{D*v==!}u!&IxPrhaiOH ztREb2y&sB&W&#yt$#tPOZrmu}RANTf?86Vy!$}pA%?7Ii`oXx!g<@`l_ug3j^BOxs zUZ1=GB;VwA-K|<+<)mkfha7V59paA)xv{!zAFVqO(K&$1ULc?4F_K?y)wb+ zWYSSc;~5L^u^+!bCRr7B1OUQ@o350b_a%HIZ`VnvqaB3Y*~E4f_r!6Bfg55A-S^l$ zJ!t+H5j*MPy7XzbC|~sOkW7iLjZ~?0Q9p5J=t9Q(UFR~J^ppt>a4bK*Ivxx zokEh4+TxAW@Q@pR%e}y_X4~=5jm5N$f2R2~MZr~V*jTIvOFeSH^z@qWT*MmdW+cW zLFOKICK))UzbAXADztvn*Oq*#u=P<^0dbLUEOubi*YSm#Eg{k`fw=((DJCF51ya_f#xB2 z0??pqYQjdteU8CXyo?fX<9@H{&smkdWv7v&BR^7P6F?A3&iKp7*I(wgftAn+L9P~pUI9)&1>J`eOsOEK6CO1h3Q+Q z#b^jQ*VKM8YS0&ERJ*DvB`qqYYTQn;EtFY)pLNqYiGE9))H=K8;ACwh4nb~78evpo zl7kZlPtMPP|H=^=NaD{YxVM&^DC#5SIr3B5nD)iN4$Eqz&IH=kp<&2J`tM_TB2*RiFyw|u zBV3{2bk1jG>(Ud$ zaE8Sw6s`eb*Cj(J0S!ez^2a}uUOL*@B!ms$f7tilbkVm0TD|Z-hxyV4Rw@HKz4pEE zIz<)RSLpkMe3G#=d2LZGpjr>7#1o~S=$>-DA!wpWJ*w;Mny_+vE7Ot{#PkH^Vn+pw z`%Xs_tPEg%$QmD(y+fG_EM+0UGz$UD1`u6bzh_N{TSP?;{}QY1(~3%4_(@mry3w;3 znReb?`%BufXri;hp%2fVuhB}v8VoZkEGcG)h)Vl znA1=q)y2Z^SJ%ZKX!5{htCeet)ZL8mg7&d?MVBZnbNc7kxuq<80EIjhWZpm)t~e=7 zP*jnrjjG($g~p$)XDSsp`TXGoBhS)nBAZa86Ui-5dgU7YZm#2jzS@Oe#FC2beq=D2 zRi+lXv^$?k(-uOzm@bx;H#P0yW%dY2Nu#CfmFv|V{JvyPPRl_>p{Fg>(rC{k)s+Wb zqH%_UEgmY~y|h3jrIwxlx&$Su%j`?=Vg++VZA~el7I|~+H zE6E-jGrPum|*Skcdxj;|zqG&bB?Tbr!F0->I%@HK+HQNz}jx91UL$9t> zTDbVJNJw}?Pz3Jv>}es~@fY-fO!VsIca^CN>9D3+{_x<6<)w6(0%M7<&#Wc}_XAU# zdlOMvXpo42y!~$-(i`rNAA#QmoHhaT~4n+TsEjXbHe*n z1JrC6%7^E?O-$ZbW!ya{aE)Wq-1~H6*Nl84m7hv&lkOe)S>T;dL^GNT;7K+a%4vQL zL5#P{*1D;<>mjjGWDF0iMe)+$bRPLvj>{pH?xlU9QRR=99J+WJEjJOV^^SK}m8`~U zA_t!IS#8^7lZR_~TQsI-%rt|gcDo80=NFN?l1nGv;JkJzW)YH3Q zsHkDbuJT>NQ!8WlRLt#YVu(ZHz$#kGrmfgZy^Qe58(l%+K+|ZOr;v0E>b{Ne%gBU7 z`R-?W2HYcvX|*UNSPFhVDsdl6kaH6r0#fJs$4wSqF0QCgxvxwG#+Q$^u0|-=Pr2QOV)b9{T$8OGiAqDz zSE-eVMV9@3+UAI~K7n-KT66b4l{cPmR19xUjW%98fb)YIP^0S@WThKAdqeZ_Y6;Kh z>y}Sn5frD(>>_vvSO?N(gSbDJ_64uaWF+O0o!l{?9?@H#(^F7bOUr`$kE)p}2J<9^ zY||A?FR!NqL$#~iM8gYuN7U8;QBKj6dEsg4DO=~-Anw^S zGnmC`fx@9QYCV zg6_PT$(U<8!OM;d!^~!NW-yd_d@Tt9k4ZpTEtYlKv7jXadUHXt_0*Xb#6DL?0<9Wl z!o4yJ$0m;4j4!vUvv8@p!~yx!?&AhI`rszlMQP+LyGU>Ribaz{?ROa#yRljvN51FzBn^ zSG>}`^d_UW(#1WchSpmy@UVV`IPLp=CL==tQ;GSGSF9nL5Zp`gzH35-%N|)?w~^%e z1~Pf>HnJ3%e0HYgacR}ai;R~S>OkSu_kA1YAGZt08LH3a zueR6avJJbvH`of$BWE}Perkj#3vM{>i?G?nSd*$I9l2-QZH5m-E_SKo8S! zZ(F5r;9Sjv*yUR~)Rw+*yk{0YH)AIajU6fN$<2uVLf!f=1Gg2f4vd;DyOvL%yftOs zP|f!p`blP>!Mv-S|6_-ZCU8Nfew#m_Xoh{459li@Eb`pPubn+E)K-aKlXBo(F~XK> z1OI68^537=sir(tS(znpfgGmWlcT9A%O^PclF?Vs4=bMqoDwf>IfM8#NbU1&J0VuL zb^t%-!*7dI1R5v|lDhEe7F_pmi>a}s(ASK7w~pmY50zZ@g#;wvM>f4U{d?C;1BJit z+#;qJhr9^6x|1C%`|V|g@nx__>$qO2$qq&R7Oz@}^_Tk(c5h)j>3=;B-UL1x)1Sf5 zu6zX{=ij5rwDn*A!%)V-|MX(rgdt&>oQ&S+I1N|@GZg(N&=|k`%$^ZP3*_fZ$ z+NpTbKJdlIfB#~oNuI=G!L02%a$D9^{^rniOPB#{ew!^~0*{e-|5~#xkdTh7I>?_( z@_*7luct7*3W6saDj=;KB3~b^(?U=;XdytEy)__(fLx(h1HXT%!Q3c!bI5ABU|jbP z70=17UXzV!tZ4|O^FF}qv619koH9qAi3gDdAF0iI*|y;ap4FekofD&lIDxN zaBg$I{6jJR-!MOr&W5zD5bI>E%!n{V_u5fz(ZieA2V&>%4g&~vFopy2-HvE{o-msE zCd;^kghHS}G5?|({78iCj; zo8|$O(;tGE2^?LY{MA$7J#5}S_2mH+(M+~wX>G#c_>`GtVE5LKCj;9aFAmgfk~`a@ zk>x$&kSlm%<42&@oBi>1jF}@2mDkzdePWOq(RGkhEZ%J0ZHF8KtO%LA1#H;_j1n^q z$4A1MTR;8;ZF6ZR*7v-rokjdJFUdcTfb~7PT~~&0bErP(;DB7fhBPcs_d*0xKKFwG+x?c1PKkPLf(Tm)4$g0g7o@#thWZRC0WSj-}7eU^zbcy zKES98;JA7sRD~_gK2B_$C^qIr&_6ItwD4D~Z?~fos4!-aBJy9Opk`ean`F35E`<{B zV%~hr5$1debLijL$_;M=@&dG0?-Y@60tLczzWso-qGPo&2swJ6%1g}NG)s=M-Izow z2)cj^_Wq*IJrU0Y03dopmEH4KQrWjfY?Mt3@qFB7?zRf(U)}iy#BWBLK=~5;3_5O@ z&X7M)U{IrS3Z1`M9(`!tA3V&5R~OOC<2??m!{|}~%>sZ`=UZ14(hZgZmwbACR-CCC z{Ohz69+`&+g9@;*QufBG86Zh6h>Uo^&B^UxnCmw;mt-!O&XDIi#?$8Qccn3BGWEJ@ zKK^W>-1?z#YiHM@{yG=|mBV5>h^$T@kZ``Fvv0L&7!IdlR zWqa_O-b#S0rb(#;SHDVm2SUysabKjDKQ zpy8T(p|a5oxICc4^qp94JKUrCj6qkMbJVg|Uq8^lZI_Qnz+Ost$G!*fJD(jY4kiGO ziSD)OmEze%xACt5bgiqho$f0I+h|B;IA4{y16p;y^zp3>TRi3dE7s2^vY0`KB)S|Y zB*+&FqUi*0_**yYtX8c$q2N*HRepCqr+T`(Kk~#YPZbQ$Hc=@fG@3_mw!^1KLasy+ z)1+3>cFO$s>TH}_P~vtkvt6kfoZBE701Unct6X(k>F->w><(fd`l4H72G=5mxdQei zsLXrX;82tn^@7jOMC)F}yMKAfgXG69+!OEfv46$-me?_3tdnILu_u&ko4_J2P{_Of zsuqUF0xL|*55xJ@H$~xE3C9EJv-a3L_4tJB&+DSj6ja&oj)hpugWHx_$HrEsnynq| zzrD8K)Z7O-u}z@bao?Kx^zOp&hQ`=q@tdDVtIK&yi|CG#kFQ1;s-cJgdfAZRzkD(s zuY#?+=o5K9T{|-(KQi;HWa)|h>q{TYqqZ(C2Eo!tKs(rACK)TSgZ^Ge&{M3R>OiKd z6#OB0zY|J)Kk)JfcsF9H#>HKjw~1rd@gJgsBXiHckwrO0R|Qb&e>__|IOG`L8Sd8) zj%iNk#@IQ**h@~ckxHn~RG$rbt1euEp?B2zoEdSz6s&z~Zt%azedCY2uSImRLe7Hd zYvFqLb!4_m7*GLkL*%-S$!Xkp(=PU#MAzTM_g|PNcV-VB^|ud~DXv;B+mF0)ei-$n z{+iwAm{%=garqcP0|n_zpEJL_8* zsI)q2fSqvkRbE%2Vei(>WXNl9TSUBrQ-H$h84NYEIQddS<;z^NHS9wqwaZE82>sVV zDX$?59&I-0&(onaZC!L>E25^=t{--s2j*V&WQ=t{#psT5 zT5BJA!;4ktXYU@m7&!lRvxNC?{Qfy(q71UiQX~Yv#v`Lrn{b&G5y=rM15>A`3E5Z< z^=I+HojwR!ajD1~F6Gjt9zl7WOYL&~&Xb0JTKa7efc;9AgM)c-Sx$%~WlK}G{Oira&QzoI%EEPxvBWUJvGNj7xJ zS>>byPk3O7yU=gqQK5@#nEaFZ=-$Xd&?)Kq>be zuf6S|9E@oM;3HvGc1HL@u4^)@?X+AFZP=mnR?f4Ya@_ll#N#YOX`uV5z}OR^zG4@& zn5@QHSuHa@9X0UDG;cYpG$5+{asN!i=@D`7yX?m$!Q-TJ?8o1-AOA2Rg08;pAL|_C zqsOg-XQEUM6dycdaI(4G-riv=zx*Hw3=&!T$g?JriUzc)lT^<};hm$A#8=U+b!1)K>2i%7t%}#fA z^;y?Cdc5s_qQ`?_{rTMhXlEE3ojw4T|LZk1F@3wkZ@~B?0LSBRfbk$e1Lng6<}=fL zy8vK4Qqlx>(OecUv(AmZA-P>Q&rIEC$lLqQYch#1*t|vl z7q7lxeuJAm;33Vgd)ktg78I@d%)fn9Ey#QR5A>BjVkj^n*;I5?_SSeBvSHxu{s$QN zI{$xwf&XiQ*R{(5{!pv->R~HRv8tvV;ht}>UrKz1Z!QPrH+YEX_%{3aV`487>-glm z-_)Y>+MpsGn{Ok!w9Qs*RaZM^SG45~tQ(8v-=t5*`6pYI*yb(kxVv5)9R3rqeVlFM1x^wPMnMeE>~!t!FkY==PJu-(X? zNo*kc*}48QDr)SfFymaOyu;knH0fT0z3PwSIt-#)Hb1PvSKbCpse;e*2z54&5HpKZ zg+!y24jEs7tniDS*UliwOOu9UbL0)@QX8Yn%Y-c-9q|e}Y*FT5pD1BV2dt#obNwQq zt`czJLcz6a7twI8VN=*M+g#WBkLZ&CaXY|`yZBOBZ`}2`f5_`}b<^5A<_3wqiGi!q zZrbV{#|NhNaPIWe$x>D-G^}mxsPj(q0wCKKJ}=s@-Omfi5=I+eb4@>%Za5ICDI~2A zpvAoh^!#fon*D#?RlOE)Nd4|JduLY9Tlp3l^MY*+j>bP|D}))q~l?w!qPfsZ)mUaE>5j_`4t&R6^3vOP^~j#*9I*R5;%1MMChG?6AI z=)g+~YS$rCuK|8YmLZ=ksp$|k`>ZCL({p{qv5z>f0Aamjj4aP}Zf4v2@iO7rLZ)LB ztn4ZO)XEtE5hjM<)*Yvy7Urgs#1OqGCs0z~5DN*FB zGGA55*7QCSyY@4eQuI7V<9XwfKvg5_6<~S)^XzQw&d_5CZWFmI^~IF&N8>Va0H`!m zxJKzuTyMQi8mv`(+Cc<792yWG2IJDjEcdw88g>Z8=@8)5uANeN>T;4O!2W~*gzqw6 z?jw_qsj@Y~U}{;DUCLqLTN}psMo8j&7<{f^uxB?w;MOY)Ij3>%jQd{o>wDG5nRzS19=jHwtbes0jDI`Ylqjf?tHtNKo6R`*A6umheX5~ zgYE;9`q+%8F}kVP(%N34mW7Q`;xNT?Vm27j^&0E3wNh`j=F^UG+Z#r|&pISz44lDY z*IOEdagBWXWnr#E*CAPt)22-$2Jn?%KHc9Of@f&9e`@jCrCSxYck!&`ZYhI&e94zG z0~iO&Q7f*vsRd!1I2KaIplvcVrW^_QGjIvH6drrSEl7E1x_zcj;B*1DQCa=EPUc~a zv>9Lih{og7t)+`@Xsssm!-u)-FvXP3m^AKUEO}0n^Mn!*t=L~Do3^>3kVv-&>lD5l;azF6X^_HFyX$xIGi7^eW!PZp z;M=QU)`?!;naV0cH=d^-9bD@g=b0wI9_>#s{SuRySv$MUaz@n16^N&T{WB9KYRiL#*J;@|NjJYf5_Oop4^K8 z6@i_tQ@hv;`)4pb@qcz{94rtA^)^u+Mw{!*@?N;n6i~EDL}wJ zDSv6IdbKNjs+K-M!_Zj7&QKsa{>MR_Qs)K1)?K{z)%1HcD**f!l2`Y8H~#)^P2*M& zwqneD1XxdnE-@tZwK*pUq5mHiI5WFv{YkbV{>Y{F2hJtr_@{q*>cVy0FeZYXs84wOH8{Xns?yUjG?UYC!=*3aB}uHw5E%|C7;kTK;M;d7>v zTs$Ke|2gKEO(ValpG^>Y5xR9qB;*0dE(b>0eN@5b%rC@P_}Sd*OO5@;QoNv>iW9QJ z)@@^;zfL65FcqG(xLGTA-(AAm$PoYOlCE;Iwd(Ah8NTk>f^qX&Yx}$+R<}vr4KH7U z7UUg3X_+OiQ42PK+zXUg$(+wYL(HsC$q)sC;uZb4ix@bV|ntC#gTz)}G zIwkR9C-C%u)p)8B?1Ncqf9ajH@5}0^ScTVY&@$)m2@~TV956ud6fU~;rRDSZbsc{D zF2nfE`{Gx_bO9;Z>?jO>nE z#>)l`Pw_jjwAT+0kFIc)_e#NM>_mLJg{e_*)aDmaD7r0joJ}Pl(vxHwR0H5~rB;XB z8hk=ZgPu2fu6CBL^6n-m+0-p9hleRo+M%-pWje|pH|JwVOc1H)J%HoM!(?n}x%mLW zE4DFUY0jca${+)+?w~y;_>Hkp>7>^3%t|G%i~k3eT!e=w7mJp{f?*cPEwo!CIQit3 zkX4|R6^IvqiC=PcDA1Bs8(X+`!_F`v*|6!G(T&_;g|<^FuEnl8Szgo!FH4JDU!rhd_!VPN&?!24)2l?V;N>J=rn&5A19Vs#kQtFroj3Z<;Hl~ zdu-QTpq@>Xto%7y*MPfwmuBDhIvX}rxHwC^S9)jV*R@At{=K@k*wt?_jUDgrM3Zu5 zD9{YlTt}d4&bYs{DE92AzuKJFg9;6zh;SahEWUW3d^dU4g6tXdqr!kFnr=mC9Gg3n zfd!cL>C1wR3@3*RL?giw>N#1hVdaNG(ZgN{`=GhE%Qj!ul5&FDOQr0zN6UQEu+6Pj z=+nX+kWpD)UF_J`mYM-+BkXjUc|{?wqde~7WpQCwD|@w1NwQp?M`j|ACm0z%HPl)3 zl!>N(V+>)IWiTrSnHLU0ce-i?+a7@$*==8VIPt7p_QoJ*M55K8vi*$L*!6nx71Lps zp~GNQcCpAs(yZ1U-h@X??{%r;?aL01rjM(0*iME{2^4IOURkLUPyj&8uaz&!tR}}0 zJpvq&!HQdj>=u?`=*xP5iCQ@W?QRaQU}8PH(Qbz`lwO!g0nmg`NXvao`*@ z`d&BHwiJK9eB+?(3C{;JU#$pB5958Fc$s#*^UOMJK%Q$HFu>TS#d@ffcn>_wo!2J~ zyI4wocOo6gcvaTZ)px8*7^YCvBK}9XIQ`+2qcQxeg54!wWZ9dA^s%Ktn=$1e!zH_} zm}B92>RthFRs3r$)|Kpzv~GYDpOhbks%>8~R!8Qn>MJa+M$aF%>bbDD(}VI8#XMn* zNf`S~{$2zFlRTMTS&Kcm;YCi2wbN(7NGr~W88&-F@ev9r8PAAd{s&5H)aGuXQl zMeH`m={9GO4GkG9$jO!_=yq3$o80_IrUXx2r&;E~`pQ@HyySm?+2j$Xwf3W-o-2Il<7MCR$QZw0i{-v*kWtzs zZDnH8T-HpxW0ECz(Zl7r*LAwKy7_n|^;R5Zb_yi|D771P^vJOk^pVnB6D&PTAyR}|0Fv@p%z(fokJcWe{nv>X$N5F@)S z3tN)=BHKJ4Ji|wR;omd9K!M%@yj<7RjvbCHg)PqeS`*-B49{%i(H(SWoTU1TU+fzb zttHxNWy=sU-l&1^x<_18)1G#npbNuV<@^s z`WJdYeee5PC;+nFhE75owU=}%RYc|=U)dJY60nGrxM1Ur;b>^0`U}s(^@t|+mI&K1 z|Ds93VubDQOQCsem-?)|kSSbPIKhF502e}z!{g3#uXm=DGpi^~4D@}|n!FC_t1ka; z`xwJ8wflvomk3|mDhz}V#X6Cov7-+URX8*;{pV`6)ebrz!t~}DViR5uk5$&+<@Evu$ZWh9dQRZj4Fm7=j*zg4_;S;_U%A%Gol`CZa?JeR?r9>kfImAZNH0nCH|`oKexMIN#M22o5_i7mWx&Tgjc1@ zm3N%4XkU@rM~PbUEvyVqEU%G#WAef{85d7gu6Zsa-!+@G`eO3aJ9;k<`p&3anh{AG4$!O{b^{HNNK2z1}~BFc;24=OI+nP!;(E zs=&L^0MzlCT1d#j7mnF)o+a#MEf1MjNjNEgI+OP149W;ARiw|q-v(>%jPX0@5|37f zp}i1Fi)-fru4wnMAmpo1+P+G|cL2k5Z-pHwu2(M&bcx!W1{6@ zLBDSj_ijmXP1zz3y**C_@P_$VQO89yLb_COAYn*$JXO?D^qVw^{i2W?-_487Yi8rz_+| zE7F*A9)8w^>SO)XA<-{=xvCJ6@|~3Dg7+-UV`?S!l7QmiE7-9y!>1FDN?vmTVG*BSu#_aKYu{uGQvJj~a=Y7a4mrqfj{DP*EeR!= z11_pU*m6JbTrt1H@+Ck}wq2Lic3Q)eUsv+&7uZnMYo3-pZ8Nig6?sa?{bq~uCd(Mc zUdZ?De;f0M_BQGNAZ@sIvqk0?GczEn0Jj)ZcSQ=MZ`+`-+-ePw+__pDsU)?1<;_XF}aa7%T zzRz*Wi`t%YNH#k&W9O|~>dfo6kC@gJ66YjJ$^Jr+KW+dwF9k52W}xi{c0mTW(JnOqsKn(2z=vR8z_FL8Of_+;NCtcN<`e$VFgR+&TvL!QDG0=< zCFoIQ+RA;aFkR&gn?hzj2=*$r#FoNZYy(N7KPPFT>Ujn@(;1ft3oZrVE;DfiCurBL zqSN_{DG8x-GcApSpuPAqmuB3mAUM7Gld@f-AH-NrG5OIgr#@kng#17vv28sWStxv_ zsV-tAI_X+^fa83|+CN*x8=zMo2^00J5w)0l5vu`RT1O0(^IaY!NpZU!e(9A^ zPI)m&)5DqFZ%8z280Og@w?N4>x49+!e0SWPXUJm*KnI=;sNK-TiK)Gu^Cq^|ZPF)z zRhMNsMQg>GvuPGOSMK|_#=RNAY=JnxoxSKc5qrM$j#pO4C;lL>*q4x_6n8sGr?%Pg zdS_L%(HXu+o4K?~)1)|$N%a(E5p5iVg=TwJ)%aq49rkzo+JP!41LC8EY_Ixhy}Cf3 zn7SjPV!w{nPzoDF#gafVm^<(Tl(&hEsPF&YBbMI=g@QbB&!ypNX+ZEI^~Ly=G4IkU zYpF+m@$`l9!$V5ZXzGV`VsMs?v?$uYTp#~V-Oh;7Y~Cf)!mtfy>RR6_vzsH{uDOPx zpe!C8McAP_sf^`9${-feQ4=6RHQ9b5z;#t;X0=W&`*UwOnLaakSoc%UFGy+SK z@EV22jXFwk$quTpumI!+E`2=sO)g^5pp?5Mg?i|eQxDfJR+uR0xC9tiiY`LiUwLAZ zXM2KO!XNB#2~R{jzIHp7&pZ=6dvi24Co=Sv3OD^^8_R-D5x*(N#C&r27 z`DV5z^obcwjDGfcp$p*d5mXkVx0n;s#ISWo(PqRbznP_KUwv-fzqq%b=DNsEnpr*+ z+t!X;%wz5Q#LhJ?j903$dG>buKL$(@*npw5@lj$QE;fhj0G=rRS+0d#EoD!)6PkPH z+6mY?zVxaX-~)MNHh8%K{WkPy$9Y|l)`Jt6)pI$1J|d68bGw!*4g6OgcDC)FpXf0# zvpQ4TX|?T=@an_xfENk5*Epn`TpgdbPM%mUxVFuC@1mfx0;M0LN&*PasO_k zzFf13<{<8S-^sRJXLoso>^sx*sUMHAQ_~~F&zlVBr>K$o8k-PgL|2So_knm#kx4C* z%A(ry&3owq_JZiEy5y?W<*Q1|9wi`l{T`GT@$kjiE_0^f(u@C}_Rc&I>h1skQ{5=l zSW-!bM2SjVl#HdK?AsthD0La`#9)kV5ET-GY!R~WTUXXWU0WsVq$y)5gfTG~8teF- z8E&`x@At3YAD{V)IcLuHe!tIoo!9%k9#75#NJ5VDso<{wYl%(O*Q_g*pnKwnyT_H1hLFB;@u5S&mx=5oXGwW^w}II;&Jh}l9RK(g}vu0 zdKS2p_PSq4hm9MHL2b(0p$s}@~x=nw8F!D9VXnv zgShC2%QeDvcg}aD*_=`i+ZLKC>n6t`p5gs>2L z6_wXMll5k2fNgdf9AUCZKSWhCE_#(MET8rB@!Q;4;XpG2N9S+ls~44)H_hCsFaz&> z<)zLv@^e%aiwzH->^#JnGexhL>yT;in>yb{4`VK*qHWih@lqT&K34keJkO<b9(6v-!yFF8h5^Grpis%Vrn0aj)a%YI^~!wgS{k$uqYL`88r^@?0fqowbf7 zwPBHY71Ef8gJ1ENE?P7n?_X%bAP!Cix# zX(us+;{#2ZTL=17`f7U+mJK<0EJb6e)9ZUZx4N*&`|x3EOWnJutgL^IPD#**v2rx^KC~7Z*3p0>({Y?iGU~Zs}&4+CH22z{_kU>eYPui#1H!w zmhW+T$h5v+db%;P2>_#B^&QUa*Z~m=W4%Ny${7?Br`&lTHO4mC5mGLzZ9uL%l$1R$ zpX~!=cE(K{R7*zp05VeFgK5FypE+t*Q zm$ZUvX1k<-TVm_JQMnvr)5@j&L2?7|sH|Y_#cic#-V*~bcf(}!e7RCgHL(==A>Z6P zRhs|4qyGaDrVVx8jlSrV_@jv$+NY3+%$z1ES!b^wEH)gaql~`Y)b~3p-`SRjgaN^s z`{LD3%)>jkw$ALa>J5jts}o^7T*9|Ft+5VE273ovcwj_X#*3tx-zhreg4v7h2uY*v z8;7_Kxe1oqpOc3jX*{$tg@g0Qc%-ir7nYezcVk6|_So%Rx$u3(9SRXR%-Z8_7OtDt z`GaR|0PmNAgOA&E@`#|Hs%wp`GX_uk+dkZ-o#d6W%;br&lU{K5n(Dd$u{+AzoNsRb zB9)e>)>bnQt|SdB@W9Da{HyjSRtkcWm?AfO44f)yyR7E6?9;X2cb*Q?bZVN>V(q{ooZ1 z%6`ZU%35@)@?JW6)~iv%Cih1!)hEzoazcM6Byk&SOZ``pCq61`B(g+l0(C1_#nTV= zM>E`zU)Zr$d9N|2CDGH{HJ_AVSa`?DD_`DlNRpw5%1y{e1RB?xWKs-b-lShOkr9PD z%=gYJclW5qSGJJJ{E)C*WdFes6K}~^Cm+B^WLiWM3l>tB9W>+cj2p*8{7V8wmnL|C zQ}E~5Yq!7#1>9n*G!~lD5oJf-m9tvaScshZhbz= zug;D7D>%3WYXQ_&a8?5DV6OEU@y(&t59BN>cV^pXd(Wfpu6{;;lK(ij^VmkwcE}%r zKOd*hVcXQ1(Om8hge)X(%GB8#dcw~wEMqUQYT9QrnLd+<{E z-UpoCuHEOw(Gmnx{S+sZrd6n`mZZ$Al5PbIMV5OA9OT18KM)bTF^XTh*Fqdug{)f` zAaKb2b(i3;^RHW&Qq$CIt-26=2%MV0WG!0W(`9(Eh)K^V<;g8VJBPJ zs{}KmI1@%&h^^~y^?74LN&Bnnrq}r+Ot#sNI_!h|asTH~AjhJ_JpEVii|fM}IR==$ zT2S0tX2gzY0r{m1N3(fee{GHxsha!I4F7$>GVX|+xG_)ma;>mSDR8^`tLe7S%4y4s z$edd*%7;MYSVXH$_lUfbf;gIor->6lmygd!H8<6He$pj8CYa3N-ik<184!XFppqj# z*Dxx_s2G&mwFQ4jy0#(=CLCoYY z_iTnixzec5!_WrvPtRGlM=0n8m*#?H`>fmIv;Elj_L>7&`MioqL<_V!1bJ9GWcP|- zFbCbMD;G#e1L{tkI9Zh<4 zq@U0P!<;_$`r+`Nj!_hL$uwz5G%R;+uFt&wu8&$^`mzK6e{SY0qW9o0r7+L?(!1dE zsX5KC6|HuRVtViI2Wlr*KSkq3wM~FVSpCdoVTG_h@q;L7Rsfo(vwE_@`7%{8K0f^$ z{FTv#qR`hSS<{S#euD@6&}5()GVOe-v}qMK%z4I&d@$j#~;>R_@E#!6yo^pJsr=wdrC#flAjZYT*=r5gVmJ&PVySKRN4%Qkmpw zG~A?wv2D8e??xvxZVEE&Z+-&N)7KGNd{yP@79$KUHv4OHLWuF;y5c|TvKB#GE}^ZI z(CRVNk3<*0(IX1LA^?&YKyw{!W%V~-qwOyRj~BV0oG-!FQ)}6jvLORoT2}4qkE+IX z;>~`uo#HRXqMG}7;+Ir*u+d@cCd)`jJUCYV5y) z&y`y!(WB9oaQS%4#X%W=+Gf1G-Bn<>=;dQi#!NjhEe3rDf&njDqs04CDxCc{e$A6D z%dfpS$gQ?ETQvxXXZcntAeMP}tz&pi?&jx0sMhT}qHkf-T~?`nUtc0gYr@;v;5D{Y zoES87)Yyt%ir5E4&-yJd-WpyQn;4Q|_^kS>uKp>?k8W{o{s#t-$P3m{lWxsFKYU#4 zv#Pp_%kwYMlKrlj)39jOxVUlstS!LC-s@zxg3U~?@gZ<&Z*^Ah$HG6C?n^Q|=$aQy0qU)@O&-E8~0l_@j1 z>Es+=+eNNdF^_x3w?QH`z@+}?oVU2d#(^UML?$pgu<*^)a=bSvX2JyX`R-*tyP8%& za)4-N7<0%}N`3GG;dz*PexC(NKx|^=eqhR_109T(J%3;P)k?(AGW7tUg2kcBN6hxT z+@*Eyfjd!!l>=m8UjYH)CiF_EQy*vmgOH?uwjO$b0E56Wip4-kxhC_C$a3!D?|=bA z?q&>Rg}hLG@~#WkW3DnQ@AfImByTp`)W+fT86sE}7HX9v;>ioV!aEQ7&lc!VkzBGB z1B%57zIs|2%OfucgX4EvZ{~O_7!W^=<`e#eG|_2WM)KqQ+8twGLqwRB2#8xAXlr3t z4G4r5ayv;d(j2;{J!W^*CqQZ+QL$?RLtTU;o<2mXSe7(F4NGtKM@~kY3g<350x^K- zzq#}$(5cs&lnKsS84jhBg^ahWuqxvw1wC>cUDjCUmd(S4?EN_Zc|1Aptfw zv;VC6*DGURSrkgCyWvYEd?I3~G@FT4X{g(XCpbSTBfakb&zgN2NR0us8hzzivJmv- zF2^S!;;Cn8OXv5I$`E;9DE3|>MxxxOnz4z^-&XHND;x0+AI?~;K*FKST@mqjZ0_!L zRvt{Z-)(2HQg5=LU1_=EOrHlRmqB{g{j#0_fR&JexKcSdZ2GO9RSlm11c zJuGfmVWdt;r~RM{mK4?8-hq7fPUvGZ+;z=3c}-dnGWsq+Z5zZq6c{WPK5SUZ%Z7;) zgZFsVk}}|`^JU`P+H2@!H!wSG0RVZ4} zi{aBRl$xsq=f8DCLv}>@t&YmhYNF=hj*!QOjlNQwi?x9I1S?qf`IiswCJ9l^m#&f~ zTpasLM77tbve~b$P#-tpG&O|_P7=CZ%}7xiaWoU+{FT>H8+`bNct_QaVUGl^K;jbi z(54O2+6|y2zll3`PYh&5*3DFQr|_)UybgjhxlWzt*5*en9TqB=*Gs=Ftm9}6O7nAg zSgB6VLJ?(3%;do)l1(u1h+aD}|vmLn;`$OavWevV% zh^bTAG1nE7?st3J)Ca=MFIa?%-uDu8&jTdWn?ddA_oX=Y``qB#y=Hu{BjFS(IVcps zM87oyc2TsHE(Rb(N)IB&Kq&Z~F!%paT%~~8$6U+9{+!u)ax7@5jpa-?mgI7Jc zBL=K+H}1NCdB$-x?MXSsUSaOSQK<)FT)LG!QGgti?NAI!j3kR}T~Gv=Faa&$t=g$y zmdb}7>$}(7cd(I~Ti=2?(~o{WfZp|C z7zEOGANucaenzA!a{M;|%$S#d;o5921T5f!2Qf5FML_yydmuWO-Wp;gQ0pq|Nd}*yBLytCHIT>U_UDYaWjCw~- zrwvCJXuxjZ9=8%(eNMztUMiJDS5DaHE7!+oehUKxOy<&k_-7U{^Y4_~xDOJ!bAkyj zhGCHpDtp>=vPYvu=|_{1Hr)ddCV+&yX+`{>J` zD3~$EDd9c(zTe9oxwI>w++7THIyn2@c9rOBZ8NvtiMLw&OugL5z3e%uI6iOxd~woY z5tE;>RF_Xv!B-j*lPi13MaUIGm;3lAh**L^5+3*6bk%$hlfisizU#@<7{++ zZ>T(!+NZqiH@6-}RC)&3YXBzLg-}i%l5QuR>OZkQFhLw2=>lp>J!rZNDm065G9=6I_;Kg8RudJ91U8&7JE6HvG4Nc zp*~^w%mNSVq@Z14h@2nRB!UzD@N08INg;wr<=QO^zWeOBQ#5!Q%obe+F=SoJgG_9&fT&y1#(( zNkcVKp9o@S2*lSk7m__M=?LDXVILZXIuOt>BHNyDC>Yj7TAX;@uHs=`uckjgXPIg< zL93T9CeoV$j&WL3S(tU3m&siVNiP;VVdG*|^JHe@br;-mhA^=~y^(aS-Ho$*lwQ^h zqaboCP|v)M^dZk@mG2c#V&7e%?3p-Ef*Bo}mDBmcle2keN)3Z-onlu3lG) zN2l`PiRa#?Q_hr-uWHszNc>Wxzp>NYS);nwL3k{OuDS=rFXkkP1j7Y*n-??T;Q_5#{!&>kv zil>1FNSMfI_qi6}5-s>03{+8;eCblX@i&^`vo> zV+CHcOuMWceis*c-GE$z?`U2e-=^OQM(lk(;e<^t(%UDckPNv}d zo1tF&MNXL!)Gv+P;2yWnbt0!K-ry%CG^%Ca@f|h`NyVeJtgj)-!`|uB-}}9P zpdYv6`+w+De<*U(d`|07Bd~9pU8RJvINF_+2?Wh};79eJoPsu`A9)kfzYcMu(k?iL zsre>d10+peipuQoFAem~eYgpDS;wAAXA97W;f?Bm5%1cDF87>Y9-MxqTR8?9ImQx3 zDH{5P&}^k>DHBd(qL$&Pr>8`Q)EV1vk@nxS9#vhZ{-_*F`R;e4h7f#X zWDb43ylKcZ8h<07V2$-Mi)NT)uRj`5Mz0R=x=5h{4yi_hFevXyi{_)3YK6jkeHPsh z1ScpG7U&1t)edDW&(ATJoyiFT=a#D{XdwZq6)J+c^UT)KLjeiODGbp77ef7VZ8MoS z;Y@1V>dV{x+y_|0Z~Z&_kva%~zdA7Z&J#>qx49R$IE@a#pO>5DlFH@GEkl&jmNz=X zb1-e!iQaH|Wn06r4Mro%5*7ZD7vA50aJq_AT-tv%WWNs#>4SO#|66L>eJ_un-@Nze zxmNgI@y`9jJ9?PFNoJglaXOrBf1R%>zIx-rw5DHIg+XzhhhCjfc+R4eAUA2gqy6;y zKy2lu_An}mkYS(aJyPB4A3Gyn4)jcDRuln8GM%D9{pjUlKgLiCa9NYvkMBV&FR?oE z>Nr^It22|Z{Vgd2h!C1o-d_dN#tsKwt(^w+K9IrnN__Xt*_1umbqDw(9jz$=?@NPd z7Tqb^Amc1cxF%u-c>Nb#e>!LA-G^nH~}%(Cxq)I;8i;SxCtc3-bp)=C>tb z93Tv(>(=a#0{+O8r=RLx9GN)h2;cVp37P%WRo{mK7sO`0-J$>cn>GIbw{h519AK@W z7l9}H)wPrS=wwC}V!aLQIRQ=qsE)9Ze%`tTYAHJDZyNQ!ox=yRconaX1E=N3W87Dm zSEQ=YA>+(OD!Ta8^=y!1n`5 z-S1L3A&JTMm!to3NW=YjDY8DPDdImCt(mHORt2_gH^>qgJa7*ZSokB!v|c?L_-yJg zrN8M&KA)zKf!8;zjy*AK_1>)8W5nP$h~D(1(HMZx8@8}ne5~Kw*NAO{*i&JTCNt%r zS9(c@5QAs|1n{kaL`bfy!*)n(meH8GNehoUMv|Yk6}GB-cxG{%|asVvQ{>0DnMXSM9+P()kl{(kfjDVL*ZBByOtX7y{c#$=#U&O&UwdOcP4d6zP z3@pOoqE2MSh)d?AK=(Pe@b!F&KqRJ(U?P<2{r75PBy0vWR#Hr-FpZO z2Cz9}l{3z&HA?AcdxZdcL!kFHn{ow`6HkHesj~))xr0CtR}M&s_cOV02s*LZ$QOB*n2E` zLcR#>+E^_Dgud-|n;S(|1!eNA(l+s@tYlr*u diff --git a/media/signature-as-manifest.png b/media/signature-as-manifest.png index e8e1e72f310fb47170abb89143dad96165072677..8d1ce0138d115cb82bf7721ad86b8c57e2265a1e 100644 GIT binary patch literal 40394 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 Z`ISXCu-~~h`6plJ*K_Jj!T^$V*5NJ0R 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 PJA_fwx=^TcIp}`@XYN{y From 7902d29bedb229680a0b6cb355b9842c6f399dbe Mon Sep 17 00:00:00 2001 From: Steve Lasker Date: Mon, 24 Aug 2020 16:34:01 -0700 Subject: [PATCH 07/69] Fix extra curly bracket Signed-off-by: Steve Lasker --- docs/distribution/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/distribution/README.md b/docs/distribution/README.md index 3f5223343..81c040866 100644 --- a/docs/distribution/README.md +++ b/docs/distribution/README.md @@ -263,7 +263,6 @@ This model is a hybrid of the 1 & 2, but moves the persistance of the signature "digest": "sha256:222mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222m", "size": 7023, "config_mediaType": "application/vnd.cncf.notary.config.v2+jwt" - } } ] } From a1b85a7c2e75d81192d5d46c3343dadf74be10c4 Mon Sep 17 00:00:00 2001 From: Steve Lasker Date: Mon, 24 Aug 2020 16:38:17 -0700 Subject: [PATCH 08/69] Fix extra curly bracket Signed-off-by: Steve Lasker --- docs/distribution/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/distribution/README.md b/docs/distribution/README.md index 81c040866..1b59280dd 100644 --- a/docs/distribution/README.md +++ b/docs/distribution/README.md @@ -305,7 +305,6 @@ This model is a hybrid of the 1 & 2, but moves the persistance of the signature "digest": "sha256:333mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb333m", "size": 7023, "config_mediaType": "application/vnd.cncf.notary.config.v2+jwt" - } } ] } From cbd9bfa2002f15340409279f1d3023f886fa2eda Mon Sep 17 00:00:00 2001 From: Steve Lasker Date: Thu, 27 Aug 2020 13:32:23 -0700 Subject: [PATCH 09/69] Add examples of signing a multi-arch image Signed-off-by: Steve Lasker --- docs/distribution/README.md | 200 +++++++++++++++++- ...ture-as-index-signing-multi-arch-index.png | Bin 0 -> 144312 bytes media/signature-as-index.png | Bin 40096 -> 41901 bytes media/signature-as-manifest-via-index.png | Bin 72895 -> 67354 bytes 4 files changed, 193 insertions(+), 7 deletions(-) create mode 100644 media/signature-as-index-signing-multi-arch-index.png diff --git a/docs/distribution/README.md b/docs/distribution/README.md index 1b59280dd..d963e0109 100644 --- a/docs/distribution/README.md +++ b/docs/distribution/README.md @@ -48,11 +48,12 @@ It's presumed artifact clients like docker, oras, buildkit would support these n The challenge with using oci-manifest is how the registry tracks the linkage between the signature and the original artifact. - + Example **manifests** for a container image (`net-monitor:v1`) and two signatures (**wabbit-networks**, **acme-rockets**): -1. **manifest digest for the `net-monitor:v1` image:** `sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m"` +1. **manifest digest for the `net-monitor:v1` image:** `sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m"` + ```JSON { "schemaVersion": 2, @@ -76,7 +77,9 @@ Example **manifests** for a container image (`net-monitor:v1`) and two signature ] } ``` + 2. **manifest digest for the wabbit-networks signature** `sha256:222mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222m` + ```json { "schemaVersion": 2, @@ -89,7 +92,35 @@ Example **manifests** for a container image (`net-monitor:v1`) and two signature "layers": [] } ``` + + The `manifest.config` contains the following signature information: + + ```json + { + "signed": { + "mediaType": "application/vnd.oci.image.manifest.v2+json", + "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", + "size": 528, + "references": [ + "registry.wabbit-networks.com/net-monitor:v1" + ], + "exp": 1627555319, + "nbf": 1596019319, + "iat": 1596019319 + }, + "signature": { + "typ": "x509", + "sig": "UFqN24K2fLj...", + "alg": "RS256", + "x5c": [ + "MIIDszCCApugAwIBAgIUL1anEU/..." + ] + } + } + ``` + 3. **manifest digest for the acme-rockets signature** `sha256:333mc0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333m` + ```json { "schemaVersion": 2, @@ -103,6 +134,32 @@ Example **manifests** for a container image (`net-monitor:v1`) and two signature } ``` + The `manifest.config` contains the following signature information: + + ```json + { + "signed": { + "mediaType": "application/vnd.oci.image.manifest.v2+json", + "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", + "size": 528, + "references": [ + "registry.acme-rockets.com/net-monitor:v1" + ], + "exp": 1627555319, + "nbf": 1596019319, + "iat": 1596019319 + }, + "signature": { + "typ": "x509", + "sig": "UFqN24K2fLj...", + "alg": "RS256", + "x5c": [ + "MIIDszCCApugAwIBAgIUL1anEU/..." + ] + } + } + ``` + **Pros with this approach:** * OCI Artifacts already supports manifest based artifacts, through the `manifest.config.mediaType` @@ -116,11 +173,12 @@ Example **manifests** for a container image (`net-monitor:v1`) and two signature This option is similar to using oci-manifest. However, instead of parsing the signature object to determine the linkage between an artifact and signature, the `index.manifests` collection is utilized. - + Example **manifests** for a container image (`net-monitor:v1`) and two signatures (**wabbit-networks**, **acme-rockets**). The signatures are persisted as OCI Indexes, with a new `index.config` object: 1. **manifest digest for the `net-monitor:v1` image:** `sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m"` + ```JSON { "schemaVersion": 2, @@ -144,7 +202,9 @@ Example **manifests** for a container image (`net-monitor:v1`) and two signature ] } ``` + 2. **index digest for the wabbit-networks signature** `sha256:222ibbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222i` + ```json { "schemaVersion": 2, @@ -167,7 +227,35 @@ Example **manifests** for a container image (`net-monitor:v1`) and two signature ] } ``` + + The `manifest.config` contains the following signature information: + + ```json + { + "signed": { + "mediaType": "application/vnd.oci.image.manifest.v2+json", + "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", + "size": 528, + "references": [ + "registry.wabbit-networks.com/net-monitor:v1" + ], + "exp": 1627555319, + "nbf": 1596019319, + "iat": 1596019319 + }, + "signature": { + "typ": "x509", + "sig": "UFqN24K2fLj...", + "alg": "RS256", + "x5c": [ + "MIIDszCCApugAwIBAgIUL1anEU/..." + ] + } + } + ``` + 3. **index digest for the acme-rockets signature** `sha256:333ic0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333i` + ```json { "schemaVersion": 2, @@ -191,6 +279,32 @@ Example **manifests** for a container image (`net-monitor:v1`) and two signature } ``` + The `manifest.config` contains the following signature information: + + ```json + { + "signed": { + "mediaType": "application/vnd.oci.image.manifest.v2+json", + "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", + "size": 528, + "references": [ + "registry.acme-rockets.com/net-monitor:v1" + ], + "exp": 1627555319, + "nbf": 1596019319, + "iat": 1596019319 + }, + "signature": { + "typ": "x509", + "sig": "UFqN24K2fLj...", + "alg": "RS256", + "x5c": [ + "MIIDszCCApugAwIBAgIUL1anEU/..." + ] + } + } + ``` + **Pros with this approach:** * Utilize the existing `index.manifests` collection for linking artifacts @@ -208,13 +322,24 @@ Example **manifests** for a container image (`net-monitor:v1`) and two signature > **Note:** this is our working/preferred method: See OCI image-spec issue: [Add Index Support for Artifact Type #806](https://github.com/opencontainers/image-spec/issues/806) +### Signature Persistance - Option 2a: oci-index signing a multi-arch manifest + +Takin the above scenario further, a signature can be associated with an individual manifest, or a signature can be applied to an index. The index could be a multi-arch index (windows & linux), or the index might represent a [CNAB][cnab]. + +In the below case, the `net-monitor` software is available as windows (`net-monitor:v1-win`) and linux (`net-monitor:v1-lin`) images, as well as a multi-arch index (`net-monitor:v1`) +The platform specific images, and the multi-arch index are all signed by **wabbit-networks** and **acme-rockets**. + + + + ### Signature Persistance - Option 3: oci-manifest linked through oci-index This model is a hybrid of the 1 & 2, but moves the persistance of the signature from the config object to a layer of an additional manifest. - + + +1. **manifest digest for the `net-monitor:v1` image:** `sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m"` -1. **manifest digest for the `net-monitor:v1` image:** `sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m"` ```JSON { "schemaVersion": 2, @@ -238,13 +363,15 @@ This model is a hybrid of the 1 & 2, but moves the persistance of the signature ] } ``` + 2. **index digest for the wabbit-networks signature** `sha256:222ibbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222i` + ```json { "schemaVersion": 2, "mediaType": "application/vnd.oci.image.index.v2+json", "config": { - "mediaType": "application/vnd.cncf.notary.config.v2+jwt", + "mediaType": "application/vnd.cncf.notary.index.config.v2+jwt", "digest": "sha256:222cb130c152895905abe66279dd9feaa68091ba55619f5b900f2ebed38b222c", "size": 1906 }, @@ -267,7 +394,9 @@ This model is a hybrid of the 1 & 2, but moves the persistance of the signature ] } ``` + 3. **manifest digest for the wabbit-networks signature** `sha256:222mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222m` + ```json { "schemaVersion": 2, @@ -280,13 +409,41 @@ This model is a hybrid of the 1 & 2, but moves the persistance of the signature "layers": [] } ``` + + The `manifest.config` contains the following signature information: + + ```json + { + "signed": { + "mediaType": "application/vnd.oci.image.manifest.v2+json", + "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", + "size": 528, + "references": [ + "registry.wabbit-networks.com/net-monitor:v1" + ], + "exp": 1627555319, + "nbf": 1596019319, + "iat": 1596019319 + }, + "signature": { + "typ": "x509", + "sig": "UFqN24K2fLj...", + "alg": "RS256", + "x5c": [ + "MIIDszCCApugAwIBAgIUL1anEU/..." + ] + } + } + ``` + 4. **index digest for the acme-rockets signature** `sha256:333ic0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333i` + ```json { "schemaVersion": 2, "mediaType": "application/vnd.oci.image.index.v2+json", "config": { - "mediaType": "application/vnd.cncf.notary.config.v2+jwt", + "mediaType": "application/vnd.cncf.notary.index.config.v2+jwt", "digest": "sha256:333cc44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b785c333c", "size": 1906 }, @@ -308,7 +465,10 @@ This model is a hybrid of the 1 & 2, but moves the persistance of the signature } ] } + ``` + 5. **manifest digest for the acme-rockets signature** `sha256:333mc0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333m` + ```json { "schemaVersion": 2, @@ -322,6 +482,32 @@ This model is a hybrid of the 1 & 2, but moves the persistance of the signature } ``` + The `manifest.config` contains the following signature information: + + ```json + { + "signed": { + "mediaType": "application/vnd.oci.image.manifest.v2+json", + "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", + "size": 528, + "references": [ + "registry.acme-rockets.com/net-monitor:v1" + ], + "exp": 1627555319, + "nbf": 1596019319, + "iat": 1596019319 + }, + "signature": { + "typ": "x509", + "sig": "UFqN24K2fLj...", + "alg": "RS256", + "x5c": [ + "MIIDszCCApugAwIBAgIUL1anEU/..." + ] + } + } + ``` + **Pros with this approach:** * Conforms to norms of indexes as collections of manifests with no config data diff --git a/media/signature-as-index-signing-multi-arch-index.png b/media/signature-as-index-signing-multi-arch-index.png new file mode 100644 index 0000000000000000000000000000000000000000..bb89f2e70208e7d9f4d3ef85b510f1de51a7964b GIT binary patch literal 144312 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

cl>Gh(08LhtbZ79O z%{BSeS6X{qih%J45WQZ(Mx&ZTmYy+svl4vC@bwfn&J8C1q6{Tvk=ffFWtm#6)kFKe`6Xu3j5?PMNCPpI%b{Cx~=u zt=|2LBGbFMob}|3A+oB1gfcYh|6>(LVbm6oG!oC(vZ>xsoOB#WL(!VfB~!~LI4vkv zY_QX6*}k=bC$S}Lv42zvntl9HeeOZ7R#r*X9l4Y+VrdYr%=NP?hUz{}UbKgtG3qe) zUoYfKc@TA6s87(awTQiKKG^)bc<;xm zhx~f7h{9)_FV0uPBDy_F3iA1*7T)ZcPbkU0%Z_2_kT7ELBJBQ( z4^-38VnB2@ANiJcSD{n^=abS!mo}HaazERxR3Q&0uw@)uMGRdqZL4@etmtCjq#1z( z6<1(N(hV1?-;3{6aV(!B8MMbio68rk;gNWf3>u4zX`=_+eb#`@qaYnYx=poQyH6Zs zn^6+hSCUm&s>N%D1E%N5uSqcs-x(LL(G{gOj*FTmyUR4dtA^(*4!+%`XyGV&YOO|l zh^jN)20+XLs{n`HReHuI^-_ddZ6k@ePCiLFj3`au8E-!K)v$s``#z^STsanP`6#C6 z`UqQb;CoLaz7^0vXc4s=y`bo6;K1VLsRo5hn3Y#(r7?tkKycZl?fn`upFRL~AsN+& za2xn$ET5jdwlJ;G<(`g{C64pT{-P|$Q3wi$x9N1C(nh?7Bc|%mVg*)MbzPMHIm2_* z6Ih$!%~kQ7%nDp{Vt2L$!=q<+YNY+nVY>Ww}#9IEVgx9p`X z7zwEw;b>Ha@=K;fw|P|DOM7+=_pT`$(ur5cY%C;!{7cWtzn20EZ-7_J%(5jgjQDHS z$v1jDa&7ugwF#krC?<v6IdMCnhLcM&r?S_r@Q<}uthe_|vURMA-OPZg% z)|3nqIWqYJ9yLNP9qmIO+$J5h(?mD39=A(h_Oatirj_hKjz&SoRay4tx+Ssti? ziYsWgs+5rwXU}`C}$M$P`BE+np_Io2dd^I9>z~O_Dw_SxeITVb~V^$~E8C;5$Yu_9;^`n741G&0S#gXdx= z6`kS0OIWaR@`_4HUC8!c&n-#aiyPXct*tWC(&`xUnrD-c8*%u9*Np!u9dBS70X>qc zI7Fd;HqgU&hTV5B{BX4xYV$xj%#R_46jQhQDRRl3UsO6|HTLbAr@aU zSuyQm*Xb0@qNS!HsyK<@Nt-phQz|hWF}%4dVS0y7gadYA&IZE9E{Y^-+S>M~+mQ29 zHz^R%Lf=T}u#ukw!BQVE|M1~WL1^NjfRugo`z5?VT%waWHquRdR>ciJ#^w*NNpA2l#;T+q@gMh1~H@u)Ct$r{7)#=^Whb6Pqqu z7vV?=ATa+mp)`9}PNO~d_C#Jix;_>9<)UkX+0(d-QB`q#MOAkat}L^6J}eC8_Kt*; zKfbf+H^La^{J|O*>^1y{2?k}1i5>=dsO4am=jB11EJ!SVkfCc>> z7uZVzcZ!jeI6n5%<^&6IPjF3%!LunUmt8-{>Tgpnh&-un8H@9Jau>i%ou>wm9V24! zu7iLMlNv?Zohb-q#+fh9s;S4g#~*ZuvN0-)T0bHZQyKpXW3+nBvs@!PUDom>%8Bos zgkZOm!5RcZ7cVqwJgdjpj#Io^l)339cV4TT00HbcQ)5r^GPa4axjDsI_6N~@?W(5kiI1Z@DZ<`ve);yLyXvldQuwdt1SLv4nP zqCS~tMLlC~-L$x!x*D0R^9iE+v3|jZywH5WrgoSTF=XL2{-wvN?gZjaR2Lmj>np;l z>mSLMtVV&zo$9P*HwPWoMbDaGk}!6h9!4p8 zVuz>D+F2%ik{|g;Up@_N+2F0fvUf_jTXbM6Y2v5B#1CoS;Yt) z+bX0uOkD3#6@dS?9(V+NL2|zN;#kDquhl3PVf#;G5#i}o;WpL{$X9Tbpa9=PMFezk zsgx%=Nk9;XoITxF480;At)rX}Dh|K(kfJkZNb{z`f=*DmhEmeAIoM_O{%#H1Jj5Cv zK&yjV>lzyc;_D78+}B`K6meiQ^~waQ4_#}*NwZS#NOnqTWlQBkPe)VQah3N9C%_y_ z?0@X93b^e6pNdoi!>2a?6U|-wXmg1dZAHy!tJkf21nU+WwI<-*%PL-NTc0W)>R7&H zE3B0+lK#UI* ze=&hX+YcJMqLb{QV}4O=gYzk`vb7omvp-f(s%tn|P;~VyipJV^fxsCotkXKAEp%G4 zbtFS?x2H-ck=MnZ1~y-1`+lcICCcP@7GnQwcY$awOBYvFY%ec-&f3$&;YFpRkqSI- zvdB!+aJO&Qiq*`>rrujb>mlyG8^L*YejD1JIMJf)V){WFuLifa>pu&#nO~fYks z&q>G7_GY|9SBr?l1Qrb)`d@-_s%*{FwDggK=q zLsJjeWcga}=fVkOZ)5pZ5X&qrWo%tib$1HUjm+HUNTw>RyUbRH}z@>g5nX zw*3>q!HXnw7V0ERGg-vd0sLe1dySI+_BePI5dc7WEU;hAR`gQF!6Vc^^>wDv;7=dK zqexb})u|Lla4X$@Byw0t8rdIMKg0**gcXkc8&SS|d~%=v)Y=~DKium-jLod^K0_i* z|A~}A@~t1lmjj0m9x2K`v}Fab`Ah>H)v>|MizVN54!{ zLrD<0Nb@-UuX)Hv0PTmp$L6<@;af+nE<_G(So}3{UwT1qAIK^NNpJZ7z32uODK7@ ztX$nUEA~LAxS&b3g9nK{nd^0?S(a{V?yFE%H7x}ZLR$@Km`8Qix?p~I@7!o^KPLDRw`Tz|-4j$_qrC!>6>;0u8U zAbYT5zmbT%;=>EBOcO~ml=j!JuY~vXbU12G0Fu6=Md2Rr3dCDK|2#lhJ2e_$($ zpCLHlPf`6`t;b#oX>>)N8Lt8g?}5#B9mV1-7cfbhO27e~lZ)~ItFE^Fx!O)A?$<7c z0IVHMz3p4*F2hSsGu_U|=A{2oKyAA9ps_&`%p@4>m$avnHZXb|#{XH)ZQ=PUZm?}+ zexaX}wzAejI7V>rBhcc)(l|S5@ikICuqo+0)kwem_}{-|+|J4{h{y{B_~}5blt!JQ zftE+W=JBNSL@ko&U;yCvk@8~-{7b4D0Du62u&2VdtSI7BLKR|MHMGO16boHsVQUi{ zS!eEe-7nrYO_`~X5MJ%d*{CYGyQE;hk{Cfr$Scx!J`Mq22joaQnIoO7R7 z2a9pnTWe@p8+UqCoB>B9%yl#(3AiSN?N7TbBD)!$bVe3Go`d#u0N?HPHQpD4Pa~dl z7trqanv9DPbGmWKqJ=zqpcddnItV?keW-t$<9HEBR$=VY`ZI&^cakabjGJ(GPZHN!ZRy zq>n!#5dn>p5YI_yLRV>fY60W}kl2D#Sgb=Fobj4v3h3BJxT`ZXiV-T&$a`b1G2$;j zZQZbCWP}giOb%wV8M<4}VYW|vL$ouj1c1BErPlRD@1!FJ-@x~hNkjBCDu{})H}U*= z;#ZM9L%O!j3*Y3vT8>vATkp_zOyWzEvMDdg+%paVDHsSn#@zfy+^7ZveF<@(B)&n^9!+eDCxF3W8iEV#T z+!3CCq6^rzcc;>%;Q+4+Mhl-|XDxK8?b|wBW-ab%h3xM)ZQW+xmA-G1rvoT4fxI&y z`#loA!jWoSu!C^Kj2YmK1ION#S^SQl~r0Ac?fDgVx^ zRskrYTJY}6B_BoUE*>dEK1mMKnDxy}k7YbN0Akw8e$cm^W3Gz)>bTcC)a12wC>mt0 zKG(2x1*^wzI2_zGHv*7uNU>BhS|`&-<@U&93?=Ujy!4>r5OCY)enV$(to4D53y}KB zMis$b654w&w7&BCIf?F-v>mYwQT-Zq3izcumv&|@#MabPXJVgwYO?&^w@$oSxN$TR z>w8$~7Idy!O`Ad8PWTs*g1_u7+o7<&R?a#iD9VWo(SpaT<+>$GfoD~ij?{1A4r1oM zO6Pymr)f%_!3zHgNW{J`Qk>Q7 zw3aj1j&A?GN2*=id)H8Sois0JVwigjv<;qF5tEH7TKi(5e&L^+utg8)o&!cO*@G*j z&J;%tf{(H_?0v}Ok6pePHPX|;=x|kP|65>p+q6=qcx)9RXKf)9obMkbYvO@hO;d>h zgoNKt#`nxl8oXaeZ-l`!HiIKRfp)+rkOlYzo&Y|9e|}`|v*fS_Y<{wmvo+b|;1M}G z)EA84Q1gf#f!>;S(J_H*`D+fp4wUwv1J$s3`l9e3-Q%fSL^2yulRuOZ_}UIB55|I?UDc9OH06L{IuG zX3>pa2jJRCto0agU`&t|952EH0!>maeVgUGfSKT^TaFE@GwZAE-E$9z6=_nEedbA` zcerB(Um(!}I1^FvCWfXHg7F0H)QwGE#Ypg6X27XCB@e%a50@g$9w}-EU}>)Gt4D3M z_H#8t)E0@~M${akL6{~{wSY%0ZE1u>|DnB2(1@mfcyZ^NmP6Als=JtV*L~_PU9ZC)h^vUVjBsg zjXJ|*f1%vRH9vK4CVD6wUXZLDL!iQ(XYKX0RIm6$(ODS6BJoux@lX7Ch<0aAuw|zF z+IWPz7^@D0tt!h&Fp3 zMoajVgK6%HnKYT;jXl`3GFe+&JK#yMKmJ|F7^32%04Q6A{l&Q`ww(ei<0PJ)bQ)vR zBKk;Cw%E9lt-->s`YC0Lakkgaq3r;4H{W)!K_}q>))u3_)0p$gc z>(TG$ygN|}ZD?>zk?dTqHuCcH>A^l(vmn}#y}@ePke(LH02!JyLcuA#y)T`)Ecm0z ziKNM2p1Ks`R@5dty>i^1h83h=O3wV0S@6CBoW5?$hpe3*-gu3EB0ARmR@`)4X2asL zZXC07##?|eIMwoWTK>zFkyA$cz5Anq=@`#FZdTR-QNF&(5Q<0gI)h?N8Kt~9;l9^B zYfcBA_xn_W=FCh?3SB%2?)EoAr)Y9oI_nljp)fX|hCwM_J zI=5%_wRKcD7Y=r_Ab(SBGWfZds;iu-~P7h z)n^n=Cq~(@ZuirgBFcT=r-q8y!`gd!+KJbuiLZbV|BaPAxhRIUyp+j_b$2g98rT8?FU zz)XAeE!L+6_7~zf$h9%zYI8H~^7p2yIA)C<^UIcQi}Q*C^lr{6)~$D2IH#WMiUJzN zY8}~D^pi6J(duUB>)QLOol@NTjo-$Ef6b`W#GSm7ti{Co4HC7owdP6}JT=d~R^n5! za2H=?DCj#gu_dz-<+;5Mnnnx5rcSn^OH*9G>T78e5$a80C&(}@O}R-HVbl-Gvoe`X zw=*ULgOHabJDLA59m`NV8|yAEUNc3jm*PKpX}GnK79CX6GpPU4e^mrlt&&TfY?bT6 zUU92yu}VlVScb3G`CK|rYD^MsY592Om`THsu5LOb_UTx0QhY_M_-yg5SRyvqIVy>SsbWMrg5y^28E{;FH^^`v_ zJneP-gam426e;q><&^5GtTkV`>z!d`kh${s>N-;Dn%cUZr|5Gq+f-`Ux(qC?AN$=I zFvBH(2XayaRnJxlRRgfEo%ltQK(=up@7FOqCXlJE69UoGat%%_PK-i!43ah&Ws89= zBdEpN)xtxLf_^1-_A&??AMRV?pPuu^qFj|lVUX8$coUyXOgOYFcv1o?;NvJUu9OH6BD2u0IJwgCj? zI(wg?P3@$*jG*NGB5{s{lP6BX=C5zPlsR7es5S(Js?(moW@E=VACG%d^4aN*k-M7P zOV}3zqfqd!at?n`JX)pwujy_hH+X~N!~(ZbHmA{74_Rw0cQL0JdN(JyMhI6rEsGQR zddd{3U{7ozP%FW*_8PUGBkNu0w?bde-a|T=F6VpL%Y_DR{)?YiyOP|x^^x;DV#DGW#lEsHr`0$E5Iw#-0Z8%?FA)@E+16Qxr1NEPzwsS%8BP&C)oaZz>} zl4TKD1*?k*hqvy+Z3efn)gN8)3DTRcR9&(SIe<$6-^jy+jWzeS{kRN(XNyfh3q%QQ z&#=y54zR2%1u&Qy)0w&7R$r`?eZsI8m;}15kfE=(R64(aE-KM^w=)o?M{xCJj$|vtdDTS?3`3H6SB7rtS?Fx1 zQv<4WSvGXbz@eqS&{=2Ubd7hElT;=O8FDpsaem!U|1u zL6`^zVleHmV^-FzqjqWtBA4CvZ?!sev${`fGzq+4Tyq&wu83j9iiCR`x6B7-Rte2E z2{|AdCa>%_0XFQ9u^{=~MT3;Mcj!HUFrT4>&+V4*9+cosF{v0Q7HMhE?UI#^Im2^g(tRj}L&0WiEl&5S!S6AWHQ!rx#FH*X&f00p z<&itzG}9q6kgxU)Rsy8c;^KE8ao^YKKawhwPpcS`)AMfhAK z<<2gHec+qIRH-7fq({<_vf)3=a?>~D9n_TroxET*uq(_$U5LVE_1(goSdX^VlxmrA zC+yeYKAuXmC0%8DRxNEbvIkeYC(pI^SZC_a&W=$K`|RqY+BG*R!T1=Rye5=gP};fb za9;X^gV2Sj?uY6Y{E^t3st2JkOc9Mkv^<_Wb)w<<;xv2?j&oh}4w$L`9qcSWtsJlQ zqPiqrZ*h*yk5om|JjOp9;jM_mH*UrCzGp*a+>gDdn`RKzRUcMdw)D8K!um8QXxwW@ z3zlo*c#%S3W}$$ATz*lE!p2)`!Zkc8Iz0H|ym4K%+jmvOI$@Q>DN8Y5Dq4vZX{VzJ zfL^D65h%{?SU-zO87~zuc4L|E=`s{*ESdO&tSZPyC978yO>vv@I{7B@i(1yWUnHs( zqGEHkF=y}5!u3_{z{{+c=tK%R|JmiXjm|;mk?&DK*hY^NGlq8PRe7tkTkn8# zgP{2-9szgTtZdNy(iHoJvA-s@4}CaRo{kiPRD&j%<^CYxDu*$__RAfgU3V1ZLGKXZoawok|)b*;)jEkLC z=2?+Oc9kin(^RknO};&K+w9>^tL&VL>w-z>69^ZuBQ$FQN~bqr@Iv{)5eR|DTjZ@=bAn4VHGo^@|v<2H2{ zzT1uxk)o}Bh6>(r+Id8O*Ij6lNSA{1Op}pIi}oCAFP5i)^1BZ?{4E~xmf7lgyJi|C`e#9D;H&e0ODfsg>x z^NDdYTL!a^!;Zp@)dQp}4SoBptI&N0z7R9<_gk6p6~vm;nW1}v^Jl7GZG_?|?|&_g z^Je^9D)8~?e0w$_OgUpz2HBkjaYAO5^7yQGt-_d&#%8BHR9umS`S z_6$dcq=cW44?{>8opO>bjBXqCyY%#i=xOzA?VGdKUHvJ69-lWZ)pbotJneORWf{>m zbFz+>XBM$+ls0A{{Pnf9VXVNDxWvcI#MfT%$2&yV+cAjgJgEK6iu9U1!?X&Qio)UN z6W1-mcke92*2-fL=vZmjGb`O}Ex6G%Sk8XMN>;Yn9lR=Ubr&B`TDI8$^KG?NBbBUT z>3S$r`$M!I=B4aXoo7NnWmd5l_W?48N@N-GXwt*Pwid$?r?kjyx`>nS>^9~N45#Bs zb6bQs*E!hD=9WyzaLs*&-+$|B-wsQfsP7j!kKw?^pJ?~WV+x{kJbS)>E{EX6Jjud~ zxP2e?xiEutGlnJe4Cz28BiT>OKB$^2Wy(csTs*{!5Uq8~l!&sM%ji{xBUeKK95-`* zzYIsL6|<=YxAqru5a4hYu4@Xx(GiQDs$=!kcjUaoR(zRF0Z+;l-qyI`a9z%3Xx}xg z`|a}OzGBiNOMvOpIL_BC)OT60Nnn*>w2KHBhtLqhiDBpJ^X?4Uq&8N|_T}nH&-k!< z#XjwZjckqn&M_kBGqqzhag+!&vt^kyu9-U_DH3xYs+8847w}w) zm$M)gD_wS3;Xqe!M2I0@3d%g{(cn?LRlAs9p~M1O-t}0z>^e%L&uu+TH9fZ@?wH0fJ6eB!+A zXXnEfFLviU&){VQ;E`Eg6k{JjJkFPT^I%cXLq``{?H(lp`8*N?}xVNmuPex$Q4WB-|k*yU}#+EPu@7 zp*jl@;opDi*&ngN6%Up1YccB{qv*!36F7Yw`~3~ToLjWm7#T(QR;AWeA9;h-`k&~Z zAz&Et--rzNuJ}RXuzt|7*pBrHza6`iV^+-*T4S>FQ2DoO0lR-DS!hsys_V)LE_XA( z-BmGESNYmK5kE^0wG%6~XPGb0tuT}b{x6Bp$jMWgdO*TWnfSId7-N^X`(my z8PCtnn~b2vM!OP+5vj>O+aE00S5IqCbSZj{cvg{i&DvDa*|akT#2}wbtdd+!XnRWd z_5X!YqBr~_Ece*7*>R19wX5%?a0&i*0=@PYlDS93(5TSaJ^c}?&b>%bksx)@>-QlY zJEfuKsEWFDNEt0}qJgc{T%?_U-!wGuXfMe}kxfSNJ;?N%qIQE6em#J(P2@^!HtHUW zn@P&|C+qlC*;pPDOeX+o4@yzbY$x}~PI`J}CPiNw{4tZg$kr( z&P^YGLv5P}wmj?fuZc^D{TB@aXA-rWUW?oP45pv>fAL(z)AOkBzcC`sN~dv6Brz2K zv~hu|kx!JVI@W;{6!cI43=_|Gseheb$in^&RH$TX@{~)z1g=z^>~7SwEhB8vbwT`T zGRm(C(Z0RagRI;cnqy(1kBT>^$4 zAfT&)(gJ~ibde@qkX~&N=@NQ^ASEDON*CrM>UZ-s-wXhVC?MJQZg0Sg z4S(xf8ToiQv2F8FG4p5YwQcyjFqo7VK)=Kb@86$@akX(R&|P>e_bD9cF*H5AbV(>T z?4#<`yUhZhbD|N%uhLk#lSK95`Wy?{BYUb5-ZG6|HyjUHo171AHYvC8xy||qjTQS~ z?5`gy@n5ef9Bn3T%bye8bSuj(b#?`@?+oayeB{J*SDH<38_BzG#IUb78E&_B_?3jC zS&zeRovasvP0k7Fr!wwcL%w!ZAjoh}QS~HNq&NQ7lh7GFrnjFOB+GcaF7YKe9<8UU zUF4io{*%1UTAD4siEmEO@8$Q1Q;Yu)od+ffx~zk_+h!*_-I;F@AUovo{xpr17F6D| zeEkqG+pQyJT|qjv@+z+xeqNQ7)mdJy9}#dkaZu08|FhQxP$bnD{#LtpWA^T^@7pjb zyIqf;Mr9V}!f1lLK25iNp-p~^Gi!MFppjCi@9?IchhU!$qqRgC3|*6mW5&8f#>EI$ zD5o&SE#AElQ>oS8ALHFj^V-&*^Z1A_fx=J{^->ELrNwK3jNWf7U|ZkKIoifRO^rc2GV=1u z15f?wHG#+38)!%cR?Z~BoV_RXoe!?pVIXZmN^;#b?&*oFg|%*-c9oWpsqPUoMLhw5 z-5j57Q^Kl{W{TYucWqv{r;^EP4wZCPBdJiOI|dUPLc$nTqLwN`I&3QtbR&la5~8w|J-T+2h;MHL{vzt8k!Di;oUwq!`p zNaz@qqJd9+x#;a=PpuXIaO9oA6nCGs&o&1;LG8MOSYjZAc0g@jCL7?5h7^yA*HJI} zB#s6EMFoCv+3Upi<5K~PV<;{2acOzo(h|Y1tqf|z%w4b)=+_sZBbg^D&Tq>^|kNH#MV0|CpM^7wKKhE;5qnt;J%LeeFh%9fFuMDPLcM zj;3BlLHXXF7|ARLYBMy-Bbi)Dx$OBjM5wqRs@Mw4e%iHqNd(XLQ2Wpe^`gOuZb(CH zQ|1Dtxa6g!R4{Y7!^MWDJR_#jmPvJOZ}_%#lh@NU5QiOWV|ksXA^t&xoD00prRXbJ zfYjq<*%6N%^_v2P7kLO?3F$7`7v`RS4^Eq#QA7@e58Ud@H37OjGh$GmE4ks7bqn{S zd9(4A(+r4s*b$mnm)I^4|Bh(2>@HeTwUf!kNQR!ih*=Q@-5=j_`(EbWw_M--tFLk+ zl1~)A7qhQ&;Zr}+5>EwM2e8#RcPIJ!*{53wHN-s~Du9gMs1Rml^b1bw@X?7pJJ}kM zcfr7WGoAlvR!6&X3Xg$}W{RSMZo0cA3pjXQvAeZ8>Z7BmU;)+iViUTnD>WI~`YgPy zUB$#7dPY>}{j=}Fc?c0!8#RvYZH)YD@SRlHMv_0id^=xpy3%q7(I90bRl&j7R?fnF z8wQ$;`nD~m?9Gi>B1eJn{E!^lrL~K6sgw!Jy9E*IIM+qj(m{Na?(M&uuKxaYae3Pv z^&=^a5gW;bmu&c)lIhEK>Ey+tk}#f02KyLz-=ZPD6WO$R@qm^3$|ibV-0$w+tHD{2 zJ81~1JaDzu!yZ_E$is)PMRJ zyzPG~KpYkrv6>>;KB9RslFnD`SSPR4ssvAZNz298`A)#c#!NJV-BzFUa>@U;HaKR| zRov97(%BM0Rj82?q`Wk2dzp9PAPo!Cwtvbd-7wRC_Pg2yajv8xUzdR^tzv;3*)=mO z`Y~>g-o`2Ig(MJ*?t`XZYAh;y`H-?nXjo`?`z?6E-!C>)_VN1-C52)wsf_{(XhcZ= zCMhC_Ua(Qg>`0QC@eTm&Gb!Cc(Eim?G=QTl8`wAQW$8d*h+5K7 zWGxwv6}<01{#BArm`l+}$^qRO;VvVjHSEiXy@(c?FrI1spvSmGF-ex|n2zM1I1{tL zfW0VCe#C@VuE2ow$ODJuTY_W@QgVVzS{Ghi$q9!_0T8L|v8CzK4(SC#D{Sb@5gKKs zdSB(uxdhH%>`u>jo)RqR?c+a5jM z9p|+p*QWG1U?6P;e zG$~2E!0`~k@y;G{@N_?=;OfW&;Yz`BMa`mN$dp>KDQ=j_@ME^&bs`rtf{`cebmd|90}m{sH~4UM3B z*Y=8S|9@}*pY?xU-}rn@rCzbm`rK+vv%M*|-efmt4#T*Fk;FjB+N|)o!U=T;&t$qA zFrK)xVTx!M5&E>I%#y^w*ru1E-j$)%VlT>EO~)(DtykENEetET`CEq93dl~3&?;^1kQ`#D}v0A|KcChk@@m#ZZ@y)J+W5h6PQ`=5W=^JkvUDX zCO!sQCpKN`x|(t%+ZdB9#;cbrst1XWtZd5s4yxTR*1vwgE5=27#er(As;;GP>xzn= z@A$V@05F4yj5K6wmNgRK)U+F`{_%2Vy6zOYZ`TH{uv~15-@8Cx+S%+V8xW>D`cPCl z{vpS@TK!7@REOMFp=pMMq%xFC_827PEkk7XS8t!ZyEkWKHVY7qDe5f}?+Ke16qY0^ zYUu%gWl-*?&>uQ1EI}Y?-UATc&lm2MoxStRT-0z(0nxV>+mVxVcUAZn0RDo^^7wi@ z_2#~2d8V%VR@qCJjlhL`xaH&%0A=f$_7rUM3-vy4y>nPMF2Y3cz3bujatv>laeQ#@ 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

cl>Gh(08LhtbZ79O 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%0A=f$_7rUM3-vy4y>nPMF2Y3cz3bujatv>laeQ#@ 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 diff --git a/media/signature-as-manifest-via-index.png b/media/signature-as-manifest-via-index.png deleted file mode 100644 index 286374a0199e3a0e274f78fac051746671350612..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67354 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 V;9%lE(ih-n(s4(SSo?o~m-X~=T}>bDtCH6H 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 Z`ISXCu-~~h`6p Date: Mon, 6 Sep 2021 10:50:31 +0800 Subject: [PATCH 43/69] bump notation-go-lib Signed-off-by: Shiwei Zhang --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 30fa816bf..476e561ac 100644 --- a/go.mod +++ b/go.mod @@ -26,4 +26,4 @@ require ( gotest.tools/v3 v3.0.3 // indirect ) -replace github.com/notaryproject/notation-go-lib => github.com/shizhMSFT/notation-go-lib v0.0.0-20210830093102-4cf866d49e92 +replace github.com/notaryproject/notation-go-lib => github.com/shizhMSFT/notation-go-lib v0.0.0-20210906023928-fdc1ad1f8b03 diff --git a/go.sum b/go.sum index 7eeb11acc..206856ae9 100644 --- a/go.sum +++ b/go.sum @@ -101,8 +101,8 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shizhMSFT/notation-go-lib v0.0.0-20210830093102-4cf866d49e92 h1:IkiOEbFLTEoQw6XMatJU3CfKSanzsYgGn/TNTrKz/0c= -github.com/shizhMSFT/notation-go-lib v0.0.0-20210830093102-4cf866d49e92/go.mod h1:KL5EBS/9X5UI7GnDC4NbYg2az6HVmoyH5M2Bv8a9E24= +github.com/shizhMSFT/notation-go-lib v0.0.0-20210906023928-fdc1ad1f8b03 h1:uAlOjYbqNiB/6CwwJN43Halu9PJtRDXfW2rPV3YPCxY= +github.com/shizhMSFT/notation-go-lib v0.0.0-20210906023928-fdc1ad1f8b03/go.mod h1:KL5EBS/9X5UI7GnDC4NbYg2az6HVmoyH5M2Bv8a9E24= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= From 62b35efb83fadfa24abddad04cba2107923563ed Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Mon, 6 Sep 2021 10:51:24 +0800 Subject: [PATCH 44/69] prepare for 0.5.1 release Signed-off-by: Shiwei Zhang --- internal/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/version/version.go b/internal/version/version.go index 7adc4bb7f..213ae7bfc 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -2,7 +2,7 @@ package version var ( // Version shows the current notation version, optionally with pre-release. - Version = "0.5.0" + Version = "0.5.1" // BuildMetadata stores the build metadata. BuildMetadata = "unreleased" From db7b4d8d09b9ef344e2245177695d4faea41ed0d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Sep 2021 02:53:09 +0000 Subject: [PATCH 45/69] refine notation sign Signed-off-by: Shiwei Zhang --- .github/workflows/golang.yml | 2 +- .github/workflows/release-github.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/golang.yml b/.github/workflows/golang.yml index b5157365c..611838a13 100644 --- a/.github/workflows/golang.yml +++ b/.github/workflows/golang.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Set up Go ${{ matrix.go-version }} - uses: actions/setup-go@v2.1.3 + uses: actions/setup-go@v2.1.4 with: go-version: ${{ matrix.go-version }} diff --git a/.github/workflows/release-github.yml b/.github/workflows/release-github.yml index 70a3401f6..a9fe1b34f 100644 --- a/.github/workflows/release-github.yml +++ b/.github/workflows/release-github.yml @@ -15,7 +15,7 @@ jobs: fail-fast: true steps: - name: Set up Go ${{ matrix.go-version }} - uses: actions/setup-go@v2 + uses: actions/setup-go@v2.1.4 with: go-version: ${{ matrix.go-version }} - name: Checkout From b7ad88ff98f750d3c068432179bae598f52f5f65 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Sep 2021 02:53:08 +0000 Subject: [PATCH 46/69] Bump actions/cache from 2.1.4 to 2.1.6 Bumps [actions/cache](https://github.com/actions/cache) from 2.1.4 to 2.1.6. - [Release notes](https://github.com/actions/cache/releases) - [Commits](https://github.com/actions/cache/compare/v2.1.4...v2.1.6) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/golang.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/golang.yml b/.github/workflows/golang.yml index 611838a13..b3cedc7be 100644 --- a/.github/workflows/golang.yml +++ b/.github/workflows/golang.yml @@ -27,7 +27,7 @@ jobs: uses: actions/checkout@v2.3.4 - name: Cache Go modules - uses: actions/cache@v2.1.4 + uses: actions/cache@v2.1.6 id: go-mod-cache with: path: ~/go/pkg/mod From 0d295191f4858415a204c17b639b238754e82fb3 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Mon, 6 Sep 2021 17:20:07 +0800 Subject: [PATCH 47/69] extract `list` from `pull --peek` Signed-off-by: Shiwei Zhang --- cmd/notation/list.go | 54 ++++++++++++++++++++++++++++++++++++++++++++ cmd/notation/main.go | 1 + cmd/notation/pull.go | 52 ++++++++++++++++++------------------------ 3 files changed, 77 insertions(+), 30 deletions(-) create mode 100644 cmd/notation/list.go diff --git a/cmd/notation/list.go b/cmd/notation/list.go new file mode 100644 index 000000000..1b067f9ef --- /dev/null +++ b/cmd/notation/list.go @@ -0,0 +1,54 @@ +package main + +import ( + "errors" + "fmt" + + "github.com/notaryproject/notation/pkg/registry" + "github.com/urfave/cli/v2" +) + +var listCommand = &cli.Command{ + Name: "list", + Usage: "List signatures from remote", + Aliases: []string{"ls"}, + ArgsUsage: "", + Flags: []cli.Flag{ + usernameFlag, + passwordFlag, + plainHTTPFlag, + }, + Action: runList, +} + +func runList(ctx *cli.Context) error { + // initialize + if !ctx.Args().Present() { + return errors.New("no reference specified") + } + + reference := ctx.Args().First() + sigRepo, err := getSignatureRepository(ctx, reference) + if err != nil { + return err + } + + // core process + manifest, err := getManifestsFromReference(ctx, reference) + if err != nil { + return err + } + manifestDesc := registry.OCIDescriptorFromNotation(manifest.Descriptor) + + sigDigests, err := sigRepo.Lookup(ctx.Context, manifestDesc.Digest) + if err != nil { + return fmt.Errorf("lookup signature failure: %v", err) + } + + // write out + for _, sigDigest := range sigDigests { + fmt.Println(sigDigest) + } + + return nil +} diff --git a/cmd/notation/main.go b/cmd/notation/main.go index b2a5c195a..b041b5bc1 100644 --- a/cmd/notation/main.go +++ b/cmd/notation/main.go @@ -24,6 +24,7 @@ func main() { verifyCommand, pushCommand, pullCommand, + listCommand, certCommand, keyCommand, cacheCommand, diff --git a/cmd/notation/pull.go b/cmd/notation/pull.go index 92e9024f4..b60a9b0d1 100644 --- a/cmd/notation/pull.go +++ b/cmd/notation/pull.go @@ -18,10 +18,6 @@ var pullCommand = &cli.Command{ Usage: "Pull signatures from remote", ArgsUsage: "", Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "peek", - Usage: "view signatures without pulling", - }, &cli.BoolFlag{ Name: "strict", Usage: "strict pull without lookup", @@ -64,20 +60,18 @@ func runPull(ctx *cli.Context) error { path := ctx.String(outputFlag.Name) for _, sigDigest := range sigDigests { - if !ctx.Bool("peek") { - sig, err := sigRepo.Get(ctx.Context, sigDigest) - if err != nil { - return fmt.Errorf("get signature failure: %v: %v", sigDigest, err) - } - var outputPath string - if path == "" { - outputPath = config.SignaturePath(manifestDesc.Digest, sigDigest) - } else { - outputPath = filepath.Join(path, sigDigest.Encoded()+config.SignatureExtension) - } - if err := os.WriteFile(outputPath, sig); err != nil { - return fmt.Errorf("fail to write signature: %v: %v", sigDigest, err) - } + sig, err := sigRepo.Get(ctx.Context, sigDigest) + if err != nil { + return fmt.Errorf("get signature failure: %v: %v", sigDigest, err) + } + var outputPath string + if path == "" { + outputPath = config.SignaturePath(manifestDesc.Digest, sigDigest) + } else { + outputPath = filepath.Join(path, sigDigest.Encoded()+config.SignatureExtension) + } + if err := os.WriteFile(outputPath, sig); err != nil { + return fmt.Errorf("fail to write signature: %v: %v", sigDigest, err) } // write out @@ -93,18 +87,16 @@ func pullSignatureStrict(ctx *cli.Context, sigRepo notation.SignatureRepository, return fmt.Errorf("invalid signature digest: %v", err) } - if !ctx.Bool("peek") { - sig, err := sigRepo.Get(ctx.Context, sigDigest) - if err != nil { - return fmt.Errorf("get signature failure: %v: %v", sigDigest, err) - } - outputPath := ctx.String(outputFlag.Name) - if outputPath == "" { - outputPath = sigDigest.Encoded() + config.SignatureExtension - } - if err := os.WriteFile(outputPath, sig); err != nil { - return fmt.Errorf("fail to write signature: %v: %v", sigDigest, err) - } + sig, err := sigRepo.Get(ctx.Context, sigDigest) + if err != nil { + return fmt.Errorf("get signature failure: %v: %v", sigDigest, err) + } + outputPath := ctx.String(outputFlag.Name) + if outputPath == "" { + outputPath = sigDigest.Encoded() + config.SignatureExtension + } + if err := os.WriteFile(outputPath, sig); err != nil { + return fmt.Errorf("fail to write signature: %v: %v", sigDigest, err) } // write out From 6502bbde80c53dca48117faebd2bae692be626f3 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Mon, 6 Sep 2021 17:33:55 +0800 Subject: [PATCH 48/69] rename digest to sigDigests for code readability Signed-off-by: Shiwei Zhang --- cmd/docker-notation/pull.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/docker-notation/pull.go b/cmd/docker-notation/pull.go index 4d2206614..d93038294 100644 --- a/cmd/docker-notation/pull.go +++ b/cmd/docker-notation/pull.go @@ -124,12 +124,12 @@ func downloadSignatures(ctx context.Context, ref string, manifestDigest digest.D func verifySignatures( ctx context.Context, service notation.SigningService, - digests []digest.Digest, + sigDigests []digest.Digest, desc ocispec.Descriptor, ) (digest.Digest, []string, error) { var lastError error - for _, digest := range digests { - path := config.SignaturePath(desc.Digest, digest) + for _, sigDigest := range sigDigests { + path := config.SignaturePath(desc.Digest, sigDigest) sig, err := os.ReadFile(path) if err != nil { return "", nil, err @@ -140,7 +140,7 @@ func verifySignatures( lastError = err continue } - return digest, references, nil + return sigDigest, references, nil } return "", nil, lastError } From 3baeee3c1e47ac4ccd2ec20c26e57674e5b720f3 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Mon, 6 Sep 2021 17:51:35 +0800 Subject: [PATCH 49/69] update doc for building Signed-off-by: Shiwei Zhang --- building.md | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/building.md b/building.md index 16cef244a..c09a83f57 100644 --- a/building.md +++ b/building.md @@ -1,34 +1,33 @@ -# Building NV2 +# Building Notation -The nv2 repo contains the following: +The notation repo contains the following: -- `nv2` - A CLI for signing and verifying with Notary v2 +- `notation` - A CLI for signing and verifying with Notation - `docker-generate` - Extends docker with `docker generate` to create locally persisted manifest for signing, without having to push to a registry. -- `docker-nv2` - Extends docker with `docker nv2 notary` to enable, sign and verify Notary v2 signatures on `docker pull` +- `docker-notation` - Extends docker with `docker notation` to enable, sign and verify Notation signatures. -This plugin requires [golang](https://golang.org/dl/) with version `>= 1.16`. +Building above binaries requires [golang](https://golang.org/dl/) with version `>= 1.17`. ## Windows with WSL - Build the binaries, installing them to: - - `~/bin/nv2` + - `~/bin/notation` - `~/.docker/cli-plugins/docker-generate` - - `~/.docker/cli-plugins/docker-nv2` - ```shell - git clone https://github.com/notaryproject/nv2.git - cd nv2 - git checkout prototype-2 + - `~/.docker/cli-plugins/docker-notation` + ```sh + git clone https://github.com/notaryproject/notation.git + cd notation make install ``` - Verify binaries are installed - ```bash + ```sh docker --help # look for Management Commands: generate* Generate artifacts (github.com/shizhMSFT, 0.1.0) - nv2* Notary V2 Signature extension (Sajay Antony, Shiwei Zhang, 0.2.3) + notation* Manage signatures on Docker images (Sajay Antony, Shiwei Zhang, 0.5.1) - which nv2 + which notation # output - /home/]/bin/nv2 + /home/]/bin/notation ``` From 107767c8453c11096f081fa48e5bfcdd59a83586 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Mon, 6 Sep 2021 19:16:46 +0800 Subject: [PATCH 50/69] refine doc for building Signed-off-by: Shiwei Zhang --- building.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/building.md b/building.md index c09a83f57..1180f1974 100644 --- a/building.md +++ b/building.md @@ -2,11 +2,11 @@ The notation repo contains the following: -- `notation` - A CLI for signing and verifying with Notation +- `notation` - A CLI for signing and verifying artifacts with Notation - `docker-generate` - Extends docker with `docker generate` to create locally persisted manifest for signing, without having to push to a registry. - `docker-notation` - Extends docker with `docker notation` to enable, sign and verify Notation signatures. -Building above binaries requires [golang](https://golang.org/dl/) with version `>= 1.17`. +Building above binaries require [golang](https://golang.org/dl/) with version `>= 1.17`. ## Windows with WSL @@ -29,5 +29,5 @@ Building above binaries requires [golang](https://golang.org/dl/) with version ` which notation # output - /home/]/bin/notation + /home//bin/notation ``` From 07dada7f6f5eb607b43045c4c0989cf4476ec2d1 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Mon, 6 Sep 2021 19:16:54 +0800 Subject: [PATCH 51/69] plain http in config Signed-off-by: Shiwei Zhang --- cmd/notation/cache.go | 5 ++++- cmd/notation/manifest.go | 13 +++++++++++-- cmd/notation/pull.go | 6 +++++- cmd/notation/registry.go | 12 ++++++++++-- pkg/config/util.go | 10 +++------- pkg/registry/manifest.go | 7 +++---- pkg/registry/reference.go | 20 +++++++++++++++----- 7 files changed, 51 insertions(+), 22 deletions(-) diff --git a/cmd/notation/cache.go b/cmd/notation/cache.go index 4455030ed..f0a1637fb 100644 --- a/cmd/notation/cache.go +++ b/cmd/notation/cache.go @@ -217,7 +217,10 @@ func getManifestDigestFromContext(ctx *cli.Context, ref string) (manifestDigest return } - reference := registry.ParseReference(ref) + reference, err := registry.ParseReference(ref) + if err != nil { + return + } manifestDigest, err = reference.Digest() if err == nil { return diff --git a/cmd/notation/manifest.go b/cmd/notation/manifest.go index c5b290bb0..a0a917217 100644 --- a/cmd/notation/manifest.go +++ b/cmd/notation/manifest.go @@ -7,6 +7,7 @@ import ( "os" "github.com/notaryproject/notation-go-lib/signature" + "github.com/notaryproject/notation/pkg/config" "github.com/notaryproject/notation/pkg/registry" "github.com/opencontainers/go-digest" "github.com/urfave/cli/v2" @@ -32,14 +33,22 @@ func getManifestFromContextWithReference(ctx *cli.Context, ref string) (signatur return getManifestsFromReference(ctx, ref) } -func getManifestsFromReference(ctx *cli.Context, ref string) (signature.Manifest, error) { +func getManifestsFromReference(ctx *cli.Context, reference string) (signature.Manifest, error) { + ref, err := registry.ParseReference(reference) + if err != nil { + return signature.Manifest{}, err + } + plainHTTP := ctx.Bool(plainHTTPFlag.Name) + if !plainHTTP { + plainHTTP = config.IsRegistryInsecure(ref.Registry) + } remote := registry.NewClient( registry.NewAuthtransport( nil, ctx.String(usernameFlag.Name), ctx.String(passwordFlag.Name), ), - ctx.Bool(plainHTTPFlag.Name), + plainHTTP, ) return remote.GetManifestMetadata(ref) } diff --git a/cmd/notation/pull.go b/cmd/notation/pull.go index b60a9b0d1..03fd94b16 100644 --- a/cmd/notation/pull.go +++ b/cmd/notation/pull.go @@ -82,7 +82,11 @@ func runPull(ctx *cli.Context) error { } func pullSignatureStrict(ctx *cli.Context, sigRepo notation.SignatureRepository, reference string) error { - sigDigest, err := registry.ParseReference(reference).Digest() + ref, err := registry.ParseReference(reference) + if err != nil { + return err + } + sigDigest, err := ref.Digest() if err != nil { return fmt.Errorf("invalid signature digest: %v", err) } diff --git a/cmd/notation/registry.go b/cmd/notation/registry.go index ad861dc7e..6d56d8b20 100644 --- a/cmd/notation/registry.go +++ b/cmd/notation/registry.go @@ -3,12 +3,20 @@ package main import ( "github.com/notaryproject/notation-go-lib" registryn "github.com/notaryproject/notation-go-lib/registry" + "github.com/notaryproject/notation/pkg/config" "github.com/notaryproject/notation/pkg/registry" "github.com/urfave/cli/v2" ) func getSignatureRepository(ctx *cli.Context, reference string) (notation.SignatureRepository, error) { - ref := registry.ParseReference(reference) + ref, err := registry.ParseReference(reference) + if err != nil { + return nil, err + } + plainHTTP := ctx.Bool(plainHTTPFlag.Name) + if !plainHTTP { + plainHTTP = config.IsRegistryInsecure(ref.Registry) + } remote := registryn.NewClient( registry.NewAuthtransport( nil, @@ -16,7 +24,7 @@ func getSignatureRepository(ctx *cli.Context, reference string) (notation.Signat ctx.String(passwordFlag.Name), ), ref.Registry, - ctx.Bool(plainHTTPFlag.Name), + plainHTTP, ) return remote.Repository(ctx.Context, ref.Repository), nil } diff --git a/pkg/config/util.go b/pkg/config/util.go index 32abe6cf0..27b126c7d 100644 --- a/pkg/config/util.go +++ b/pkg/config/util.go @@ -2,7 +2,6 @@ package config import ( "errors" - "os" ) // ErrNotationDisabled indicates that notation is disabled @@ -10,12 +9,9 @@ var ErrNotationDisabled = errors.New("notation disabled") // CheckNotationEnabled checks the config file whether notation is enabled or not. func CheckNotationEnabled() error { - config, err := Load() + config, err := LoadOrDefaultOnce() if err != nil { - if !os.IsNotExist(err) { - return err - } - config = New() + return err } if config.Enabled { return nil @@ -25,7 +21,7 @@ func CheckNotationEnabled() error { // IsRegistryInsecure checks whether the registry is in the list of insecure registries. func IsRegistryInsecure(target string) bool { - config, err := Load() + config, err := LoadOrDefaultOnce() if err != nil { return false } diff --git a/pkg/registry/manifest.go b/pkg/registry/manifest.go index 386aeb6f0..703ecd0ea 100644 --- a/pkg/registry/manifest.go +++ b/pkg/registry/manifest.go @@ -19,8 +19,7 @@ var supportedMediaTypes = []string{ } // GetManifestMetadata returns signature manifest information -func (c *Client) GetManifestMetadata(reference string) (signature.Manifest, error) { - ref := ParseReference(reference) +func (c *Client) GetManifestMetadata(ref Reference) (signature.Manifest, error) { scheme := "https" if c.plainHTTP { scheme = "http" @@ -33,7 +32,7 @@ func (c *Client) GetManifestMetadata(reference string) (signature.Manifest, erro ) req, err := http.NewRequest(http.MethodHead, url, nil) if err != nil { - return signature.Manifest{}, fmt.Errorf("invalid reference: %v", reference) + return signature.Manifest{}, fmt.Errorf("invalid reference: %v", ref) } req.Header.Set("Connection", "close") for _, mediaType := range supportedMediaTypes { @@ -49,7 +48,7 @@ func (c *Client) GetManifestMetadata(reference string) (signature.Manifest, erro case http.StatusOK: // no op case http.StatusUnauthorized, http.StatusNotFound: - return signature.Manifest{}, fmt.Errorf("%v: %s", reference, resp.Status) + return signature.Manifest{}, fmt.Errorf("%v: %s", ref, resp.Status) default: return signature.Manifest{}, fmt.Errorf("%v: %s", url, resp.Status) } diff --git a/pkg/registry/reference.go b/pkg/registry/reference.go index 8647a21e6..c00348371 100644 --- a/pkg/registry/reference.go +++ b/pkg/registry/reference.go @@ -1,6 +1,7 @@ package registry import ( + "errors" "strings" "github.com/opencontainers/go-digest" @@ -20,12 +21,10 @@ type Reference struct { Reference string } -func ParseReference(raw string) Reference { +func ParseReference(raw string) (Reference, error) { parts := strings.SplitN(raw, "/", 2) if len(parts) == 1 { - return Reference{ - Registry: raw, - } + return Reference{}, errors.New("invalid reference") } registry, path := parts[0], parts[1] var repository string @@ -43,7 +42,7 @@ func ParseReference(raw string) Reference { Registry: registry, Repository: repository, Reference: reference, - } + }, nil } // Host returns the host name of the registry @@ -66,3 +65,14 @@ func (r Reference) ReferenceOrDefault() string { func (r Reference) Digest() (digest.Digest, error) { return digest.Parse(r.Reference) } + +func (r Reference) String() string { + ref := r.Registry + "/" + r.Repository + if r.Reference == "" { + return ref + } + if d, err := r.Digest(); err != nil { + return ref + "@" + d.String() + } + return ref + ":" + r.Reference +} From 9c5c74920db7589c3701876732bc9a652f6bbf12 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Mon, 6 Sep 2021 20:52:00 +0800 Subject: [PATCH 52/69] no default trust on generated cert Signed-off-by: Shiwei Zhang --- cmd/notation/cert.go | 6 +++++- cmd/notation/cert_gen.go | 12 +++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/cmd/notation/cert.go b/cmd/notation/cert.go index 0b0a969f4..fbcedd892 100644 --- a/cmd/notation/cert.go +++ b/cmd/notation/cert.go @@ -47,7 +47,7 @@ var ( certRemoveCommand = &cli.Command{ Name: "remove", - Usage: "Remove certificate from verification list", + Usage: "Remove certificate from the verification list", Aliases: []string{"rm"}, ArgsUsage: " ...", Action: removeCerts, @@ -75,6 +75,10 @@ var ( Usage: "certificate expiry", Value: 365 * 24 * time.Hour, }, + &cli.BoolFlag{ + Name: "trust", + Usage: "add the generated certificate to the verification list", + }, keyDefaultFlag, }, Action: generateTestCert, diff --git a/cmd/notation/cert_gen.go b/cmd/notation/cert_gen.go index b968ad8ce..a6f6c810e 100644 --- a/cmd/notation/cert_gen.go +++ b/cmd/notation/cert_gen.go @@ -67,18 +67,24 @@ func generateTestCert(ctx *cli.Context) error { if err != nil { return err } - if err := addCertCore(cfg, name, certPath); err != nil { - return err + trust := ctx.Bool("trust") + if trust { + if err := addCertCore(cfg, name, certPath); err != nil { + return err + } } if err := cfg.Save(); err != nil { return err } // write out - fmt.Printf("%s: added to key and certificate lists\n", name) + fmt.Printf("%s: added to the key list\n", name) if isDefaultKey { fmt.Printf("%s: marked as default\n", name) } + if trust { + fmt.Printf("%s: added to the certificate list\n", name) + } return nil } From 35ea92333d4072f51ab12d43bf4457d26fa4d9cc Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Tue, 7 Sep 2021 14:27:23 +0800 Subject: [PATCH 53/69] clean up media type Signed-off-by: Shiwei Zhang --- pkg/registry/manifest.go | 6 ++++-- pkg/registry/mediatype.go | 7 ------- 2 files changed, 4 insertions(+), 9 deletions(-) delete mode 100644 pkg/registry/mediatype.go diff --git a/pkg/registry/manifest.go b/pkg/registry/manifest.go index 703ecd0ea..9b4ef99f7 100644 --- a/pkg/registry/manifest.go +++ b/pkg/registry/manifest.go @@ -5,14 +5,16 @@ import ( "net/http" "strconv" + "github.com/distribution/distribution/v3/manifest/manifestlist" + "github.com/distribution/distribution/v3/manifest/schema2" "github.com/notaryproject/notation-go-lib/signature" ocispec "github.com/opencontainers/image-spec/specs-go/v1" artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1" ) var supportedMediaTypes = []string{ - MediaTypeManifestList, - MediaTypeManifest, + manifestlist.MediaTypeManifestList, + schema2.MediaTypeManifest, ocispec.MediaTypeImageIndex, ocispec.MediaTypeImageManifest, artifactspec.MediaTypeArtifactManifest, diff --git a/pkg/registry/mediatype.go b/pkg/registry/mediatype.go deleted file mode 100644 index a21335ef6..000000000 --- a/pkg/registry/mediatype.go +++ /dev/null @@ -1,7 +0,0 @@ -package registry - -// docker media types -const ( - MediaTypeManifestList = "application/vnd.docker.distribution.manifest.list.v2+json" - MediaTypeManifest = "application/vnd.docker.distribution.manifest.v2+json" -) From 913848d48c7c5614e691319307d3f9c14d0f48e7 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Tue, 7 Sep 2021 15:45:49 +0800 Subject: [PATCH 54/69] refine docker-notation Signed-off-by: Shiwei Zhang --- cmd/docker-notation/notation.go | 28 ---------------- cmd/docker-notation/pull.go | 8 ++--- cmd/docker-notation/push.go | 8 ++--- cmd/docker-notation/sign.go | 59 +++++++++++++++++++++++---------- cmd/docker-notation/util.go | 20 +---------- cmd/notation/sign.go | 20 ++--------- pkg/config/config.go | 1 - pkg/config/util.go | 53 ++++++++++++++++++++--------- 8 files changed, 87 insertions(+), 110 deletions(-) diff --git a/cmd/docker-notation/notation.go b/cmd/docker-notation/notation.go index c5f02a14b..7cbb396b2 100644 --- a/cmd/docker-notation/notation.go +++ b/cmd/docker-notation/notation.go @@ -1,9 +1,6 @@ package main import ( - "os" - - "github.com/notaryproject/notation/pkg/config" "github.com/urfave/cli/v2" ) @@ -15,29 +12,4 @@ var notationCommand = &cli.Command{ pushCommand, signCommand, }, - Flags: []cli.Flag{ - notationEnabledFlag, - }, - Action: setNotation, -} - -var notationEnabledFlag = &cli.BoolFlag{ - Name: "enabled", - Usage: "Enable Notation support", -} - -func setNotation(ctx *cli.Context) error { - if !ctx.IsSet(notationEnabledFlag.Name) { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - - cfg, err := config.Load() - if err != nil { - if !os.IsNotExist(err) { - return err - } - cfg = config.New() - } - cfg.Enabled = ctx.Bool(notationEnabledFlag.Name) - return cfg.Save() } diff --git a/cmd/docker-notation/pull.go b/cmd/docker-notation/pull.go index d93038294..499e2d3f0 100644 --- a/cmd/docker-notation/pull.go +++ b/cmd/docker-notation/pull.go @@ -18,16 +18,12 @@ import ( var pullCommand = &cli.Command{ Name: "pull", - Usage: "Pull an image or a repository from a registry", - ArgsUsage: "[]", + Usage: "Verify and pull an image from a registry", + ArgsUsage: "", Action: pullImage, } func pullImage(ctx *cli.Context) error { - if err := passThroughIfNotationDisabled(ctx); err != nil { - return err - } - originalRef := ctx.Args().First() ref, err := verifyRemoteImage(ctx.Context, originalRef) if err != nil { diff --git a/cmd/docker-notation/push.go b/cmd/docker-notation/push.go index 8c84a8a14..642ef6bd0 100644 --- a/cmd/docker-notation/push.go +++ b/cmd/docker-notation/push.go @@ -20,16 +20,12 @@ import ( var pushCommand = &cli.Command{ Name: "push", - Usage: "Push an image or a repository to a registry", - ArgsUsage: "[]", + Usage: "Push an image to a registry with its signatures", + ArgsUsage: "", Action: pushImage, } func pushImage(ctx *cli.Context) error { - if err := passThroughIfNotationDisabled(ctx); err != nil { - return err - } - desc, err := pushImageAndGetOCIDescriptor(ctx) if err != nil { return err diff --git a/cmd/docker-notation/sign.go b/cmd/docker-notation/sign.go index 44bd98153..6733b4577 100644 --- a/cmd/docker-notation/sign.go +++ b/cmd/docker-notation/sign.go @@ -3,6 +3,7 @@ package main import ( "fmt" + "github.com/notaryproject/notation-go-lib" "github.com/notaryproject/notation/cmd/docker-notation/crypto" "github.com/notaryproject/notation/cmd/docker-notation/docker" ios "github.com/notaryproject/notation/internal/os" @@ -13,20 +14,27 @@ import ( var signCommand = &cli.Command{ Name: "sign", - Usage: "Sign a docker image", - ArgsUsage: "[]", + Usage: "Sign a image", + ArgsUsage: "", Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "key", + Aliases: []string{"k"}, + Usage: "signing key name", + }, &cli.PathFlag{ - Name: "key", - Aliases: []string{"k"}, + Name: "key-file", Usage: "signing key file", TakesFile: true, - Required: true, }, - &cli.PathFlag{ - Name: "cert", - Aliases: []string{"c"}, - Usage: "signing cert", + &cli.StringFlag{ + Name: "cert", + Aliases: []string{"c"}, + Usage: "signing certificate name", + }, + &cli.StringFlag{ + Name: "cert-file", + Usage: "signing certificate file", TakesFile: true, }, &cli.StringSliceFlag{ @@ -43,14 +51,7 @@ var signCommand = &cli.Command{ } func signImage(ctx *cli.Context) error { - if err := config.CheckNotationEnabled(); err != nil { - return err - } - - service, err := crypto.GetSigningService( - ctx.Path("key"), - ctx.Path("cert"), - ) + service, err := getSigningService(ctx) if err != nil { return err } @@ -80,3 +81,27 @@ func signImage(ctx *cli.Context) error { return nil } + +func getSigningService(ctx *cli.Context) (notation.SigningService, error) { + keyPath := ctx.String("key-file") + if keyPath == "" { + path, err := config.ResolveKeyPath(ctx.String("key")) + if err != nil { + return nil, err + } + keyPath = path + } + + var certPaths []string + if path := ctx.String("cert-file"); path != "" { + certPaths = []string{path} + } else if name := ctx.String("cert"); name != "" { + path, err := config.ResolveCertificatePath(name) + if err != nil { + return nil, err + } + certPaths = []string{path} + } + + return crypto.GetSigningService(keyPath, certPaths...) +} diff --git a/cmd/docker-notation/util.go b/cmd/docker-notation/util.go index a3e7b0804..3aaade892 100644 --- a/cmd/docker-notation/util.go +++ b/cmd/docker-notation/util.go @@ -7,26 +7,8 @@ import ( "github.com/notaryproject/notation-go-lib" "github.com/notaryproject/notation/cmd/docker-notation/crypto" "github.com/notaryproject/notation/pkg/config" - "github.com/urfave/cli/v2" ) -func passThroughIfNotationDisabled(ctx *cli.Context) error { - err := config.CheckNotationEnabled() - if err == nil { - return nil - } - if err != config.ErrNotationDisabled { - return err - } - - args := append([]string{ctx.Command.Name}, ctx.Args().Slice()...) - if err := runCommand("docker", args...); err != nil { - return err - } - os.Exit(0) - panic("process should be terminated") -} - func runCommand(command string, args ...string) error { cmd := exec.Command(command, args...) cmd.Stdin = os.Stdin @@ -42,7 +24,7 @@ func runCommand(command string, args ...string) error { } func getVerificationService() (notation.SigningService, error) { - cfg, err := config.Load() + cfg, err := config.LoadOrDefaultOnce() if err != nil { return nil, err } diff --git a/cmd/notation/sign.go b/cmd/notation/sign.go index be25b991b..1502753ff 100644 --- a/cmd/notation/sign.go +++ b/cmd/notation/sign.go @@ -1,7 +1,6 @@ package main import ( - "errors" "fmt" "time" @@ -134,33 +133,20 @@ func prepareClaimsForSigning(ctx *cli.Context) (signature.Claims, error) { func getSchemeForSigning(ctx *cli.Context) (*signature.Scheme, error) { keyPath := ctx.String("key-file") if keyPath == "" { - cfg, err := config.LoadOrDefaultOnce() + path, err := config.ResolveKeyPath(ctx.String("key")) if err != nil { return nil, err } - name := ctx.String("key") - if name == "" { - name = cfg.SigningKeys.Default - } - path, ok := cfg.SigningKeys.Keys.Get(name) - if !ok { - return nil, errors.New("signing key not found") - } keyPath = path } certPath := ctx.String("cert-file") if certPath == "" { - name := ctx.String("cert") - if name != "" { - cfg, err := config.LoadOrDefaultOnce() + if name := ctx.String("cert"); name != "" { + path, err := config.ResolveCertificatePath(name) if err != nil { return nil, err } - path, ok := cfg.VerificationCertificates.Certificates.Get(name) - if !ok { - return nil, errors.New("certificate not found") - } certPath = path } } diff --git a/pkg/config/config.go b/pkg/config/config.go index cb968b17e..ba02b6f2b 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -9,7 +9,6 @@ import ( // File reflects the config file. // Specification: https://github.com/notaryproject/notation/pull/76 type File struct { - Enabled bool `json:"enabled"` VerificationCertificates VerificationCertificates `json:"verificationCerts"` SigningKeys SigningKeys `json:"signingKeys,omitempty"` InsecureRegistries []string `json:"insecureRegistries"` diff --git a/pkg/config/util.go b/pkg/config/util.go index 27b126c7d..8bc07b6f1 100644 --- a/pkg/config/util.go +++ b/pkg/config/util.go @@ -1,23 +1,14 @@ package config -import ( - "errors" -) +import "errors" -// ErrNotationDisabled indicates that notation is disabled -var ErrNotationDisabled = errors.New("notation disabled") +var ( + // ErrKeyNotFound indicates that the signing key is not found. + ErrKeyNotFound = errors.New("signing key not found") -// CheckNotationEnabled checks the config file whether notation is enabled or not. -func CheckNotationEnabled() error { - config, err := LoadOrDefaultOnce() - if err != nil { - return err - } - if config.Enabled { - return nil - } - return ErrNotationDisabled -} + // ErrCertificateNotFound indicates that the verification certificate is not found. + ErrCertificateNotFound = errors.New("verification certificate not found") +) // IsRegistryInsecure checks whether the registry is in the list of insecure registries. func IsRegistryInsecure(target string) bool { @@ -32,3 +23,33 @@ func IsRegistryInsecure(target string) bool { } return false } + +// ResolveKeyPath resolves the key path by name. +// The default key is attempted if name is empty. +func ResolveKeyPath(name string) (string, error) { + config, err := LoadOrDefaultOnce() + if err != nil { + return "", err + } + if name == "" { + name = config.SigningKeys.Default + } + path, ok := config.SigningKeys.Keys.Get(name) + if !ok { + return "", ErrKeyNotFound + } + return path, nil +} + +// ResolveCertificatePath resolves the certificate path by name. +func ResolveCertificatePath(name string) (string, error) { + config, err := LoadOrDefaultOnce() + if err != nil { + return "", err + } + path, ok := config.VerificationCertificates.Certificates.Get(name) + if !ok { + return "", ErrCertificateNotFound + } + return path, nil +} From 601f2356157a777063b4c196b14e6a1d09c82e68 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Tue, 7 Sep 2021 16:12:19 +0800 Subject: [PATCH 55/69] cached pull Signed-off-by: Shiwei Zhang --- cmd/docker-notation/pull.go | 15 ++------------- cmd/notation/pull.go | 35 +++++++++++++++-------------------- pkg/cache/pull.go | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 33 deletions(-) create mode 100644 pkg/cache/pull.go diff --git a/cmd/docker-notation/pull.go b/cmd/docker-notation/pull.go index 499e2d3f0..4f99a80c3 100644 --- a/cmd/docker-notation/pull.go +++ b/cmd/docker-notation/pull.go @@ -9,7 +9,7 @@ import ( "github.com/distribution/distribution/v3/reference" "github.com/notaryproject/notation-go-lib" "github.com/notaryproject/notation/cmd/docker-notation/docker" - ios "github.com/notaryproject/notation/internal/os" + "github.com/notaryproject/notation/pkg/cache" "github.com/notaryproject/notation/pkg/config" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" @@ -98,18 +98,7 @@ func downloadSignatures(ctx context.Context, ref string, manifestDigest digest.D } for _, sigDigest := range sigDigests { - sigPath := config.SignaturePath(manifestDigest, sigDigest) - if _, err := os.Stat(sigPath); err == nil { - continue - } else if !os.IsNotExist(err) { - return nil, err - } - - sig, err := client.Get(ctx, sigDigest) - if err != nil { - return nil, err - } - if err := ios.WriteFile(sigPath, sig); err != nil { + if err := cache.PullSignature(ctx, client, manifestDigest, sigDigest); err != nil { return nil, err } } diff --git a/cmd/notation/pull.go b/cmd/notation/pull.go index 03fd94b16..18a9df8ba 100644 --- a/cmd/notation/pull.go +++ b/cmd/notation/pull.go @@ -7,6 +7,7 @@ import ( "github.com/notaryproject/notation-go-lib" "github.com/notaryproject/notation/internal/os" + "github.com/notaryproject/notation/pkg/cache" "github.com/notaryproject/notation/pkg/config" "github.com/notaryproject/notation/pkg/registry" "github.com/opencontainers/go-digest" @@ -20,7 +21,7 @@ var pullCommand = &cli.Command{ Flags: []cli.Flag{ &cli.BoolFlag{ Name: "strict", - Usage: "strict pull without lookup", + Usage: "pull the signature without lookup the manifest", }, outputFlag, usernameFlag, @@ -60,18 +61,17 @@ func runPull(ctx *cli.Context) error { path := ctx.String(outputFlag.Name) for _, sigDigest := range sigDigests { - sig, err := sigRepo.Get(ctx.Context, sigDigest) - if err != nil { - return fmt.Errorf("get signature failure: %v: %v", sigDigest, err) - } - var outputPath string - if path == "" { - outputPath = config.SignaturePath(manifestDesc.Digest, sigDigest) - } else { - outputPath = filepath.Join(path, sigDigest.Encoded()+config.SignatureExtension) - } - if err := os.WriteFile(outputPath, sig); err != nil { - return fmt.Errorf("fail to write signature: %v: %v", sigDigest, err) + if path != "" { + outputPath := filepath.Join(path, sigDigest.Encoded()+config.SignatureExtension) + sig, err := sigRepo.Get(ctx.Context, sigDigest) + if err != nil { + return fmt.Errorf("get signature failure: %v: %v", sigDigest, err) + } + if err := os.WriteFile(outputPath, sig); err != nil { + return fmt.Errorf("fail to write signature: %v: %v", sigDigest, err) + } + } else if err := cache.PullSignature(ctx.Context, sigRepo, manifestDesc.Digest, sigDigest); err != nil { + return err } // write out @@ -120,13 +120,8 @@ func pullSignatures(ctx *cli.Context, manifestDigest digest.Digest) error { return fmt.Errorf("lookup signature failure: %v", err) } for _, sigDigest := range sigDigests { - sig, err := sigRepo.Get(ctx.Context, sigDigest) - if err != nil { - return fmt.Errorf("get signature failure: %v: %v", sigDigest, err) - } - outputPath := config.SignaturePath(manifestDigest, sigDigest) - if err := os.WriteFile(outputPath, sig); err != nil { - return fmt.Errorf("fail to write signature: %v: %v", sigDigest, err) + if err := cache.PullSignature(ctx.Context, sigRepo, manifestDigest, sigDigest); err != nil { + return err } } return nil diff --git a/pkg/cache/pull.go b/pkg/cache/pull.go new file mode 100644 index 000000000..d84485d04 --- /dev/null +++ b/pkg/cache/pull.go @@ -0,0 +1,36 @@ +package cache + +import ( + "context" + "errors" + "fmt" + "os" + + "github.com/notaryproject/notation-go-lib" + ios "github.com/notaryproject/notation/internal/os" + "github.com/notaryproject/notation/pkg/config" + "github.com/opencontainers/go-digest" +) + +// PullSignature pulls the signature if not exists in the cache. +func PullSignature(ctx context.Context, sigRepo notation.SignatureRepository, manifestDigest, sigDigest digest.Digest) error { + sigPath := config.SignaturePath(manifestDigest, sigDigest) + if info, err := os.Stat(sigPath); err == nil { + if info.IsDir() { + return errors.New("found directory at the signature file path: " + sigPath) + } + return nil + } else if !os.IsNotExist(err) { + return err + } + + // fetch remote if not cached + sig, err := sigRepo.Get(ctx, sigDigest) + if err != nil { + return fmt.Errorf("get signature failure: %v: %v", sigDigest, err) + } + if err := ios.WriteFile(sigPath, sig); err != nil { + return fmt.Errorf("fail to write signature: %v: %v", sigDigest, err) + } + return nil +} From 94b55d5cd85cedb81911898319e09140cc8705cb Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Tue, 7 Sep 2021 17:03:15 +0800 Subject: [PATCH 56/69] refactor notation code Signed-off-by: Shiwei Zhang --- cmd/notation/cache.go | 2 +- cmd/notation/list.go | 4 +--- cmd/notation/manifest.go | 42 ++++++++++++++++++-------------------- cmd/notation/pull.go | 3 +-- cmd/notation/push.go | 7 ++----- cmd/notation/sign.go | 17 ++++++++++++--- cmd/notation/verify.go | 18 ++++++++-------- pkg/registry/descriptor.go | 15 -------------- pkg/registry/manifest.go | 40 +++++++++++++++++++----------------- 9 files changed, 70 insertions(+), 78 deletions(-) delete mode 100644 pkg/registry/descriptor.go diff --git a/cmd/notation/cache.go b/cmd/notation/cache.go index f0a1637fb..aeecc69fb 100644 --- a/cmd/notation/cache.go +++ b/cmd/notation/cache.go @@ -226,7 +226,7 @@ func getManifestDigestFromContext(ctx *cli.Context, ref string) (manifestDigest return } - manifest, err := getManifestFromContextWithReference(ctx, ref) + manifest, err := getManifestDescriptorFromContextWithReference(ctx, ref) if err != nil { return } diff --git a/cmd/notation/list.go b/cmd/notation/list.go index 1b067f9ef..7c519e728 100644 --- a/cmd/notation/list.go +++ b/cmd/notation/list.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" - "github.com/notaryproject/notation/pkg/registry" "github.com/urfave/cli/v2" ) @@ -34,11 +33,10 @@ func runList(ctx *cli.Context) error { } // core process - manifest, err := getManifestsFromReference(ctx, reference) + manifestDesc, err := getManifestDescriptorFromReference(ctx, reference) if err != nil { return err } - manifestDesc := registry.OCIDescriptorFromNotation(manifest.Descriptor) sigDigests, err := sigRepo.Lookup(ctx.Context, manifestDesc.Digest) if err != nil { diff --git a/cmd/notation/manifest.go b/cmd/notation/manifest.go index a0a917217..2486f0308 100644 --- a/cmd/notation/manifest.go +++ b/cmd/notation/manifest.go @@ -6,37 +6,37 @@ import ( "math" "os" - "github.com/notaryproject/notation-go-lib/signature" "github.com/notaryproject/notation/pkg/config" "github.com/notaryproject/notation/pkg/registry" "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/urfave/cli/v2" ) -func getManifestFromContext(ctx *cli.Context) (signature.Manifest, error) { +func getManifestDescriptorFromContext(ctx *cli.Context) (ocispec.Descriptor, error) { ref := ctx.Args().First() if ref == "" { - return signature.Manifest{}, errors.New("missing reference") + return ocispec.Descriptor{}, errors.New("missing reference") } - return getManifestFromContextWithReference(ctx, ref) + return getManifestDescriptorFromContextWithReference(ctx, ref) } -func getManifestFromContextWithReference(ctx *cli.Context, ref string) (signature.Manifest, error) { +func getManifestDescriptorFromContextWithReference(ctx *cli.Context, ref string) (ocispec.Descriptor, error) { if ctx.Bool(localFlag.Name) { mediaType := ctx.String(mediaTypeFlag.Name) if ref == "-" { - return getManifestFromReader(os.Stdin, mediaType) + return getManifestDescriptorFromReader(os.Stdin, mediaType) } - return getManifestsFromFile(ref, mediaType) + return getManifestDescriptorFromFile(ref, mediaType) } - return getManifestsFromReference(ctx, ref) + return getManifestDescriptorFromReference(ctx, ref) } -func getManifestsFromReference(ctx *cli.Context, reference string) (signature.Manifest, error) { +func getManifestDescriptorFromReference(ctx *cli.Context, reference string) (ocispec.Descriptor, error) { ref, err := registry.ParseReference(reference) if err != nil { - return signature.Manifest{}, err + return ocispec.Descriptor{}, err } plainHTTP := ctx.Bool(plainHTTPFlag.Name) if !plainHTTP { @@ -50,32 +50,30 @@ func getManifestsFromReference(ctx *cli.Context, reference string) (signature.Ma ), plainHTTP, ) - return remote.GetManifestMetadata(ref) + return remote.GetManifestDescriptor(ref) } -func getManifestsFromFile(path, mediaType string) (signature.Manifest, error) { +func getManifestDescriptorFromFile(path, mediaType string) (ocispec.Descriptor, error) { file, err := os.Open(path) if err != nil { - return signature.Manifest{}, err + return ocispec.Descriptor{}, err } defer file.Close() - return getManifestFromReader(file, mediaType) + return getManifestDescriptorFromReader(file, mediaType) } -func getManifestFromReader(r io.Reader, mediaType string) (signature.Manifest, error) { +func getManifestDescriptorFromReader(r io.Reader, mediaType string) (ocispec.Descriptor, error) { lr := &io.LimitedReader{ R: r, N: math.MaxInt64, } digest, err := digest.SHA256.FromReader(lr) if err != nil { - return signature.Manifest{}, err + return ocispec.Descriptor{}, err } - return signature.Manifest{ - Descriptor: signature.Descriptor{ - MediaType: mediaType, - Digest: digest.String(), - Size: math.MaxInt64 - lr.N, - }, + return ocispec.Descriptor{ + MediaType: mediaType, + Digest: digest, + Size: math.MaxInt64 - lr.N, }, nil } diff --git a/cmd/notation/pull.go b/cmd/notation/pull.go index 18a9df8ba..2667683d9 100644 --- a/cmd/notation/pull.go +++ b/cmd/notation/pull.go @@ -48,11 +48,10 @@ func runPull(ctx *cli.Context) error { return pullSignatureStrict(ctx, sigRepo, reference) } - manifest, err := getManifestsFromReference(ctx, reference) + manifestDesc, err := getManifestDescriptorFromReference(ctx, reference) if err != nil { return err } - manifestDesc := registry.OCIDescriptorFromNotation(manifest.Descriptor) sigDigests, err := sigRepo.Lookup(ctx.Context, manifestDesc.Digest) if err != nil { diff --git a/cmd/notation/push.go b/cmd/notation/push.go index 5990b6b5b..e76584b8a 100644 --- a/cmd/notation/push.go +++ b/cmd/notation/push.go @@ -6,7 +6,6 @@ import ( "os" "github.com/notaryproject/notation/pkg/config" - "github.com/notaryproject/notation/pkg/registry" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/urfave/cli/v2" ) @@ -30,11 +29,10 @@ func runPush(ctx *cli.Context) error { return errors.New("no reference specified") } ref := ctx.Args().First() - manifest, err := getManifestsFromReference(ctx, ref) + manifestDesc, err := getManifestDescriptorFromReference(ctx, ref) if err != nil { return err } - manifestDesc := registry.OCIDescriptorFromNotation(manifest.Descriptor) sigPaths := ctx.StringSlice(signatureFlag.Name) if len(sigPaths) == 0 { sigDigests, err := config.SignatureDigests(manifestDesc.Digest) @@ -78,11 +76,10 @@ func pushSignature(ctx *cli.Context, ref string, sig []byte) (ocispec.Descriptor if err != nil { return ocispec.Descriptor{}, err } - manifest, err := getManifestsFromReference(ctx, ref) + manifestDesc, err := getManifestDescriptorFromReference(ctx, ref) if err != nil { return ocispec.Descriptor{}, err } - manifestDesc := registry.OCIDescriptorFromNotation(manifest.Descriptor) // core process sigDesc, err := sigRepo.Put(ctx.Context, sig) diff --git a/cmd/notation/sign.go b/cmd/notation/sign.go index 1502753ff..12a752225 100644 --- a/cmd/notation/sign.go +++ b/cmd/notation/sign.go @@ -9,6 +9,7 @@ import ( "github.com/notaryproject/notation/internal/os" "github.com/notaryproject/notation/pkg/config" "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/urfave/cli/v2" ) @@ -111,15 +112,17 @@ func runSign(ctx *cli.Context) error { } func prepareClaimsForSigning(ctx *cli.Context) (signature.Claims, error) { - manifest, err := getManifestFromContext(ctx) + manifestDesc, err := getManifestDescriptorFromContext(ctx) if err != nil { return signature.Claims{}, err } - manifest.References = ctx.StringSlice("reference") now := time.Now() nowUnix := now.Unix() claims := signature.Claims{ - Manifest: manifest, + Manifest: signature.Manifest{ + Descriptor: convertDescriptorToNotation(manifestDesc), + References: ctx.StringSlice("reference"), + }, IssuedAt: nowUnix, } if expiry := ctx.Duration("expiry"); expiry != 0 { @@ -159,3 +162,11 @@ func getSchemeForSigning(ctx *cli.Context) (*signature.Scheme, error) { scheme.RegisterSigner("", signer) return scheme, nil } + +func convertDescriptorToNotation(desc ocispec.Descriptor) signature.Descriptor { + return signature.Descriptor{ + MediaType: desc.MediaType, + Digest: desc.Digest.String(), + Size: desc.Size, + } +} diff --git a/cmd/notation/verify.go b/cmd/notation/verify.go index 199d71f95..d3d656f77 100644 --- a/cmd/notation/verify.go +++ b/cmd/notation/verify.go @@ -10,6 +10,7 @@ import ( x509n "github.com/notaryproject/notation-go-lib/signature/x509" "github.com/notaryproject/notation/pkg/config" "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/urfave/cli/v2" ) @@ -58,7 +59,7 @@ func runVerify(ctx *cli.Context) error { if err != nil { return err } - manifest, err := getManifestFromContext(ctx) + manifestDesc, err := getManifestDescriptorFromContext(ctx) if err != nil { return err } @@ -66,11 +67,11 @@ func runVerify(ctx *cli.Context) error { sigPaths := ctx.StringSlice(signatureFlag.Name) if len(sigPaths) == 0 { if !ctx.Bool(localFlag.Name) && ctx.Bool("pull") { - if err := pullSignatures(ctx, digest.Digest(manifest.Digest)); err != nil { + if err := pullSignatures(ctx, digest.Digest(manifestDesc.Digest)); err != nil { return err } } - manifestDigest := digest.Digest(manifest.Digest) + manifestDigest := digest.Digest(manifestDesc.Digest) sigDigests, err := config.SignatureDigests(manifestDigest) if err != nil { return err @@ -81,16 +82,16 @@ func runVerify(ctx *cli.Context) error { } // core process - if err := verifySignatures(scheme, manifest, sigPaths); err != nil { + if err := verifySignatures(scheme, manifestDesc, sigPaths); err != nil { return err } // write out - fmt.Println(manifest.Digest) + fmt.Println(manifestDesc.Digest) return nil } -func verifySignatures(scheme *signature.Scheme, manifest signature.Manifest, sigPaths []string) error { +func verifySignatures(scheme *signature.Scheme, manifestDesc ocispec.Descriptor, sigPaths []string) error { if len(sigPaths) == 0 { return errors.New("verification failure: no signatures found") } @@ -106,8 +107,9 @@ func verifySignatures(scheme *signature.Scheme, manifest signature.Manifest, sig lastErr = fmt.Errorf("verification failure: %v", err) continue } - if manifest.Descriptor != claims.Manifest.Descriptor { - lastErr = fmt.Errorf("verification failure: %s", manifest.Digest) + + if convertDescriptorToNotation(manifestDesc) != claims.Manifest.Descriptor { + lastErr = fmt.Errorf("verification failure: %s", manifestDesc.Digest) continue } return nil diff --git a/pkg/registry/descriptor.go b/pkg/registry/descriptor.go deleted file mode 100644 index eaa88643a..000000000 --- a/pkg/registry/descriptor.go +++ /dev/null @@ -1,15 +0,0 @@ -package registry - -import ( - "github.com/notaryproject/notation-go-lib/signature" - digest "github.com/opencontainers/go-digest" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" -) - -func OCIDescriptorFromNotation(desc signature.Descriptor) ocispec.Descriptor { - return ocispec.Descriptor{ - MediaType: desc.MediaType, - Digest: digest.Digest(desc.Digest), - Size: desc.Size, - } -} diff --git a/pkg/registry/manifest.go b/pkg/registry/manifest.go index 9b4ef99f7..f4248eb43 100644 --- a/pkg/registry/manifest.go +++ b/pkg/registry/manifest.go @@ -7,7 +7,7 @@ import ( "github.com/distribution/distribution/v3/manifest/manifestlist" "github.com/distribution/distribution/v3/manifest/schema2" - "github.com/notaryproject/notation-go-lib/signature" + digest "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1" ) @@ -20,8 +20,8 @@ var supportedMediaTypes = []string{ artifactspec.MediaTypeArtifactManifest, } -// GetManifestMetadata returns signature manifest information -func (c *Client) GetManifestMetadata(ref Reference) (signature.Manifest, error) { +// GetManifestDescriptor returns signature manifest information +func (c *Client) GetManifestDescriptor(ref Reference) (ocispec.Descriptor, error) { scheme := "https" if c.plainHTTP { scheme = "http" @@ -34,7 +34,7 @@ func (c *Client) GetManifestMetadata(ref Reference) (signature.Manifest, error) ) req, err := http.NewRequest(http.MethodHead, url, nil) if err != nil { - return signature.Manifest{}, fmt.Errorf("invalid reference: %v", ref) + return ocispec.Descriptor{}, fmt.Errorf("invalid reference: %v", ref) } req.Header.Set("Connection", "close") for _, mediaType := range supportedMediaTypes { @@ -43,40 +43,42 @@ func (c *Client) GetManifestMetadata(ref Reference) (signature.Manifest, error) resp, err := c.base.RoundTrip(req) if err != nil { - return signature.Manifest{}, fmt.Errorf("%v: %v", url, err) + return ocispec.Descriptor{}, fmt.Errorf("%v: %v", url, err) } resp.Body.Close() switch resp.StatusCode { case http.StatusOK: // no op case http.StatusUnauthorized, http.StatusNotFound: - return signature.Manifest{}, fmt.Errorf("%v: %s", ref, resp.Status) + return ocispec.Descriptor{}, fmt.Errorf("%v: %s", ref, resp.Status) default: - return signature.Manifest{}, fmt.Errorf("%v: %s", url, resp.Status) + return ocispec.Descriptor{}, fmt.Errorf("%v: %s", url, resp.Status) } header := resp.Header mediaType := header.Get("Content-Type") if mediaType == "" { - return signature.Manifest{}, fmt.Errorf("%v: missing Content-Type", url) + return ocispec.Descriptor{}, fmt.Errorf("%v: missing Content-Type", url) } - digest := header.Get("Docker-Content-Digest") - if digest == "" { - return signature.Manifest{}, fmt.Errorf("%v: missing Docker-Content-Digest", url) + contentDigest := header.Get("Docker-Content-Digest") + if contentDigest == "" { + return ocispec.Descriptor{}, fmt.Errorf("%v: missing Docker-Content-Digest", url) + } + parsedDigest, err := digest.Parse(contentDigest) + if err != nil { + return ocispec.Descriptor{}, fmt.Errorf("%v: invalid Docker-Content-Digest: %s", url, contentDigest) } length := header.Get("Content-Length") if length == "" { - return signature.Manifest{}, fmt.Errorf("%v: missing Content-Length", url) + return ocispec.Descriptor{}, fmt.Errorf("%v: missing Content-Length", url) } size, err := strconv.ParseInt(length, 10, 64) if err != nil { - return signature.Manifest{}, fmt.Errorf("%v: invalid Content-Length", url) + return ocispec.Descriptor{}, fmt.Errorf("%v: invalid Content-Length", url) } - return signature.Manifest{ - Descriptor: signature.Descriptor{ - MediaType: mediaType, - Digest: digest, - Size: size, - }, + return ocispec.Descriptor{ + MediaType: mediaType, + Digest: parsedDigest, + Size: size, }, nil } From 7ac7bfb3e347c0b2f878cb9b95f97f59f650f50a Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Tue, 7 Sep 2021 17:33:02 +0800 Subject: [PATCH 57/69] fix reference print Signed-off-by: Shiwei Zhang --- pkg/registry/reference.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/registry/reference.go b/pkg/registry/reference.go index c00348371..e09a9c41f 100644 --- a/pkg/registry/reference.go +++ b/pkg/registry/reference.go @@ -71,7 +71,7 @@ func (r Reference) String() string { if r.Reference == "" { return ref } - if d, err := r.Digest(); err != nil { + if d, err := r.Digest(); err == nil { return ref + "@" + d.String() } return ref + ":" + r.Reference From bd80447d83a708e24b6c8e3360a431ef485a0324 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Tue, 7 Sep 2021 17:33:51 +0800 Subject: [PATCH 58/69] refactor docker-notation code Signed-off-by: Shiwei Zhang --- cmd/docker-notation/docker/manifest.go | 80 +++----------------------- cmd/docker-notation/pull.go | 18 ++---- 2 files changed, 14 insertions(+), 84 deletions(-) diff --git a/cmd/docker-notation/docker/manifest.go b/cmd/docker-notation/docker/manifest.go index 952e61db9..c0c92df5a 100644 --- a/cmd/docker-notation/docker/manifest.go +++ b/cmd/docker-notation/docker/manifest.go @@ -2,16 +2,13 @@ package docker import ( "context" - "fmt" "net" - "net/http" "os/exec" - "strconv" - "strings" "github.com/distribution/distribution/v3/manifest/schema2" "github.com/notaryproject/notation/pkg/config" "github.com/notaryproject/notation/pkg/docker" + "github.com/notaryproject/notation/pkg/registry" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -49,76 +46,15 @@ func GenerateManifestOCIDescriptor(reference string) (ocispec.Descriptor, error) } // GetManifestOCIDescriptor get manifest descriptor from remote registry -func GetManifestOCIDescriptor(ctx context.Context, hostname, repository, ref string) (ocispec.Descriptor, error) { - tr, err := Transport(hostname) +func GetManifestOCIDescriptor(ctx context.Context, ref registry.Reference) (ocispec.Descriptor, error) { + tr, err := Transport(ref.Registry) if err != nil { return ocispec.Descriptor{}, err } - - scheme := "https" - if config.IsRegistryInsecure(hostname) { - scheme = "http" - } - if host, _, _ := net.SplitHostPort(hostname); host == "localhost" { - scheme = "http" - } - url := fmt.Sprintf("%s://%s/v2/%s/manifests/%s", - scheme, - hostname, - repository, - ref, - ) - req, err := http.NewRequest(http.MethodHead, url, nil) - if err != nil { - return ocispec.Descriptor{}, err - } - req.Header.Set("Connection", "close") - req.Header.Set("Accept", schema2.MediaTypeManifest) - - resp, err := tr.RoundTrip(req) - if err != nil { - return ocispec.Descriptor{}, fmt.Errorf("%v: %v", url, err) - } - resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return ocispec.Descriptor{}, fmt.Errorf("%v: %s", url, resp.Status) - } - - header := resp.Header - mediaType := header.Get("Content-Type") - if mediaType != schema2.MediaTypeManifest { - return ocispec.Descriptor{}, fmt.Errorf("%v: media type mismatch: %s", url, mediaType) - } - contentDigest := header.Get("Docker-Content-Digest") - if contentDigest == "" { - return ocispec.Descriptor{}, fmt.Errorf("%v: missing Docker-Content-Digest", url) - } - parsedDigest, err := digest.Parse(contentDigest) - if err != nil { - return ocispec.Descriptor{}, fmt.Errorf("%v: invalid Docker-Content-Digest: %s", url, contentDigest) - } - length := header.Get("Content-Length") - if length == "" { - return ocispec.Descriptor{}, fmt.Errorf("%v: missing Content-Length", url) - } - size, err := strconv.ParseInt(length, 10, 64) - if err != nil { - return ocispec.Descriptor{}, fmt.Errorf("%v: invalid Content-Length", url) - } - return ocispec.Descriptor{ - MediaType: schema2.MediaTypeManifest, - Digest: parsedDigest, - Size: size, - }, nil -} - -// GetManifestReference returns the tag or the digest of the reference string -func GetManifestReference(ref string) string { - if index := strings.Index(ref, "@"); index != -1 { - return ref[index+1:] - } else if index := strings.LastIndex(ref, ":"); index != -1 { - return ref[index+1:] - } else { - return "latest" + insecure := config.IsRegistryInsecure(ref.Registry) + if host, _, _ := net.SplitHostPort(ref.Registry); host == "localhost" { + insecure = true } + client := registry.NewClient(tr, insecure) + return client.GetManifestDescriptor(ref) } diff --git a/cmd/docker-notation/pull.go b/cmd/docker-notation/pull.go index 4f99a80c3..b58192da8 100644 --- a/cmd/docker-notation/pull.go +++ b/cmd/docker-notation/pull.go @@ -6,11 +6,11 @@ import ( "fmt" "os" - "github.com/distribution/distribution/v3/reference" "github.com/notaryproject/notation-go-lib" "github.com/notaryproject/notation/cmd/docker-notation/docker" "github.com/notaryproject/notation/pkg/cache" "github.com/notaryproject/notation/pkg/config" + "github.com/notaryproject/notation/pkg/registry" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/urfave/cli/v2" @@ -37,28 +37,21 @@ func pullImage(ctx *cli.Context) error { } func verifyRemoteImage(ctx context.Context, ref string) (string, error) { - named, err := reference.ParseNamed(ref) + manifestRef, err := registry.ParseReference(ref) if err != nil { return "", err } - hostname, repository := reference.SplitHostname(named) - manifestRef := docker.GetManifestReference(ref) service, err := getVerificationService() if err != nil { return "", err } - manifestDesc, err := docker.GetManifestOCIDescriptor( - ctx, - hostname, - repository, - manifestRef, - ) + manifestDesc, err := docker.GetManifestOCIDescriptor(ctx, manifestRef) if err != nil { return "", err } - fmt.Println(manifestRef, "digest:", manifestDesc.Digest, "size:", manifestDesc.Size) + fmt.Println(manifestRef.ReferenceOrDefault(), "digest:", manifestDesc.Digest, "size:", manifestDesc.Size) fmt.Println("Looking up for signatures") sigDigests, err := downloadSignatures(ctx, ref, manifestDesc.Digest) @@ -84,7 +77,8 @@ func verifyRemoteImage(ctx context.Context, ref string) (string, error) { } } - return fmt.Sprintf("%s@%s", named.Name(), manifestDesc.Digest), nil + manifestRef.Reference = manifestDesc.Digest.String() + return manifestRef.String(), nil } func downloadSignatures(ctx context.Context, ref string, manifestDigest digest.Digest) ([]digest.Digest, error) { From 2862bb491f1448f060a7a4ff44782b18a585cada Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Tue, 7 Sep 2021 18:18:25 +0800 Subject: [PATCH 59/69] compare registry host case insensitively Signed-off-by: Shiwei Zhang --- pkg/config/util.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pkg/config/util.go b/pkg/config/util.go index 8bc07b6f1..336744026 100644 --- a/pkg/config/util.go +++ b/pkg/config/util.go @@ -1,6 +1,9 @@ package config -import "errors" +import ( + "errors" + "strings" +) var ( // ErrKeyNotFound indicates that the signing key is not found. @@ -17,7 +20,7 @@ func IsRegistryInsecure(target string) bool { return false } for _, registry := range config.InsecureRegistries { - if registry == target { + if strings.EqualFold(registry, target) { return true } } From 4c4a3c389af08f4b06f7394df94ed9b70c2ceefa Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Tue, 7 Sep 2021 18:27:29 +0800 Subject: [PATCH 60/69] refine docker-notation pull output Signed-off-by: Shiwei Zhang --- cmd/docker-notation/pull.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/docker-notation/pull.go b/cmd/docker-notation/pull.go index b58192da8..28baa914f 100644 --- a/cmd/docker-notation/pull.go +++ b/cmd/docker-notation/pull.go @@ -51,7 +51,7 @@ func verifyRemoteImage(ctx context.Context, ref string) (string, error) { if err != nil { return "", err } - fmt.Println(manifestRef.ReferenceOrDefault(), "digest:", manifestDesc.Digest, "size:", manifestDesc.Size) + fmt.Printf("%s: digest: %v size: %v\n", manifestRef.ReferenceOrDefault(), manifestDesc.Digest, manifestDesc.Size) fmt.Println("Looking up for signatures") sigDigests, err := downloadSignatures(ctx, ref, manifestDesc.Digest) From 8746d03601bf103a930297ef766e0c820977aca9 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Tue, 7 Sep 2021 19:12:57 +0800 Subject: [PATCH 61/69] safer prune Signed-off-by: Shiwei Zhang --- cmd/notation/cache.go | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/cmd/notation/cache.go b/cmd/notation/cache.go index aeecc69fb..516801828 100644 --- a/cmd/notation/cache.go +++ b/cmd/notation/cache.go @@ -1,6 +1,7 @@ package main import ( + "bufio" "errors" "fmt" "io/fs" @@ -49,10 +50,14 @@ var ( Aliases: []string{"a"}, Usage: "prune all cached signatures", }, + &cli.BoolFlag{ + Name: "purge", + Usage: "remove the signature directory, combined with --all", + }, &cli.BoolFlag{ Name: "force", Aliases: []string{"f"}, - Usage: "prune entire directory, combined with --all", + Usage: "do not prompt for confirmation", }, localFlag, usernameFlag, @@ -113,6 +118,17 @@ func listManifestsWithCachedSignature() error { func pruneCachedSignatures(ctx *cli.Context) error { if ctx.Bool("all") { + if !ctx.Bool("force") { + fmt.Println("WARNING! This will remove:") + fmt.Println("- all cached signatures") + if ctx.Bool("purge") { + fmt.Println("- all files in the cache signature directory") + } + fmt.Println() + if confirmed := promptConfirmation(); !confirmed { + return nil + } + } if err := walkCachedSignatureTree( config.SignatureStoreDirPath, func(algorithm string, value fs.DirEntry) error { @@ -131,7 +147,7 @@ func pruneCachedSignatures(ctx *cli.Context) error { ); err != nil { return err } - if ctx.Bool("force") { + if ctx.Bool("purge") { return os.RemoveAll(config.SignatureStoreDirPath) } return nil @@ -140,7 +156,18 @@ func pruneCachedSignatures(ctx *cli.Context) error { if !ctx.Args().Present() { return errors.New("nothing to prune") } - for _, ref := range ctx.Args().Slice() { + refs := ctx.Args().Slice() + if !ctx.Bool("force") { + fmt.Println("WARNING! This will remove cached signatures for manifests below:") + for _, ref := range refs { + fmt.Println("-", ref) + } + fmt.Println() + if confirmed := promptConfirmation(); !confirmed { + return nil + } + } + for _, ref := range refs { manifestDigest, err := getManifestDigestFromContext(ctx, ref) if err != nil { return err @@ -233,3 +260,9 @@ func getManifestDigestFromContext(ctx *cli.Context, ref string) (manifestDigest manifestDigest = digest.Digest(manifest.Digest) return } + +func promptConfirmation() bool { + fmt.Printf("Are you sure you want to continue? [y/N]: ") + scanner := bufio.NewScanner(os.Stdin) + return scanner.Scan() && strings.EqualFold(scanner.Text(), "y") +} From 379b37adea6fb21119966e950a1616abfa04374f Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Tue, 7 Sep 2021 19:14:18 +0800 Subject: [PATCH 62/69] prepare for v0.5.2 release Signed-off-by: Shiwei Zhang --- internal/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/version/version.go b/internal/version/version.go index 213ae7bfc..e64e8398c 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -2,7 +2,7 @@ package version var ( // Version shows the current notation version, optionally with pre-release. - Version = "0.5.1" + Version = "0.5.2" // BuildMetadata stores the build metadata. BuildMetadata = "unreleased" From 46918e88dc2fbbc2ac9a7e4f19e7567ff724dc83 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Fri, 10 Sep 2021 23:43:48 +0800 Subject: [PATCH 63/69] update notation-go-lib dependency Signed-off-by: Shiwei Zhang --- go.mod | 2 +- go.sum | 4 ++-- internal/version/version.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 476e561ac..30fa816bf 100644 --- a/go.mod +++ b/go.mod @@ -26,4 +26,4 @@ require ( gotest.tools/v3 v3.0.3 // indirect ) -replace github.com/notaryproject/notation-go-lib => github.com/shizhMSFT/notation-go-lib v0.0.0-20210906023928-fdc1ad1f8b03 +replace github.com/notaryproject/notation-go-lib => github.com/shizhMSFT/notation-go-lib v0.0.0-20210830093102-4cf866d49e92 diff --git a/go.sum b/go.sum index 206856ae9..7eeb11acc 100644 --- a/go.sum +++ b/go.sum @@ -101,8 +101,8 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shizhMSFT/notation-go-lib v0.0.0-20210906023928-fdc1ad1f8b03 h1:uAlOjYbqNiB/6CwwJN43Halu9PJtRDXfW2rPV3YPCxY= -github.com/shizhMSFT/notation-go-lib v0.0.0-20210906023928-fdc1ad1f8b03/go.mod h1:KL5EBS/9X5UI7GnDC4NbYg2az6HVmoyH5M2Bv8a9E24= +github.com/shizhMSFT/notation-go-lib v0.0.0-20210830093102-4cf866d49e92 h1:IkiOEbFLTEoQw6XMatJU3CfKSanzsYgGn/TNTrKz/0c= +github.com/shizhMSFT/notation-go-lib v0.0.0-20210830093102-4cf866d49e92/go.mod h1:KL5EBS/9X5UI7GnDC4NbYg2az6HVmoyH5M2Bv8a9E24= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= diff --git a/internal/version/version.go b/internal/version/version.go index e64e8398c..7d11d3173 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -2,7 +2,7 @@ package version var ( // Version shows the current notation version, optionally with pre-release. - Version = "0.5.2" + Version = "0.5.3" // BuildMetadata stores the build metadata. BuildMetadata = "unreleased" From 68b632e7aa7f5c977e5cdb2699504055de3089d4 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Tue, 14 Sep 2021 08:17:07 +0800 Subject: [PATCH 64/69] update release for go releaser Signed-off-by: Shiwei Zhang --- .goreleaser.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.goreleaser.yml b/.goreleaser.yml index 4409cda36..e57a34eb8 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -57,3 +57,5 @@ archives: format: zip files: - LICENSE +release: + prerelease: auto From b3b65a54d63868b45b9594ad62cca7dc27665802 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Wed, 15 Sep 2021 10:38:34 +0800 Subject: [PATCH 65/69] update notation-go-lib dependency Signed-off-by: Shiwei Zhang --- go.mod | 4 +--- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 30fa816bf..9dbcb8fb1 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/distribution/distribution/v3 v3.0.0-20210804104954-38ab4c606ee3 github.com/docker/cli v20.10.8+incompatible github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 - github.com/notaryproject/notation-go-lib v0.0.0 + github.com/notaryproject/notation-go-lib v0.0.0-20210915023405-484c01cab2ee github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.1 github.com/oras-project/artifacts-spec v0.0.0-20210827194259-6e52c5a2ed3d @@ -25,5 +25,3 @@ require ( golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect gotest.tools/v3 v3.0.3 // indirect ) - -replace github.com/notaryproject/notation-go-lib => github.com/shizhMSFT/notation-go-lib v0.0.0-20210830093102-4cf866d49e92 diff --git a/go.sum b/go.sum index 7eeb11acc..762fcf941 100644 --- a/go.sum +++ b/go.sum @@ -76,6 +76,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/notaryproject/notation-go-lib v0.0.0-20210915023405-484c01cab2ee h1:idY+JlWPCkaXRIww/SuvqlaIWalN2o5o3jIcj2+mc9M= +github.com/notaryproject/notation-go-lib v0.0.0-20210915023405-484c01cab2ee/go.mod h1:KL5EBS/9X5UI7GnDC4NbYg2az6HVmoyH5M2Bv8a9E24= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= @@ -101,8 +103,6 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shizhMSFT/notation-go-lib v0.0.0-20210830093102-4cf866d49e92 h1:IkiOEbFLTEoQw6XMatJU3CfKSanzsYgGn/TNTrKz/0c= -github.com/shizhMSFT/notation-go-lib v0.0.0-20210830093102-4cf866d49e92/go.mod h1:KL5EBS/9X5UI7GnDC4NbYg2az6HVmoyH5M2Bv8a9E24= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= From 73d6fe00e7ab100327cf35dc05f6d4c49c8bee8e Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Wed, 15 Sep 2021 11:08:39 +0800 Subject: [PATCH 66/69] update authors Signed-off-by: Shiwei Zhang --- building.md | 4 ++-- cmd/docker-generate/metadata.go | 3 ++- cmd/docker-notation/metadata.go | 2 +- cmd/notation/main.go | 3 +-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/building.md b/building.md index 1180f1974..65d54b6b5 100644 --- a/building.md +++ b/building.md @@ -24,8 +24,8 @@ Building above binaries require [golang](https://golang.org/dl/) with version `> docker --help # look for Management Commands: - generate* Generate artifacts (github.com/shizhMSFT, 0.1.0) - notation* Manage signatures on Docker images (Sajay Antony, Shiwei Zhang, 0.5.1) + generate* Generate artifacts (CNCF Notary Project, 0.1.0) + notation* Manage signatures on Docker images (CNCF Notary Project, 0.5.3-alpha) which notation # output diff --git a/cmd/docker-generate/metadata.go b/cmd/docker-generate/metadata.go index 66750d8de..b099b3588 100644 --- a/cmd/docker-generate/metadata.go +++ b/cmd/docker-generate/metadata.go @@ -10,9 +10,10 @@ import ( var pluginMetadata = docker.PluginMetadata{ SchemaVersion: "0.1.0", - Vendor: "github.com/shizhMSFT", + Vendor: "CNCF Notary Project", Version: "0.1.0", ShortDescription: "Generate artifacts", + URL: "https://github.com/notaryproject/notation", Experimental: true, } diff --git a/cmd/docker-notation/metadata.go b/cmd/docker-notation/metadata.go index c093f61c7..e5421067f 100644 --- a/cmd/docker-notation/metadata.go +++ b/cmd/docker-notation/metadata.go @@ -11,7 +11,7 @@ import ( var pluginMetadata = docker.PluginMetadata{ SchemaVersion: "0.1.0", - Vendor: "Sajay Antony, Shiwei Zhang", + Vendor: "CNCF Notary Project", Version: version.GetVersion(), ShortDescription: "Manage signatures on Docker images", URL: "https://github.com/notaryproject/notation", diff --git a/cmd/notation/main.go b/cmd/notation/main.go index b041b5bc1..a51fa425d 100644 --- a/cmd/notation/main.go +++ b/cmd/notation/main.go @@ -15,8 +15,7 @@ func main() { Version: version.GetVersion(), Authors: []*cli.Author{ { - Name: "Shiwei Zhang", - Email: "shizh@microsoft.com", + Name: "CNCF Notary Project", }, }, Commands: []*cli.Command{ From b75d34f9f39ec5c52620bf949dd30faf29806b0b Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Wed, 15 Sep 2021 14:47:03 +0800 Subject: [PATCH 67/69] make github workflow consistent Signed-off-by: Shiwei Zhang --- .github/workflows/{golang.yml => build.yml} | 23 +++++++-------------- .github/workflows/release-github.yml | 2 +- 2 files changed, 8 insertions(+), 17 deletions(-) rename .github/workflows/{golang.yml => build.yml} (81%) diff --git a/.github/workflows/golang.yml b/.github/workflows/build.yml similarity index 81% rename from .github/workflows/golang.yml rename to .github/workflows/build.yml index b3cedc7be..4d573eba0 100644 --- a/.github/workflows/golang.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: Go CI +name: build on: push: @@ -6,38 +6,29 @@ on: jobs: build: - runs-on: ubuntu-20.04 - - name: Continuous Integration if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository - + name: Continuous Integration + runs-on: ubuntu-20.04 strategy: matrix: go-version: [1.17] - fail-fast: true - steps: - name: Set up Go ${{ matrix.go-version }} - uses: actions/setup-go@v2.1.4 + uses: actions/setup-go@v2 with: go-version: ${{ matrix.go-version }} - - name: Check out code - uses: actions/checkout@v2.3.4 - + uses: actions/checkout@v2 - name: Cache Go modules - uses: actions/cache@v2.1.6 + uses: actions/cache@v2 id: go-mod-cache with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - - name: Get dependencies run: make download - - name: Build - run: | - make build + run: make build diff --git a/.github/workflows/release-github.yml b/.github/workflows/release-github.yml index a9fe1b34f..70a3401f6 100644 --- a/.github/workflows/release-github.yml +++ b/.github/workflows/release-github.yml @@ -15,7 +15,7 @@ jobs: fail-fast: true steps: - name: Set up Go ${{ matrix.go-version }} - uses: actions/setup-go@v2.1.4 + uses: actions/setup-go@v2 with: go-version: ${{ matrix.go-version }} - name: Checkout From 33d34e6800e427bbca359d39598a83ef700b385d Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Wed, 15 Sep 2021 15:01:08 +0800 Subject: [PATCH 68/69] output stderr for docker-generate Signed-off-by: Shiwei Zhang --- cmd/docker-generate/manifest.go | 1 + cmd/docker-generate/metadata.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/docker-generate/manifest.go b/cmd/docker-generate/manifest.go index c93a33b9c..7c717b9a6 100644 --- a/cmd/docker-generate/manifest.go +++ b/cmd/docker-generate/manifest.go @@ -27,6 +27,7 @@ func generateManifest(ctx *cli.Context) error { var reader io.Reader if reference := ctx.Args().First(); reference != "" { cmd := exec.Command("docker", "save", reference) + cmd.Stderr = os.Stderr stdout, err := cmd.StdoutPipe() if err != nil { return err diff --git a/cmd/docker-generate/metadata.go b/cmd/docker-generate/metadata.go index b099b3588..c7ad710f0 100644 --- a/cmd/docker-generate/metadata.go +++ b/cmd/docker-generate/metadata.go @@ -11,7 +11,7 @@ import ( var pluginMetadata = docker.PluginMetadata{ SchemaVersion: "0.1.0", Vendor: "CNCF Notary Project", - Version: "0.1.0", + Version: "0.1.1", ShortDescription: "Generate artifacts", URL: "https://github.com/notaryproject/notation", Experimental: true, From 875faddbae6d2c7aeec144c3a0f2e2491a8fe5fc Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Wed, 15 Sep 2021 15:18:14 +0800 Subject: [PATCH 69/69] move implementations to the correct package Signed-off-by: Shiwei Zhang --- cmd/docker-notation/push.go | 3 ++- cmd/notation/push.go | 3 ++- cmd/notation/verify.go | 3 ++- pkg/cache/signature.go | 52 +++++++++++++++++++++++++++++++++++++ pkg/config/path.go | 43 ------------------------------ 5 files changed, 58 insertions(+), 46 deletions(-) create mode 100644 pkg/cache/signature.go diff --git a/cmd/docker-notation/push.go b/cmd/docker-notation/push.go index 642ef6bd0..c324995ed 100644 --- a/cmd/docker-notation/push.go +++ b/cmd/docker-notation/push.go @@ -12,6 +12,7 @@ import ( "github.com/distribution/distribution/v3/manifest/schema2" "github.com/notaryproject/notation/cmd/docker-notation/docker" + "github.com/notaryproject/notation/pkg/cache" "github.com/notaryproject/notation/pkg/config" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" @@ -32,7 +33,7 @@ func pushImage(ctx *cli.Context) error { } fmt.Println("Pushing signature") - sigDigests, err := config.SignatureDigests(desc.Digest) + sigDigests, err := cache.SignatureDigests(desc.Digest) if err != nil { return err } diff --git a/cmd/notation/push.go b/cmd/notation/push.go index e76584b8a..af8ea594f 100644 --- a/cmd/notation/push.go +++ b/cmd/notation/push.go @@ -5,6 +5,7 @@ import ( "fmt" "os" + "github.com/notaryproject/notation/pkg/cache" "github.com/notaryproject/notation/pkg/config" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/urfave/cli/v2" @@ -35,7 +36,7 @@ func runPush(ctx *cli.Context) error { } sigPaths := ctx.StringSlice(signatureFlag.Name) if len(sigPaths) == 0 { - sigDigests, err := config.SignatureDigests(manifestDesc.Digest) + sigDigests, err := cache.SignatureDigests(manifestDesc.Digest) if err != nil { return err } diff --git a/cmd/notation/verify.go b/cmd/notation/verify.go index d3d656f77..4fd8c4367 100644 --- a/cmd/notation/verify.go +++ b/cmd/notation/verify.go @@ -8,6 +8,7 @@ import ( "github.com/notaryproject/notation-go-lib/signature" x509n "github.com/notaryproject/notation-go-lib/signature/x509" + "github.com/notaryproject/notation/pkg/cache" "github.com/notaryproject/notation/pkg/config" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" @@ -72,7 +73,7 @@ func runVerify(ctx *cli.Context) error { } } manifestDigest := digest.Digest(manifestDesc.Digest) - sigDigests, err := config.SignatureDigests(manifestDigest) + sigDigests, err := cache.SignatureDigests(manifestDigest) if err != nil { return err } diff --git a/pkg/cache/signature.go b/pkg/cache/signature.go new file mode 100644 index 000000000..513968728 --- /dev/null +++ b/pkg/cache/signature.go @@ -0,0 +1,52 @@ +package cache + +import ( + "os" + "path/filepath" + "strings" + + "github.com/notaryproject/notation/pkg/config" + "github.com/opencontainers/go-digest" +) + +// SignatureDigests returns the digest of signatures for a manifest +func SignatureDigests(manifestDigest digest.Digest) ([]digest.Digest, error) { + rootPath := config.SignatureRootPath(manifestDigest) + algorithmEntries, err := os.ReadDir(rootPath) + if err != nil { + if os.IsNotExist(err) { + return nil, nil + } + return nil, err + } + + var digests []digest.Digest + for _, algorithmEntry := range algorithmEntries { + if !algorithmEntry.Type().IsDir() { + continue + } + + algorithm := algorithmEntry.Name() + signatureEntries, err := os.ReadDir(filepath.Join(rootPath, algorithm)) + if err != nil { + return nil, err + } + + for _, signatureEntry := range signatureEntries { + if !signatureEntry.Type().IsRegular() { + continue + } + encoded := signatureEntry.Name() + if !strings.HasSuffix(encoded, config.SignatureExtension) { + continue + } + encoded = strings.TrimSuffix(encoded, config.SignatureExtension) + digest := digest.NewDigestFromEncoded(digest.Algorithm(algorithm), encoded) + if err := digest.Validate(); err != nil { + return nil, err + } + digests = append(digests, digest) + } + } + return digests, nil +} diff --git a/pkg/config/path.go b/pkg/config/path.go index 2ca350d14..8926d1f0a 100644 --- a/pkg/config/path.go +++ b/pkg/config/path.go @@ -3,7 +3,6 @@ package config import ( "os" "path/filepath" - "strings" "github.com/opencontainers/go-digest" ) @@ -87,48 +86,6 @@ func SignaturePath(manifestDigest, signatureDigest digest.Digest) string { ) } -// SignatureDigests returns the digest of signatures for a manifest -func SignatureDigests(manifestDigest digest.Digest) ([]digest.Digest, error) { - rootPath := SignatureRootPath(manifestDigest) - algorithmEntries, err := os.ReadDir(rootPath) - if err != nil { - if os.IsNotExist(err) { - return nil, nil - } - return nil, err - } - - var digests []digest.Digest - for _, algorithmEntry := range algorithmEntries { - if !algorithmEntry.Type().IsDir() { - continue - } - - algorithm := algorithmEntry.Name() - signatureEntries, err := os.ReadDir(filepath.Join(rootPath, algorithm)) - if err != nil { - return nil, err - } - - for _, signatureEntry := range signatureEntries { - if !signatureEntry.Type().IsRegular() { - continue - } - encoded := signatureEntry.Name() - if !strings.HasSuffix(encoded, SignatureExtension) { - continue - } - encoded = strings.TrimSuffix(encoded, SignatureExtension) - digest := digest.NewDigestFromEncoded(digest.Algorithm(algorithm), encoded) - if err := digest.Validate(); err != nil { - return nil, err - } - digests = append(digests, digest) - } - } - return digests, nil -} - // KeyPath returns the path of a signing key func KeyPath(name string) string { return filepath.Join(KeyStoreDirPath, name+KeyExtension)

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 literal 40096 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 z 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 RmqLe6TG<}2IC}Aq{{yk@vO)j= From 4e392caddd3a432ec8917bbf473d426618a2f9c1 Mon Sep 17 00:00:00 2001 From: Steve Lasker Date: Thu, 27 Aug 2020 14:58:38 -0700 Subject: [PATCH 10/69] Fix paging api link Signed-off-by: Steve Lasker --- docs/distribution/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/distribution/README.md b/docs/distribution/README.md index d963e0109..b9fd2668f 100644 --- a/docs/distribution/README.md +++ b/docs/distribution/README.md @@ -706,7 +706,7 @@ There are three identified patterns for paging results: #### Distribution Spec - Tags Listing API The [OCI distribution-spec][distribution-spec-paging] identifies paging with `n` and `last` parameters: -[tags-api] +[distribution-spec-paging] Get a list of paginated signatures from the registry. The response will include an opaque URL that can be followed to obtain the next page of results. @@ -921,4 +921,3 @@ See [nv2 signature spec][nv2-signature-spec] for more details. [oci-manifest]: https://github.com/opencontainers/image-spec/blob/master/manifest.md [oras]: https://github.com/deislabs/oras [oci-dist-spec-manifest-put]: https://github.com/opencontainers/distribution-spec/blob/master/spec.md#put-manifest -[tags-api]: https://github.com/opencontainers/distribution-spec From 24207bb1c078a3e7c1b89a54c99f1232fde9d187 Mon Sep 17 00:00:00 2001 From: Steve Lasker Date: Mon, 31 Aug 2020 09:38:55 -0700 Subject: [PATCH 11/69] Resolve spelling errors Signed-off-by: Steve Lasker --- docs/distribution/README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/distribution/README.md b/docs/distribution/README.md index b9fd2668f..999f5e018 100644 --- a/docs/distribution/README.md +++ b/docs/distribution/README.md @@ -1,24 +1,24 @@ # OCI Distribution - Notary v2 Signature Support -To support [Notary v2 goals][notaryv2-goals], upload, persistance and discovery of signatures must be supported. +To support [Notary v2 goals][notaryv2-goals], upload, Persistence and discovery of signatures must be supported. To minimize the complexity of registry operators and projects to adopt Notary v2, a balance between leveraging what already exists and new patterns to support secure discovery are explored. ## Table of Contents -* [Signature Persistance](#signature-persistance) +* [Signature Persistence](#signature-Persistence) * [Signature Push](#signature-push) * [Signature Discovery](#signature-discovery) * [Signature Pull](#signature-pull) * [Example Artifacts](#example-artifacts) -## Signature Persistance +## Signature Persistence Several options for how to persist a signature were explored. We measure these options against the [goals of Notary v2][notaryv2-goals], specifically: * Maintain the original artifact digest and collection of associated tags, supporting existing dev through deployment workflows * Multiple signatures per artifact, enabling the originating vendor signature, public registry certification and user/environment signatures -* Native persistance within an OCI Artifact enabled, distribution*spec based registry +* Native Persistence within an OCI Artifact enabled, distribution*spec based registry * Artifact and signature copying within and across OCI Artifact enabled, distribution spec based registries * Support multi-tenant registries enabling cloud providers and enterprises to support managed services at scale * Support private registries, where public content may be copied to, and new content originated within @@ -31,7 +31,7 @@ The config object contains the signature and signed content. See [nv2-signature- Storing a signature as a separate artifact enables the above goals, most importantly the ability to maintain the existing tag and and digest for a given artifact. -### Persistance as Manifest or Index +### Persistence as Manifest or Index A typical signing workflow would involve: @@ -40,11 +40,11 @@ A typical signing workflow would involve: It's presumed artifact clients like docker, oras, buildkit would support these new workflows. The question is what oci schema they are pushed with: -* [Option 1: oci-manifest](#signature-persistance---option-1-oci-manifest) -* [Option 2: oci-index](#signature-persistance---option-2-oci-index) -* [Option 3: oci-manifest-linked through index](#signature-persistance---option-3-oci-manifest-linked-through-oci-index) +* [Option 1: oci-manifest](#signature-Persistence---option-1-oci-manifest) +* [Option 2: oci-index](#signature-Persistence---option-2-oci-index) +* [Option 3: oci-manifest-linked through index](#signature-Persistence---option-3-oci-manifest-linked-through-oci-index) -### Signature Persistance - Option 1: oci-manifest +### Signature Persistence - Option 1: oci-manifest The challenge with using oci-manifest is how the registry tracks the linkage between the signature and the original artifact. @@ -169,7 +169,7 @@ Example **manifests** for a container image (`net-monitor:v1`) and two signature * Manifests have no means to reference other artifacts. * An alternative is required to link a target artifact with it's signature. Either through parsing the signature `manifest.config` object, or [a separate API for linking objects](#linking-signatures-to-artifacts). -### Signature Persistance - Option 2: oci-index +### Signature Persistence - Option 2: oci-index This option is similar to using oci-manifest. However, instead of parsing the signature object to determine the linkage between an artifact and signature, the `index.manifests` collection is utilized. @@ -322,7 +322,7 @@ Example **manifests** for a container image (`net-monitor:v1`) and two signature > **Note:** this is our working/preferred method: See OCI image-spec issue: [Add Index Support for Artifact Type #806](https://github.com/opencontainers/image-spec/issues/806) -### Signature Persistance - Option 2a: oci-index signing a multi-arch manifest +### Signature Persistence - Option 2a: oci-index signing a multi-arch manifest Takin the above scenario further, a signature can be associated with an individual manifest, or a signature can be applied to an index. The index could be a multi-arch index (windows & linux), or the index might represent a [CNAB][cnab]. @@ -332,9 +332,9 @@ The platform specific images, and the multi-arch index are all signed by **wabbi -### Signature Persistance - Option 3: oci-manifest linked through oci-index +### Signature Persistence - Option 3: oci-manifest linked through oci-index -This model is a hybrid of the 1 & 2, but moves the persistance of the signature from the config object to a layer of an additional manifest. +This model is a hybrid of the 1 & 2, but moves the Persistence of the signature from the config object to a layer of an additional manifest. From 276abe450feec8f3b54f0774b7dfb47f36670cc5 Mon Sep 17 00:00:00 2001 From: Steve Lasker Date: Tue, 1 Sep 2020 15:47:07 -0700 Subject: [PATCH 12/69] Fix examples to include full descriptor Signed-off-by: Steve Lasker --- docs/distribution/README.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/distribution/README.md b/docs/distribution/README.md index 999f5e018..94be56294 100644 --- a/docs/distribution/README.md +++ b/docs/distribution/README.md @@ -551,6 +551,8 @@ Partial config object, referring to the digest and tag of the `net-monitor:v1` c "references": [ "registry.acme-rockets.com/net-monitor:v1" ] + } +} ``` **Pros with this approach:** @@ -625,10 +627,10 @@ The following options are offered: ### Signature Discovery - Option 1: Signature Listing API Similar to the [_tags api][tags-api], a new signatures API is proposed. The signatures API uses the digest as the path to find all signatures related to said digest. -In the below example, the `net-monitor:v1` tag has a digest of: `sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042` +In the below example, the `net-monitor:v1` tag has a digest of: `sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m` ```HTTP -GET /v2//manifests/sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042/signatures/ +GET /v2//manifests/sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m/signatures/ ``` The response will be in the following format: @@ -637,16 +639,18 @@ The response will be in the following format: 200 OK Content-Type: application/json { - "digest": "sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042", + "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "size": "1331", "signatures": [ { - "digest": "sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042", + "digest": "sha256:222ibbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222i", "mediaType": "application/vnd.oci.image.index.v1+json", "size": "1024", "signature-typ": "x509" }, { - "digest": "sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b", + "digest": "sha256:333ic0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333i", "mediaType": "application/vnd.oci.image.index.v1+json", "size": "1025", "signature-typ": "x509" @@ -835,8 +839,8 @@ These assume: ### Artifacts submitted to a registry The following are artifacts that represent a container image, or signature artifact. Depending on the example above, the signatures are represented as an oci manifest or oci index. -|Artifact |`config.mediaType` | Digest | -|----------------------------------|-------------------------------------------|-------------------------------------------------------------------------| +|Artifact |`config.mediaType` | Digest | +|--------------------------------------|-------------------------------------------|-------------------------------------------------------------------------| |`net-monitor:v1` image **manifest** |`application/vnd.oci.image.config.v1+json` |`sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m`| |`net-monitor:v1` multi-arch **index** |`application/vnd.oci.image.config.v1+json` |`sha256:111ia2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111i`| |wabbit-networks signature **manifest**|`application/vnd.cncf.notary.config.v2+jwt`|`sha256:222mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222m`| From 6298cd23f6058709f57b613cdab9fce88c9a1267 Mon Sep 17 00:00:00 2001 From: Steve Lasker Date: Thu, 17 Sep 2020 16:41:03 -0700 Subject: [PATCH 13/69] typo feedback Signed-off-by: Steve Lasker --- docs/distribution/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/distribution/README.md b/docs/distribution/README.md index 94be56294..92c2af21a 100644 --- a/docs/distribution/README.md +++ b/docs/distribution/README.md @@ -18,7 +18,7 @@ Several options for how to persist a signature were explored. We measure these o * Maintain the original artifact digest and collection of associated tags, supporting existing dev through deployment workflows * Multiple signatures per artifact, enabling the originating vendor signature, public registry certification and user/environment signatures -* Native Persistence within an OCI Artifact enabled, distribution*spec based registry +* Native Persistence within an OCI Artifact enabled, distribution spec based registry * Artifact and signature copying within and across OCI Artifact enabled, distribution spec based registries * Support multi-tenant registries enabling cloud providers and enterprises to support managed services at scale * Support private registries, where public content may be copied to, and new content originated within @@ -228,7 +228,7 @@ Example **manifests** for a container image (`net-monitor:v1`) and two signature } ``` - The `manifest.config` contains the following signature information: + The `index.config` contains the following signature information: ```json { @@ -364,7 +364,7 @@ This model is a hybrid of the 1 & 2, but moves the Persistence of the signature } ``` -2. **index digest for the wabbit-networks signature** `sha256:222ibbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222i` +2. **index digest for the wabbit-networks signature of the `net-monitor:v1` image** `sha256:222ibbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222i` ```json { From 578ecadb001f54f5c8fbfab43e1e5a16abf7e551 Mon Sep 17 00:00:00 2001 From: Steve Lasker Date: Sun, 20 Sep 2020 19:45:56 -0700 Subject: [PATCH 14/69] Renamed as options to keep as reference. Updated digest references Signed-off-by: Steve Lasker --- ...ME.md => persistance-discovery-options.md} | 77 ++++++++++--------- 1 file changed, 42 insertions(+), 35 deletions(-) rename docs/distribution/{README.md => persistance-discovery-options.md} (87%) diff --git a/docs/distribution/README.md b/docs/distribution/persistance-discovery-options.md similarity index 87% rename from docs/distribution/README.md rename to docs/distribution/persistance-discovery-options.md index 92c2af21a..be3c1d3f8 100644 --- a/docs/distribution/README.md +++ b/docs/distribution/persistance-discovery-options.md @@ -1,6 +1,8 @@ -# OCI Distribution - Notary v2 Signature Support +# OCI Distribution - Notary v2 Signature Persistance & Discovery Options -To support [Notary v2 goals][notaryv2-goals], upload, Persistence and discovery of signatures must be supported. +> This document explores the various options that were considered for the prototype. The current implementation is documented under the [README.md](./README.md) document. + +To support [Notary v2 goals][notaryv2-goals], upload, persistence and discovery of signatures must be supported. To minimize the complexity of registry operators and projects to adopt Notary v2, a balance between leveraging what already exists and new patterns to support secure discovery are explored. @@ -171,6 +173,8 @@ Example **manifests** for a container image (`net-monitor:v1`) and two signature ### Signature Persistence - Option 2: oci-index +> **Note:** this is our working prototype/preferred method: See OCI image-spec issue: [Add Index Support for Artifact Type #806](https://github.com/opencontainers/image-spec/issues/806) + This option is similar to using oci-manifest. However, instead of parsing the signature object to determine the linkage between an artifact and signature, the `index.manifests` collection is utilized. @@ -318,9 +322,7 @@ Example **manifests** for a container image (`net-monitor:v1`) and two signature * OCI index does not yet support the [OCI config descriptor][oci-descriptor]. This would require a schema change to oci-index, with a version bump. * This has been a [desired item for OCI Artifacts][oci-artifacts-index] to support other artifact types which would base on Index. -* An additional role check is performed, based on the artifact type. Also noted as a pro as registry operators may want to utilize this for other artifact types, making it a consistent model. - -> **Note:** this is our working/preferred method: See OCI image-spec issue: [Add Index Support for Artifact Type #806](https://github.com/opencontainers/image-spec/issues/806) +* Registries that wish to implement role based authorization would implement and additional role check, based on the artifact type. Also noted as a pro as registry operators may want to utilize this for other artifact types, making it a consistent model. This likely minimizes this as a con-but noted for completeness. ### Signature Persistence - Option 2a: oci-index signing a multi-arch manifest @@ -661,36 +663,38 @@ Content-Type: application/json ### Signature Discovery - Option 2: Generic Reference Listing API -A slight alternative to the signatures API is to provide a generic reference listing API, where a paged collection of references are returned. +A slight alternative to the signatures API is to provide a generic reference listing API, where a paged collection of references are returned. The intent is to provide a broader usage API, beyond the signature type. For example, returning any multi-arch index references. -In the below example, the `net-monitor:v1` tag has a digest of: `sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042` + + +Using the diagram above, the `net-monitor:v1` manifest tag (4) has a digest of: `sha256:11wma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a11wm`. When requesting the referenced objects, we see 2 signature objects being returned (wabbit-networks (6) & acme-rockets(7)), and an OCI multi-arch index (1). ```HTTP -GET /v2//manifests/sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042/references/ +GET /v2//manifests/sha256:11wma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a11wm/references/ ``` -The response will be in the following format: +The response could be in the following format. Note the additional `config-mediaType` to identify the specific artifact type in the results. ```HTTP 200 OK Content-Type: application/json { - "digest": "sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042", + "digest": "sha256:11wma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a11wm", "references": [ { - "digest": "sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042", + "digest": "sha256:222mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222m", "mediaType": "application/vnd.oci.image.index.v1+json", "size": "1024", "config-mediaType": "application/vnd.cncf.notary.config.v2+jwt" }, { - "digest": "sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b", + "digest": "sha256:333mc0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333m", "mediaType": "application/vnd.oci.image.index.v1+json", "size": "1025", "config-mediaType": "application/vnd.cncf.notary.config.v2+jwt" }, { - "digest": "sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b", + "digest": "sha256:111ia2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111i", "mediaType": "application/vnd.oci.image.index.v1+json", "size": "1025", "config-mediaType": "application/vnd.oci.image.index.v1+json" @@ -717,7 +721,7 @@ Get a list of paginated signatures from the registry. The response will include Paginated tag results can be retrieved by adding an `n` parameter to the request URL, declaring that the response SHOULD be limited to `n` results. Starting a paginated flow MAY begin as follows: ```HTTP -GET /v2//manifests/sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042/references/list?n= +GET /v2//manifests/sha256:11wma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a11wm/references/list?n= ``` The above specifies that a tags response SHOULD be returned, from the start of the result set, ordered lexically, limiting the number of results to `n`. The response to such a request would look as follows: @@ -727,23 +731,23 @@ The above specifies that a tags response SHOULD be returned, from the start of t Content-Type: application/json Link: <?n=&last=>; rel="next" { - "digest": "sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042", + "digest": "sha256:11wma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a11wm", "@nextLink": "{opaqueUrl}", "references": [ { - "digest": "sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042", + "digest": "sha256:222mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222m", "mediaType": "application/vnd.oci.image.index.v1+json", "size": "1024", "config-mediaType": "application/vnd.cncf.notary.config.v2+jwt" }, { - "digest": "sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b", + "digest": "sha256:333mc0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333m", "mediaType": "application/vnd.oci.image.index.v1+json", "size": "1025", "config-mediaType": "application/vnd.cncf.notary.config.v2+jwt" }, { - "digest": "sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b", + "digest": "sha256:111ia2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111i", "mediaType": "application/vnd.oci.image.index.v1+json", "size": "1025", "config-mediaType": "application/vnd.oci.image.index.v1+json" @@ -786,30 +790,30 @@ To support pagination (returning list results in pages) in a List method, the AP To retrieve the next page of results, client **shall** pass the value of response's `next_page_token` in the subsequent `List` method call (in the request message's `page_token` field): ```HTTP -GET /v2//manifests/sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042/references/list?page_token=1&page_size=10&next_page_token= +GET /v2//manifests/sha256:11wma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a11wm/references/list?page_token=1&page_size=10&next_page_token= ``` The above specifies that a tags response SHOULD be returned, from the start of the result set, ordered lexically, limiting the number of results to `n`. The response to such a request would look as follows: ```json { - "digest": "sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042", + "digest": "sha256:11wma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a11wm", "@next_page_token": "{opaqueUrl}", "references": [ { - "digest": "sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042", + "digest": "sha256:222mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222m", "mediaType": "application/vnd.oci.image.index.v1+json", "size": "1024", "config-mediaType": "application/vnd.cncf.notary.config.v2+jwt" }, { - "digest": "sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b", + "digest": "sha256:333mc0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333m", "mediaType": "application/vnd.oci.image.index.v1+json", "size": "1025", "config-mediaType": "application/vnd.cncf.notary.config.v2+jwt" }, { - "digest": "sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b", + "digest": "sha256:111ia2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111i", "mediaType": "application/vnd.oci.image.index.v1+json", "size": "1025", "config-mediaType": "application/vnd.oci.image.index.v1+json" @@ -838,15 +842,18 @@ These assume: ### Artifacts submitted to a registry -The following are artifacts that represent a container image, or signature artifact. Depending on the example above, the signatures are represented as an oci manifest or oci index. -|Artifact |`config.mediaType` | Digest | -|--------------------------------------|-------------------------------------------|-------------------------------------------------------------------------| -|`net-monitor:v1` image **manifest** |`application/vnd.oci.image.config.v1+json` |`sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m`| -|`net-monitor:v1` multi-arch **index** |`application/vnd.oci.image.config.v1+json` |`sha256:111ia2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111i`| -|wabbit-networks signature **manifest**|`application/vnd.cncf.notary.config.v2+jwt`|`sha256:222mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222m`| -|wabbit-networks signature **index** |`application/vnd.cncf.notary.config.v2+jwt`|`sha256:222ibbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222i`| -|acme-rockets signature **manifest** |`application/vnd.cncf.notary.config.v2+jwt`|`sha256:333mc0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333m`| -|acme-rockets signature **index** |`application/vnd.cncf.notary.config.v2+jwt`|`sha256:333ic0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333i`| +The following are artifacts that represent container images and signature artifacts. Depending on the example above, the signatures are represented as an oci manifest or oci index. Some tags are re-used to represent platform neutral examples. For instance, `net-monitor:v1` is represented as both a default linux image manifest, and a multi-arch index. In some examples, the platform is removed from the tag for brevity and focus on the topic at hand. _It is not suggested `:v1` tags can point to multiple things at the same time._ + +|Artifact |`config.mediaType` | Digest | +|------------------------------------------|-------------------------------------------|-------------------------------------------------------------------------| +|`net-monitor:v1` image **manifest** |`application/vnd.oci.image.config.v1+json` |`sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m`| +|`net-monitor:v1-linux` image **manifest** |`application/vnd.oci.image.config.v1+json` |`sha256:11lma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a11lm`| +|`net-monitor:v1-win` image **manifest** |`application/vnd.oci.image.config.v1+json` |`sha256:11wma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a11wm`| +|`net-monitor:v1` multi-arch **index** |`application/vnd.oci.image.config.v1+json` |`sha256:111ia2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111i`| +|wabbit-networks signature **manifest** |`application/vnd.cncf.notary.config.v2+jwt`|`sha256:222mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222m`| +|wabbit-networks signature **index** |`application/vnd.cncf.notary.config.v2+jwt`|`sha256:222ibbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222i`| +|acme-rockets signature **manifest** |`application/vnd.cncf.notary.config.v2+jwt`|`sha256:333mc0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333m`| +|acme-rockets signature **index** |`application/vnd.cncf.notary.config.v2+jwt`|`sha256:333ic0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333i`| ### Config Objects - referenced by manifests @@ -858,7 +865,7 @@ The following are descriptors, representing config objects within a manifest and |wabbit-networks signature |`sha256:222cb130c152895905abe66279dd9feaa68091ba55619f5b900f2ebed38b222c`| |acme-rockets signature |`sha256:333cc44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b785c333c`| -### Example manifest for the **container image**: `registry.acme-rockets.com/net-monitor:v1` +### Example manifest for the platform agnostic **container image**: `registry.acme-rockets.com/net-monitor:v1` ```json { @@ -866,7 +873,7 @@ The following are descriptors, representing config objects within a manifest and "mediaType": "application/vnd.oci.image.manifest.v2+json", "config": { "mediaType": "application/vnd.oci.image.config.v1+json", - "digest": "sha256:1101a3788f3464fd9a06386c4d7a8e3018b525278ac4b9da872943d4cfe97fe8", + "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", "size": 1906 }, "layers": [ @@ -891,7 +898,7 @@ See [nv2 signature spec][nv2-signature-spec] for more details. ```json { "signed": { - "digest": "sha256:2235d2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49cc77c", + "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", "size": 528, "references": [ "registry.acme-rockets.com/net-monitor:v1" From 73112f44e791328a9b45c5a4b32428a542316367 Mon Sep 17 00:00:00 2001 From: Steve Lasker Date: Tue, 2 Mar 2021 19:01:26 -0800 Subject: [PATCH 15/69] Doc and Demo updates Signed-off-by: Steve Lasker --- docs/nv2/README.md | 68 ++++++------ docs/nv2/demo-script.md | 195 +++++++++++++++++++++++++++++++++ media/notary-e2e-scenarios.png | Bin 54561 -> 0 bytes media/notary-e2e-scenarios.svg | 1 + 4 files changed, 229 insertions(+), 35 deletions(-) create mode 100644 docs/nv2/demo-script.md delete mode 100644 media/notary-e2e-scenarios.png create mode 100644 media/notary-e2e-scenarios.svg diff --git a/docs/nv2/README.md b/docs/nv2/README.md index 319cfbfcd..22445dbf1 100644 --- a/docs/nv2/README.md +++ b/docs/nv2/README.md @@ -42,9 +42,9 @@ openssl req \ -nodes \ -newkey rsa:2048 \ -days 365 \ - -subj "/CN=registry.example.com/O=example inc/C=US/ST=Washington/L=Seattle" \ - -keyout example.key \ - -out example.crt + -subj "/CN=registry.wabbit-networks.io/O=wabbit-networks inc/C=US/ST=Washington/L=Seattle" \ + -keyout wabbit-networks.key \ + -out wabbit-networks.crt ``` When generating the certificate, make sure that the Common Name (`CN`) is set properly in the `Subject` field. The Common Name will be verified against the registry name within the signature. @@ -82,35 +82,35 @@ Signing and verification are based on [OCI manifests](https://github.com/opencon Notary v2 signing is accomplished by signing the OCI manifest representing the artifact. When building docker images, the manifest is not generated until the image is pushed to a registry. To accomplish offline/local signing, the manifest must first exist. -- Build the hello-world image +- Build the sample `net-monitor` image ``` shell docker build \ - -f Dockerfile.build \ - -t registry.acme-rockets.io/hello-world:v1 \ - https://github.com/docker-library/hello-world.git + -f Dockerfile \ + -t registry.wabbit-networks.io/net-monitor:v1 \ + https://github.com/wabbit-networks/net-monitor.git#main ``` -- Generate a manifest, saving it as `hello-world_v1-manifest.json` +- Generate a manifest, saving it as `net-monitor_v1-manifest.json` ``` shell - docker generate manifest registry.acme-rockets.io/hello-world:v1 > hello-world_v1-manifest.json + docker generate manifest registry.wabbit-networks.io/net-monitor:v1 > net-monitor_v1-manifest.json ``` ### Signing using `x509` -To sign the manifest `hello-world_v1-manifest.json` using the key `key.key` from the `x509` certificate `cert.crt` with the Common Name `registry.acme-rockets.io`, run +To sign the manifest `net-monitor_v1-manifest.json` using the `--key` from the `x509` `--cert` with the Common Name `registry.wabbit-networks.io`, run: ```shell -nv2 sign --method x509 \ - -k key.key \ - -c cert.crt \ - -r registry.acme-rockets.io/hello-world:v1 \ - -o hello-world.signature.config.jwt \ - file:hello-world_v1-manifest.json +./nv2 sign --method x509 \ + -k wabbit-networks.key \ + -c wabbit-networks.crt \ + -r registry.wabbit-networks.io/net-monitor:v1 \ + -o net-monitor_v1.signature.config.jwt \ + file:net-monitor_v1-manifest.json ``` -The formatted x509 signature: `hello-world.signature.config.jwt` is: +The formatted x509 signature: `net-monitor_v1.signature.config.jwt` is: ``` json { @@ -124,7 +124,7 @@ The formatted x509 signature: `hello-world.signature.config.jwt` is: "digest": "sha256:24a74900a4e749ef31295e5aabde7093e3244b119582bd6e64b1a88c71c410d0", "size": 3056, "references": [ - "registry.acme-rockets.io/hello-world:v1" + "registry.wabbit-networks.io/net-monitor:v1" ], "iat": 1597053936 }.[Signature] @@ -133,15 +133,14 @@ The formatted x509 signature: `hello-world.signature.config.jwt` is: If the embedded cert chain `x5c` is not desired, it can be replaced by a key ID `kid` by omitting the `-c` option. ```shell -nv2 sign -m x509 \ - -k key.key \ - -r registry.acme-rockets.io/hello-world:v1 \ - -o hello-world.signature.config.jwt \ - file:hello-world_v1-manifest.json +./nv2 sign -m x509 \ + -k wabbit-networks.key \ + -r registry.wabbit-networks.io/net-monitor:v1 \ + -o net-monitor_v1.signature.config.jwt \ + file:net-monitor_v1-manifest.json ``` -The formatted x509, without the `x5c` chain signature: `hello-world.signature.config.jwt` is: - +The formatted x509, without the `x5c` chain signature: `net-monitor_v1.signature.config.jwt` is: ```json { @@ -153,7 +152,7 @@ The formatted x509, without the `x5c` chain signature: `hello-world.signature.co "digest": "sha256:24a74900a4e749ef31295e5aabde7093e3244b119582bd6e64b1a88c71c410d0", "size": 3056, "references": [ - "registry.acme-rockets.io/hello-world:v1" + "registry.wabbit-networks.io/net-monitor:v1" ], "iat": 1597053992 }.[Signature] @@ -188,18 +187,18 @@ To verify a manifest `example.json` with a signature file `example.nv2`, run Since the manifest was signed by a self-signed certificate, that certificate `cert.pem` is required to be provided to `nv2`. ```shell -nv2 verify \ - -f hello-world.signature.config.jwt \ - -c cert.crt \ - file:hello-world_v1-manifest.json +./nv2 verify \ + -f net-monitor_v1.signature.config.jwt \ + -c wabbit-networks.crt \ + file:net-monitor_v1-manifest.json ``` If the cert isn't self-signed, you can omit the `-c` parameter. ``` shell -nv2 verify \ - -f hello-world.signature.config.jwt \ - file:hello-world_v1-manifest.json +./nv2 verify \ + -f net-monitor_v1.signature.config.jwt \ + file:net-monitor_v1-manifest.json sha256:3351c53952446db17d21b86cfe5829ae70f823aff5d410fbf09dff820a39ab55 ``` @@ -244,8 +243,7 @@ If neither `tag` nor `digest` is specified, the default tag `latest` is used. OCI registry works the same as Docker but with the scheme `oci`. - -``` shell +```shell nv2 sign -m x509 \ -k key.key \ -o hello-world_latest.signature.config.jwt \ diff --git a/docs/nv2/demo-script.md b/docs/nv2/demo-script.md new file mode 100644 index 000000000..8bedadaa5 --- /dev/null +++ b/docs/nv2/demo-script.md @@ -0,0 +1,195 @@ +# nv2 Demo Script + +The following is a summary when presenting a demo of Notary v2. + +## Demo Setup + +Perform the following steps prior to the demo: + +- Install [Docker Desktop](https://www.docker.com/products/docker-desktop) for local docker operations +- [Install and Build the nv2 Prerequisites](./README.md#prerequisites) +- Copy nv2 to the bin directory: + ``` + sudo cp ./nv2 /usr/bin/nv2 + ``` +- Create an empty working directory: + ```bash + mkdir nv2-demo + cd nv2-demo/ + ``` +- Generate the Wabbit Networks Public and Private Keys: + ```bash + # mkdir -p /usr/local/share/certs/private + openssl req \ + -x509 \ + -sha256 \ + -nodes \ + -newkey rsa:2048 \ + -days 365 \ + -subj "/CN=registry.wabbit-networks.io/O=wabbit-networks inc/C=US/ST=Washington/L=Seattle" \ + -addext "subjectAltName=DNS:registry.wabbit-networks.io" \ + -keyout ./wabbit-networks.key \ + -out ./wabbit-networks.crt + ``` +- Start a local registry instance: + ```bash + docker run -d -p 80:5000 --restart always --name registry notaryv2/registry:nv2-prototype-1 + ``` +- Add a `etc/hosts` entry to simulate pushing to registry.wabbit-networks.io + - If running on windows, _even if using wsl_, add the following entry to: `C:\Windows\System32\drivers\etc\hosts` + ```hosts + 127.0.0.1 registry.wabbit-networks.io + ``` + +## Demo Reset + +If iterating through the demo, these are the steps required to reset to a clean state: + +- `unalias docker` +- Reset the local registry: + ``` + docker rm -f $(docker ps -a -q) + docker run -d -p 80:5000 --restart always --name registry notaryv2/registry:nv2-prototype-1 + ``` + +## Demo Steps + +### Explain the end to end experience being presented + +![](../../media/notary-e2e-scenarios.svg) + +- Wabbit Networks is a small software company that produces network monitoring software. +- ACME Rockets wishes to acquire network monitoring software. +- ACME Rockets doesn't know about Wabbit Networks, but finds their [net-monitor software in Docker Hub](https://hub.docker.com/r/wabbitnetworks/net-monitor) +- Since they've never heard of Wabbit Networks, they're a little reluctant to run network software without some validations. +- ACME Rockets has a policy to only import Docker Hub certified software, or approved vendors. +- Wabbit Networks works with Docker Hub to get certified, to help with their customer confidence. +- ACME Rockets will only deploy software that's been scanned and approved by the ACME Rockets security team. They know it's been approved because all approved software has been signed by the ACME Rockets security team. + +### Show Notary Extension + +To demonstrate a clean end to end experience, using the docker cli, we're using the [docker-generate][docker-generate] extension. + +To see the extension capabilities, review the `Management Commands:`: + +```bash +docker --help + +Management Commands: + ... + generate* Generate artifacts (github.com/shizhMSFT, 0.1.0) + nv2* Notary V2 Signature extension (Sajay Antony, Shiwei Zhang, 0.1.0) + +``` + +To see the sub commands of `nv2` and `nv2 notary`: + +```bash +docker nv2 --help +docker nv2 notary --help +``` + +To avoid having to type `docker nv2` each time, we'll create an alias to mask over this: + +```bash +alias docker="docker nv2" +``` + +To avoid having to type the fully qualified registry name, we'll create an environment variable: + +```bash +export image=registry.wabbit-networks.io/net-monitor:v1 +``` + +### Wabbit Networks Build, Sign, Promote Process + +Let's walk through the sequence of operations Wabbit Networks takes to build, sign and promote their software. + +Within the automation of Wabbit Networks, the following steps are completed: + +#### Build the `net-monitor` image + + ```bash + docker build \ + -t $image \ + https://github.com/wabbit-networks/net-monitor.git#main + ``` + +#### Acquire the private key + +- As a best practice, we'll always build on an ephemeral client, with no previous state. +- The ephemeral client will retrieve the private signing key from the companies secured key vault provider. + +These specific steps are product/cloud specific, so we'll assume these steps have been completed. + +#### Sign the image + +Using the private key, we'll sign the net-monitor image. Note, we're signing the image with a registry name that we haven't yet pushed to. This enables offline signing scenarios. This is important as the image will eventually be published on `registry.wabbit-networks.io/`, however their internal staging and promotion process may publish to internal registries before promotion to the public registry. + +This generates an [nv2 signature][nv2-signature], persisted locally as `net-monitor_v1.signature.config.jwt` + +```shell +docker notary --enabled + +docker notary sign \ + --key ./wabbit-networks.key \ + --cert ./wabbit-networks.crt \ + $image + +# view the signature referenced from docker notary sign +cat +``` + +#### Push the image & signature to the registry + +These steps are broken out for clarity, as we hope all container builders will incorporate notary v2 into their build process. + +```shell +docker push $image +``` + +#### Clear the local image + +To simulate another client, we'll clear out the `net-monitor:v1` image + +```bash +docker rmi -f registry.wabbit-networks.io/net-monitor:v1 +rm ~/.docker/nv2/sha256/*.* +``` + +#### Validate the image + +To validate an image, `docker pull` with `docker notary --enabled` will attempt to validate the image, based on the local keys. + +- Get the local manifest: + ```bash + docker pull $image + ``` + +- The above command will fail, as we haven't configured the `nv2` client access to the public keys. + ```bash + Looking up for signatures + Found 1 signatures + 2021/03/02 18:34:47 none of the signatures are valid: verification failure: x509: certificate signed by unknown authority + ``` + +- Open the `nv2.json` configuration file: + ```bash + code ~/.docker/nv2.json + ``` + +- Add the wabbit networks public key: + ```json + { + "enabled": true, + "verificationCerts": [ + "/home/stevelas/nv2-demo/wabbit-networks.crt" + ] + } + ``` + +This shows the target experience we're shooting for, within various build and container runtime tooling. + + +[nv2-signature]: ../signature/README.md +[docker-generate]: https://github.com/shizhMSFT/docker-generate \ No newline at end of file diff --git a/media/notary-e2e-scenarios.png b/media/notary-e2e-scenarios.png deleted file mode 100644 index 2669f3fd447a8bf92873dddc415f09484256f03d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54561 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%0DNEEB07lzZwGE$5@hY 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 RegistryNotary v2 ScopeInteroperability with other projectsImageSBoMsrcIndexArtifact Build Environment14PolicyManagement5ContainerHost3Private RegistryImageSBoMsrcIndexImageSBoMIndexsrcDocker HubACME RocketsdeployImageSBoMIndexsrcArtifact PushArtifact ImportArtifact DeploymentImage \ No newline at end of file From a5bac5ddee57d60c1005badc3267a36c743f2e38 Mon Sep 17 00:00:00 2001 From: Steve Lasker Date: Tue, 2 Mar 2021 19:03:53 -0800 Subject: [PATCH 16/69] Doc and Demo updates Signed-off-by: Steve Lasker --- README.md | 4 ++-- docs/nv2/demo-script.md | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1eb1b9ddc..2997124dd 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ nv2 is an incubation and prototype for the [Notary v2][notary-v2] efforts, securing artifacts stored in [distribution-spec][distribution-spec] based registries. The `nv2` prototype covers the scenarios outlined in [notaryproject/requirements](https://github.com/notaryproject/requirements/blob/master/scenarios.md#scenarios). It also follows the [prototyping approach described here](https://github.com/stevelasker/nv2#prototyping-approach). -![nv2-components](media/notary-e2e-scenarios.png) +![nv2-components](media/notary-e2e-scenarios.svg) To enable the above workflow: @@ -11,7 +11,7 @@ To enable the above workflow: - The [ORAS][oras] client (4) can then push the artifact (2) and the Notary v2 signature (3) to an OCI Artifacts supported registry (5) - In a subsequent prototype, signatures may be retrieved from the OCI Artifacts supported registry (5) -![nv2-components](media/nv2-client-components.png) +![nv2-components](./media/nv2-client-components.png) ## Table of Contents diff --git a/docs/nv2/demo-script.md b/docs/nv2/demo-script.md index 8bedadaa5..5823d7684 100644 --- a/docs/nv2/demo-script.md +++ b/docs/nv2/demo-script.md @@ -190,6 +190,5 @@ To validate an image, `docker pull` with `docker notary --enabled` will attempt This shows the target experience we're shooting for, within various build and container runtime tooling. - [nv2-signature]: ../signature/README.md [docker-generate]: https://github.com/shizhMSFT/docker-generate \ No newline at end of file From 3a6d3a665f2cf34d74d5ed4340bb71b9e72b5095 Mon Sep 17 00:00:00 2001 From: Steve Lasker Date: Tue, 2 Mar 2021 20:19:14 -0800 Subject: [PATCH 17/69] nv2 demo script updates Signed-off-by: Steve Lasker --- docs/nv2/demo-script.md | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/docs/nv2/demo-script.md b/docs/nv2/demo-script.md index 5823d7684..40ba90e2c 100644 --- a/docs/nv2/demo-script.md +++ b/docs/nv2/demo-script.md @@ -8,10 +8,6 @@ Perform the following steps prior to the demo: - Install [Docker Desktop](https://www.docker.com/products/docker-desktop) for local docker operations - [Install and Build the nv2 Prerequisites](./README.md#prerequisites) -- Copy nv2 to the bin directory: - ``` - sudo cp ./nv2 /usr/bin/nv2 - ``` - Create an empty working directory: ```bash mkdir nv2-demo @@ -19,7 +15,6 @@ Perform the following steps prior to the demo: ``` - Generate the Wabbit Networks Public and Private Keys: ```bash - # mkdir -p /usr/local/share/certs/private openssl req \ -x509 \ -sha256 \ @@ -51,6 +46,7 @@ If iterating through the demo, these are the steps required to reset to a clean docker rm -f $(docker ps -a -q) docker run -d -p 80:5000 --restart always --name registry notaryv2/registry:nv2-prototype-1 ``` +- Remove certs: `code ~/.docker/nv2.json` ## Demo Steps @@ -161,7 +157,7 @@ rm ~/.docker/nv2/sha256/*.* To validate an image, `docker pull` with `docker notary --enabled` will attempt to validate the image, based on the local keys. -- Get the local manifest: +- Attempt to pull the `net-monitor:v1` image: ```bash docker pull $image ``` @@ -188,6 +184,24 @@ To validate an image, `docker pull` with `docker notary --enabled` will attempt } ``` +- Pull the `net-monitor:v1` image, using the public key for verification: + ```bash + docker pull $image + ``` +- The validated pull can be seen: + ```bash + v1 digest: sha256:48575dfb9ef2ebb9d67c6ed3cfbd784d635fcfae8ec820235ffa24968b3474dc size: 527 + Looking up for signatures + Found 1 signatures + Found valid signature: sha256:282f5475ac4788f5c0ce3c0c44995726192385c2cae85d0f04da12595707a73f + The image is originated from: + - registry.wabbit-networks.io/net-monitor:v1 + registry.wabbit-networks.io/net-monitor@sha256:48575dfb9ef2ebb9d67c6ed3cfbd784d635fcfae8ec820235ffa24968b3474dc: Pulling from net-monitor + Digest: sha256:48575dfb9ef2ebb9d67c6ed3cfbd784d635fcfae8ec820235ffa24968b3474dc + Status: Downloaded newer image for registry.wabbit-networks.io/net-monitor@sha256:48575dfb9ef2ebb9d67c6ed3cfbd784d635fcfae8ec820235ffa24968b3474dc + registry.wabbit-networks.io/net-monitor@sha256:48575dfb9ef2ebb9d67c6ed3cfbd784d635fcfae8ec820235ffa24968b3474dc + ``` + This shows the target experience we're shooting for, within various build and container runtime tooling. [nv2-signature]: ../signature/README.md From a7ae4ebfe077b1a796be20b1781a0f6243f705dc Mon Sep 17 00:00:00 2001 From: Steve Lasker Date: Wed, 3 Mar 2021 08:27:39 -0800 Subject: [PATCH 18/69] nv2 demo: cleanup steps Signed-off-by: Steve Lasker --- docs/nv2/demo-script.md | 79 ++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/docs/nv2/demo-script.md b/docs/nv2/demo-script.md index 40ba90e2c..620556d90 100644 --- a/docs/nv2/demo-script.md +++ b/docs/nv2/demo-script.md @@ -40,13 +40,23 @@ Perform the following steps prior to the demo: If iterating through the demo, these are the steps required to reset to a clean state: -- `unalias docker` -- Reset the local registry: +- Remove docker alias: + ```bash + unalias docker ``` +- Reset the local registry: + ```bash docker rm -f $(docker ps -a -q) docker run -d -p 80:5000 --restart always --name registry notaryv2/registry:nv2-prototype-1 ``` -- Remove certs: `code ~/.docker/nv2.json` +- Remove the `net-monitor:v1` image: + ```bash + docker rmi -f registry.wabbit-networks.io/net-monitor:v1 + ``` +- Remove `wabbit-networks.crt` from `"verificationCerts"`: + ```bash + code ~/.docker/nv2.json + ``` ## Demo Steps @@ -97,63 +107,68 @@ To avoid having to type the fully qualified registry name, we'll create an envir export image=registry.wabbit-networks.io/net-monitor:v1 ``` -### Wabbit Networks Build, Sign, Promote Process +## Wabbit Networks Build, Sign, Promote Process Let's walk through the sequence of operations Wabbit Networks takes to build, sign and promote their software. Within the automation of Wabbit Networks, the following steps are completed: -#### Build the `net-monitor` image +### Build the `net-monitor` image - ```bash - docker build \ - -t $image \ - https://github.com/wabbit-networks/net-monitor.git#main - ``` +```bash +docker build \ + -t $image \ + https://github.com/wabbit-networks/net-monitor.git#main +``` -#### Acquire the private key +### Acquire the private key - As a best practice, we'll always build on an ephemeral client, with no previous state. - The ephemeral client will retrieve the private signing key from the companies secured key vault provider. These specific steps are product/cloud specific, so we'll assume these steps have been completed. -#### Sign the image +### Sign the image Using the private key, we'll sign the net-monitor image. Note, we're signing the image with a registry name that we haven't yet pushed to. This enables offline signing scenarios. This is important as the image will eventually be published on `registry.wabbit-networks.io/`, however their internal staging and promotion process may publish to internal registries before promotion to the public registry. -This generates an [nv2 signature][nv2-signature], persisted locally as `net-monitor_v1.signature.config.jwt` +- Generate an [nv2 signature][nv2-signature], persisted locally as `net-monitor_v1.signature.config.jwt` -```shell -docker notary --enabled + ```shell + docker notary --enabled -docker notary sign \ - --key ./wabbit-networks.key \ - --cert ./wabbit-networks.crt \ - $image + docker notary sign \ + --key ./wabbit-networks.key \ + --cert ./wabbit-networks.crt \ + $image + ``` +- view the signature referenced from docker notary sign + ```bash + cat + ``` -# view the signature referenced from docker notary sign -cat -``` +- View the manifest the signature is based upon: + ```bash + docker generate manifest $image + ``` -#### Push the image & signature to the registry +### Push the image & signature to the registry -These steps are broken out for clarity, as we hope all container builders will incorporate notary v2 into their build process. +Push the image, and its signature in one user gesture. Note the push links the signature to the image for later retrevial by a `:tag` or `digest`. ```shell docker push $image ``` -#### Clear the local image - -To simulate another client, we'll clear out the `net-monitor:v1` image +### Clear the local image -```bash -docker rmi -f registry.wabbit-networks.io/net-monitor:v1 -rm ~/.docker/nv2/sha256/*.* -``` +- To simulate another client, we'll clear out the `net-monitor:v1` image + ```bash + docker rmi -f registry.wabbit-networks.io/net-monitor:v1 + rm ~/.docker/nv2/sha256/*.* + ``` -#### Validate the image +### Validate the image To validate an image, `docker pull` with `docker notary --enabled` will attempt to validate the image, based on the local keys. From 24fc5c56428759aaf57ab16b2d83a71065f2dd8e Mon Sep 17 00:00:00 2001 From: Steve Lasker Date: Tue, 9 Mar 2021 17:17:15 -0800 Subject: [PATCH 19/69] Prototype-2 initial mocks Signed-off-by: Steve Lasker --- docs/nv2/demo-script-detailed.md | 375 ++++++++++++++++++++ docs/nv2/demo-script.md | 2 +- media/net-monitor-sbom-signed-artifacts.svg | 1 + media/net-monitor-sbom-signed-detailed.svg | 1 + 4 files changed, 378 insertions(+), 1 deletion(-) create mode 100644 docs/nv2/demo-script-detailed.md create mode 100644 media/net-monitor-sbom-signed-artifacts.svg create mode 100644 media/net-monitor-sbom-signed-detailed.svg diff --git a/docs/nv2/demo-script-detailed.md b/docs/nv2/demo-script-detailed.md new file mode 100644 index 000000000..dc362b967 --- /dev/null +++ b/docs/nv2/demo-script-detailed.md @@ -0,0 +1,375 @@ +# Detailed Demo Steps + +The following demonstrates the underlying details of **prototype-2**. + +> At this point, this is a target experience, that is still being developed. + +## Demo Setup + +Perform the following steps prior to the demo: + +- Install [Docker Desktop](https://www.docker.com/products/docker-desktop) for local docker operations +- [Install and Build the nv2 Prerequisites](./README.md#prerequisites) +- Create an empty working directory: + ```bash + mkdir nv2-demo + cd nv2-demo/ + ``` +- Generate the Wabbit Networks Public and Private Keys: + ```bash + openssl req \ + -x509 \ + -sha256 \ + -nodes \ + -newkey rsa:2048 \ + -days 365 \ + -subj "/CN=registry.wabbit-networks.io/O=wabbit-networks inc/C=US/ST=Washington/L=Seattle" \ + -addext "subjectAltName=DNS:registry.wabbit-networks.io" \ + -keyout ./wabbit-networks.key \ + -out ./wabbit-networks.crt + ``` +- Start a local registry instance: + ```bash + # NOTE: the nv2-prototype-2 image does not yet exist + docker run -d -p 80:5000 --restart always --name registry notaryv2/registry:nv2-prototype-2 + ``` +- Add a `etc/hosts` entry to simulate pushing to registry.wabbit-networks.io + - If running on windows, _even if using wsl_, add the following entry to: `C:\Windows\System32\drivers\etc\hosts` + ```hosts + 127.0.0.1 registry.wabbit-networks.io + ``` + +## Demo Reset + +If iterating through the demo, these are the steps required to reset to a clean state: + +- Remove docker alias: + ```bash + unalias docker + ``` +- Reset the local registry: + ```bash + docker rm -f $(docker ps -a -q) + docker run -d -p 80:5000 --restart always --name registry notaryv2/registry:nv2-prototype-1 + ``` +- Remove the `net-monitor:v1` image: + ```bash + docker rmi -f registry.wabbit-networks.io/net-monitor:v1 + ``` +- Remove `wabbit-networks.crt` from `"verificationCerts"`: + ```bash + code ~/.docker/nv2.json + ``` + +## The End to End Experience + +![](../../media/notary-e2e-scenarios.svg) + +- Wabbit Networks is a small software company that produces network monitoring software. +- ACME Rockets wishes to acquire network monitoring software. +- ACME Rockets doesn't know about Wabbit Networks, but finds their [net-monitor software in Docker Hub](https://hub.docker.com/r/wabbitnetworks/net-monitor) +- Since they've never heard of Wabbit Networks, they're a little reluctant to run network software without some validations. +- ACME Rockets has a policy to only import Docker Hub certified software, or approved vendors. +- Wabbit Networks works with Docker Hub to get certified, to help with their customer confidence. +- ACME Rockets will only deploy software that's been scanned and approved by the ACME Rockets security team. They know it's been approved because all approved software has been signed by the ACME Rockets security team. + +## Wabbit Networks Build, Sign, Promote Process + +Let's walk through the sequence of operations Wabbit Networks takes to build, sign and promote their software. + +Within the automation of Wabbit Networks, the following steps are completed: + +### Build the `net-monitor` image + + ```bash + docker build \ + -t registry.wabbit-networks.io/net-monitor:v1 \ + https://github.com/wabbit-networks/net-monitor.git#main + ``` + +### Generate the manifest + +In normal docker operations, the image manifest is a hidden element the user doesn't have to deal with. For the sake full transparency, we'll highlight the full workflow by generating the manifest to sign the digest: + +```bash +docker generate manifest registry.wabbit-networks.io/net-monitor:v1 > net-monitor_v1-manifest.json + +# view the manifest +cat ./net-monitor_v1-manifest.json +``` + +### Acquire the private key + +> TODO: Add any key management prototype steps here: + +- As a best practice, we'll always build on an ephemeral client, with no previous state. +- The ephemeral client will retrieve the private signing key from the companies secured key vault provider. + +These specific steps are product/cloud specific, so we'll assume these steps have been completed and we have the required keys. + +### Sign the image + +Using the private key, we'll sign the `net-monitor:v1` image. Note, we're signing the image with a registry name that we haven't yet pushed to. This enables offline signing scenarios. This is important as the image will eventually be published on `registry.wabbit-networks.io/`, however their internal staging and promotion process may publish to internal registries before promotion to the public registry. + +- Generates an [nv2 signature][nv2-signature], persisted locally as `net-monitor_v1.signature.jwt` + + ```shell + nv2 sign -m x509 \ + -o net-monitor_v1.signature-jwt \ + -k ~/.ssh/wabbit-networks.key \ + -r registry.wabbit-networks.io/net-monitor:v1 \ + file:net-monitor_v1-manifest.json + + # view the signature + cat ./net-monitor_v1-signature.jwt + ``` + +### Generate an SBoM + +This demo focuses on the signing of additional content, including an SBoM. It doesn't focus on a specific SBoM format. As a result, we'll generate the most basic, and _admittedly_ useless SBoM document: + +```bash +echo '{"version": "0.0.0.0", "image": "registry.wabbit-networks.io/net-monitor:v1", "contents": "good"}' > sbom_v1.json +``` + +### Sign the SBoM + +This is where some of the Notary v2 signature and persistance formats come through. Notary v2 signs a _**Registry Manifest**_. Registry manifests are things that describe the content that's persisted in the registry. There are two manifest formats today: [image-manifest][oci-image-manifest] and [image-index][oci-image-index]. These manifests describe self-contained content, for container images. Since Notary v2 signatures are enhancements to exiting content, we need a way to describe self-contained content that references existing content. An SBoM is yet another type of reference content. The [oci.artifact.manifest][oci-artifact-manifest] provides the ability to describe self-contained content, and link to existing content. + +To enable a Notary v2 signature of an [oci.artifact.manifest][oci-artifact-manifest], we first need to generate that manifest. In the container scenarios, we used the [docker-generate][docker-generate] plug-in to generate a manifest for container images. + +- For non-container images, we'll use the [ORAS cli][oras] to generate an [oci.artifact.manifest][oci-artifact-manifest]. + ```bash + oras generate-manifest \ + --manifest-type application/vnd.oci.artifact.manifest.v1 \ + --artifact-type application/vnd.example.sbom.v0 \ + --manifests oci://registry.wabbit-networks.io/net-monitor@sha256:1a0a0a89a \ + --output sbom_v1-manifest.json \ + ./sbom_v1.json + + # view the manifest + cat sbom_v1-manifest.json + ``` + +- Sign the manifest that represents the SBoM. + + ```bash + nv2 sign -m x509 \ + -k ~/.ssh/wabbit-networks.key \ + -r registry.wabbit-networks.io/net-monitor:v1 \ + -o net-monitor_v1-sbom.signature.jwt \ + file:sbom_v1-manifest.json + + # view the signature + cat ./net-monitor_v1-sbom.signature.jwt + ``` + +### Summary of artifacts + +At this point we have the following artifacts and content: + +![](../../media/net-monitor-sbom-signed-detailed.svg) + +- the `net-monitor:v1` image + - the blob content of the `net-monitor:v1` image +- a wabbit-networks signature of the `net-monitor:v1` image + - the blob content of the signature +- an SBoM for the `net-monitor:v1` image + - the blob content of the sbom +- a wabbit-networks signature of the `net-monitor:v1` sbom + - the blob content of the signature for the sbom + +![](../../media/net-monitor-sbom-signed-artifacts.svg) + +Viewed with less detail, the above image represents 4 artifacts connected through linked manifests: + +1. the `net-monitor:v1` image +1. a wabbit-networks signature of the `net-monitor:v1` image +1. an SBoM for the `net-monitor:v1` image +1. a wabbit-networks signature of the `net-monitor:v1` sbom + +### Push artifacts to the registry + +- Push the container image + + ```bash + docker push registry.wabbit-networks.io/net-monitor:v1 + ``` + +- Push the `net-monitor:v1` signature to the registry using ORAS + + ```bash + # implies a new means to push an artifact to a repo, without a tag + # need a good design for how to declare content is pushed, where the digest is computed by ORAS, or the underlying tool + # linked-manifest uses digests to assure links are established to the specific artifact, avoiding conflicts to updating tags + # artifact-type replaces + oras push registry.wabbit-networks.io/net-monitor \ + --push-as-digest \ + --artifact-type application/vnd.cncf.notary.v2 \ + --manifest-type application/vnd.oci.artifact.manifest.v1 \ + --manifests registry.wabbit-networks.io/net-monitor@sha256:12as1201... \ + --plain-http \ + ./net-monitor_v1.signature.jwt + ``` + +- Push the `net-monitor:v1` **sbom** to the registry using ORAS + + ```bash + oras push registry.wabbit-networks.io/net-monitor \ + --push-as-digest \ + --artifact-type application/vnd.example.sbom.v0 \ + --manifest-type application/vnd.oci.artifact.manifest.v1 \ + --manifest registry.wabbit-networks.io/net-monitor@sha256:12as1201... \ + --plain-http \ + ./sbom_v1-manifest.json + # Note: need to capture the digest of the pushed SBoM, for the linkage of the signature + ``` + +- Push the `net-monitor:v1` **sbom signature** to the registry using ORAS + + ```bash + oras push registry.wabbit-networks.io/net-monitor \ + --push-as-digest \ + --artifact-type application/vnd.cncf.notary.v2 \ + --manifest-type application/vnd.oci.artifact.manifest.v1 \ + --manifest registry.wabbit-networks.io/net-monitor@sha256:12as1201... \ + --plain-http \ + ./net-monitor_v1-sbom.signature.jwt + ``` + +## Pulling Validated Content + +To represent a deployed, ephemeral node, we'll pull the `net-monitor:v1` image, validating the signature of the image and the sbom. + +### Clear the build content + +To simulate another client, we'll clear out the `net-monitor:v1` image and signature, simulating a new environment. + +> Note: The public and private keys are maintained, deferring to key management prototypes for how keys should be acquired. + +```bash +docker rmi -f registry.wabbit-networks.io/net-monitor:v1 +rm *.jwt +rm *.json +``` + +### Attempt, and fail to pull the image + +Simulate a notary enabled client, which doesn't yet have the public keys configured. + +- Get the digest for the `net-monitor:v1` image: + ```bash + NET_MONITOR_DIGEST=$(curl -v -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \ + registry.wabbit-networks.io/v2/net-monitor/manifests/v1 2>&1 | \ + grep -i 'Docker-Content-Digest:' | \ + awk '{print $3}') + ``` +- Query for Notary v2 linked artifacts + ```bash + curl -v -H "Accept: artifactType=application/vnd.cncf.notary.v2" \ + registry.wabbit-networks.io/v2/_ext/oci-artifacts/net-monitor/manifests/${NET_MONITOR_DIGEST}/links + NET_MONITOR_SIG_DIGEST=^ + ``` +- Retrieve the `net-monitor:v1` notary v2 signature + ```bash + oras pull registry.wabbit-networks.io/net-monitor@sha256:${NET_MONITOR_SIG_DIGEST} \ + --plain-http + ``` +- Validate the signature + ```bash + nv2 verify \ + -c ./wabbit-networks.crt \ + -f net-monitor_v1.signature.jwt \ + oci://registry.wabbit-networks.io/net-monitor:v1 + ``` + The above validation will fail, as we haven't yet configured notary to find the `wabbit-networks.crt` public key. +- Configure Notary access to the wabbit-networks key + ```bash + code ~/.docker/nv2.json + ``` +- Add the path to the cert: + ```json + "verificationCerts": [ + "/home/stevelas/nv2-demo/wabbit-networks.crt" + ] + ``` +- Validate the signature + ```bash + nv2 verify \ + -c ./wabbit-networks.crt \ + -f net-monitor_v1.signature.jwt \ + oci://registry.wabbit-networks.io/net-monitor:v1 + ``` + +- Pull the image, as the signature validation succeeded + ```bash + docker pull $image + ``` + +## Appendix + +### Convert the tag to a digest + +```bash +curl -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -vvv -k registry.wabbit-networks.io/v2/net-monitor/manifests/v1 +curl -H "Accept: application/vnd.oci.image.manifest.v2+json" -vvv -k registry.wabbit-networks.io/v2/net-monitor/manifests/v1 +curl -vvv -k registry.wabbit-networks.io/v2/net-monitor/manifests/v1 + +curl -v -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \ + https://mcr.microsoft.com/v2/aks/hcp/etcd-azure/manifests/v3.1.19 2>&1 | \ + grep -i 'Docker-Content-Digest:' | \ + awk '{print $3}' +curl -v -H "Accept: application/vnd.oci.image.manifest.v2+json" \ + https://mcr.microsoft.com/v2/aks/hcp/etcd-azure/manifests/v3.1.19 2>&1 | \ + grep -i 'Docker-Content-Digest:' | \ + awk '{print $3}' + +curl -v -H "Accept: application/vnd.oci.image.manifest.v2+json" \ + https://mcr.microsoft.com/v2/aks/hcp/etcd-azure/manifests/v3.1.19 2>&1 | \ + grep -i 'Docker-Content-Digest:' | \ + awk '{print $3}' + + + +curl -v -H "Accept: application/vnd.oci.image.manifest.v2+json" \ + registry.wabbit-networks.io/v2/net-monitor/manifests/v1 2>&1 | \ + grep -i 'Docker-Content-Digest:' | \ + awk '{print $3}' +``` + +### Query for linked artifacts + +```bash +GET /v2/_ext/{repository}/manifests/{digest}/links?artifactType=application/vnd.oci.notary.v2.config+json&n=10 +GET registry.wabbit-networks.io/v2/_ext/net-monitor/manifests/{digest}/links?artifactType=application/vnd.oci.notary.v2.config+json + +``` + +#### Validate the image + +To validate an image, we need the signature, which can be pulled prior to the image. We want to avoid pulling images we haven't validated, as this could be a trojan horse type exploit. + +```bash +oras pull registry.wabbit-networks.io/net-monitor:v1-signature -a --plain-http +``` +> TODO: Fix CN validation +```bash +nv2 verify \ + -c ~/.ssh/wabbit-networks.crt \ + -f net-monitor_v1.signature.jwt \ + file:net-monitor_v1-manifest.json + +nv2 verify \ + -c ~/.ssh/wabbit-networks.crt \ + -f net-monitor_v1.signature.jwt \ + oci://registry.wabbit-networks.io/net-monitor:v1 + +2021/03/02 14:27:38 verification failure: x509: certificate relies on legacy Common Name field, use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0 +``` + +[docker-generate]: https://github.com/shizhMSFT/docker-generate +[nv2-signature]: ../signature/README.md +[oci-image-manifest]: https://github.com/opencontainers/image-spec/blob/master/manifest.md +[oci-image-index]: https://github.com/opencontainers/image-spec/blob/master/image-index.md +[oci-artifact-manifest]: https://github.com/opencontainers/artifacts/blob/3e34f029537052639eed59b469cb6c43706ac3d0/artifact-manifest.md +[oras]: https://github.com/deislabs/oras \ No newline at end of file diff --git a/docs/nv2/demo-script.md b/docs/nv2/demo-script.md index 620556d90..66b867b87 100644 --- a/docs/nv2/demo-script.md +++ b/docs/nv2/demo-script.md @@ -1,6 +1,6 @@ # nv2 Demo Script -The following is a summary when presenting a demo of Notary v2. +The following is a summary when presenting a demo of Notary v2 - prototype-2. ## Demo Setup diff --git a/media/net-monitor-sbom-signed-artifacts.svg b/media/net-monitor-sbom-signed-artifacts.svg new file mode 100644 index 000000000..2e4ec4ef5 --- /dev/null +++ b/media/net-monitor-sbom-signed-artifacts.svg @@ -0,0 +1 @@ +net-monitor:v1SBoMdocumentSBoMWabbit Networks signatureWabbit Networks signaturecontent (blobs) \ No newline at end of file diff --git a/media/net-monitor-sbom-signed-detailed.svg b/media/net-monitor-sbom-signed-detailed.svg new file mode 100644 index 000000000..7002954e2 --- /dev/null +++ b/media/net-monitor-sbom-signed-detailed.svg @@ -0,0 +1 @@ +signature content (blob)net-monitor:v1SBoMdocumentSBoMWabbit Networks signatureWabbit Networks signaturelayer1 (blob)layer2 (blob)config (blob)sbomcontent (blob)signature content (blob) \ No newline at end of file From 9f54b68f64f4bc127f7b591e0873e0653e81ae13 Mon Sep 17 00:00:00 2001 From: Steve Lasker Date: Tue, 9 Mar 2021 18:58:25 -0800 Subject: [PATCH 20/69] Prototype-2 initial mocks Signed-off-by: Steve Lasker --- docs/nv2/demo-script-detailed.md | 119 ++++++++++++++++--------------- 1 file changed, 62 insertions(+), 57 deletions(-) diff --git a/docs/nv2/demo-script-detailed.md b/docs/nv2/demo-script-detailed.md index dc362b967..cdb8e8754 100644 --- a/docs/nv2/demo-script-detailed.md +++ b/docs/nv2/demo-script-detailed.md @@ -79,6 +79,36 @@ Let's walk through the sequence of operations Wabbit Networks takes to build, si Within the automation of Wabbit Networks, the following steps are completed: +1. Build the container image +1. Sign the container image +1. Create an SBoM +1. Sign the SBoM +1. Push the image, sbom, and the associated signatures to the registry + +### Summary of artifacts + +The following graph of artifacts will be created and pushed to the registry + +![](../../media/net-monitor-sbom-signed-detailed.svg) + +- the `net-monitor:v1` image + - the blob content of the `net-monitor:v1` image +- a wabbit-networks signature of the `net-monitor:v1` image + - the blob content of the signature +- an SBoM for the `net-monitor:v1` image + - the blob content of the sbom +- a wabbit-networks signature of the `net-monitor:v1 sbom` + - the blob content of the signature for the sbom + +![](../../media/net-monitor-sbom-signed-artifacts.svg) + +Viewed with less detail, the above image represents 4 artifacts connected through linked manifests: + +1. the `net-monitor:v1` image +1. a wabbit-networks signature of the `net-monitor:v1` image +1. an SBoM for the `net-monitor:v1` image +1. a wabbit-networks signature of the `net-monitor:v1 sbom` + ### Build the `net-monitor` image ```bash @@ -89,10 +119,11 @@ Within the automation of Wabbit Networks, the following steps are completed: ### Generate the manifest -In normal docker operations, the image manifest is a hidden element the user doesn't have to deal with. For the sake full transparency, we'll highlight the full workflow by generating the manifest to sign the digest: +Notary v2 signs the manifests of the content as they're represented within a registry. In normal docker operations, the image manifest is a hidden element the user doesn't have to deal with. For the sake full transparency, we'll highlight the full workflow by generating the manifest to sign the digest. ```bash -docker generate manifest registry.wabbit-networks.io/net-monitor:v1 > net-monitor_v1-manifest.json +docker generate manifest registry.wabbit-networks.io/net-monitor:v1 \ + > net-monitor_v1-manifest.json # view the manifest cat ./net-monitor_v1-manifest.json @@ -107,24 +138,46 @@ cat ./net-monitor_v1-manifest.json These specific steps are product/cloud specific, so we'll assume these steps have been completed and we have the required keys. -### Sign the image +### Sign and Push Using the private key, we'll sign the `net-monitor:v1` image. Note, we're signing the image with a registry name that we haven't yet pushed to. This enables offline signing scenarios. This is important as the image will eventually be published on `registry.wabbit-networks.io/`, however their internal staging and promotion process may publish to internal registries before promotion to the public registry. -- Generates an [nv2 signature][nv2-signature], persisted locally as `net-monitor_v1.signature.jwt` +- Generates an [nv2 signature][nv2-signature], persisted locally as `net-monitor_v1-signature.jwt` ```shell nv2 sign -m x509 \ - -o net-monitor_v1.signature-jwt \ + -o net-monitor_v1-signature.jwt \ -k ~/.ssh/wabbit-networks.key \ -r registry.wabbit-networks.io/net-monitor:v1 \ - file:net-monitor_v1-manifest.json + file:./net-monitor_v1-manifest.json # view the signature cat ./net-monitor_v1-signature.jwt ``` -### Generate an SBoM +- Push the container image + + ```bash + docker push registry.wabbit-networks.io/net-monitor:v1 + ``` + +- Push the `net-monitor:v1` signature to the registry using ORAS + + ```bash + # implies a new means to push an artifact to a repo, without a tag + # need a good design for how to declare content is pushed, where the digest is computed by ORAS, or the underlying tool + # linked-manifest uses digests to assure links are established to the specific artifact, avoiding conflicts to updating tags + # artifact-type replaces + oras push registry.wabbit-networks.io/net-monitor \ + --push-as-digest \ + --artifact-type application/vnd.cncf.notary.v2 \ + --manifest-type application/vnd.oci.artifact.manifest.v1 \ + --manifests registry.wabbit-networks.io/net-monitor@sha256:12as1201... \ + --plain-http \ + ./net-monitor_v1.signature.jwt + ``` + +## Generate an SBoM This demo focuses on the signing of additional content, including an SBoM. It doesn't focus on a specific SBoM format. As a result, we'll generate the most basic, and _admittedly_ useless SBoM document: @@ -164,54 +217,6 @@ To enable a Notary v2 signature of an [oci.artifact.manifest][oci-artifact-manif cat ./net-monitor_v1-sbom.signature.jwt ``` -### Summary of artifacts - -At this point we have the following artifacts and content: - -![](../../media/net-monitor-sbom-signed-detailed.svg) - -- the `net-monitor:v1` image - - the blob content of the `net-monitor:v1` image -- a wabbit-networks signature of the `net-monitor:v1` image - - the blob content of the signature -- an SBoM for the `net-monitor:v1` image - - the blob content of the sbom -- a wabbit-networks signature of the `net-monitor:v1` sbom - - the blob content of the signature for the sbom - -![](../../media/net-monitor-sbom-signed-artifacts.svg) - -Viewed with less detail, the above image represents 4 artifacts connected through linked manifests: - -1. the `net-monitor:v1` image -1. a wabbit-networks signature of the `net-monitor:v1` image -1. an SBoM for the `net-monitor:v1` image -1. a wabbit-networks signature of the `net-monitor:v1` sbom - -### Push artifacts to the registry - -- Push the container image - - ```bash - docker push registry.wabbit-networks.io/net-monitor:v1 - ``` - -- Push the `net-monitor:v1` signature to the registry using ORAS - - ```bash - # implies a new means to push an artifact to a repo, without a tag - # need a good design for how to declare content is pushed, where the digest is computed by ORAS, or the underlying tool - # linked-manifest uses digests to assure links are established to the specific artifact, avoiding conflicts to updating tags - # artifact-type replaces - oras push registry.wabbit-networks.io/net-monitor \ - --push-as-digest \ - --artifact-type application/vnd.cncf.notary.v2 \ - --manifest-type application/vnd.oci.artifact.manifest.v1 \ - --manifests registry.wabbit-networks.io/net-monitor@sha256:12as1201... \ - --plain-http \ - ./net-monitor_v1.signature.jwt - ``` - - Push the `net-monitor:v1` **sbom** to the registry using ORAS ```bash @@ -219,7 +224,7 @@ Viewed with less detail, the above image represents 4 artifacts connected throug --push-as-digest \ --artifact-type application/vnd.example.sbom.v0 \ --manifest-type application/vnd.oci.artifact.manifest.v1 \ - --manifest registry.wabbit-networks.io/net-monitor@sha256:12as1201... \ + --manifests oci://registry.wabbit-networks.io/net-monitor@sha256:1a0a0a89a \ --plain-http \ ./sbom_v1-manifest.json # Note: need to capture the digest of the pushed SBoM, for the linkage of the signature @@ -232,7 +237,7 @@ Viewed with less detail, the above image represents 4 artifacts connected throug --push-as-digest \ --artifact-type application/vnd.cncf.notary.v2 \ --manifest-type application/vnd.oci.artifact.manifest.v1 \ - --manifest registry.wabbit-networks.io/net-monitor@sha256:12as1201... \ + --manifests oci://registry.wabbit-networks.io/net-monitor@${NET_MONITOR_SBOM_DIGEST} \ --plain-http \ ./net-monitor_v1-sbom.signature.jwt ``` From 7fbc45fe928b9f0c6e0ae5f4507dfa41eea1e222 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Tue, 30 Mar 2021 18:51:30 +0800 Subject: [PATCH 21/69] Use library implementation Signed-off-by: Shiwei Zhang --- cmd/nv2/common.go | 6 +- cmd/nv2/main.go | 2 +- cmd/nv2/manifest.go | 8 +- cmd/nv2/sign.go | 6 +- cmd/nv2/verify.go | 11 ++- docs/nv2/README.md | 10 +-- go.mod | 4 +- go.sum | 5 ++ internal/crypto/x509.go | 51 ----------- pkg/registry/client.go | 14 +-- pkg/registry/manifest.go | 4 +- pkg/signature/encoding.go | 30 ------- pkg/signature/errors.go | 14 --- pkg/signature/interface.go | 12 --- pkg/signature/model.go | 28 ------ pkg/signature/scheme.go | 117 ------------------------- pkg/signature/x509/header.go | 18 ---- pkg/signature/x509/signer.go | 113 ------------------------ pkg/signature/x509/type.go | 4 - pkg/signature/x509/verifier.go | 155 --------------------------------- 20 files changed, 38 insertions(+), 574 deletions(-) delete mode 100644 internal/crypto/x509.go delete mode 100644 pkg/signature/encoding.go delete mode 100644 pkg/signature/errors.go delete mode 100644 pkg/signature/interface.go delete mode 100644 pkg/signature/model.go delete mode 100644 pkg/signature/scheme.go delete mode 100644 pkg/signature/x509/header.go delete mode 100644 pkg/signature/x509/signer.go delete mode 100644 pkg/signature/x509/type.go delete mode 100644 pkg/signature/x509/verifier.go diff --git a/cmd/nv2/common.go b/cmd/nv2/common.go index 981b36788..5502225a1 100644 --- a/cmd/nv2/common.go +++ b/cmd/nv2/common.go @@ -13,9 +13,9 @@ var ( Aliases: []string{"p"}, Usage: "password for generic remote access", } - insecureFlag = &cli.BoolFlag{ - Name: "insecure", - Usage: "enable insecure remote access", + plainHTTPFlag = &cli.BoolFlag{ + Name: "plain-http", + Usage: "remote access via plain HTTP", } mediaTypeFlag = &cli.StringFlag{ Name: "media-type", diff --git a/cmd/nv2/main.go b/cmd/nv2/main.go index 93c82436d..61d21d716 100644 --- a/cmd/nv2/main.go +++ b/cmd/nv2/main.go @@ -11,7 +11,7 @@ func main() { app := &cli.App{ Name: "nv2", Usage: "Notary V2 - Prototype", - Version: "0.2.0", + Version: "0.2.1", Authors: []*cli.Author{ { Name: "Shiwei Zhang", diff --git a/cmd/nv2/manifest.go b/cmd/nv2/manifest.go index 588e696a2..780ebc640 100644 --- a/cmd/nv2/manifest.go +++ b/cmd/nv2/manifest.go @@ -8,8 +8,8 @@ import ( "os" "strings" + "github.com/notaryproject/notary/v2/signature" "github.com/notaryproject/nv2/pkg/registry" - "github.com/notaryproject/nv2/pkg/signature" "github.com/opencontainers/go-digest" "github.com/urfave/cli/v2" ) @@ -59,9 +59,9 @@ func getManfestsFromURI(ctx *cli.Context, uri string) (signature.Manifest, error r = file case "docker", "oci": remote := registry.NewClient(nil, ®istry.ClientOptions{ - Username: ctx.String(usernameFlag.Name), - Password: ctx.String(passwordFlag.Name), - Insecure: ctx.Bool(insecureFlag.Name), + Username: ctx.String(usernameFlag.Name), + Password: ctx.String(passwordFlag.Name), + PlainHTTP: ctx.Bool(plainHTTPFlag.Name), }) return remote.GetManifestMetadata(parsed) default: diff --git a/cmd/nv2/sign.go b/cmd/nv2/sign.go index df79d2af4..2efcc5c42 100644 --- a/cmd/nv2/sign.go +++ b/cmd/nv2/sign.go @@ -6,8 +6,8 @@ import ( "strings" "time" - "github.com/notaryproject/nv2/pkg/signature" - "github.com/notaryproject/nv2/pkg/signature/x509" + "github.com/notaryproject/notary/v2/signature" + "github.com/notaryproject/notary/v2/signature/x509" "github.com/urfave/cli/v2" ) @@ -53,7 +53,7 @@ var signCommand = &cli.Command{ }, usernameFlag, passwordFlag, - insecureFlag, + plainHTTPFlag, mediaTypeFlag, }, Action: runSign, diff --git a/cmd/nv2/verify.go b/cmd/nv2/verify.go index 2db1652a7..71c7ffa44 100644 --- a/cmd/nv2/verify.go +++ b/cmd/nv2/verify.go @@ -5,9 +5,8 @@ import ( "fmt" "io/ioutil" - "github.com/notaryproject/nv2/internal/crypto" - "github.com/notaryproject/nv2/pkg/signature" - x509nv2 "github.com/notaryproject/nv2/pkg/signature/x509" + "github.com/notaryproject/notary/v2/signature" + x509nv2 "github.com/notaryproject/notary/v2/signature/x509" "github.com/urfave/cli/v2" ) @@ -36,7 +35,7 @@ var verifyCommand = &cli.Command{ }, usernameFlag, passwordFlag, - insecureFlag, + plainHTTPFlag, mediaTypeFlag, }, Action: runVerify, @@ -97,7 +96,7 @@ func getX509Verifier(ctx *cli.Context) (signature.Verifier, error) { var certs []*x509.Certificate for _, path := range ctx.StringSlice("cert") { - bundledCerts, err := crypto.ReadCertificateFile(path) + bundledCerts, err := x509nv2.ReadCertificateFile(path) if err != nil { return nil, err } @@ -107,7 +106,7 @@ func getX509Verifier(ctx *cli.Context) (signature.Verifier, error) { } } for _, path := range ctx.StringSlice("ca-cert") { - bundledCerts, err := crypto.ReadCertificateFile(path) + bundledCerts, err := x509nv2.ReadCertificateFile(path) if err != nil { return nil, err } diff --git a/docs/nv2/README.md b/docs/nv2/README.md index 22445dbf1..ac75487d5 100644 --- a/docs/nv2/README.md +++ b/docs/nv2/README.md @@ -71,7 +71,7 @@ OPTIONS: --output value, -o value write signature to a specific path --username value, -u value username for generic remote access --password value, -p value password for generic remote access - --insecure enable insecure remote access (default: false) + --plain-http remote access via plain HTTP (default: false) --media-type value specify the media type of the manifest read from file or stdin (default: "application/vnd.docker.distribution.manifest.v2+json") --help, -h show help (default: false) ``` @@ -177,7 +177,7 @@ OPTIONS: --ca-cert value CA certs for verification [x509] --username value, -u value username for generic remote access --password value, -p value password for generic remote access - --insecure enable insecure remote access (default: false) + --plain-http remote access via plain HTTP (default: false) --media-type value specify the media type of the manifest read from file or stdin (default: "application/vnd.docker.distribution.manifest.v2+json") --help, -h show help (default: false) ``` @@ -261,9 +261,9 @@ sha256:0ebe6f409b373c8baf39879fccee6cae5e718003ec3167ded7d54cb2b5da2946 **Note** The digest of the OCI manifest is different from the Docker manifest for the same image since their format is different. Therefore, the signer should be careful with the manifest type when signing. -### Insecure Registries +### Plain-HTTP Registries -To sign and verify images from insecure registries accessed via `HTTP`, such as `localhost`, the option `--insecure` is required. +To sign and verify images from registries accessed via `HTTP`, such as `localhost`, the option `--plain-http` is required. ``` shell docker tag example localhost:5000/example @@ -271,7 +271,7 @@ docker push localhost:5000/example The push refers to repository [localhost:5000/example] 50644c29ef5a: Pushed latest: digest: sha256:3351c53952446db17d21b86cfe5829ae70f823aff5d410fbf09dff820a39ab55 size: 528 -nv2 verify -f example.nv2 --insecure docker://localhost:5000/example +nv2 verify -f example.nv2 --plain-http docker://localhost:5000/example sha256:3351c53952446db17d21b86cfe5829ae70f823aff5d410fbf09dff820a39ab55 ``` diff --git a/go.mod b/go.mod index 745083dc8..cfc82736c 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,10 @@ module github.com/notaryproject/nv2 go 1.14 require ( - github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 + github.com/notaryproject/notary/v2 v2.0.0-00010101000000-000000000000 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.1 github.com/urfave/cli/v2 v2.2.0 ) + +replace github.com/notaryproject/notary/v2 => github.com/shizhMSFT/notary/v2 v2.0.0-20210330091034-dc6e56acc97a diff --git a/go.sum b/go.sum index 83b110164..dc68c8c1c 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,9 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/aviral26/artifacts v0.0.0-20210128064216-9526869307d7/go.mod h1:Xr7BjEvr8VVrtyC9LX3q5975UVkEvyaXmb34JsCvSJ0= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/docker/go v1.5.1-1 h1:hr4w35acWBPhGBXlzPoHpmZ/ygPjnmFVxGxxGnMyP7k= +github.com/docker/go v1.5.1-1/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= @@ -11,6 +14,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shizhMSFT/notary/v2 v2.0.0-20210330091034-dc6e56acc97a h1:zGrZ/u7V9xoGpJGPBEuU2ax0UiSQfMu2Ohc6HCq15+o= +github.com/shizhMSFT/notary/v2 v2.0.0-20210330091034-dc6e56acc97a/go.mod h1:CN708S2wKRKpzzvAbfKY3NETWwnCNEFje3nWFUl5rU0= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4= diff --git a/internal/crypto/x509.go b/internal/crypto/x509.go deleted file mode 100644 index e53173d06..000000000 --- a/internal/crypto/x509.go +++ /dev/null @@ -1,51 +0,0 @@ -package crypto - -import ( - "crypto/x509" - "encoding/pem" - "errors" - "io/ioutil" - - "github.com/docker/libtrust" -) - -// ReadPrivateKeyFile reads a key PEM file as a libtrust key -func ReadPrivateKeyFile(path string) (libtrust.PrivateKey, error) { - raw, err := ioutil.ReadFile(path) - if err != nil { - return nil, err - } - block, _ := pem.Decode(raw) - if block == nil { - return nil, errors.New("no PEM data found") - } - switch block.Type { - case "PRIVATE KEY": - key, err := x509.ParsePKCS8PrivateKey(block.Bytes) - if err != nil { - return nil, err - } - return libtrust.FromCryptoPrivateKey(key) - default: - return libtrust.UnmarshalPrivateKeyPEM(raw) - } -} - -// ReadCertificateFile reads a certificate PEM file -func ReadCertificateFile(path string) ([]*x509.Certificate, error) { - raw, err := ioutil.ReadFile(path) - if err != nil { - return nil, err - } - var certs []*x509.Certificate - block, rest := pem.Decode(raw) - for block != nil { - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return nil, err - } - certs = append(certs, cert) - block, rest = pem.Decode(rest) - } - return certs, nil -} diff --git a/pkg/registry/client.go b/pkg/registry/client.go index 8bfd056ae..c20107445 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -6,15 +6,15 @@ import ( // Client is a customized registry client type Client struct { - base http.RoundTripper - insecure bool + base http.RoundTripper + plainHTTP bool } // ClientOptions configures the client type ClientOptions struct { - Username string - Password string - Insecure bool + Username string + Password string + PlainHTTP bool } // NewClient creates a new registry client @@ -26,7 +26,7 @@ func NewClient(base http.RoundTripper, opts *ClientOptions) *Client { opts = &ClientOptions{} } return &Client{ - base: newV2transport(base, opts.Username, opts.Password), - insecure: opts.Insecure, + base: newV2transport(base, opts.Username, opts.Password), + plainHTTP: opts.PlainHTTP, } } diff --git a/pkg/registry/manifest.go b/pkg/registry/manifest.go index 694d73f1f..135997fe0 100644 --- a/pkg/registry/manifest.go +++ b/pkg/registry/manifest.go @@ -7,7 +7,7 @@ import ( "strconv" "strings" - "github.com/notaryproject/nv2/pkg/signature" + "github.com/notaryproject/notary/v2/signature" v1 "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -61,7 +61,7 @@ func (c *Client) getManifestMetadata(uri *url.URL, mediaTypes ...string) (signat reference = "latest" } scheme := "https" - if c.insecure { + if c.plainHTTP { scheme = "http" } url := fmt.Sprintf("%s://%s/v2/%s/manifests/%s", diff --git a/pkg/signature/encoding.go b/pkg/signature/encoding.go deleted file mode 100644 index 325e8ad55..000000000 --- a/pkg/signature/encoding.go +++ /dev/null @@ -1,30 +0,0 @@ -package signature - -import ( - "encoding/base64" - "encoding/json" - "fmt" -) - -// EncodeSegment JWT specific base64url encoding with padding stripped -func EncodeSegment(seg []byte) string { - return base64.RawURLEncoding.EncodeToString(seg) -} - -// DecodeSegment JWT specific base64url encoding with padding stripped -func DecodeSegment(seg string) ([]byte, error) { - return base64.RawURLEncoding.DecodeString(seg) -} - -// DecodeClaims JWT specific base64url encoding with padding stripped as Claims -func DecodeClaims(seg string) (Claims, error) { - bytes, err := DecodeSegment(seg) - if err != nil { - return Claims{}, fmt.Errorf("invalid base64 encoded claims: %v", err) - } - var claims Claims - if err := json.Unmarshal(bytes, &claims); err != nil { - return Claims{}, fmt.Errorf("invalid JSON encoded claims: %v", err) - } - return claims, nil -} diff --git a/pkg/signature/errors.go b/pkg/signature/errors.go deleted file mode 100644 index 9387af88a..000000000 --- a/pkg/signature/errors.go +++ /dev/null @@ -1,14 +0,0 @@ -package signature - -import "errors" - -// common errors -var ( - ErrInvalidToken = errors.New("invalid token") - ErrInvalidSignatureType = errors.New("invalid signature type") - ErrUnknownSignatureType = errors.New("unknown signature type") - ErrUnknownSigner = errors.New("unknown signer") - ErrDigestMismatch = errors.New("digest mismatch") - ErrSizeMismatch = errors.New("size mismatch") - ErrMediaTypeMismatch = errors.New("media type mismatch") -) diff --git a/pkg/signature/interface.go b/pkg/signature/interface.go deleted file mode 100644 index 0cc0d14d4..000000000 --- a/pkg/signature/interface.go +++ /dev/null @@ -1,12 +0,0 @@ -package signature - -// Signer signs content -type Signer interface { - Sign(claims string) (string, []byte, error) -} - -// Verifier verifies content -type Verifier interface { - Type() string - Verify(header Header, signed string, sig []byte) error -} diff --git a/pkg/signature/model.go b/pkg/signature/model.go deleted file mode 100644 index 282c48ea7..000000000 --- a/pkg/signature/model.go +++ /dev/null @@ -1,28 +0,0 @@ -package signature - -// Header defines the signature header -type Header struct { - Raw []byte `json:"-"` - Type string `json:"typ"` -} - -// Claims contains the claims to be signed -type Claims struct { - Manifest - Expiration int64 `json:"exp,omitempty"` - IssuedAt int64 `json:"iat,omitempty"` - NotBefore int64 `json:"nbf,omitempty"` -} - -// Manifest to be signed -type Manifest struct { - Descriptor - References []string `json:"references,omitempty"` -} - -// Descriptor describes the basic information of the target content -type Descriptor struct { - MediaType string `json:"mediaType,omitempty"` - Digest string `json:"digest"` - Size int64 `json:"size"` -} diff --git a/pkg/signature/scheme.go b/pkg/signature/scheme.go deleted file mode 100644 index d531be54f..000000000 --- a/pkg/signature/scheme.go +++ /dev/null @@ -1,117 +0,0 @@ -package signature - -import ( - "encoding/json" - "fmt" - "strings" - "time" -) - -// Scheme is a signature scheme -type Scheme struct { - signers map[string]Signer - verifiers map[string]Verifier -} - -// NewScheme creates a new scheme -func NewScheme() *Scheme { - return &Scheme{ - signers: make(map[string]Signer), - verifiers: make(map[string]Verifier), - } -} - -// RegisterSigner registers signer with a name -func (s *Scheme) RegisterSigner(signerID string, signer Signer) { - s.signers[signerID] = signer -} - -// RegisterVerifier registers verifier -func (s *Scheme) RegisterVerifier(verifier Verifier) { - s.verifiers[verifier.Type()] = verifier -} - -// Sign signs claims by a signer -func (s *Scheme) Sign(signerID string, claims Claims) (string, error) { - bytes, err := json.Marshal(claims) - if err != nil { - return "", err - } - return s.SignRaw(signerID, bytes) -} - -// SignRaw signs raw content by a signer -func (s *Scheme) SignRaw(signerID string, content []byte) (string, error) { - signer, found := s.signers[signerID] - if !found { - return "", ErrUnknownSigner - } - - signed, sig, err := signer.Sign(EncodeSegment(content)) - if err != nil { - return "", nil - } - - return strings.Join([]string{ - signed, - EncodeSegment(sig), - }, "."), nil -} - -// Verify verifies the JWT-like token -func (s *Scheme) Verify(token string) (Claims, error) { - parts := strings.Split(token, ".") - if len(parts) != 3 { - return Claims{}, ErrInvalidToken - } - - if err := s.verifySignature(parts); err != nil { - return Claims{}, err - } - - claims, err := DecodeClaims(parts[1]) - if err != nil { - return Claims{}, err - } - - return claims, s.verifyClaims(claims) -} - -func (s *Scheme) verifySignature(parts []string) error { - rawHeader, err := DecodeSegment(parts[0]) - if err != nil { - return ErrInvalidToken - } - var header Header - if json.Unmarshal(rawHeader, &header); err != nil { - return ErrInvalidToken - } - header.Raw = rawHeader - - verifier, found := s.verifiers[header.Type] - if !found { - return ErrUnknownSignatureType - } - - sig, err := DecodeSegment(parts[2]) - if err != nil { - return ErrInvalidToken - } - - return verifier.Verify( - header, - strings.Join(parts[:2], "."), - sig, - ) -} - -func (s *Scheme) verifyClaims(claims Claims) error { - now := time.Now().Unix() - if claims.Expiration != 0 && now > claims.Expiration { - return fmt.Errorf("content expired: %d: current: %d", claims.Expiration, now) - } - if claims.NotBefore != 0 && now < claims.NotBefore { - return fmt.Errorf("content is not available yet: %d: current: %d", claims.NotBefore, now) - } - return nil -} diff --git a/pkg/signature/x509/header.go b/pkg/signature/x509/header.go deleted file mode 100644 index fb5ebdddf..000000000 --- a/pkg/signature/x509/header.go +++ /dev/null @@ -1,18 +0,0 @@ -package x509 - -import ( - "github.com/notaryproject/nv2/pkg/signature" -) - -// Header defines the signature header -type Header struct { - signature.Header - Parameters -} - -// Parameters defines the signature parameters -type Parameters struct { - Algorithm string `json:"alg,omitempty"` - KeyID string `json:"kid,omitempty"` - X5c [][]byte `json:"x5c,omitempty"` -} diff --git a/pkg/signature/x509/signer.go b/pkg/signature/x509/signer.go deleted file mode 100644 index eb39882d0..000000000 --- a/pkg/signature/x509/signer.go +++ /dev/null @@ -1,113 +0,0 @@ -package x509 - -import ( - "crypto" - "crypto/x509" - "encoding/json" - "errors" - "io" - "strings" - - "github.com/docker/libtrust" - cryptoutil "github.com/notaryproject/nv2/internal/crypto" - "github.com/notaryproject/nv2/pkg/signature" -) - -type signer struct { - key libtrust.PrivateKey - keyID string - cert *x509.Certificate - rawCerts [][]byte - hash crypto.Hash -} - -// NewSignerFromFiles creates a signer from files -func NewSignerFromFiles(keyPath, certPath string) (signature.Signer, error) { - key, err := cryptoutil.ReadPrivateKeyFile(keyPath) - if err != nil { - return nil, err - } - if certPath == "" { - return NewSigner(key, nil) - } - - certs, err := cryptoutil.ReadCertificateFile(certPath) - if err != nil { - return nil, err - } - return NewSigner(key, certs) -} - -// NewSigner creates a signer -func NewSigner(key libtrust.PrivateKey, certs []*x509.Certificate) (signature.Signer, error) { - s := &signer{ - key: key, - keyID: key.KeyID(), - hash: crypto.SHA256, - } - if len(certs) == 0 { - return s, nil - } - - cert := certs[0] - publicKey, err := libtrust.FromCryptoPublicKey(crypto.PublicKey(cert.PublicKey)) - if err != nil { - return nil, err - } - if s.keyID != publicKey.KeyID() { - return nil, errors.New("key and certificate mismatch") - } - s.cert = cert - - rawCerts := make([][]byte, 0, len(certs)) - for _, cert := range certs { - rawCerts = append(rawCerts, cert.Raw) - } - s.rawCerts = rawCerts - - return s, nil -} - -func (s *signer) Sign(claims string) (string, []byte, error) { - if s.cert != nil { - if err := verifyReferences(claims, s.cert); err != nil { - return "", nil, err - } - } - - // Generate header - // We have to sign an empty string for the proper algorithm string first. - _, alg, err := s.key.Sign(io.MultiReader(), s.hash) - if err != nil { - return "", nil, err - } - header := Header{ - Header: signature.Header{ - Type: Type, - }, - Parameters: Parameters{ - Algorithm: alg, - }, - } - if s.cert != nil { - header.X5c = s.rawCerts - } else { - header.KeyID = s.keyID - } - headerJSON, err := json.Marshal(header) - if err != nil { - return "", nil, err - } - - // Generate signature - signed := strings.Join([]string{ - signature.EncodeSegment(headerJSON), - claims, - }, ".") - - sig, _, err := s.key.Sign(strings.NewReader(signed), s.hash) - if err != nil { - return "", nil, err - } - return signed, sig, nil -} diff --git a/pkg/signature/x509/type.go b/pkg/signature/x509/type.go deleted file mode 100644 index 82dd54370..000000000 --- a/pkg/signature/x509/type.go +++ /dev/null @@ -1,4 +0,0 @@ -package x509 - -// Type indicates the signature type -const Type = "x509" diff --git a/pkg/signature/x509/verifier.go b/pkg/signature/x509/verifier.go deleted file mode 100644 index 97eb17c99..000000000 --- a/pkg/signature/x509/verifier.go +++ /dev/null @@ -1,155 +0,0 @@ -package x509 - -import ( - "crypto" - "crypto/x509" - "encoding/json" - "errors" - "strings" - - "github.com/docker/libtrust" - "github.com/notaryproject/nv2/pkg/signature" -) - -type verifier struct { - keys map[string]libtrust.PublicKey - certs map[string]*x509.Certificate - roots *x509.CertPool -} - -// NewVerifier creates a verifier -func NewVerifier(certs []*x509.Certificate, roots *x509.CertPool) (signature.Verifier, error) { - if roots == nil { - if certs == nil { - pool, err := x509.SystemCertPool() - if err != nil { - return nil, err - } - roots = pool - } else { - roots = x509.NewCertPool() - } - for _, cert := range certs { - roots.AddCert(cert) - } - } - - keys := make(map[string]libtrust.PublicKey, len(certs)) - keyedCerts := make(map[string]*x509.Certificate, len(certs)) - for _, cert := range certs { - key, err := libtrust.FromCryptoPublicKey(crypto.PublicKey(cert.PublicKey)) - if err != nil { - return nil, err - } - keyID := key.KeyID() - keys[keyID] = key - keyedCerts[keyID] = cert - } - - return &verifier{ - keys: keys, - certs: keyedCerts, - roots: roots, - }, nil -} - -func (v *verifier) Type() string { - return Type -} - -func (v *verifier) Verify(header signature.Header, signed string, sig []byte) error { - if header.Type != Type { - return signature.ErrInvalidSignatureType - } - var params Parameters - if err := json.Unmarshal(header.Raw, ¶ms); err != nil { - return err - } - - key, cert, err := v.getVerificationKeyPair(params) - if err != nil { - return err - } - if err := key.Verify(strings.NewReader(signed), params.Algorithm, sig); err != nil { - return err - } - - parts := strings.Split(signed, ".") - if len(parts) != 2 { - return errors.New("invalid signed content") - } - - return verifyReferences(parts[1], cert) -} - -func (v *verifier) getVerificationKeyPair(params Parameters) (libtrust.PublicKey, *x509.Certificate, error) { - switch { - case len(params.X5c) > 0: - return v.getVerificationKeyPairFromX5c(params.X5c) - case params.KeyID != "": - return v.getVerificationKeyPairFromKeyID(params.KeyID) - default: - return nil, nil, errors.New("missing verification key") - } -} - -func (v *verifier) getVerificationKeyPairFromKeyID(keyID string) (libtrust.PublicKey, *x509.Certificate, error) { - key, found := v.keys[keyID] - if !found { - return nil, nil, errors.New("key not found: " + keyID) - } - cert, found := v.certs[keyID] - if !found { - return nil, nil, errors.New("cert not found: " + keyID) - } - return key, cert, nil -} - -func (v *verifier) getVerificationKeyPairFromX5c(x5c [][]byte) (libtrust.PublicKey, *x509.Certificate, error) { - certs := make([]*x509.Certificate, 0, len(x5c)) - for _, certBytes := range x5c { - cert, err := x509.ParseCertificate(certBytes) - if err != nil { - return nil, nil, err - } - certs = append(certs, cert) - } - - intermediates := x509.NewCertPool() - for _, cert := range certs[1:] { - intermediates.AddCert(cert) - } - - cert := certs[0] - if _, err := cert.Verify(x509.VerifyOptions{ - Intermediates: intermediates, - Roots: v.roots, - KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, - }); err != nil { - return nil, nil, err - } - - key, err := libtrust.FromCryptoPublicKey(crypto.PublicKey(cert.PublicKey)) - if err != nil { - return nil, nil, err - } - return key, cert, nil -} - -func verifyReferences(seg string, cert *x509.Certificate) error { - claims, err := signature.DecodeClaims(seg) - if err != nil { - return err - } - roots := x509.NewCertPool() - roots.AddCert(cert) - for _, reference := range claims.Manifest.References { - if _, err := cert.Verify(x509.VerifyOptions{ - DNSName: strings.SplitN(reference, "/", 2)[0], - Roots: roots, - }); err != nil { - return err - } - } - return nil -} From 4a0a77da20cf7882d060320433f7ca1ab3468296 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Tue, 30 Mar 2021 19:14:34 +0800 Subject: [PATCH 22/69] converge docker-generate Signed-off-by: Shiwei Zhang --- cmd/docker-generate/generate.go | 12 +++ cmd/docker-generate/main.go | 21 +++++ cmd/docker-generate/manifest.go | 65 ++++++++++++++ cmd/docker-generate/metadata.go | 25 ++++++ docs/docker-plugins/README.md | 5 ++ docs/docker-plugins/docker-generate.md | 51 +++++++++++ go.mod | 1 + go.sum | 113 +++++++++++++++++++++++++ internal/io/count.go | 22 +++++ pkg/docker/schema2.go | 101 ++++++++++++++++++++++ 10 files changed, 416 insertions(+) create mode 100644 cmd/docker-generate/generate.go create mode 100644 cmd/docker-generate/main.go create mode 100644 cmd/docker-generate/manifest.go create mode 100644 cmd/docker-generate/metadata.go create mode 100644 docs/docker-plugins/README.md create mode 100644 docs/docker-plugins/docker-generate.md create mode 100644 internal/io/count.go create mode 100644 pkg/docker/schema2.go diff --git a/cmd/docker-generate/generate.go b/cmd/docker-generate/generate.go new file mode 100644 index 000000000..71f72c2ce --- /dev/null +++ b/cmd/docker-generate/generate.go @@ -0,0 +1,12 @@ +package main + +import ( + "github.com/urfave/cli/v2" +) + +var generateCommand = &cli.Command{ + Name: "generate", + Subcommands: []*cli.Command{ + manifestCommand, + }, +} diff --git a/cmd/docker-generate/main.go b/cmd/docker-generate/main.go new file mode 100644 index 000000000..83941702a --- /dev/null +++ b/cmd/docker-generate/main.go @@ -0,0 +1,21 @@ +package main + +import ( + "log" + "os" + + "github.com/urfave/cli/v2" +) + +func main() { + app := &cli.App{ + Name: "docker", + Commands: []*cli.Command{ + generateCommand, + metadataCommand, + }, + } + if err := app.Run(os.Args); err != nil { + log.Fatal(err) + } +} diff --git a/cmd/docker-generate/manifest.go b/cmd/docker-generate/manifest.go new file mode 100644 index 000000000..a224aef6f --- /dev/null +++ b/cmd/docker-generate/manifest.go @@ -0,0 +1,65 @@ +package main + +import ( + "io" + "os" + "os/exec" + + "github.com/notaryproject/nv2/pkg/docker" + "github.com/urfave/cli/v2" +) + +var manifestCommand = &cli.Command{ + Name: "manifest", + Usage: "generates the manifest of a docker image", + ArgsUsage: "[]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "output", + Aliases: []string{"o"}, + Usage: "write to a file instead of stdout", + }, + }, + Action: generateManifest, +} + +func generateManifest(ctx *cli.Context) error { + var reader io.Reader + if reference := ctx.Args().First(); reference != "" { + cmd := exec.Command("docker", "save", reference) + stdout, err := cmd.StdoutPipe() + if err != nil { + return err + } + reader = stdout + if err := cmd.Start(); err != nil { + return err + } + } else { + reader = os.Stdin + } + + var writer io.Writer + if output := ctx.String("output"); output != "" { + file, err := os.Create(output) + if err != nil { + return err + } + defer file.Close() + writer = file + } else { + writer = os.Stdout + } + + manifest, err := docker.GenerateSchema2FromDockerSave(reader) + if err != nil { + return err + } + _, payload, err := manifest.Payload() + if err != nil { + return err + } + + _, err = writer.Write(payload) + return err +} diff --git a/cmd/docker-generate/metadata.go b/cmd/docker-generate/metadata.go new file mode 100644 index 000000000..6cbcacb38 --- /dev/null +++ b/cmd/docker-generate/metadata.go @@ -0,0 +1,25 @@ +package main + +import ( + "encoding/json" + "os" + + "github.com/urfave/cli/v2" +) + +var pluginMetadata = map[string]interface{}{ + "SchemaVersion": "0.1.0", + "Vendor": "github.com/shizhMSFT", + "Version": "0.1.0", + "ShortDescription": "Generate artifacts", + "Experimental": true, +} + +var metadataCommand = &cli.Command{ + Name: "docker-cli-plugin-metadata", + Action: func(ctx *cli.Context) error { + writer := json.NewEncoder(os.Stdout) + return writer.Encode(pluginMetadata) + }, + Hidden: true, +} diff --git a/docs/docker-plugins/README.md b/docs/docker-plugins/README.md new file mode 100644 index 000000000..611509677 --- /dev/null +++ b/docs/docker-plugins/README.md @@ -0,0 +1,5 @@ +# Docker Plugins + +Multiple docker plugins are provided for `nv2` scenarios. + +- [docker-generate](docker-generate.md) \ No newline at end of file diff --git a/docs/docker-plugins/docker-generate.md b/docs/docker-plugins/docker-generate.md new file mode 100644 index 000000000..66a8bf14b --- /dev/null +++ b/docs/docker-plugins/docker-generate.md @@ -0,0 +1,51 @@ +# docker-generate +Docker CLI plugin to generate metadata **offline**. + +## Build and Install +This plugin requires [golang](https://golang.org/dl/) with version `>= 1.14`. + +To build and install, run +``` +go build -o ~/.docker/cli-plugins/docker-generate ./cmd/docker-generate +``` +Finally, follow the [documentation](https://docs.docker.com/engine/reference/commandline/cli/#experimental-features) to enable experimental features for Docker CLI. + +## Instructions +### Generate manifest +To generate a manifest of an image referenced by ``, run +``` +docker generate manifest +``` +For example, +``` +docker build -t myapp:1.0 . +docker generate manifest myapp:1.0 +``` + +#### Output to files +If a file is desired instead of standard output, try +``` +docker generate manifest > manifest.json +``` +or +``` +docker generate manifest -o manifest.json +``` + +#### From `docker save` +Manifest is also possible to be generated from a tar file saved via `docker save`. +``` +docker save > save.tar +cat save.tar | docker generate manifest +``` +Basically, +``` +docker save | docker generate manifest +``` +is equivalent to +``` +docker generate manifest +``` + +## Known Limitation +The current version of this plugin can only accept one `reference` at a time. diff --git a/go.mod b/go.mod index cfc82736c..6b3b3401d 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/notaryproject/nv2 go 1.14 require ( + github.com/docker/distribution v0.0.0-20210206161202-6200038bc715 github.com/notaryproject/notary/v2 v2.0.0-00010101000000-000000000000 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.1 diff --git a/go.sum b/go.sum index dc68c8c1c..e7a4502c7 100644 --- a/go.sum +++ b/go.sum @@ -1,24 +1,137 @@ +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/aviral26/artifacts v0.0.0-20210128064216-9526869307d7/go.mod h1:Xr7BjEvr8VVrtyC9LX3q5975UVkEvyaXmb34JsCvSJ0= +github.com/aws/aws-sdk-go v1.34.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= +github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/distribution v0.0.0-20210206161202-6200038bc715 h1:oN+Mw/t1Ua4huewY/20wTTZ0Nvye+9BJVYoCl//3tcQ= +github.com/docker/distribution v0.0.0-20210206161202-6200038bc715/go.mod h1:j0+FEax3zYG2pUod5Nc0npkx8p9I3HrKgf2TvKDc5LE= github.com/docker/go v1.5.1-1 h1:hr4w35acWBPhGBXlzPoHpmZ/ygPjnmFVxGxxGnMyP7k= github.com/docker/go v1.5.1-1/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/shizhMSFT/notary/v2 v2.0.0-20210330091034-dc6e56acc97a h1:zGrZ/u7V9xoGpJGPBEuU2ax0UiSQfMu2Ohc6HCq15+o= github.com/shizhMSFT/notary/v2 v2.0.0-20210330091034-dc6e56acc97a/go.mod h1:CN708S2wKRKpzzvAbfKY3NETWwnCNEFje3nWFUl5rU0= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4= github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= +google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/io/count.go b/internal/io/count.go new file mode 100644 index 000000000..786d7678b --- /dev/null +++ b/internal/io/count.go @@ -0,0 +1,22 @@ +package count + +import ( + "io" +) + +// CountWriter counts the written bytes +type CountWriter struct { + W io.Writer + N int64 +} + +// NewCountWriter generates a new writer +func NewCountWriter(w io.Writer) *CountWriter { + return &CountWriter{W: w} +} + +func (w *CountWriter) Write(p []byte) (n int, err error) { + n, err = w.W.Write(p) + w.N += int64(n) + return +} diff --git a/pkg/docker/schema2.go b/pkg/docker/schema2.go new file mode 100644 index 000000000..393e28276 --- /dev/null +++ b/pkg/docker/schema2.go @@ -0,0 +1,101 @@ +package docker + +import ( + "archive/tar" + "compress/gzip" + "encoding/json" + "errors" + "io" + "strings" + + "github.com/docker/distribution" + "github.com/docker/distribution/manifest/schema2" + iio "github.com/notaryproject/nv2/internal/io" + "github.com/opencontainers/go-digest" +) + +type manifestInTar struct { + Config string + RepoTags []string + Layers []string +} + +// GenerateSchema2FromDockerSave generate a docker schema2 manifest from `docker save` +func GenerateSchema2FromDockerSave(reader io.Reader) (distribution.Manifest, error) { + items, descriptors, err := extractTar(reader) + if err != nil { + return nil, err + } + if len(items) != 1 { + return nil, errors.New("unsupported number of images") + } + item := items[0] + + layers := make([]distribution.Descriptor, 0, len(item.Layers)) + for _, layer := range item.Layers { + layers = append(layers, descriptors[layer]) + } + + manifest := schema2.Manifest{ + Versioned: schema2.SchemaVersion, + Config: descriptors[item.Config], + Layers: layers, + } + return schema2.FromStruct(manifest) +} + +func extractTar(r io.Reader) ([]manifestInTar, map[string]distribution.Descriptor, error) { + var manifests []manifestInTar + descriptors := make(map[string]distribution.Descriptor) + + tr := tar.NewReader(r) + for { + file, err := tr.Next() + if err != nil { + if err == io.EOF { + break + } + return nil, nil, err + } + switch { + case file.Name == "manifest.json": + decoder := json.NewDecoder(tr) + if err := decoder.Decode(&manifests); err != nil { + return nil, nil, err + } + case strings.HasSuffix(file.Name, "/layer.tar"): + desc, err := generateLayerDescriptor(tr) + if err != nil { + return nil, nil, err + } + descriptors[file.Name] = desc + case strings.HasSuffix(file.Name, ".json"): + digest := digest.NewDigestFromEncoded(digest.SHA256, strings.TrimSuffix(file.Name, ".json")) + descriptors[file.Name] = distribution.Descriptor{ + MediaType: schema2.MediaTypeImageConfig, + Size: file.Size, + Digest: digest, + } + } + } + + return manifests, descriptors, nil +} + +func generateLayerDescriptor(r io.Reader) (distribution.Descriptor, error) { + digester := digest.SHA256.Digester() + count := iio.NewCountWriter(digester.Hash()) + w := gzip.NewWriter(count) + _, err := io.Copy(w, r) + if err != nil { + return distribution.Descriptor{}, err + } + if err := w.Close(); err != nil { + return distribution.Descriptor{}, err + } + return distribution.Descriptor{ + MediaType: schema2.MediaTypeLayer, + Size: count.N, + Digest: digester.Digest(), + }, nil +} From 3d6c0a96d83e7bfb907fab025d03ce2b3f237423 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Tue, 30 Mar 2021 19:41:45 +0800 Subject: [PATCH 23/69] converge docker-nv2 Signed-off-by: Shiwei Zhang --- cmd/docker-nv2/config/config.go | 46 +++++++++++ cmd/docker-nv2/config/path.go | 35 ++++++++ cmd/docker-nv2/config/util.go | 38 +++++++++ cmd/docker-nv2/crypto/service.go | 40 +++++++++ cmd/docker-nv2/docker/credential.go | 24 ++++++ cmd/docker-nv2/docker/manifest.go | 124 ++++++++++++++++++++++++++++ cmd/docker-nv2/docker/network.go | 20 +++++ cmd/docker-nv2/docker/signature.go | 33 ++++++++ cmd/docker-nv2/main.go | 21 +++++ cmd/docker-nv2/metadata.go | 25 ++++++ cmd/docker-nv2/notary.go | 40 +++++++++ cmd/docker-nv2/notary_sign.go | 67 +++++++++++++++ cmd/docker-nv2/nv2.go | 32 +++++++ cmd/docker-nv2/pull.go | 124 ++++++++++++++++++++++++++++ cmd/docker-nv2/push.go | 110 ++++++++++++++++++++++++ cmd/docker-nv2/util.go | 50 +++++++++++ docs/docker-plugins/README.md | 3 +- docs/docker-plugins/docker-nv2.md | 54 ++++++++++++ go.mod | 8 +- go.sum | 31 ++++++- internal/os/file.go | 15 ++++ 21 files changed, 936 insertions(+), 4 deletions(-) create mode 100644 cmd/docker-nv2/config/config.go create mode 100644 cmd/docker-nv2/config/path.go create mode 100644 cmd/docker-nv2/config/util.go create mode 100644 cmd/docker-nv2/crypto/service.go create mode 100644 cmd/docker-nv2/docker/credential.go create mode 100644 cmd/docker-nv2/docker/manifest.go create mode 100644 cmd/docker-nv2/docker/network.go create mode 100644 cmd/docker-nv2/docker/signature.go create mode 100644 cmd/docker-nv2/main.go create mode 100644 cmd/docker-nv2/metadata.go create mode 100644 cmd/docker-nv2/notary.go create mode 100644 cmd/docker-nv2/notary_sign.go create mode 100644 cmd/docker-nv2/nv2.go create mode 100644 cmd/docker-nv2/pull.go create mode 100644 cmd/docker-nv2/push.go create mode 100644 cmd/docker-nv2/util.go create mode 100644 docs/docker-plugins/docker-nv2.md create mode 100644 internal/os/file.go diff --git a/cmd/docker-nv2/config/config.go b/cmd/docker-nv2/config/config.go new file mode 100644 index 000000000..966cc4845 --- /dev/null +++ b/cmd/docker-nv2/config/config.go @@ -0,0 +1,46 @@ +package config + +import ( + "encoding/json" + "os" +) + +// File reflects the config file +type File struct { + Enabled bool `json:"enabled"` + VerificationCerts []string `json:"verificationCerts"` + InsecureRegistries []string `json:"insecureRegistries"` +} + +// New creates a new config file +func New() *File { + return &File{ + VerificationCerts: []string{}, + } +} + +// Save stores the config to file +func (f *File) Save() error { + file, err := os.Create(FilePath) + if err != nil { + return err + } + defer file.Close() + encoder := json.NewEncoder(file) + encoder.SetIndent("", "\t") + return encoder.Encode(f) +} + +// Load reads the config from file +func Load() (*File, error) { + file, err := os.Open(FilePath) + if err != nil { + return nil, err + } + defer file.Close() + var config *File + if err := json.NewDecoder(file).Decode(&config); err != nil { + return nil, err + } + return config, nil +} diff --git a/cmd/docker-nv2/config/path.go b/cmd/docker-nv2/config/path.go new file mode 100644 index 000000000..f94a16ce4 --- /dev/null +++ b/cmd/docker-nv2/config/path.go @@ -0,0 +1,35 @@ +package config + +import ( + "path/filepath" + + "github.com/docker/cli/cli/config" + "github.com/opencontainers/go-digest" +) + +const ( + // FileName is the name of config file + FileName = "nv2.json" + + // SignatureStoreDirName is the name of the signature store directory + SignatureStoreDirName = "nv2" + + // SignatureExtension defines the extension of the signature files + SignatureExtension = ".jwt" +) + +var ( + // FilePath is the path of config file + FilePath = filepath.Join(config.Dir(), FileName) + // SignatureStoreDirPath is the path of the signature store + SignatureStoreDirPath = filepath.Join(config.Dir(), SignatureStoreDirName) +) + +// SignaturePath returns the path of a signature for a manifest +func SignaturePath(manifestDigest digest.Digest) string { + return filepath.Join( + SignatureStoreDirPath, + manifestDigest.Algorithm().String(), + manifestDigest.Encoded()+SignatureExtension, + ) +} diff --git a/cmd/docker-nv2/config/util.go b/cmd/docker-nv2/config/util.go new file mode 100644 index 000000000..8798ffb03 --- /dev/null +++ b/cmd/docker-nv2/config/util.go @@ -0,0 +1,38 @@ +package config + +import ( + "errors" + "os" +) + +// ErrNotaryDisabled indicates that notary is disabled +var ErrNotaryDisabled = errors.New("notary disabled") + +// CheckNotaryEnabled checks the config file whether notary is enabled or not. +func CheckNotaryEnabled() error { + config, err := Load() + if err != nil { + if !os.IsNotExist(err) { + return err + } + config = New() + } + if config.Enabled { + return nil + } + return ErrNotaryDisabled +} + +// IsRegistryInsecure checks whether the registry is in the list of insecure registries. +func IsRegistryInsecure(target string) bool { + config, err := Load() + if err != nil { + return false + } + for _, registry := range config.InsecureRegistries { + if registry == target { + return true + } + } + return false +} diff --git a/cmd/docker-nv2/crypto/service.go b/cmd/docker-nv2/crypto/service.go new file mode 100644 index 000000000..5e9617128 --- /dev/null +++ b/cmd/docker-nv2/crypto/service.go @@ -0,0 +1,40 @@ +package crypto + +import ( + "crypto/x509" + + "github.com/docker/libtrust" + "github.com/notaryproject/notary/v2" + x509nv2 "github.com/notaryproject/notary/v2/signature/x509" + "github.com/notaryproject/notary/v2/simple" +) + +// GetSigningService returns a signing service +func GetSigningService(keyPath string, certPaths ...string) (notary.SigningService, error) { + var ( + key libtrust.PrivateKey + commonCerts []*x509.Certificate + rootCerts *x509.CertPool + err error + ) + if keyPath != "" { + key, err = x509nv2.ReadPrivateKeyFile(keyPath) + if err != nil { + return nil, err + } + } + if len(certPaths) != 0 { + rootCerts = x509.NewCertPool() + for _, certPath := range certPaths { + certs, err := x509nv2.ReadCertificateFile(certPath) + if err != nil { + return nil, err + } + commonCerts = append(commonCerts, certs...) + for _, cert := range certs { + rootCerts.AddCert(cert) + } + } + } + return simple.NewSigningService(key, commonCerts, commonCerts, rootCerts) +} diff --git a/cmd/docker-nv2/docker/credential.go b/cmd/docker-nv2/docker/credential.go new file mode 100644 index 000000000..18b303bd5 --- /dev/null +++ b/cmd/docker-nv2/docker/credential.go @@ -0,0 +1,24 @@ +package docker + +import ( + "github.com/docker/cli/cli/config" + "github.com/docker/cli/cli/config/credentials" +) + +// BasicCredentialFromDockerConfig fetches the credentials for basic auth +// from docker config +func BasicCredentialFromDockerConfig(hostname string) (string, string, error) { + cfg, err := config.Load(config.Dir()) + if err != nil { + return "", "", err + } + if !cfg.ContainsAuth() { + cfg.CredentialsStore = credentials.DetectDefaultStore(cfg.CredentialsStore) + } + + auth, err := cfg.GetAuthConfig(hostname) + if err != nil { + return "", "", err + } + return auth.Username, auth.Password, nil +} diff --git a/cmd/docker-nv2/docker/manifest.go b/cmd/docker-nv2/docker/manifest.go new file mode 100644 index 000000000..05ec9cb8d --- /dev/null +++ b/cmd/docker-nv2/docker/manifest.go @@ -0,0 +1,124 @@ +package docker + +import ( + "context" + "fmt" + "net" + "net/http" + "os/exec" + "strconv" + "strings" + + "github.com/docker/distribution/manifest/schema2" + "github.com/notaryproject/nv2/cmd/docker-nv2/config" + "github.com/notaryproject/nv2/pkg/docker" + "github.com/opencontainers/go-digest" + oci "github.com/opencontainers/image-spec/specs-go/v1" +) + +// GenerateManifest generate manifest from docker save +func GenerateManifest(reference string) ([]byte, error) { + cmd := exec.Command("docker", "save", reference) + reader, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + if err := cmd.Start(); err != nil { + return nil, err + } + + manifest, err := docker.GenerateSchema2FromDockerSave(reader) + if err != nil { + return nil, err + } + _, payload, err := manifest.Payload() + return payload, err +} + +// GenerateManifestOCIDescriptor generate manifest descriptor from docker save +func GenerateManifestOCIDescriptor(reference string) (oci.Descriptor, error) { + manifest, err := GenerateManifest(reference) + if err != nil { + return oci.Descriptor{}, err + } + return oci.Descriptor{ + MediaType: schema2.MediaTypeManifest, + Digest: digest.FromBytes(manifest), + Size: int64(len(manifest)), + }, nil +} + +// GetManifestOCIDescriptor get manifest descriptor from remote registry +func GetManifestOCIDescriptor(ctx context.Context, hostname, repository, ref string) (oci.Descriptor, error) { + tr, err := Transport(hostname) + if err != nil { + return oci.Descriptor{}, err + } + + scheme := "https" + if config.IsRegistryInsecure(hostname) { + scheme = "http" + } + if host, _, _ := net.SplitHostPort(hostname); host == "localhost" { + scheme = "http" + } + url := fmt.Sprintf("%s://%s/v2/%s/manifests/%s", + scheme, + hostname, + repository, + ref, + ) + req, err := http.NewRequest(http.MethodHead, url, nil) + if err != nil { + return oci.Descriptor{}, err + } + req.Header.Set("Connection", "close") + req.Header.Set("Accept", schema2.MediaTypeManifest) + + resp, err := tr.RoundTrip(req) + if err != nil { + return oci.Descriptor{}, fmt.Errorf("%v: %v", url, err) + } + resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return oci.Descriptor{}, fmt.Errorf("%v: %s", url, resp.Status) + } + + header := resp.Header + mediaType := header.Get("Content-Type") + if mediaType != schema2.MediaTypeManifest { + return oci.Descriptor{}, fmt.Errorf("%v: media type mismatch: %s", url, mediaType) + } + contentDigest := header.Get("Docker-Content-Digest") + if contentDigest == "" { + return oci.Descriptor{}, fmt.Errorf("%v: missing Docker-Content-Digest", url) + } + parsedDigest, err := digest.Parse(contentDigest) + if err != nil { + return oci.Descriptor{}, fmt.Errorf("%v: invalid Docker-Content-Digest: %s", url, contentDigest) + } + length := header.Get("Content-Length") + if length == "" { + return oci.Descriptor{}, fmt.Errorf("%v: missing Content-Length", url) + } + size, err := strconv.ParseInt(length, 10, 64) + if err != nil { + return oci.Descriptor{}, fmt.Errorf("%v: invalid Content-Length", url) + } + return oci.Descriptor{ + MediaType: schema2.MediaTypeManifest, + Digest: parsedDigest, + Size: size, + }, nil +} + +// GetManifestReference returns the tag or the digest of the reference string +func GetManifestReference(ref string) string { + if index := strings.Index(ref, "@"); index != -1 { + return ref[index+1:] + } else if index := strings.LastIndex(ref, ":"); index != -1 { + return ref[index+1:] + } else { + return "latest" + } +} diff --git a/cmd/docker-nv2/docker/network.go b/cmd/docker-nv2/docker/network.go new file mode 100644 index 000000000..ca395b7f1 --- /dev/null +++ b/cmd/docker-nv2/docker/network.go @@ -0,0 +1,20 @@ +package docker + +import ( + "net/http" + + "github.com/notaryproject/notary/v2/util" +) + +// Transport returns the configured round tripper for a host +func Transport(hostname string) (http.RoundTripper, error) { + tr := http.DefaultTransport + username, password, err := BasicCredentialFromDockerConfig(hostname) + if err != nil { + return nil, err + } + if username == "" { + return tr, nil + } + return util.TransportWithBasicAuth(tr, hostname, username, password), nil +} diff --git a/cmd/docker-nv2/docker/signature.go b/cmd/docker-nv2/docker/signature.go new file mode 100644 index 000000000..a84b4362b --- /dev/null +++ b/cmd/docker-nv2/docker/signature.go @@ -0,0 +1,33 @@ +package docker + +import ( + "context" + "net" + + "github.com/docker/distribution/reference" + "github.com/notaryproject/notary/v2" + "github.com/notaryproject/notary/v2/registry" + "github.com/notaryproject/nv2/cmd/docker-nv2/config" +) + +// GetSignatureRepository returns a signature repository +func GetSignatureRepository(ctx context.Context, ref string) (notary.SignatureRepository, error) { + named, err := reference.ParseNamed(ref) + if err != nil { + return nil, err + } + hostname, repository := reference.SplitHostname(named) + + tr, err := Transport(hostname) + if err != nil { + return nil, err + } + + insecure := config.IsRegistryInsecure(hostname) + if host, _, _ := net.SplitHostPort(hostname); host == "localhost" { + insecure = true + } + client := registry.NewClient(tr, hostname, insecure) + + return client.Repository(ctx, repository), nil +} diff --git a/cmd/docker-nv2/main.go b/cmd/docker-nv2/main.go new file mode 100644 index 000000000..fbb240feb --- /dev/null +++ b/cmd/docker-nv2/main.go @@ -0,0 +1,21 @@ +package main + +import ( + "log" + "os" + + "github.com/urfave/cli/v2" +) + +func main() { + app := &cli.App{ + Name: "docker", + Commands: []*cli.Command{ + nv2Command, + metadataCommand, + }, + } + if err := app.Run(os.Args); err != nil { + log.Fatal(err) + } +} diff --git a/cmd/docker-nv2/metadata.go b/cmd/docker-nv2/metadata.go new file mode 100644 index 000000000..ea51b3efa --- /dev/null +++ b/cmd/docker-nv2/metadata.go @@ -0,0 +1,25 @@ +package main + +import ( + "encoding/json" + "os" + + "github.com/urfave/cli/v2" +) + +var pluginMetadata = map[string]interface{}{ + "SchemaVersion": "0.1.0", + "Vendor": "Sajay Antony, Shiwei Zhang", + "Version": "0.2.2", + "ShortDescription": "Notary V2 Signature extension", + "URL": "https://github.com/notaryproject/nv2", +} + +var metadataCommand = &cli.Command{ + Name: "docker-cli-plugin-metadata", + Action: func(ctx *cli.Context) error { + writer := json.NewEncoder(os.Stdout) + return writer.Encode(pluginMetadata) + }, + Hidden: true, +} diff --git a/cmd/docker-nv2/notary.go b/cmd/docker-nv2/notary.go new file mode 100644 index 000000000..4b3851f5a --- /dev/null +++ b/cmd/docker-nv2/notary.go @@ -0,0 +1,40 @@ +package main + +import ( + "os" + + "github.com/notaryproject/nv2/cmd/docker-nv2/config" + "github.com/urfave/cli/v2" +) + +var notaryCommand = &cli.Command{ + Name: "notary", + Subcommands: []*cli.Command{ + notarySignCommand, + }, + Flags: []cli.Flag{ + notaryEnabledFlag, + }, + Action: setNotary, +} + +var notaryEnabledFlag = &cli.BoolFlag{ + Name: "enabled", + Usage: "Enable Notary support", +} + +func setNotary(ctx *cli.Context) error { + if !ctx.IsSet(notaryEnabledFlag.Name) { + return cli.ShowCommandHelp(ctx, ctx.Command.Name) + } + + cfg, err := config.Load() + if err != nil { + if !os.IsNotExist(err) { + return err + } + cfg = config.New() + } + cfg.Enabled = ctx.Bool(notaryEnabledFlag.Name) + return cfg.Save() +} diff --git a/cmd/docker-nv2/notary_sign.go b/cmd/docker-nv2/notary_sign.go new file mode 100644 index 000000000..31213ea76 --- /dev/null +++ b/cmd/docker-nv2/notary_sign.go @@ -0,0 +1,67 @@ +package main + +import ( + "fmt" + + "github.com/notaryproject/nv2/cmd/docker-nv2/config" + "github.com/notaryproject/nv2/cmd/docker-nv2/crypto" + "github.com/notaryproject/nv2/cmd/docker-nv2/docker" + ios "github.com/notaryproject/nv2/internal/os" + "github.com/urfave/cli/v2" +) + +var notarySignCommand = &cli.Command{ + Name: "sign", + Usage: "Sign a docker image", + ArgsUsage: "[]", + Flags: []cli.Flag{ + &cli.PathFlag{ + Name: "key", + Aliases: []string{"k"}, + Usage: "signing key file", + TakesFile: true, + Required: true, + }, + &cli.PathFlag{ + Name: "cert", + Aliases: []string{"c"}, + Usage: "signing cert", + TakesFile: true, + }, + }, + Action: notarySign, +} + +func notarySign(ctx *cli.Context) error { + if err := config.CheckNotaryEnabled(); err != nil { + return err + } + + service, err := crypto.GetSigningService( + ctx.Path("key"), + ctx.Path("cert"), + ) + if err != nil { + return err + } + + reference := ctx.Args().First() + fmt.Println("Generating Docker mainfest:", reference) + desc, err := docker.GenerateManifestOCIDescriptor(reference) + if err != nil { + return err + } + + fmt.Println("Signing", desc.Digest) + sig, err := service.Sign(ctx.Context, desc, reference) + if err != nil { + return err + } + sigPath := config.SignaturePath(desc.Digest) + if err := ios.WriteFile(sigPath, sig); err != nil { + return err + } + fmt.Println("Signature saved to", sigPath) + + return nil +} diff --git a/cmd/docker-nv2/nv2.go b/cmd/docker-nv2/nv2.go new file mode 100644 index 000000000..31b7d6732 --- /dev/null +++ b/cmd/docker-nv2/nv2.go @@ -0,0 +1,32 @@ +package main + +import ( + "os" + "os/exec" + + "github.com/urfave/cli/v2" +) + +var nv2Command = &cli.Command{ + Name: "nv2", + Subcommands: []*cli.Command{ + notaryCommand, + pullCommand, + pushCommand, + }, + Action: delegateToDocker, +} + +func delegateToDocker(ctx *cli.Context) error { + cmd := exec.Command("docker", ctx.Args().Slice()...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + if err, ok := err.(*exec.ExitError); ok { + os.Exit(err.ExitCode()) + } + return err + } + return nil +} diff --git a/cmd/docker-nv2/pull.go b/cmd/docker-nv2/pull.go new file mode 100644 index 000000000..1b9545484 --- /dev/null +++ b/cmd/docker-nv2/pull.go @@ -0,0 +1,124 @@ +package main + +import ( + "context" + "errors" + "fmt" + + "github.com/docker/distribution/reference" + "github.com/notaryproject/notary/v2" + "github.com/notaryproject/nv2/cmd/docker-nv2/docker" + "github.com/opencontainers/go-digest" + oci "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/urfave/cli/v2" +) + +var pullCommand = &cli.Command{ + Name: "pull", + Usage: "Pull an image or a repository from a registry", + ArgsUsage: "[]", + Action: pullImage, +} + +func pullImage(ctx *cli.Context) error { + if err := passThroughIfNotaryDisabled(ctx); err != nil { + return err + } + + originalRef := ctx.Args().First() + ref, err := verifyRemoteImage(ctx.Context, originalRef) + if err != nil { + return err + } + + if err := runCommand("docker", "pull", ref); err != nil { + return err + } + return runCommand("docker", "tag", ref, originalRef) +} + +func verifyRemoteImage(ctx context.Context, ref string) (string, error) { + named, err := reference.ParseNamed(ref) + if err != nil { + return "", err + } + hostname, repository := reference.SplitHostname(named) + manifestRef := docker.GetManifestReference(ref) + + service, err := getVerificationService() + if err != nil { + return "", err + } + + manifestDesc, err := docker.GetManifestOCIDescriptor( + ctx, + hostname, + repository, + manifestRef, + ) + if err != nil { + return "", err + } + fmt.Println(manifestRef, "digest:", manifestDesc.Digest, "size:", manifestDesc.Size) + + fmt.Println("Looking up for signatures") + client, err := docker.GetSignatureRepository(ctx, ref) + if err != nil { + return "", err + } + sigDigests, err := client.Lookup(ctx, manifestDesc.Digest) + if err != nil { + return "", err + } + switch n := len(sigDigests); n { + case 0: + return "", errors.New("no signature found") + default: + fmt.Println("Found", n, "signatures") + } + + sigDigest, originRefs, err := verifySignatures( + ctx, + service, + client, + sigDigests, + manifestDesc, + ) + if err != nil { + return "", fmt.Errorf("none of the signatures are valid: %v", err) + } + fmt.Println("Found valid signature:", sigDigest) + if len(originRefs) != 0 { + fmt.Println("The image is originated from:") + for _, origin := range originRefs { + fmt.Println("-", origin) + } + } + + return fmt.Sprintf("%s@%s", named.Name(), manifestDesc.Digest), nil +} + +func verifySignatures( + ctx context.Context, + service notary.SigningService, + client notary.SignatureRepository, + digests []digest.Digest, + desc oci.Descriptor, +) (digest.Digest, []string, error) { + var lastError error + for _, digest := range digests { + sig, err := client.Get(ctx, digest) + if err != nil { + lastError = err + continue + } + + references, err := service.Verify(ctx, desc, sig) + if err != nil { + lastError = err + continue + } + return digest, references, nil + } + return "", nil, lastError +} diff --git a/cmd/docker-nv2/push.go b/cmd/docker-nv2/push.go new file mode 100644 index 000000000..3d9e13ff7 --- /dev/null +++ b/cmd/docker-nv2/push.go @@ -0,0 +1,110 @@ +package main + +import ( + "bufio" + "errors" + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "strconv" + "strings" + + "github.com/docker/distribution/manifest/schema2" + "github.com/notaryproject/nv2/cmd/docker-nv2/config" + "github.com/notaryproject/nv2/cmd/docker-nv2/docker" + "github.com/opencontainers/go-digest" + oci "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/urfave/cli/v2" +) + +var pushCommand = &cli.Command{ + Name: "push", + Usage: "Push an image or a repository to a registry", + ArgsUsage: "[]", + Action: pushImage, +} + +func pushImage(ctx *cli.Context) error { + if err := passThroughIfNotaryDisabled(ctx); err != nil { + return err + } + + desc, err := pushImageAndGetOCIDescriptor(ctx) + if err != nil { + return err + } + + fmt.Println("Pushing signature") + sigPath := config.SignaturePath(desc.Digest) + sig, err := ioutil.ReadFile(sigPath) + if err != nil { + if os.IsNotExist(err) { + return errors.New("signature not found") + } + return err + } + + client, err := docker.GetSignatureRepository(ctx.Context, ctx.Args().First()) + if err != nil { + return err + } + sigDesc, err := client.Put(ctx.Context, sig) + if err != nil { + return err + } + fmt.Println("signature:", "digest:", sigDesc.Digest, "size:", sigDesc.Size) + + artifactDesc, err := client.Link(ctx.Context, desc, sigDesc) + if err != nil { + return err + } + fmt.Println("link:", "digest:", artifactDesc.Digest, "size:", artifactDesc.Size) + + return nil +} + +func pushImageAndGetOCIDescriptor(ctx *cli.Context) (oci.Descriptor, error) { + args := append([]string{"push"}, ctx.Args().Slice()...) + cmd := exec.Command("docker", args...) + cmd.Stdin = os.Stdin + cmd.Stderr = os.Stderr + stdout, err := cmd.StdoutPipe() + if err != nil { + return oci.Descriptor{}, err + } + scanner := bufio.NewScanner(io.TeeReader(stdout, os.Stdout)) + if err := cmd.Start(); err != nil { + return oci.Descriptor{}, err + } + var lastLine string + for scanner.Scan() { + lastLine = scanner.Text() + } + if err := scanner.Err(); err != nil { + return oci.Descriptor{}, err + } + if err := cmd.Wait(); err != nil { + return oci.Descriptor{}, err + } + + parts := strings.Split(lastLine, " ") + if len(parts) != 5 { + return oci.Descriptor{}, fmt.Errorf("invalid docker pull result: %s", lastLine) + } + digest, err := digest.Parse(parts[2]) + if err != nil { + return oci.Descriptor{}, fmt.Errorf("invalid digest: %s", lastLine) + } + size, err := strconv.ParseInt(parts[4], 10, 64) + if err != nil { + return oci.Descriptor{}, fmt.Errorf("invalid size: %s", lastLine) + } + + return oci.Descriptor{ + MediaType: schema2.MediaTypeManifest, + Digest: digest, + Size: size, + }, nil +} diff --git a/cmd/docker-nv2/util.go b/cmd/docker-nv2/util.go new file mode 100644 index 000000000..6ae917b4c --- /dev/null +++ b/cmd/docker-nv2/util.go @@ -0,0 +1,50 @@ +package main + +import ( + "os" + "os/exec" + + "github.com/notaryproject/notary/v2" + "github.com/notaryproject/nv2/cmd/docker-nv2/config" + "github.com/notaryproject/nv2/cmd/docker-nv2/crypto" + "github.com/urfave/cli/v2" +) + +func passThroughIfNotaryDisabled(ctx *cli.Context) error { + err := config.CheckNotaryEnabled() + if err == nil { + return nil + } + if err != config.ErrNotaryDisabled { + return err + } + + args := append([]string{ctx.Command.Name}, ctx.Args().Slice()...) + if err := runCommand("docker", args...); err != nil { + return err + } + os.Exit(0) + panic("process should be terminated") +} + +func runCommand(command string, args ...string) error { + cmd := exec.Command(command, args...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + if err, ok := err.(*exec.ExitError); ok { + os.Exit(err.ExitCode()) + } + return err + } + return nil +} + +func getVerificationService() (notary.SigningService, error) { + cfg, err := config.Load() + if err != nil { + return nil, err + } + return crypto.GetSigningService("", cfg.VerificationCerts...) +} diff --git a/docs/docker-plugins/README.md b/docs/docker-plugins/README.md index 611509677..234aba0d9 100644 --- a/docs/docker-plugins/README.md +++ b/docs/docker-plugins/README.md @@ -2,4 +2,5 @@ Multiple docker plugins are provided for `nv2` scenarios. -- [docker-generate](docker-generate.md) \ No newline at end of file +- [docker-generate](docker-generate.md) +- [docker-nv2](docker-nv2.md) \ No newline at end of file diff --git a/docs/docker-plugins/docker-nv2.md b/docs/docker-plugins/docker-nv2.md new file mode 100644 index 000000000..bef36f89f --- /dev/null +++ b/docs/docker-plugins/docker-nv2.md @@ -0,0 +1,54 @@ +# docker-nv2 +Docker CLI plugin to demonstrate Notary v2 integration with Docker CLI, leveraging the [notary v2 library](https://github.com/notaryproject/notary). + +## Build and Install +This plugin requires [golang](https://golang.org/dl/) with version `>= 1.14`. + +To build and install, run +``` +go build -o ~/.docker/cli-plugins/docker-nv2 ./cmd/docker-nv2 +``` + +## Instructions +### Create Alias +For better demonstration experience, it is suggested to create the following alias in your shell: +```bash +alias docker="docker nv2" +``` +or if you are using PowerShell on Windows, +```powershell +function docker { cmd /c docker nv2 $args } +``` + +### Example Run +On the producer machine: +```bash +docker notary --enabled +docker build -t $image . +docker notary sign --key identity.pem --cert identity.crt $image +docker push $image +``` + +On the consumer machine: +```bash +docker notary --enabled +docker pull $image +``` +It may fail since the producer machine may use a self-signed certificate, or invalid certificates detected. +See [configurations](#configurations) for more details. + +## Configurations +The config file for notary is default at `~/.docker/nv2.json`. +The intermediate signatures are stored at `~/.docker/nv2/`. + +The config file looks like +```json +{ + "enabled": true, + "verificationCerts": [ + "path/to/the/certs/for/verification" + ] +} +``` +To pull images properly, certification paths are required to be provided at `verificationCerts`. +It is suggested to use absolute paths. diff --git a/go.mod b/go.mod index 6b3b3401d..8dcd699bb 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,17 @@ module github.com/notaryproject/nv2 go 1.14 require ( + github.com/docker/cli v20.10.5+incompatible github.com/docker/distribution v0.0.0-20210206161202-6200038bc715 + github.com/docker/docker v20.10.5+incompatible // indirect + github.com/docker/docker-credential-helpers v0.6.3 // indirect + github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 github.com/notaryproject/notary/v2 v2.0.0-00010101000000-000000000000 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.1 - github.com/urfave/cli/v2 v2.2.0 + github.com/urfave/cli/v2 v2.3.0 + golang.org/x/sys v0.0.0-20210326220804-49726bf1d181 // indirect + gotest.tools/v3 v3.0.3 // indirect ) replace github.com/notaryproject/notary/v2 => github.com/shizhMSFT/notary/v2 v2.0.0-20210330091034-dc6e56acc97a diff --git a/go.sum b/go.sum index e7a4502c7..01641e196 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/aviral26/artifacts v0.0.0-20210128064216-9526869307d7 h1:GaDZS6pvOtxZRl1toVDD3fk4Ix8/UiBQOUycmVCzrkc= github.com/aviral26/artifacts v0.0.0-20210128064216-9526869307d7/go.mod h1:Xr7BjEvr8VVrtyC9LX3q5975UVkEvyaXmb34JsCvSJ0= github.com/aws/aws-sdk-go v1.34.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -19,12 +20,19 @@ github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3k github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v20.10.5+incompatible h1:bjflayQbWg+xOkF2WPEAOi4Y7zWhR7ptoPhV/VqLVDE= +github.com/docker/cli v20.10.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v0.0.0-20210206161202-6200038bc715 h1:oN+Mw/t1Ua4huewY/20wTTZ0Nvye+9BJVYoCl//3tcQ= github.com/docker/distribution v0.0.0-20210206161202-6200038bc715/go.mod h1:j0+FEax3zYG2pUod5Nc0npkx8p9I3HrKgf2TvKDc5LE= +github.com/docker/docker v20.10.5+incompatible h1:o5WL5onN4awYGwrW7+oTn5x9AF2prw7V0Ox8ZEkoCdg= +github.com/docker/docker v20.10.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/go v1.5.1-1 h1:hr4w35acWBPhGBXlzPoHpmZ/ygPjnmFVxGxxGnMyP7k= github.com/docker/go v1.5.1-1/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= @@ -44,6 +52,8 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= @@ -53,6 +63,7 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -73,6 +84,8 @@ github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3I github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -94,6 +107,7 @@ github.com/shizhMSFT/notary/v2 v2.0.0-20210330091034-dc6e56acc97a/go.mod h1:CN70 github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -101,9 +115,10 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4= -github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= @@ -113,25 +128,37 @@ golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210326220804-49726bf1d181 h1:64ChN/hjER/taL4YJuA+gpLfIMT+/NFherRZixbxOhg= +golang.org/x/sys v0.0.0-20210326220804-49726bf1d181/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789 h1:NMiUjDZiD6qDVeBOzpImftxXzQHCp2Y2QLdmaqU9MRk= gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3 h1:fvjTMHxHEw/mxHbtzPi3JCcKXQRAnQTBRo6YCJSVHKI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= diff --git a/internal/os/file.go b/internal/os/file.go new file mode 100644 index 000000000..8199bb8bf --- /dev/null +++ b/internal/os/file.go @@ -0,0 +1,15 @@ +package os + +import ( + "io/ioutil" + "os" + "path/filepath" +) + +// WriteFile writes to a path with all parent directories created. +func WriteFile(path string, data []byte) error { + if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil { + return err + } + return ioutil.WriteFile(path, data, 0666) +} From 545280ed3b2cae3bcbde68d0299aa0049c37688d Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Wed, 31 Mar 2021 14:37:00 +0800 Subject: [PATCH 24/69] refactor network transport Signed-off-by: Shiwei Zhang --- cmd/docker-nv2/docker/network.go | 4 ++-- cmd/docker-nv2/metadata.go | 2 +- docs/docker-plugins/docker-generate.md | 2 +- docs/docker-plugins/docker-nv2.md | 2 +- docs/nv2/README.md | 2 +- go.mod | 6 +++--- go.sum | 14 ++++++-------- pkg/registry/{transport.go => auth.go} | 12 +++++++----- pkg/registry/client.go | 2 +- pkg/registry/manifest.go | 6 +++--- pkg/registry/{docker.go => mediatype.go} | 0 11 files changed, 26 insertions(+), 26 deletions(-) rename pkg/registry/{transport.go => auth.go} (78%) rename pkg/registry/{docker.go => mediatype.go} (100%) diff --git a/cmd/docker-nv2/docker/network.go b/cmd/docker-nv2/docker/network.go index ca395b7f1..b2f65c95b 100644 --- a/cmd/docker-nv2/docker/network.go +++ b/cmd/docker-nv2/docker/network.go @@ -3,7 +3,7 @@ package docker import ( "net/http" - "github.com/notaryproject/notary/v2/util" + "github.com/notaryproject/nv2/pkg/registry" ) // Transport returns the configured round tripper for a host @@ -16,5 +16,5 @@ func Transport(hostname string) (http.RoundTripper, error) { if username == "" { return tr, nil } - return util.TransportWithBasicAuth(tr, hostname, username, password), nil + return registry.NewAuthtransport(tr, username, password), nil } diff --git a/cmd/docker-nv2/metadata.go b/cmd/docker-nv2/metadata.go index ea51b3efa..2c91673e3 100644 --- a/cmd/docker-nv2/metadata.go +++ b/cmd/docker-nv2/metadata.go @@ -10,7 +10,7 @@ import ( var pluginMetadata = map[string]interface{}{ "SchemaVersion": "0.1.0", "Vendor": "Sajay Antony, Shiwei Zhang", - "Version": "0.2.2", + "Version": "0.2.3", "ShortDescription": "Notary V2 Signature extension", "URL": "https://github.com/notaryproject/nv2", } diff --git a/docs/docker-plugins/docker-generate.md b/docs/docker-plugins/docker-generate.md index 66a8bf14b..e55afbde4 100644 --- a/docs/docker-plugins/docker-generate.md +++ b/docs/docker-plugins/docker-generate.md @@ -2,7 +2,7 @@ Docker CLI plugin to generate metadata **offline**. ## Build and Install -This plugin requires [golang](https://golang.org/dl/) with version `>= 1.14`. +This plugin requires [golang](https://golang.org/dl/) with version `>= 1.16`. To build and install, run ``` diff --git a/docs/docker-plugins/docker-nv2.md b/docs/docker-plugins/docker-nv2.md index bef36f89f..9c0c0aa7b 100644 --- a/docs/docker-plugins/docker-nv2.md +++ b/docs/docker-plugins/docker-nv2.md @@ -2,7 +2,7 @@ Docker CLI plugin to demonstrate Notary v2 integration with Docker CLI, leveraging the [notary v2 library](https://github.com/notaryproject/notary). ## Build and Install -This plugin requires [golang](https://golang.org/dl/) with version `>= 1.14`. +This plugin requires [golang](https://golang.org/dl/) with version `>= 1.16`. To build and install, run ``` diff --git a/docs/nv2/README.md b/docs/nv2/README.md index ac75487d5..987b78a04 100644 --- a/docs/nv2/README.md +++ b/docs/nv2/README.md @@ -12,7 +12,7 @@ ### Build and Install -This plugin requires [golang](https://golang.org/dl/) with version `>= 1.14`. +This plugin requires [golang](https://golang.org/dl/) with version `>= 1.16`. To build and install, run diff --git a/go.mod b/go.mod index 8dcd699bb..115b82c49 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/notaryproject/nv2 -go 1.14 +go 1.16 require ( github.com/docker/cli v20.10.5+incompatible @@ -12,8 +12,8 @@ require ( github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.1 github.com/urfave/cli/v2 v2.3.0 - golang.org/x/sys v0.0.0-20210326220804-49726bf1d181 // indirect + golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 // indirect gotest.tools/v3 v3.0.3 // indirect ) -replace github.com/notaryproject/notary/v2 => github.com/shizhMSFT/notary/v2 v2.0.0-20210330091034-dc6e56acc97a +replace github.com/notaryproject/notary/v2 => github.com/shizhMSFT/notary/v2 v2.0.0-20210331055547-ae76f458b5d2 diff --git a/go.sum b/go.sum index 01641e196..648393851 100644 --- a/go.sum +++ b/go.sum @@ -5,8 +5,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/aviral26/artifacts v0.0.0-20210128064216-9526869307d7 h1:GaDZS6pvOtxZRl1toVDD3fk4Ix8/UiBQOUycmVCzrkc= -github.com/aviral26/artifacts v0.0.0-20210128064216-9526869307d7/go.mod h1:Xr7BjEvr8VVrtyC9LX3q5975UVkEvyaXmb34JsCvSJ0= github.com/aws/aws-sdk-go v1.34.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -79,6 +77,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/notaryproject/artifacts v0.0.0-20210325201627-49d06c9f1a07 h1:geJlhRFBwSJXhIv7KMgAXBz1Ie6wsuFeE5vuau3B4AQ= +github.com/notaryproject/artifacts v0.0.0-20210325201627-49d06c9f1a07/go.mod h1:za0DINIIQLPCBn9AhLfPjywgT51o0zll644gbIXiQiQ= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= @@ -102,8 +102,8 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shizhMSFT/notary/v2 v2.0.0-20210330091034-dc6e56acc97a h1:zGrZ/u7V9xoGpJGPBEuU2ax0UiSQfMu2Ohc6HCq15+o= -github.com/shizhMSFT/notary/v2 v2.0.0-20210330091034-dc6e56acc97a/go.mod h1:CN708S2wKRKpzzvAbfKY3NETWwnCNEFje3nWFUl5rU0= +github.com/shizhMSFT/notary/v2 v2.0.0-20210331055547-ae76f458b5d2 h1:tQCLyuSmS8zdkygWzZiZ+j9fpaa/4gki5fm+vL8TvLE= +github.com/shizhMSFT/notary/v2 v2.0.0-20210331055547-ae76f458b5d2/go.mod h1:M5eWeevjpg7uQi00HNeg8XRPom29qkq9pEp+d4cZg3w= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -142,11 +142,10 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210326220804-49726bf1d181 h1:64ChN/hjER/taL4YJuA+gpLfIMT+/NFherRZixbxOhg= -golang.org/x/sys v0.0.0-20210326220804-49726bf1d181/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -154,7 +153,6 @@ google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11K google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789 h1:NMiUjDZiD6qDVeBOzpImftxXzQHCp2Y2QLdmaqU9MRk= gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/pkg/registry/transport.go b/pkg/registry/auth.go similarity index 78% rename from pkg/registry/transport.go rename to pkg/registry/auth.go index a4ff6eb21..8177dac4b 100644 --- a/pkg/registry/transport.go +++ b/pkg/registry/auth.go @@ -10,21 +10,23 @@ import ( var authHeaderRegex = regexp.MustCompile(`(realm|service|scope)="([^"]*)`) -type v2Transport struct { +type authTransport struct { base http.RoundTripper username string password string } -func newV2transport(base http.RoundTripper, username, password string) http.RoundTripper { - return &v2Transport{ +// NewAuthtransport creates wraps a round tripper with auth strategies. +// It tries basic auth first and then falls back to token auth. +func NewAuthtransport(base http.RoundTripper, username, password string) http.RoundTripper { + return &authTransport{ base: base, username: username, password: password, } } -func (t *v2Transport) RoundTrip(originalReq *http.Request) (*http.Response, error) { +func (t *authTransport) RoundTrip(originalReq *http.Request) (*http.Response, error) { req := originalReq.Clone(originalReq.Context()) if t.username != "" { req.SetBasicAuth(t.username, t.password) @@ -57,7 +59,7 @@ func (t *v2Transport) RoundTrip(originalReq *http.Request) (*http.Response, erro return t.base.RoundTrip(req) } -func (t *v2Transport) fetchToken(params map[string]string) (string, *http.Response, error) { +func (t *authTransport) fetchToken(params map[string]string) (string, *http.Response, error) { req, err := http.NewRequest(http.MethodGet, params["realm"], nil) if err != nil { return "", nil, err diff --git a/pkg/registry/client.go b/pkg/registry/client.go index c20107445..ee369eb3f 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -26,7 +26,7 @@ func NewClient(base http.RoundTripper, opts *ClientOptions) *Client { opts = &ClientOptions{} } return &Client{ - base: newV2transport(base, opts.Username, opts.Password), + base: NewAuthtransport(base, opts.Username, opts.Password), plainHTTP: opts.PlainHTTP, } } diff --git a/pkg/registry/manifest.go b/pkg/registry/manifest.go index 135997fe0..fdb834df5 100644 --- a/pkg/registry/manifest.go +++ b/pkg/registry/manifest.go @@ -8,7 +8,7 @@ import ( "strings" "github.com/notaryproject/notary/v2/signature" - v1 "github.com/opencontainers/image-spec/specs-go/v1" + oci "github.com/opencontainers/image-spec/specs-go/v1" ) // GetManifestMetadata returns signature manifest information by URI scheme @@ -36,8 +36,8 @@ func (c *Client) GetDockerManifestMetadata(uri *url.URL) (signature.Manifest, er // from a remote OCI manifest func (c *Client) GetOCIManifestMetadata(uri *url.URL) (signature.Manifest, error) { return c.getManifestMetadata(uri, - v1.MediaTypeImageIndex, - v1.MediaTypeImageManifest, + oci.MediaTypeImageIndex, + oci.MediaTypeImageManifest, ) } diff --git a/pkg/registry/docker.go b/pkg/registry/mediatype.go similarity index 100% rename from pkg/registry/docker.go rename to pkg/registry/mediatype.go From cd28c19ae066a9cb11f611f6387cdc9223c60004 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Wed, 31 Mar 2021 15:15:07 +0800 Subject: [PATCH 25/69] add makefile Signed-off-by: Shiwei Zhang --- .gitignore | 5 + Makefile | 36 +++++ cmd/docker-generate/generate.go | 24 +-- cmd/docker-generate/main.go | 42 +++--- cmd/docker-generate/manifest.go | 130 ++++++++-------- cmd/docker-generate/metadata.go | 50 +++---- cmd/nv2/common.go | 50 +++---- cmd/nv2/manifest.go | 142 +++++++++--------- cmd/nv2/sign.go | 258 ++++++++++++++++---------------- cmd/nv2/verify.go | 238 ++++++++++++++--------------- internal/io/count.go | 44 +++--- pkg/docker/schema2.go | 202 ++++++++++++------------- pkg/registry/auth.go | 224 +++++++++++++-------------- pkg/registry/client.go | 64 ++++---- pkg/registry/manifest.go | 240 ++++++++++++++--------------- pkg/registry/mediatype.go | 14 +- 16 files changed, 902 insertions(+), 861 deletions(-) create mode 100644 .gitignore create mode 100644 Makefile diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..a6dfa2f56 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +# VS Code +.vscode + +# Custom +bin/ \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..fd6130dab --- /dev/null +++ b/Makefile @@ -0,0 +1,36 @@ +GO_BUILD_FLAGS = +DOCKER_PLUGINS = docker-generate docker-nv2 +COMMANDS = nv2 $(DOCKER_PLUGINS) + +define BUILD_BINARY = + go build $(GO_BUILD_FLAGS) -o $@ ./$< +endef + +.PHONY: all +all: build + +bin/%: cmd/% + $(BUILD_BINARY) + +.PHONY: build +build: $(addprefix bin/,$(COMMANDS)) + +.PHONY: clean +clean: + git status --ignored --short | grep '^!! ' | sed 's/!! //' | xargs rm -rf + +.PHONY: check-encoding +check-encoding: + ! find cmd pkg internal -name "*.go" -type f -exec file "{}" ";" | grep CRLF + +.PHONY: fix-encoding +fix-encoding: + find cmd pkg internal -type f -name "*.go" -exec sed -i -e "s/\r//g" {} + + +.PHONY: vendor +vendor: + GO111MODULE=on go mod vendor + +.PHONY: install-docker-plugins +install-docker-plugins: $(addprefix bin/,$(DOCKER_PLUGINS)) + cp $(addprefix bin/,$(DOCKER_PLUGINS)) ~/.docker/cli-plugins/ diff --git a/cmd/docker-generate/generate.go b/cmd/docker-generate/generate.go index 71f72c2ce..32ceecbc7 100644 --- a/cmd/docker-generate/generate.go +++ b/cmd/docker-generate/generate.go @@ -1,12 +1,12 @@ -package main - -import ( - "github.com/urfave/cli/v2" -) - -var generateCommand = &cli.Command{ - Name: "generate", - Subcommands: []*cli.Command{ - manifestCommand, - }, -} +package main + +import ( + "github.com/urfave/cli/v2" +) + +var generateCommand = &cli.Command{ + Name: "generate", + Subcommands: []*cli.Command{ + manifestCommand, + }, +} diff --git a/cmd/docker-generate/main.go b/cmd/docker-generate/main.go index 83941702a..86fef92cc 100644 --- a/cmd/docker-generate/main.go +++ b/cmd/docker-generate/main.go @@ -1,21 +1,21 @@ -package main - -import ( - "log" - "os" - - "github.com/urfave/cli/v2" -) - -func main() { - app := &cli.App{ - Name: "docker", - Commands: []*cli.Command{ - generateCommand, - metadataCommand, - }, - } - if err := app.Run(os.Args); err != nil { - log.Fatal(err) - } -} +package main + +import ( + "log" + "os" + + "github.com/urfave/cli/v2" +) + +func main() { + app := &cli.App{ + Name: "docker", + Commands: []*cli.Command{ + generateCommand, + metadataCommand, + }, + } + if err := app.Run(os.Args); err != nil { + log.Fatal(err) + } +} diff --git a/cmd/docker-generate/manifest.go b/cmd/docker-generate/manifest.go index a224aef6f..c593c14ae 100644 --- a/cmd/docker-generate/manifest.go +++ b/cmd/docker-generate/manifest.go @@ -1,65 +1,65 @@ -package main - -import ( - "io" - "os" - "os/exec" - - "github.com/notaryproject/nv2/pkg/docker" - "github.com/urfave/cli/v2" -) - -var manifestCommand = &cli.Command{ - Name: "manifest", - Usage: "generates the manifest of a docker image", - ArgsUsage: "[]", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "output", - Aliases: []string{"o"}, - Usage: "write to a file instead of stdout", - }, - }, - Action: generateManifest, -} - -func generateManifest(ctx *cli.Context) error { - var reader io.Reader - if reference := ctx.Args().First(); reference != "" { - cmd := exec.Command("docker", "save", reference) - stdout, err := cmd.StdoutPipe() - if err != nil { - return err - } - reader = stdout - if err := cmd.Start(); err != nil { - return err - } - } else { - reader = os.Stdin - } - - var writer io.Writer - if output := ctx.String("output"); output != "" { - file, err := os.Create(output) - if err != nil { - return err - } - defer file.Close() - writer = file - } else { - writer = os.Stdout - } - - manifest, err := docker.GenerateSchema2FromDockerSave(reader) - if err != nil { - return err - } - _, payload, err := manifest.Payload() - if err != nil { - return err - } - - _, err = writer.Write(payload) - return err -} +package main + +import ( + "io" + "os" + "os/exec" + + "github.com/notaryproject/nv2/pkg/docker" + "github.com/urfave/cli/v2" +) + +var manifestCommand = &cli.Command{ + Name: "manifest", + Usage: "generates the manifest of a docker image", + ArgsUsage: "[]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "output", + Aliases: []string{"o"}, + Usage: "write to a file instead of stdout", + }, + }, + Action: generateManifest, +} + +func generateManifest(ctx *cli.Context) error { + var reader io.Reader + if reference := ctx.Args().First(); reference != "" { + cmd := exec.Command("docker", "save", reference) + stdout, err := cmd.StdoutPipe() + if err != nil { + return err + } + reader = stdout + if err := cmd.Start(); err != nil { + return err + } + } else { + reader = os.Stdin + } + + var writer io.Writer + if output := ctx.String("output"); output != "" { + file, err := os.Create(output) + if err != nil { + return err + } + defer file.Close() + writer = file + } else { + writer = os.Stdout + } + + manifest, err := docker.GenerateSchema2FromDockerSave(reader) + if err != nil { + return err + } + _, payload, err := manifest.Payload() + if err != nil { + return err + } + + _, err = writer.Write(payload) + return err +} diff --git a/cmd/docker-generate/metadata.go b/cmd/docker-generate/metadata.go index 6cbcacb38..9ddc8f16d 100644 --- a/cmd/docker-generate/metadata.go +++ b/cmd/docker-generate/metadata.go @@ -1,25 +1,25 @@ -package main - -import ( - "encoding/json" - "os" - - "github.com/urfave/cli/v2" -) - -var pluginMetadata = map[string]interface{}{ - "SchemaVersion": "0.1.0", - "Vendor": "github.com/shizhMSFT", - "Version": "0.1.0", - "ShortDescription": "Generate artifacts", - "Experimental": true, -} - -var metadataCommand = &cli.Command{ - Name: "docker-cli-plugin-metadata", - Action: func(ctx *cli.Context) error { - writer := json.NewEncoder(os.Stdout) - return writer.Encode(pluginMetadata) - }, - Hidden: true, -} +package main + +import ( + "encoding/json" + "os" + + "github.com/urfave/cli/v2" +) + +var pluginMetadata = map[string]interface{}{ + "SchemaVersion": "0.1.0", + "Vendor": "github.com/shizhMSFT", + "Version": "0.1.0", + "ShortDescription": "Generate artifacts", + "Experimental": true, +} + +var metadataCommand = &cli.Command{ + Name: "docker-cli-plugin-metadata", + Action: func(ctx *cli.Context) error { + writer := json.NewEncoder(os.Stdout) + return writer.Encode(pluginMetadata) + }, + Hidden: true, +} diff --git a/cmd/nv2/common.go b/cmd/nv2/common.go index 5502225a1..6a5628cbc 100644 --- a/cmd/nv2/common.go +++ b/cmd/nv2/common.go @@ -1,25 +1,25 @@ -package main - -import "github.com/urfave/cli/v2" - -var ( - usernameFlag = &cli.StringFlag{ - Name: "username", - Aliases: []string{"u"}, - Usage: "username for generic remote access", - } - passwordFlag = &cli.StringFlag{ - Name: "password", - Aliases: []string{"p"}, - Usage: "password for generic remote access", - } - plainHTTPFlag = &cli.BoolFlag{ - Name: "plain-http", - Usage: "remote access via plain HTTP", - } - mediaTypeFlag = &cli.StringFlag{ - Name: "media-type", - Usage: "specify the media type of the manifest read from file or stdin", - Value: "application/vnd.docker.distribution.manifest.v2+json", - } -) +package main + +import "github.com/urfave/cli/v2" + +var ( + usernameFlag = &cli.StringFlag{ + Name: "username", + Aliases: []string{"u"}, + Usage: "username for generic remote access", + } + passwordFlag = &cli.StringFlag{ + Name: "password", + Aliases: []string{"p"}, + Usage: "password for generic remote access", + } + plainHTTPFlag = &cli.BoolFlag{ + Name: "plain-http", + Usage: "remote access via plain HTTP", + } + mediaTypeFlag = &cli.StringFlag{ + Name: "media-type", + Usage: "specify the media type of the manifest read from file or stdin", + Value: "application/vnd.docker.distribution.manifest.v2+json", + } +) diff --git a/cmd/nv2/manifest.go b/cmd/nv2/manifest.go index 780ebc640..3615490e7 100644 --- a/cmd/nv2/manifest.go +++ b/cmd/nv2/manifest.go @@ -1,71 +1,71 @@ -package main - -import ( - "fmt" - "io" - "math" - "net/url" - "os" - "strings" - - "github.com/notaryproject/notary/v2/signature" - "github.com/notaryproject/nv2/pkg/registry" - "github.com/opencontainers/go-digest" - "github.com/urfave/cli/v2" -) - -func getManifestFromContext(ctx *cli.Context) (signature.Manifest, error) { - if uri := ctx.Args().First(); uri != "" { - return getManfestsFromURI(ctx, uri) - } - return getManifestFromReader(os.Stdin, ctx.String(mediaTypeFlag.Name)) -} - -func getManifestFromReader(r io.Reader, mediaType string) (signature.Manifest, error) { - lr := &io.LimitedReader{ - R: r, - N: math.MaxInt64, - } - digest, err := digest.SHA256.FromReader(lr) - if err != nil { - return signature.Manifest{}, err - } - return signature.Manifest{ - Descriptor: signature.Descriptor{ - MediaType: mediaType, - Digest: digest.String(), - Size: math.MaxInt64 - lr.N, - }, - }, nil -} - -func getManfestsFromURI(ctx *cli.Context, uri string) (signature.Manifest, error) { - parsed, err := url.Parse(uri) - if err != nil { - return signature.Manifest{}, err - } - var r io.Reader - switch strings.ToLower(parsed.Scheme) { - case "file": - path := parsed.Path - if parsed.Opaque != "" { - path = parsed.Opaque - } - file, err := os.Open(path) - if err != nil { - return signature.Manifest{}, err - } - defer file.Close() - r = file - case "docker", "oci": - remote := registry.NewClient(nil, ®istry.ClientOptions{ - Username: ctx.String(usernameFlag.Name), - Password: ctx.String(passwordFlag.Name), - PlainHTTP: ctx.Bool(plainHTTPFlag.Name), - }) - return remote.GetManifestMetadata(parsed) - default: - return signature.Manifest{}, fmt.Errorf("unsupported URI scheme: %s", parsed.Scheme) - } - return getManifestFromReader(r, ctx.String(mediaTypeFlag.Name)) -} +package main + +import ( + "fmt" + "io" + "math" + "net/url" + "os" + "strings" + + "github.com/notaryproject/notary/v2/signature" + "github.com/notaryproject/nv2/pkg/registry" + "github.com/opencontainers/go-digest" + "github.com/urfave/cli/v2" +) + +func getManifestFromContext(ctx *cli.Context) (signature.Manifest, error) { + if uri := ctx.Args().First(); uri != "" { + return getManfestsFromURI(ctx, uri) + } + return getManifestFromReader(os.Stdin, ctx.String(mediaTypeFlag.Name)) +} + +func getManifestFromReader(r io.Reader, mediaType string) (signature.Manifest, error) { + lr := &io.LimitedReader{ + R: r, + N: math.MaxInt64, + } + digest, err := digest.SHA256.FromReader(lr) + if err != nil { + return signature.Manifest{}, err + } + return signature.Manifest{ + Descriptor: signature.Descriptor{ + MediaType: mediaType, + Digest: digest.String(), + Size: math.MaxInt64 - lr.N, + }, + }, nil +} + +func getManfestsFromURI(ctx *cli.Context, uri string) (signature.Manifest, error) { + parsed, err := url.Parse(uri) + if err != nil { + return signature.Manifest{}, err + } + var r io.Reader + switch strings.ToLower(parsed.Scheme) { + case "file": + path := parsed.Path + if parsed.Opaque != "" { + path = parsed.Opaque + } + file, err := os.Open(path) + if err != nil { + return signature.Manifest{}, err + } + defer file.Close() + r = file + case "docker", "oci": + remote := registry.NewClient(nil, ®istry.ClientOptions{ + Username: ctx.String(usernameFlag.Name), + Password: ctx.String(passwordFlag.Name), + PlainHTTP: ctx.Bool(plainHTTPFlag.Name), + }) + return remote.GetManifestMetadata(parsed) + default: + return signature.Manifest{}, fmt.Errorf("unsupported URI scheme: %s", parsed.Scheme) + } + return getManifestFromReader(r, ctx.String(mediaTypeFlag.Name)) +} diff --git a/cmd/nv2/sign.go b/cmd/nv2/sign.go index 2efcc5c42..f18f84b6e 100644 --- a/cmd/nv2/sign.go +++ b/cmd/nv2/sign.go @@ -1,129 +1,129 @@ -package main - -import ( - "fmt" - "io/ioutil" - "strings" - "time" - - "github.com/notaryproject/notary/v2/signature" - "github.com/notaryproject/notary/v2/signature/x509" - "github.com/urfave/cli/v2" -) - -const signerID = "nv2" - -var signCommand = &cli.Command{ - Name: "sign", - Usage: "signs OCI Artifacts", - ArgsUsage: "[]", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "method", - Aliases: []string{"m"}, - Usage: "signing method", - Required: true, - }, - &cli.StringFlag{ - Name: "key", - Aliases: []string{"k"}, - Usage: "signing key file [x509]", - TakesFile: true, - }, - &cli.StringFlag{ - Name: "cert", - Aliases: []string{"c"}, - Usage: "signing cert [x509]", - TakesFile: true, - }, - &cli.DurationFlag{ - Name: "expiry", - Aliases: []string{"e"}, - Usage: "expire duration", - }, - &cli.StringSliceFlag{ - Name: "reference", - Aliases: []string{"r"}, - Usage: "original references", - }, - &cli.StringFlag{ - Name: "output", - Aliases: []string{"o"}, - Usage: "write signature to a specific path", - }, - usernameFlag, - passwordFlag, - plainHTTPFlag, - mediaTypeFlag, - }, - Action: runSign, -} - -func runSign(ctx *cli.Context) error { - // initialize - scheme, err := getSchemeForSigning(ctx) - if err != nil { - return err - } - - // core process - claims, err := prepareClaimsForSigning(ctx) - if err != nil { - return err - } - sig, err := scheme.Sign(signerID, claims) - if err != nil { - return err - } - - // write out - path := ctx.String("output") - if path == "" { - path = strings.Split(claims.Manifest.Digest, ":")[1] + ".nv2" - } - if err := ioutil.WriteFile(path, []byte(sig), 0666); err != nil { - return err - } - - fmt.Println(claims.Manifest.Digest) - return nil -} - -func prepareClaimsForSigning(ctx *cli.Context) (signature.Claims, error) { - manifest, err := getManifestFromContext(ctx) - if err != nil { - return signature.Claims{}, err - } - manifest.References = ctx.StringSlice("reference") - now := time.Now() - nowUnix := now.Unix() - claims := signature.Claims{ - Manifest: manifest, - IssuedAt: nowUnix, - } - if expiry := ctx.Duration("expiry"); expiry != 0 { - claims.NotBefore = nowUnix - claims.Expiration = now.Add(expiry).Unix() - } - - return claims, nil -} - -func getSchemeForSigning(ctx *cli.Context) (*signature.Scheme, error) { - var ( - signer signature.Signer - err error - ) - switch method := ctx.String("method"); method { - case "x509": - signer, err = x509.NewSignerFromFiles(ctx.String("key"), ctx.String("cert")) - default: - return nil, fmt.Errorf("unsupported signing method: %s", method) - } - scheme := signature.NewScheme() - if err != nil { - return nil, err - } - scheme.RegisterSigner(signerID, signer) - return scheme, nil -} +package main + +import ( + "fmt" + "io/ioutil" + "strings" + "time" + + "github.com/notaryproject/notary/v2/signature" + "github.com/notaryproject/notary/v2/signature/x509" + "github.com/urfave/cli/v2" +) + +const signerID = "nv2" + +var signCommand = &cli.Command{ + Name: "sign", + Usage: "signs OCI Artifacts", + ArgsUsage: "[]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "method", + Aliases: []string{"m"}, + Usage: "signing method", + Required: true, + }, + &cli.StringFlag{ + Name: "key", + Aliases: []string{"k"}, + Usage: "signing key file [x509]", + TakesFile: true, + }, + &cli.StringFlag{ + Name: "cert", + Aliases: []string{"c"}, + Usage: "signing cert [x509]", + TakesFile: true, + }, + &cli.DurationFlag{ + Name: "expiry", + Aliases: []string{"e"}, + Usage: "expire duration", + }, + &cli.StringSliceFlag{ + Name: "reference", + Aliases: []string{"r"}, + Usage: "original references", + }, + &cli.StringFlag{ + Name: "output", + Aliases: []string{"o"}, + Usage: "write signature to a specific path", + }, + usernameFlag, + passwordFlag, + plainHTTPFlag, + mediaTypeFlag, + }, + Action: runSign, +} + +func runSign(ctx *cli.Context) error { + // initialize + scheme, err := getSchemeForSigning(ctx) + if err != nil { + return err + } + + // core process + claims, err := prepareClaimsForSigning(ctx) + if err != nil { + return err + } + sig, err := scheme.Sign(signerID, claims) + if err != nil { + return err + } + + // write out + path := ctx.String("output") + if path == "" { + path = strings.Split(claims.Manifest.Digest, ":")[1] + ".nv2" + } + if err := ioutil.WriteFile(path, []byte(sig), 0666); err != nil { + return err + } + + fmt.Println(claims.Manifest.Digest) + return nil +} + +func prepareClaimsForSigning(ctx *cli.Context) (signature.Claims, error) { + manifest, err := getManifestFromContext(ctx) + if err != nil { + return signature.Claims{}, err + } + manifest.References = ctx.StringSlice("reference") + now := time.Now() + nowUnix := now.Unix() + claims := signature.Claims{ + Manifest: manifest, + IssuedAt: nowUnix, + } + if expiry := ctx.Duration("expiry"); expiry != 0 { + claims.NotBefore = nowUnix + claims.Expiration = now.Add(expiry).Unix() + } + + return claims, nil +} + +func getSchemeForSigning(ctx *cli.Context) (*signature.Scheme, error) { + var ( + signer signature.Signer + err error + ) + switch method := ctx.String("method"); method { + case "x509": + signer, err = x509.NewSignerFromFiles(ctx.String("key"), ctx.String("cert")) + default: + return nil, fmt.Errorf("unsupported signing method: %s", method) + } + scheme := signature.NewScheme() + if err != nil { + return nil, err + } + scheme.RegisterSigner(signerID, signer) + return scheme, nil +} diff --git a/cmd/nv2/verify.go b/cmd/nv2/verify.go index 71c7ffa44..37a145c92 100644 --- a/cmd/nv2/verify.go +++ b/cmd/nv2/verify.go @@ -1,119 +1,119 @@ -package main - -import ( - "crypto/x509" - "fmt" - "io/ioutil" - - "github.com/notaryproject/notary/v2/signature" - x509nv2 "github.com/notaryproject/notary/v2/signature/x509" - "github.com/urfave/cli/v2" -) - -var verifyCommand = &cli.Command{ - Name: "verify", - Usage: "verifies OCI Artifacts", - ArgsUsage: "[]", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "signature", - Aliases: []string{"s", "f"}, - Usage: "signature file", - Required: true, - TakesFile: true, - }, - &cli.StringSliceFlag{ - Name: "cert", - Aliases: []string{"c"}, - Usage: "certs for verification [x509]", - TakesFile: true, - }, - &cli.StringSliceFlag{ - Name: "ca-cert", - Usage: "CA certs for verification [x509]", - TakesFile: true, - }, - usernameFlag, - passwordFlag, - plainHTTPFlag, - mediaTypeFlag, - }, - Action: runVerify, -} - -func runVerify(ctx *cli.Context) error { - // initialize - scheme, err := getSchemeForVerification(ctx) - if err != nil { - return err - } - sig, err := readSignatrueFile(ctx.String("signature")) - if err != nil { - return err - } - - // core process - claims, err := scheme.Verify(sig) - if err != nil { - return fmt.Errorf("verification failure: %v", err) - } - manifest, err := getManifestFromContext(ctx) - if err != nil { - return err - } - if manifest.Descriptor != claims.Manifest.Descriptor { - return fmt.Errorf("verification failure: %s: ", manifest.Digest) - } - - // write out - fmt.Println(manifest.Digest) - return nil -} - -func readSignatrueFile(path string) (string, error) { - bytes, err := ioutil.ReadFile(path) - if err != nil { - return "", err - } - return string(bytes), nil -} - -func getSchemeForVerification(ctx *cli.Context) (*signature.Scheme, error) { - scheme := signature.NewScheme() - - // add x509 verifier - verifier, err := getX509Verifier(ctx) - if err != nil { - return nil, err - } - scheme.RegisterVerifier(verifier) - - return scheme, nil -} - -func getX509Verifier(ctx *cli.Context) (signature.Verifier, error) { - roots := x509.NewCertPool() - - var certs []*x509.Certificate - for _, path := range ctx.StringSlice("cert") { - bundledCerts, err := x509nv2.ReadCertificateFile(path) - if err != nil { - return nil, err - } - certs = append(certs, bundledCerts...) - for _, cert := range bundledCerts { - roots.AddCert(cert) - } - } - for _, path := range ctx.StringSlice("ca-cert") { - bundledCerts, err := x509nv2.ReadCertificateFile(path) - if err != nil { - return nil, err - } - for _, cert := range bundledCerts { - roots.AddCert(cert) - } - } - - return x509nv2.NewVerifier(certs, roots) -} +package main + +import ( + "crypto/x509" + "fmt" + "io/ioutil" + + "github.com/notaryproject/notary/v2/signature" + x509nv2 "github.com/notaryproject/notary/v2/signature/x509" + "github.com/urfave/cli/v2" +) + +var verifyCommand = &cli.Command{ + Name: "verify", + Usage: "verifies OCI Artifacts", + ArgsUsage: "[]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "signature", + Aliases: []string{"s", "f"}, + Usage: "signature file", + Required: true, + TakesFile: true, + }, + &cli.StringSliceFlag{ + Name: "cert", + Aliases: []string{"c"}, + Usage: "certs for verification [x509]", + TakesFile: true, + }, + &cli.StringSliceFlag{ + Name: "ca-cert", + Usage: "CA certs for verification [x509]", + TakesFile: true, + }, + usernameFlag, + passwordFlag, + plainHTTPFlag, + mediaTypeFlag, + }, + Action: runVerify, +} + +func runVerify(ctx *cli.Context) error { + // initialize + scheme, err := getSchemeForVerification(ctx) + if err != nil { + return err + } + sig, err := readSignatrueFile(ctx.String("signature")) + if err != nil { + return err + } + + // core process + claims, err := scheme.Verify(sig) + if err != nil { + return fmt.Errorf("verification failure: %v", err) + } + manifest, err := getManifestFromContext(ctx) + if err != nil { + return err + } + if manifest.Descriptor != claims.Manifest.Descriptor { + return fmt.Errorf("verification failure: %s: ", manifest.Digest) + } + + // write out + fmt.Println(manifest.Digest) + return nil +} + +func readSignatrueFile(path string) (string, error) { + bytes, err := ioutil.ReadFile(path) + if err != nil { + return "", err + } + return string(bytes), nil +} + +func getSchemeForVerification(ctx *cli.Context) (*signature.Scheme, error) { + scheme := signature.NewScheme() + + // add x509 verifier + verifier, err := getX509Verifier(ctx) + if err != nil { + return nil, err + } + scheme.RegisterVerifier(verifier) + + return scheme, nil +} + +func getX509Verifier(ctx *cli.Context) (signature.Verifier, error) { + roots := x509.NewCertPool() + + var certs []*x509.Certificate + for _, path := range ctx.StringSlice("cert") { + bundledCerts, err := x509nv2.ReadCertificateFile(path) + if err != nil { + return nil, err + } + certs = append(certs, bundledCerts...) + for _, cert := range bundledCerts { + roots.AddCert(cert) + } + } + for _, path := range ctx.StringSlice("ca-cert") { + bundledCerts, err := x509nv2.ReadCertificateFile(path) + if err != nil { + return nil, err + } + for _, cert := range bundledCerts { + roots.AddCert(cert) + } + } + + return x509nv2.NewVerifier(certs, roots) +} diff --git a/internal/io/count.go b/internal/io/count.go index 786d7678b..52135dfce 100644 --- a/internal/io/count.go +++ b/internal/io/count.go @@ -1,22 +1,22 @@ -package count - -import ( - "io" -) - -// CountWriter counts the written bytes -type CountWriter struct { - W io.Writer - N int64 -} - -// NewCountWriter generates a new writer -func NewCountWriter(w io.Writer) *CountWriter { - return &CountWriter{W: w} -} - -func (w *CountWriter) Write(p []byte) (n int, err error) { - n, err = w.W.Write(p) - w.N += int64(n) - return -} +package count + +import ( + "io" +) + +// CountWriter counts the written bytes +type CountWriter struct { + W io.Writer + N int64 +} + +// NewCountWriter generates a new writer +func NewCountWriter(w io.Writer) *CountWriter { + return &CountWriter{W: w} +} + +func (w *CountWriter) Write(p []byte) (n int, err error) { + n, err = w.W.Write(p) + w.N += int64(n) + return +} diff --git a/pkg/docker/schema2.go b/pkg/docker/schema2.go index 393e28276..650551862 100644 --- a/pkg/docker/schema2.go +++ b/pkg/docker/schema2.go @@ -1,101 +1,101 @@ -package docker - -import ( - "archive/tar" - "compress/gzip" - "encoding/json" - "errors" - "io" - "strings" - - "github.com/docker/distribution" - "github.com/docker/distribution/manifest/schema2" - iio "github.com/notaryproject/nv2/internal/io" - "github.com/opencontainers/go-digest" -) - -type manifestInTar struct { - Config string - RepoTags []string - Layers []string -} - -// GenerateSchema2FromDockerSave generate a docker schema2 manifest from `docker save` -func GenerateSchema2FromDockerSave(reader io.Reader) (distribution.Manifest, error) { - items, descriptors, err := extractTar(reader) - if err != nil { - return nil, err - } - if len(items) != 1 { - return nil, errors.New("unsupported number of images") - } - item := items[0] - - layers := make([]distribution.Descriptor, 0, len(item.Layers)) - for _, layer := range item.Layers { - layers = append(layers, descriptors[layer]) - } - - manifest := schema2.Manifest{ - Versioned: schema2.SchemaVersion, - Config: descriptors[item.Config], - Layers: layers, - } - return schema2.FromStruct(manifest) -} - -func extractTar(r io.Reader) ([]manifestInTar, map[string]distribution.Descriptor, error) { - var manifests []manifestInTar - descriptors := make(map[string]distribution.Descriptor) - - tr := tar.NewReader(r) - for { - file, err := tr.Next() - if err != nil { - if err == io.EOF { - break - } - return nil, nil, err - } - switch { - case file.Name == "manifest.json": - decoder := json.NewDecoder(tr) - if err := decoder.Decode(&manifests); err != nil { - return nil, nil, err - } - case strings.HasSuffix(file.Name, "/layer.tar"): - desc, err := generateLayerDescriptor(tr) - if err != nil { - return nil, nil, err - } - descriptors[file.Name] = desc - case strings.HasSuffix(file.Name, ".json"): - digest := digest.NewDigestFromEncoded(digest.SHA256, strings.TrimSuffix(file.Name, ".json")) - descriptors[file.Name] = distribution.Descriptor{ - MediaType: schema2.MediaTypeImageConfig, - Size: file.Size, - Digest: digest, - } - } - } - - return manifests, descriptors, nil -} - -func generateLayerDescriptor(r io.Reader) (distribution.Descriptor, error) { - digester := digest.SHA256.Digester() - count := iio.NewCountWriter(digester.Hash()) - w := gzip.NewWriter(count) - _, err := io.Copy(w, r) - if err != nil { - return distribution.Descriptor{}, err - } - if err := w.Close(); err != nil { - return distribution.Descriptor{}, err - } - return distribution.Descriptor{ - MediaType: schema2.MediaTypeLayer, - Size: count.N, - Digest: digester.Digest(), - }, nil -} +package docker + +import ( + "archive/tar" + "compress/gzip" + "encoding/json" + "errors" + "io" + "strings" + + "github.com/docker/distribution" + "github.com/docker/distribution/manifest/schema2" + iio "github.com/notaryproject/nv2/internal/io" + "github.com/opencontainers/go-digest" +) + +type manifestInTar struct { + Config string + RepoTags []string + Layers []string +} + +// GenerateSchema2FromDockerSave generate a docker schema2 manifest from `docker save` +func GenerateSchema2FromDockerSave(reader io.Reader) (distribution.Manifest, error) { + items, descriptors, err := extractTar(reader) + if err != nil { + return nil, err + } + if len(items) != 1 { + return nil, errors.New("unsupported number of images") + } + item := items[0] + + layers := make([]distribution.Descriptor, 0, len(item.Layers)) + for _, layer := range item.Layers { + layers = append(layers, descriptors[layer]) + } + + manifest := schema2.Manifest{ + Versioned: schema2.SchemaVersion, + Config: descriptors[item.Config], + Layers: layers, + } + return schema2.FromStruct(manifest) +} + +func extractTar(r io.Reader) ([]manifestInTar, map[string]distribution.Descriptor, error) { + var manifests []manifestInTar + descriptors := make(map[string]distribution.Descriptor) + + tr := tar.NewReader(r) + for { + file, err := tr.Next() + if err != nil { + if err == io.EOF { + break + } + return nil, nil, err + } + switch { + case file.Name == "manifest.json": + decoder := json.NewDecoder(tr) + if err := decoder.Decode(&manifests); err != nil { + return nil, nil, err + } + case strings.HasSuffix(file.Name, "/layer.tar"): + desc, err := generateLayerDescriptor(tr) + if err != nil { + return nil, nil, err + } + descriptors[file.Name] = desc + case strings.HasSuffix(file.Name, ".json"): + digest := digest.NewDigestFromEncoded(digest.SHA256, strings.TrimSuffix(file.Name, ".json")) + descriptors[file.Name] = distribution.Descriptor{ + MediaType: schema2.MediaTypeImageConfig, + Size: file.Size, + Digest: digest, + } + } + } + + return manifests, descriptors, nil +} + +func generateLayerDescriptor(r io.Reader) (distribution.Descriptor, error) { + digester := digest.SHA256.Digester() + count := iio.NewCountWriter(digester.Hash()) + w := gzip.NewWriter(count) + _, err := io.Copy(w, r) + if err != nil { + return distribution.Descriptor{}, err + } + if err := w.Close(); err != nil { + return distribution.Descriptor{}, err + } + return distribution.Descriptor{ + MediaType: schema2.MediaTypeLayer, + Size: count.N, + Digest: digester.Digest(), + }, nil +} diff --git a/pkg/registry/auth.go b/pkg/registry/auth.go index 8177dac4b..556b9fcab 100644 --- a/pkg/registry/auth.go +++ b/pkg/registry/auth.go @@ -1,112 +1,112 @@ -package registry - -import ( - "encoding/json" - "net/http" - "net/url" - "regexp" - "strings" -) - -var authHeaderRegex = regexp.MustCompile(`(realm|service|scope)="([^"]*)`) - -type authTransport struct { - base http.RoundTripper - username string - password string -} - -// NewAuthtransport creates wraps a round tripper with auth strategies. -// It tries basic auth first and then falls back to token auth. -func NewAuthtransport(base http.RoundTripper, username, password string) http.RoundTripper { - return &authTransport{ - base: base, - username: username, - password: password, - } -} - -func (t *authTransport) RoundTrip(originalReq *http.Request) (*http.Response, error) { - req := originalReq.Clone(originalReq.Context()) - if t.username != "" { - req.SetBasicAuth(t.username, t.password) - } - - resp, err := t.base.RoundTrip(req) - if err != nil { - return nil, err - } - if resp.StatusCode != http.StatusUnauthorized { - return resp, nil - } - - scheme, params := parseAuthHeader(resp.Header.Get("Www-Authenticate")) - if scheme != "bearer" { - return resp, nil - } - resp.Body.Close() - - token, resp, err := t.fetchToken(params) - if err != nil { - if resp != nil { - return resp, nil - } - return nil, err - } - - req = originalReq.Clone(originalReq.Context()) - req.Header.Set("Authorization", "Bearer "+token) - return t.base.RoundTrip(req) -} - -func (t *authTransport) fetchToken(params map[string]string) (string, *http.Response, error) { - req, err := http.NewRequest(http.MethodGet, params["realm"], nil) - if err != nil { - return "", nil, err - } - if t.username != "" { - req.SetBasicAuth(t.username, t.password) - } - - query := url.Values{} - if service, ok := params["service"]; ok { - query.Set("service", service) - } - if scope, ok := params["scope"]; ok { - query.Set("scope", scope) - } - req.URL.RawQuery = query.Encode() - - resp, err := t.base.RoundTrip(req) - if err != nil { - return "", nil, err - } - if resp.StatusCode != http.StatusOK { - return "", resp, nil - } - defer resp.Body.Close() - - var result struct { - AccessToken string `json:"access_token"` - } - if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { - return "", nil, err - } - return result.AccessToken, nil, nil -} - -func parseAuthHeader(header string) (string, map[string]string) { - parts := strings.SplitN(header, " ", 2) - scheme := strings.ToLower(parts[0]) - if len(parts) < 2 { - return scheme, nil - } - - params := make(map[string]string) - result := authHeaderRegex.FindAllStringSubmatch(parts[1], -1) - for _, match := range result { - params[strings.ToLower(match[1])] = match[2] - } - - return scheme, params -} +package registry + +import ( + "encoding/json" + "net/http" + "net/url" + "regexp" + "strings" +) + +var authHeaderRegex = regexp.MustCompile(`(realm|service|scope)="([^"]*)`) + +type authTransport struct { + base http.RoundTripper + username string + password string +} + +// NewAuthtransport creates wraps a round tripper with auth strategies. +// It tries basic auth first and then falls back to token auth. +func NewAuthtransport(base http.RoundTripper, username, password string) http.RoundTripper { + return &authTransport{ + base: base, + username: username, + password: password, + } +} + +func (t *authTransport) RoundTrip(originalReq *http.Request) (*http.Response, error) { + req := originalReq.Clone(originalReq.Context()) + if t.username != "" { + req.SetBasicAuth(t.username, t.password) + } + + resp, err := t.base.RoundTrip(req) + if err != nil { + return nil, err + } + if resp.StatusCode != http.StatusUnauthorized { + return resp, nil + } + + scheme, params := parseAuthHeader(resp.Header.Get("Www-Authenticate")) + if scheme != "bearer" { + return resp, nil + } + resp.Body.Close() + + token, resp, err := t.fetchToken(params) + if err != nil { + if resp != nil { + return resp, nil + } + return nil, err + } + + req = originalReq.Clone(originalReq.Context()) + req.Header.Set("Authorization", "Bearer "+token) + return t.base.RoundTrip(req) +} + +func (t *authTransport) fetchToken(params map[string]string) (string, *http.Response, error) { + req, err := http.NewRequest(http.MethodGet, params["realm"], nil) + if err != nil { + return "", nil, err + } + if t.username != "" { + req.SetBasicAuth(t.username, t.password) + } + + query := url.Values{} + if service, ok := params["service"]; ok { + query.Set("service", service) + } + if scope, ok := params["scope"]; ok { + query.Set("scope", scope) + } + req.URL.RawQuery = query.Encode() + + resp, err := t.base.RoundTrip(req) + if err != nil { + return "", nil, err + } + if resp.StatusCode != http.StatusOK { + return "", resp, nil + } + defer resp.Body.Close() + + var result struct { + AccessToken string `json:"access_token"` + } + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + return "", nil, err + } + return result.AccessToken, nil, nil +} + +func parseAuthHeader(header string) (string, map[string]string) { + parts := strings.SplitN(header, " ", 2) + scheme := strings.ToLower(parts[0]) + if len(parts) < 2 { + return scheme, nil + } + + params := make(map[string]string) + result := authHeaderRegex.FindAllStringSubmatch(parts[1], -1) + for _, match := range result { + params[strings.ToLower(match[1])] = match[2] + } + + return scheme, params +} diff --git a/pkg/registry/client.go b/pkg/registry/client.go index ee369eb3f..dd632ffbf 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -1,32 +1,32 @@ -package registry - -import ( - "net/http" -) - -// Client is a customized registry client -type Client struct { - base http.RoundTripper - plainHTTP bool -} - -// ClientOptions configures the client -type ClientOptions struct { - Username string - Password string - PlainHTTP bool -} - -// NewClient creates a new registry client -func NewClient(base http.RoundTripper, opts *ClientOptions) *Client { - if base == nil { - base = http.DefaultTransport - } - if opts == nil { - opts = &ClientOptions{} - } - return &Client{ - base: NewAuthtransport(base, opts.Username, opts.Password), - plainHTTP: opts.PlainHTTP, - } -} +package registry + +import ( + "net/http" +) + +// Client is a customized registry client +type Client struct { + base http.RoundTripper + plainHTTP bool +} + +// ClientOptions configures the client +type ClientOptions struct { + Username string + Password string + PlainHTTP bool +} + +// NewClient creates a new registry client +func NewClient(base http.RoundTripper, opts *ClientOptions) *Client { + if base == nil { + base = http.DefaultTransport + } + if opts == nil { + opts = &ClientOptions{} + } + return &Client{ + base: NewAuthtransport(base, opts.Username, opts.Password), + plainHTTP: opts.PlainHTTP, + } +} diff --git a/pkg/registry/manifest.go b/pkg/registry/manifest.go index fdb834df5..e2ba14906 100644 --- a/pkg/registry/manifest.go +++ b/pkg/registry/manifest.go @@ -1,120 +1,120 @@ -package registry - -import ( - "fmt" - "net/http" - "net/url" - "strconv" - "strings" - - "github.com/notaryproject/notary/v2/signature" - oci "github.com/opencontainers/image-spec/specs-go/v1" -) - -// GetManifestMetadata returns signature manifest information by URI scheme -func (c *Client) GetManifestMetadata(uri *url.URL) (signature.Manifest, error) { - switch scheme := strings.ToLower(uri.Scheme); scheme { - case "docker": - return c.GetDockerManifestMetadata(uri) - case "oci": - return c.GetOCIManifestMetadata(uri) - default: - return signature.Manifest{}, fmt.Errorf("unsupported scheme: %s", scheme) - } -} - -// GetDockerManifestMetadata returns signature manifest information -// from a remote Docker manifest -func (c *Client) GetDockerManifestMetadata(uri *url.URL) (signature.Manifest, error) { - return c.getManifestMetadata(uri, - MediaTypeManifestList, - MediaTypeManifest, - ) -} - -// GetOCIManifestMetadata returns signature manifest information -// from a remote OCI manifest -func (c *Client) GetOCIManifestMetadata(uri *url.URL) (signature.Manifest, error) { - return c.getManifestMetadata(uri, - oci.MediaTypeImageIndex, - oci.MediaTypeImageManifest, - ) -} - -// GetManifestMetadata returns signature manifest information -func (c *Client) getManifestMetadata(uri *url.URL, mediaTypes ...string) (signature.Manifest, error) { - host := uri.Host - if host == "docker.io" { - host = "registry-1.docker.io" - } - var repository string - var reference string - path := strings.TrimPrefix(uri.Path, "/") - if index := strings.Index(path, "@"); index != -1 { - repository = path[:index] - reference = path[index+1:] - } else if index := strings.Index(path, ":"); index != -1 { - repository = path[:index] - reference = path[index+1:] - } else { - repository = path - reference = "latest" - } - scheme := "https" - if c.plainHTTP { - scheme = "http" - } - url := fmt.Sprintf("%s://%s/v2/%s/manifests/%s", - scheme, - host, - repository, - reference, - ) - req, err := http.NewRequest(http.MethodHead, url, nil) - if err != nil { - return signature.Manifest{}, fmt.Errorf("invalid uri: %v", uri) - } - req.Header.Set("Connection", "close") - for _, mediaType := range mediaTypes { - req.Header.Add("Accept", mediaType) - } - - resp, err := c.base.RoundTrip(req) - if err != nil { - return signature.Manifest{}, fmt.Errorf("%v: %v", url, err) - } - resp.Body.Close() - switch resp.StatusCode { - case http.StatusOK: - // no op - case http.StatusUnauthorized, http.StatusNotFound: - return signature.Manifest{}, fmt.Errorf("%v: %s", uri, resp.Status) - default: - return signature.Manifest{}, fmt.Errorf("%v: %s", url, resp.Status) - } - - header := resp.Header - mediaType := header.Get("Content-Type") - if mediaType == "" { - return signature.Manifest{}, fmt.Errorf("%v: missing Content-Type", url) - } - digest := header.Get("Docker-Content-Digest") - if digest == "" { - return signature.Manifest{}, fmt.Errorf("%v: missing Docker-Content-Digest", url) - } - length := header.Get("Content-Length") - if length == "" { - return signature.Manifest{}, fmt.Errorf("%v: missing Content-Length", url) - } - size, err := strconv.ParseInt(length, 10, 64) - if err != nil { - return signature.Manifest{}, fmt.Errorf("%v: invalid Content-Length", url) - } - return signature.Manifest{ - Descriptor: signature.Descriptor{ - MediaType: mediaType, - Digest: digest, - Size: size, - }, - }, nil -} +package registry + +import ( + "fmt" + "net/http" + "net/url" + "strconv" + "strings" + + "github.com/notaryproject/notary/v2/signature" + oci "github.com/opencontainers/image-spec/specs-go/v1" +) + +// GetManifestMetadata returns signature manifest information by URI scheme +func (c *Client) GetManifestMetadata(uri *url.URL) (signature.Manifest, error) { + switch scheme := strings.ToLower(uri.Scheme); scheme { + case "docker": + return c.GetDockerManifestMetadata(uri) + case "oci": + return c.GetOCIManifestMetadata(uri) + default: + return signature.Manifest{}, fmt.Errorf("unsupported scheme: %s", scheme) + } +} + +// GetDockerManifestMetadata returns signature manifest information +// from a remote Docker manifest +func (c *Client) GetDockerManifestMetadata(uri *url.URL) (signature.Manifest, error) { + return c.getManifestMetadata(uri, + MediaTypeManifestList, + MediaTypeManifest, + ) +} + +// GetOCIManifestMetadata returns signature manifest information +// from a remote OCI manifest +func (c *Client) GetOCIManifestMetadata(uri *url.URL) (signature.Manifest, error) { + return c.getManifestMetadata(uri, + oci.MediaTypeImageIndex, + oci.MediaTypeImageManifest, + ) +} + +// GetManifestMetadata returns signature manifest information +func (c *Client) getManifestMetadata(uri *url.URL, mediaTypes ...string) (signature.Manifest, error) { + host := uri.Host + if host == "docker.io" { + host = "registry-1.docker.io" + } + var repository string + var reference string + path := strings.TrimPrefix(uri.Path, "/") + if index := strings.Index(path, "@"); index != -1 { + repository = path[:index] + reference = path[index+1:] + } else if index := strings.Index(path, ":"); index != -1 { + repository = path[:index] + reference = path[index+1:] + } else { + repository = path + reference = "latest" + } + scheme := "https" + if c.plainHTTP { + scheme = "http" + } + url := fmt.Sprintf("%s://%s/v2/%s/manifests/%s", + scheme, + host, + repository, + reference, + ) + req, err := http.NewRequest(http.MethodHead, url, nil) + if err != nil { + return signature.Manifest{}, fmt.Errorf("invalid uri: %v", uri) + } + req.Header.Set("Connection", "close") + for _, mediaType := range mediaTypes { + req.Header.Add("Accept", mediaType) + } + + resp, err := c.base.RoundTrip(req) + if err != nil { + return signature.Manifest{}, fmt.Errorf("%v: %v", url, err) + } + resp.Body.Close() + switch resp.StatusCode { + case http.StatusOK: + // no op + case http.StatusUnauthorized, http.StatusNotFound: + return signature.Manifest{}, fmt.Errorf("%v: %s", uri, resp.Status) + default: + return signature.Manifest{}, fmt.Errorf("%v: %s", url, resp.Status) + } + + header := resp.Header + mediaType := header.Get("Content-Type") + if mediaType == "" { + return signature.Manifest{}, fmt.Errorf("%v: missing Content-Type", url) + } + digest := header.Get("Docker-Content-Digest") + if digest == "" { + return signature.Manifest{}, fmt.Errorf("%v: missing Docker-Content-Digest", url) + } + length := header.Get("Content-Length") + if length == "" { + return signature.Manifest{}, fmt.Errorf("%v: missing Content-Length", url) + } + size, err := strconv.ParseInt(length, 10, 64) + if err != nil { + return signature.Manifest{}, fmt.Errorf("%v: invalid Content-Length", url) + } + return signature.Manifest{ + Descriptor: signature.Descriptor{ + MediaType: mediaType, + Digest: digest, + Size: size, + }, + }, nil +} diff --git a/pkg/registry/mediatype.go b/pkg/registry/mediatype.go index d6351dcfd..a21335ef6 100644 --- a/pkg/registry/mediatype.go +++ b/pkg/registry/mediatype.go @@ -1,7 +1,7 @@ -package registry - -// docker media types -const ( - MediaTypeManifestList = "application/vnd.docker.distribution.manifest.list.v2+json" - MediaTypeManifest = "application/vnd.docker.distribution.manifest.v2+json" -) +package registry + +// docker media types +const ( + MediaTypeManifestList = "application/vnd.docker.distribution.manifest.list.v2+json" + MediaTypeManifest = "application/vnd.docker.distribution.manifest.v2+json" +) From 41012fbdbb7166de57cfd58a9a2139811dcd3d9b Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Wed, 31 Mar 2021 18:09:15 +0800 Subject: [PATCH 26/69] update dependency Signed-off-by: Shiwei Zhang --- go.mod | 5 ++++- go.sum | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 115b82c49..89d27b976 100644 --- a/go.mod +++ b/go.mod @@ -16,4 +16,7 @@ require ( gotest.tools/v3 v3.0.3 // indirect ) -replace github.com/notaryproject/notary/v2 => github.com/shizhMSFT/notary/v2 v2.0.0-20210331055547-ae76f458b5d2 +replace ( + github.com/notaryproject/notary/v2 => github.com/shizhMSFT/notary/v2 v2.0.0-20210331100429-b6fe3e90e3d0 + github.com/opencontainers/artifacts => github.com/aviral26/artifacts v0.0.0-20210331072334-fac4f3a4da4e +) diff --git a/go.sum b/go.sum index 648393851..b299a5357 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/aviral26/artifacts v0.0.0-20210331072334-fac4f3a4da4e h1:PpLNjTpAp5mTxkuUdM2vCPckrXBPszurJQFvdFUaV1A= +github.com/aviral26/artifacts v0.0.0-20210331072334-fac4f3a4da4e/go.mod h1:IBQOjhxIKxb9G4h9NiWAJLGBgKPlIy27tcpPDTAfUQw= github.com/aws/aws-sdk-go v1.34.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -77,8 +79,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= -github.com/notaryproject/artifacts v0.0.0-20210325201627-49d06c9f1a07 h1:geJlhRFBwSJXhIv7KMgAXBz1Ie6wsuFeE5vuau3B4AQ= -github.com/notaryproject/artifacts v0.0.0-20210325201627-49d06c9f1a07/go.mod h1:za0DINIIQLPCBn9AhLfPjywgT51o0zll644gbIXiQiQ= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= @@ -102,8 +102,8 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shizhMSFT/notary/v2 v2.0.0-20210331055547-ae76f458b5d2 h1:tQCLyuSmS8zdkygWzZiZ+j9fpaa/4gki5fm+vL8TvLE= -github.com/shizhMSFT/notary/v2 v2.0.0-20210331055547-ae76f458b5d2/go.mod h1:M5eWeevjpg7uQi00HNeg8XRPom29qkq9pEp+d4cZg3w= +github.com/shizhMSFT/notary/v2 v2.0.0-20210331100429-b6fe3e90e3d0 h1:kYLJZAnD46wvFuW4N0TJMETM6VDFYSUXZ7De0TQhWVU= +github.com/shizhMSFT/notary/v2 v2.0.0-20210331100429-b6fe3e90e3d0/go.mod h1:isC0iSkBJFffROJ/A2gYQPL0c0SWEzrdCWWFo4i/1F0= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= From 62e2eee0dccdebb003ec31a902813769d13398a6 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Thu, 1 Apr 2021 19:14:52 +0800 Subject: [PATCH 27/69] push signature support Signed-off-by: Shiwei Zhang --- cmd/nv2/main.go | 3 +- cmd/nv2/manifest.go | 37 ++++++++++++---------- cmd/nv2/push.go | 65 ++++++++++++++++++++++++++++++++++++++ cmd/nv2/registry.go | 31 ++++++++++++++++++ cmd/nv2/verify.go | 6 ++-- pkg/registry/auth.go | 3 ++ pkg/registry/client.go | 16 ++-------- pkg/registry/descriptor.go | 15 +++++++++ pkg/registry/manifest.go | 24 +++----------- pkg/registry/reference.go | 56 ++++++++++++++++++++++++++++++++ 10 files changed, 202 insertions(+), 54 deletions(-) create mode 100644 cmd/nv2/push.go create mode 100644 cmd/nv2/registry.go create mode 100644 pkg/registry/descriptor.go create mode 100644 pkg/registry/reference.go diff --git a/cmd/nv2/main.go b/cmd/nv2/main.go index 61d21d716..6dbe13e85 100644 --- a/cmd/nv2/main.go +++ b/cmd/nv2/main.go @@ -11,7 +11,7 @@ func main() { app := &cli.App{ Name: "nv2", Usage: "Notary V2 - Prototype", - Version: "0.2.1", + Version: "0.4.0", Authors: []*cli.Author{ { Name: "Shiwei Zhang", @@ -21,6 +21,7 @@ func main() { Commands: []*cli.Command{ signCommand, verifyCommand, + pushCommand, }, } if err := app.Run(os.Args); err != nil { diff --git a/cmd/nv2/manifest.go b/cmd/nv2/manifest.go index 3615490e7..6b5e2ac53 100644 --- a/cmd/nv2/manifest.go +++ b/cmd/nv2/manifest.go @@ -16,7 +16,11 @@ import ( func getManifestFromContext(ctx *cli.Context) (signature.Manifest, error) { if uri := ctx.Args().First(); uri != "" { - return getManfestsFromURI(ctx, uri) + parsed, err := url.Parse(uri) + if err != nil { + return signature.Manifest{}, err + } + return getManfestsFromURI(ctx, parsed) } return getManifestFromReader(os.Stdin, ctx.String(mediaTypeFlag.Name)) } @@ -39,17 +43,13 @@ func getManifestFromReader(r io.Reader, mediaType string) (signature.Manifest, e }, nil } -func getManfestsFromURI(ctx *cli.Context, uri string) (signature.Manifest, error) { - parsed, err := url.Parse(uri) - if err != nil { - return signature.Manifest{}, err - } +func getManfestsFromURI(ctx *cli.Context, uri *url.URL) (signature.Manifest, error) { var r io.Reader - switch strings.ToLower(parsed.Scheme) { + switch strings.ToLower(uri.Scheme) { case "file": - path := parsed.Path - if parsed.Opaque != "" { - path = parsed.Opaque + path := uri.Path + if uri.Opaque != "" { + path = uri.Opaque } file, err := os.Open(path) if err != nil { @@ -58,14 +58,17 @@ func getManfestsFromURI(ctx *cli.Context, uri string) (signature.Manifest, error defer file.Close() r = file case "docker", "oci": - remote := registry.NewClient(nil, ®istry.ClientOptions{ - Username: ctx.String(usernameFlag.Name), - Password: ctx.String(passwordFlag.Name), - PlainHTTP: ctx.Bool(plainHTTPFlag.Name), - }) - return remote.GetManifestMetadata(parsed) + remote := registry.NewClient( + registry.NewAuthtransport( + nil, + ctx.String(usernameFlag.Name), + ctx.String(passwordFlag.Name), + ), + ctx.Bool(plainHTTPFlag.Name), + ) + return remote.GetManifestMetadata(uri) default: - return signature.Manifest{}, fmt.Errorf("unsupported URI scheme: %s", parsed.Scheme) + return signature.Manifest{}, fmt.Errorf("unsupported URI scheme: %s", uri.Scheme) } return getManifestFromReader(r, ctx.String(mediaTypeFlag.Name)) } diff --git a/cmd/nv2/push.go b/cmd/nv2/push.go new file mode 100644 index 000000000..93d39c201 --- /dev/null +++ b/cmd/nv2/push.go @@ -0,0 +1,65 @@ +package main + +import ( + "fmt" + "net/url" + "os" + + "github.com/notaryproject/nv2/pkg/registry" + "github.com/urfave/cli/v2" +) + +var pushCommand = &cli.Command{ + Name: "push", + Usage: "push signature to remote", + ArgsUsage: "", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "signature", + Aliases: []string{"s", "f"}, + Usage: "signature file", + Required: true, + TakesFile: true, + }, + usernameFlag, + passwordFlag, + plainHTTPFlag, + }, + Action: runPush, +} + +func runPush(ctx *cli.Context) error { + // initialize + uri, err := url.Parse(ctx.Args().First()) + if err != nil { + return err + } + sig, err := os.ReadFile(ctx.String("signature")) + if err != nil { + return err + } + sigRepo, err := getSignatureRepositoryFromURI(ctx, uri) + if err != nil { + return err + } + manifest, err := getManfestsFromURI(ctx, uri) + if err != nil { + return err + } + manifestDesc := registry.OCIDescriptorFromNotary(manifest.Descriptor) + + // core process + sigDesc, err := sigRepo.Put(ctx.Context, sig) + if err != nil { + return fmt.Errorf("push signature failure: %v", err) + } + + desc, err := sigRepo.Link(ctx.Context, manifestDesc, sigDesc) + if err != nil { + return fmt.Errorf("link signature failure: %v", err) + } + + // write out + fmt.Println(desc.Digest) + return nil +} diff --git a/cmd/nv2/registry.go b/cmd/nv2/registry.go new file mode 100644 index 000000000..bb643a63b --- /dev/null +++ b/cmd/nv2/registry.go @@ -0,0 +1,31 @@ +package main + +import ( + "fmt" + "net/url" + "strings" + + "github.com/notaryproject/notary/v2" + notaryregistry "github.com/notaryproject/notary/v2/registry" + "github.com/notaryproject/nv2/pkg/registry" + "github.com/urfave/cli/v2" +) + +func getSignatureRepositoryFromURI(ctx *cli.Context, uri *url.URL) (notary.SignatureRepository, error) { + switch strings.ToLower(uri.Scheme) { + case "docker", "oci": + ref := registry.ParseReferenceFromURL(uri) + remote := notaryregistry.NewClient( + registry.NewAuthtransport( + nil, + ctx.String(usernameFlag.Name), + ctx.String(passwordFlag.Name), + ), + ref.Registry, + ctx.Bool(plainHTTPFlag.Name), + ) + return remote.Repository(ctx.Context, ref.Repository), nil + default: + return nil, fmt.Errorf("unsupported URI scheme: %s", uri.Scheme) + } +} diff --git a/cmd/nv2/verify.go b/cmd/nv2/verify.go index 37a145c92..7f67dac25 100644 --- a/cmd/nv2/verify.go +++ b/cmd/nv2/verify.go @@ -3,7 +3,7 @@ package main import ( "crypto/x509" "fmt" - "io/ioutil" + "os" "github.com/notaryproject/notary/v2/signature" x509nv2 "github.com/notaryproject/notary/v2/signature/x509" @@ -62,7 +62,7 @@ func runVerify(ctx *cli.Context) error { return err } if manifest.Descriptor != claims.Manifest.Descriptor { - return fmt.Errorf("verification failure: %s: ", manifest.Digest) + return fmt.Errorf("verification failure: %s", manifest.Digest) } // write out @@ -71,7 +71,7 @@ func runVerify(ctx *cli.Context) error { } func readSignatrueFile(path string) (string, error) { - bytes, err := ioutil.ReadFile(path) + bytes, err := os.ReadFile(path) if err != nil { return "", err } diff --git a/pkg/registry/auth.go b/pkg/registry/auth.go index 556b9fcab..43b44004d 100644 --- a/pkg/registry/auth.go +++ b/pkg/registry/auth.go @@ -19,6 +19,9 @@ type authTransport struct { // NewAuthtransport creates wraps a round tripper with auth strategies. // It tries basic auth first and then falls back to token auth. func NewAuthtransport(base http.RoundTripper, username, password string) http.RoundTripper { + if base == nil { + base = http.DefaultTransport + } return &authTransport{ base: base, username: username, diff --git a/pkg/registry/client.go b/pkg/registry/client.go index dd632ffbf..5d5b3963e 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -10,23 +10,13 @@ type Client struct { plainHTTP bool } -// ClientOptions configures the client -type ClientOptions struct { - Username string - Password string - PlainHTTP bool -} - // NewClient creates a new registry client -func NewClient(base http.RoundTripper, opts *ClientOptions) *Client { +func NewClient(base http.RoundTripper, plainHTTP bool) *Client { if base == nil { base = http.DefaultTransport } - if opts == nil { - opts = &ClientOptions{} - } return &Client{ - base: NewAuthtransport(base, opts.Username, opts.Password), - plainHTTP: opts.PlainHTTP, + base: base, + plainHTTP: plainHTTP, } } diff --git a/pkg/registry/descriptor.go b/pkg/registry/descriptor.go new file mode 100644 index 000000000..71fd414e3 --- /dev/null +++ b/pkg/registry/descriptor.go @@ -0,0 +1,15 @@ +package registry + +import ( + "github.com/notaryproject/notary/v2/signature" + digest "github.com/opencontainers/go-digest" + oci "github.com/opencontainers/image-spec/specs-go/v1" +) + +func OCIDescriptorFromNotary(desc signature.Descriptor) oci.Descriptor { + return oci.Descriptor{ + MediaType: desc.MediaType, + Digest: digest.Digest(desc.Digest), + Size: desc.Size, + } +} diff --git a/pkg/registry/manifest.go b/pkg/registry/manifest.go index e2ba14906..2bd1d3b3d 100644 --- a/pkg/registry/manifest.go +++ b/pkg/registry/manifest.go @@ -43,32 +43,16 @@ func (c *Client) GetOCIManifestMetadata(uri *url.URL) (signature.Manifest, error // GetManifestMetadata returns signature manifest information func (c *Client) getManifestMetadata(uri *url.URL, mediaTypes ...string) (signature.Manifest, error) { - host := uri.Host - if host == "docker.io" { - host = "registry-1.docker.io" - } - var repository string - var reference string - path := strings.TrimPrefix(uri.Path, "/") - if index := strings.Index(path, "@"); index != -1 { - repository = path[:index] - reference = path[index+1:] - } else if index := strings.Index(path, ":"); index != -1 { - repository = path[:index] - reference = path[index+1:] - } else { - repository = path - reference = "latest" - } + ref := ParseReferenceFromURL(uri) scheme := "https" if c.plainHTTP { scheme = "http" } url := fmt.Sprintf("%s://%s/v2/%s/manifests/%s", scheme, - host, - repository, - reference, + ref.Host(), + ref.Repository, + ref.ReferenceOrDefault(), ) req, err := http.NewRequest(http.MethodHead, url, nil) if err != nil { diff --git a/pkg/registry/reference.go b/pkg/registry/reference.go new file mode 100644 index 000000000..9bea890e3 --- /dev/null +++ b/pkg/registry/reference.go @@ -0,0 +1,56 @@ +package registry + +import ( + "net/url" + "strings" +) + +// Reference references to a descriptor in the registry +type Reference struct { + // Registry is the name of the registry. + // It is usually the domain name of the registry. + Registry string + + // Repository is the name of the repository + Repository string + + // Reference is the reference of the object in the repository. + // A reference can be a tag and / or a digest. + Reference string +} + +func ParseReferenceFromURL(uri *url.URL) Reference { + var repository string + var reference string + path := strings.TrimPrefix(uri.Path, "/") + if index := strings.Index(path, "@"); index != -1 { + repository = path[:index] + reference = path[index+1:] + } else if index := strings.Index(path, ":"); index != -1 { + repository = path[:index] + reference = path[index+1:] + } else { + repository = path + } + return Reference{ + Registry: uri.Host, + Repository: repository, + Reference: reference, + } +} + +// Host returns the host name of the registry +func (r Reference) Host() string { + if r.Registry == "docker.io" { + return "registry-1.docker.io" + } + return r.Registry +} + +// ReferenceOrDefault returns the reference or the default reference if empty. +func (r Reference) ReferenceOrDefault() string { + if r.Reference == "" { + return "latest" + } + return r.Reference +} From 20e35b6ce1a840d346199ce9a484589ea726d764 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Thu, 1 Apr 2021 20:28:49 +0800 Subject: [PATCH 28/69] pull signature support Signed-off-by: Shiwei Zhang --- .gitignore | 3 +- cmd/nv2/common.go | 7 +++ cmd/nv2/main.go | 1 + cmd/nv2/pull.go | 108 ++++++++++++++++++++++++++++++++++++++ cmd/nv2/push.go | 4 ++ cmd/nv2/sign.go | 10 ++-- go.mod | 1 + pkg/registry/manifest.go | 2 + pkg/registry/reference.go | 9 +++- 9 files changed, 136 insertions(+), 9 deletions(-) create mode 100644 cmd/nv2/pull.go diff --git a/.gitignore b/.gitignore index a6dfa2f56..db20121cb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ .vscode # Custom -bin/ \ No newline at end of file +bin/ +vendor/ diff --git a/cmd/nv2/common.go b/cmd/nv2/common.go index 6a5628cbc..42d8a1ec4 100644 --- a/cmd/nv2/common.go +++ b/cmd/nv2/common.go @@ -7,11 +7,13 @@ var ( Name: "username", Aliases: []string{"u"}, Usage: "username for generic remote access", + EnvVars: []string{"NV2_USERNAME"}, } passwordFlag = &cli.StringFlag{ Name: "password", Aliases: []string{"p"}, Usage: "password for generic remote access", + EnvVars: []string{"NV2_PASSWORD"}, } plainHTTPFlag = &cli.BoolFlag{ Name: "plain-http", @@ -22,4 +24,9 @@ var ( Usage: "specify the media type of the manifest read from file or stdin", Value: "application/vnd.docker.distribution.manifest.v2+json", } + outputFlag = &cli.StringFlag{ + Name: "output", + Aliases: []string{"o"}, + Usage: "write signature to a specific path", + } ) diff --git a/cmd/nv2/main.go b/cmd/nv2/main.go index 6dbe13e85..2f4a7b4af 100644 --- a/cmd/nv2/main.go +++ b/cmd/nv2/main.go @@ -22,6 +22,7 @@ func main() { signCommand, verifyCommand, pushCommand, + pullCommand, }, } if err := app.Run(os.Args); err != nil { diff --git a/cmd/nv2/pull.go b/cmd/nv2/pull.go new file mode 100644 index 000000000..6583739de --- /dev/null +++ b/cmd/nv2/pull.go @@ -0,0 +1,108 @@ +package main + +import ( + "errors" + "fmt" + "net/url" + "path/filepath" + + "github.com/notaryproject/nv2/internal/os" + "github.com/notaryproject/nv2/pkg/registry" + "github.com/urfave/cli/v2" +) + +var pullCommand = &cli.Command{ + Name: "pull", + Usage: "pull signatures from remote", + ArgsUsage: "", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "peek", + Usage: "view signatures without pulling", + }, + &cli.BoolFlag{ + Name: "strict", + Usage: "struct pull without lookup", + }, + outputFlag, + usernameFlag, + passwordFlag, + plainHTTPFlag, + }, + Action: runPull, +} + +func runPull(ctx *cli.Context) error { + // initialize + if !ctx.Args().Present() { + return errors.New("no reference specified") + } + + uri, err := url.Parse(ctx.Args().First()) + if err != nil { + return err + } + sigRepo, err := getSignatureRepositoryFromURI(ctx, uri) + if err != nil { + return err + } + + // core process + if ctx.Bool("strict") { + sigDigest, err := registry.ParseReferenceFromURL(uri).Digest() + if err != nil { + return fmt.Errorf("invalid signature digest: %v", err) + } + + if !ctx.Bool("peek") { + sig, err := sigRepo.Get(ctx.Context, sigDigest) + if err != nil { + return fmt.Errorf("get signature failure: %v: %v", sigDigest, err) + } + outputPath := ctx.String(outputFlag.Name) + if outputPath == "" { + outputPath = sigDigest.Encoded() + ".jwt" + } + if err := os.WriteFile(outputPath, sig); err != nil { + return fmt.Errorf("fail to write signature: %v: %v", sigDigest, err) + } + } + + // write out + fmt.Println(sigDigest) + return nil + } + + manifest, err := getManfestsFromURI(ctx, uri) + if err != nil { + return err + } + manifestDesc := registry.OCIDescriptorFromNotary(manifest.Descriptor) + + sigDigests, err := sigRepo.Lookup(ctx.Context, manifestDesc.Digest) + if err != nil { + return fmt.Errorf("lookup signature failure: %v", err) + } + + path := ctx.String(outputFlag.Name) + if path == "" { + path = manifestDesc.Digest.Encoded() + } + for _, sigDigest := range sigDigests { + if !ctx.Bool("peek") { + sig, err := sigRepo.Get(ctx.Context, sigDigest) + if err != nil { + return fmt.Errorf("get signature failure: %v: %v", sigDigest, err) + } + outputPath := filepath.Join(path, sigDigest.Encoded()+".jwt") + if err := os.WriteFile(outputPath, sig); err != nil { + return fmt.Errorf("fail to write signature: %v: %v", sigDigest, err) + } + } + + // write out + fmt.Println(sigDigest) + } + + return nil +} diff --git a/cmd/nv2/push.go b/cmd/nv2/push.go index 93d39c201..6803c57c4 100644 --- a/cmd/nv2/push.go +++ b/cmd/nv2/push.go @@ -1,6 +1,7 @@ package main import ( + "errors" "fmt" "net/url" "os" @@ -30,6 +31,9 @@ var pushCommand = &cli.Command{ func runPush(ctx *cli.Context) error { // initialize + if !ctx.Args().Present() { + return errors.New("no reference specified") + } uri, err := url.Parse(ctx.Args().First()) if err != nil { return err diff --git a/cmd/nv2/sign.go b/cmd/nv2/sign.go index f18f84b6e..ae0c2df66 100644 --- a/cmd/nv2/sign.go +++ b/cmd/nv2/sign.go @@ -46,11 +46,7 @@ var signCommand = &cli.Command{ Aliases: []string{"r"}, Usage: "original references", }, - &cli.StringFlag{ - Name: "output", - Aliases: []string{"o"}, - Usage: "write signature to a specific path", - }, + outputFlag, usernameFlag, passwordFlag, plainHTTPFlag, @@ -77,9 +73,9 @@ func runSign(ctx *cli.Context) error { } // write out - path := ctx.String("output") + path := ctx.String(outputFlag.Name) if path == "" { - path = strings.Split(claims.Manifest.Digest, ":")[1] + ".nv2" + path = strings.Split(claims.Manifest.Digest, ":")[1] + ".jwt" } if err := ioutil.WriteFile(path, []byte(sig), 0666); err != nil { return err diff --git a/go.mod b/go.mod index 89d27b976..eaa1145bb 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/docker/docker-credential-helpers v0.6.3 // indirect github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 github.com/notaryproject/notary/v2 v2.0.0-00010101000000-000000000000 + github.com/opencontainers/artifacts v0.0.0-20210209205009-a282023000bd github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.1 github.com/urfave/cli/v2 v2.3.0 diff --git a/pkg/registry/manifest.go b/pkg/registry/manifest.go index 2bd1d3b3d..d52552eac 100644 --- a/pkg/registry/manifest.go +++ b/pkg/registry/manifest.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/notaryproject/notary/v2/signature" + artifactspec "github.com/opencontainers/artifacts/specs-go/v2" oci "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -38,6 +39,7 @@ func (c *Client) GetOCIManifestMetadata(uri *url.URL) (signature.Manifest, error return c.getManifestMetadata(uri, oci.MediaTypeImageIndex, oci.MediaTypeImageManifest, + artifactspec.MediaTypeArtifactManifest, ) } diff --git a/pkg/registry/reference.go b/pkg/registry/reference.go index 9bea890e3..65f57e942 100644 --- a/pkg/registry/reference.go +++ b/pkg/registry/reference.go @@ -3,6 +3,8 @@ package registry import ( "net/url" "strings" + + "github.com/opencontainers/go-digest" ) // Reference references to a descriptor in the registry @@ -47,10 +49,15 @@ func (r Reference) Host() string { return r.Registry } -// ReferenceOrDefault returns the reference or the default reference if empty. +// ReferenceOrDefault returns the reference or the default reference if empty func (r Reference) ReferenceOrDefault() string { if r.Reference == "" { return "latest" } return r.Reference } + +// Digest returns the reference as a digest +func (r Reference) Digest() (digest.Digest, error) { + return digest.Parse(r.Reference) +} From e7592477e00f01b9bd5496dd6ba882c47ab77690 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Thu, 1 Apr 2021 21:01:28 +0800 Subject: [PATCH 29/69] integrate sign and push Signed-off-by: Shiwei Zhang --- cmd/nv2/push.go | 36 +++++++++++++++++++++++++----------- cmd/nv2/sign.go | 26 ++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/cmd/nv2/push.go b/cmd/nv2/push.go index 6803c57c4..5eefd7270 100644 --- a/cmd/nv2/push.go +++ b/cmd/nv2/push.go @@ -7,6 +7,7 @@ import ( "os" "github.com/notaryproject/nv2/pkg/registry" + oci "github.com/opencontainers/image-spec/specs-go/v1" "github.com/urfave/cli/v2" ) @@ -34,36 +35,49 @@ func runPush(ctx *cli.Context) error { if !ctx.Args().Present() { return errors.New("no reference specified") } - uri, err := url.Parse(ctx.Args().First()) + uri := ctx.Args().First() + sig, err := os.ReadFile(ctx.String("signature")) if err != nil { return err } - sig, err := os.ReadFile(ctx.String("signature")) + + // core process + desc, err := pushSignature(ctx, uri, sig) if err != nil { return err } - sigRepo, err := getSignatureRepositoryFromURI(ctx, uri) + + // write out + fmt.Println(desc.Digest) + return nil +} + +func pushSignature(ctx *cli.Context, uri string, sig []byte) (oci.Descriptor, error) { + // initialize + parsedURI, err := url.Parse(uri) + if err != nil { + return oci.Descriptor{}, err + } + sigRepo, err := getSignatureRepositoryFromURI(ctx, parsedURI) if err != nil { - return err + return oci.Descriptor{}, err } - manifest, err := getManfestsFromURI(ctx, uri) + manifest, err := getManfestsFromURI(ctx, parsedURI) if err != nil { - return err + return oci.Descriptor{}, err } manifestDesc := registry.OCIDescriptorFromNotary(manifest.Descriptor) // core process sigDesc, err := sigRepo.Put(ctx.Context, sig) if err != nil { - return fmt.Errorf("push signature failure: %v", err) + return oci.Descriptor{}, fmt.Errorf("push signature failure: %v", err) } desc, err := sigRepo.Link(ctx.Context, manifestDesc, sigDesc) if err != nil { - return fmt.Errorf("link signature failure: %v", err) + return oci.Descriptor{}, fmt.Errorf("link signature failure: %v", err) } - // write out - fmt.Println(desc.Digest) - return nil + return desc, nil } diff --git a/cmd/nv2/sign.go b/cmd/nv2/sign.go index ae0c2df66..e747cc43d 100644 --- a/cmd/nv2/sign.go +++ b/cmd/nv2/sign.go @@ -2,12 +2,12 @@ package main import ( "fmt" - "io/ioutil" "strings" "time" "github.com/notaryproject/notary/v2/signature" "github.com/notaryproject/notary/v2/signature/x509" + "github.com/notaryproject/nv2/internal/os" "github.com/urfave/cli/v2" ) @@ -47,6 +47,14 @@ var signCommand = &cli.Command{ Usage: "original references", }, outputFlag, + &cli.BoolFlag{ + Name: "push", + Usage: "push after successful signing", + }, + &cli.StringFlag{ + Name: "push-reference", + Usage: "different remote to store signature", + }, usernameFlag, passwordFlag, plainHTTPFlag, @@ -77,10 +85,24 @@ func runSign(ctx *cli.Context) error { if path == "" { path = strings.Split(claims.Manifest.Digest, ":")[1] + ".jwt" } - if err := ioutil.WriteFile(path, []byte(sig), 0666); err != nil { + if err := os.WriteFile(path, []byte(sig)); err != nil { return err } + if ctx.Bool("push") { + uri := ctx.String("push-reference") + if uri == "" { + uri = ctx.Args().First() + } + if _, err := pushSignature(ctx, uri, []byte(sig)); err != nil { + return fmt.Errorf("fail to push signature to %q: %v: %v", + uri, + claims.Manifest.Digest, + err, + ) + } + } + fmt.Println(claims.Manifest.Digest) return nil } From 7d70eee1c24c2998c6833ba07d4ab88020118070 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Fri, 2 Apr 2021 16:22:20 +0800 Subject: [PATCH 30/69] no output on sign-then-push by default Signed-off-by: Shiwei Zhang --- cmd/nv2/sign.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cmd/nv2/sign.go b/cmd/nv2/sign.go index e747cc43d..da4c9db70 100644 --- a/cmd/nv2/sign.go +++ b/cmd/nv2/sign.go @@ -82,11 +82,13 @@ func runSign(ctx *cli.Context) error { // write out path := ctx.String(outputFlag.Name) - if path == "" { - path = strings.Split(claims.Manifest.Digest, ":")[1] + ".jwt" - } - if err := os.WriteFile(path, []byte(sig)); err != nil { - return err + if path != "" || !ctx.Bool("push") { + if path == "" { + path = strings.Split(claims.Manifest.Digest, ":")[1] + ".jwt" + } + if err := os.WriteFile(path, []byte(sig)); err != nil { + return err + } } if ctx.Bool("push") { From f7da7a7737f8589df52f55df36826f47f55619b7 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Tue, 6 Apr 2021 15:04:31 +0800 Subject: [PATCH 31/69] better ux for signature info Signed-off-by: Shiwei Zhang --- cmd/docker-nv2/push.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/docker-nv2/push.go b/cmd/docker-nv2/push.go index 3d9e13ff7..ddbdd84e7 100644 --- a/cmd/docker-nv2/push.go +++ b/cmd/docker-nv2/push.go @@ -54,13 +54,12 @@ func pushImage(ctx *cli.Context) error { if err != nil { return err } - fmt.Println("signature:", "digest:", sigDesc.Digest, "size:", sigDesc.Size) artifactDesc, err := client.Link(ctx.Context, desc, sigDesc) if err != nil { return err } - fmt.Println("link:", "digest:", artifactDesc.Digest, "size:", artifactDesc.Size) + fmt.Println("signature manifest digest:", artifactDesc.Digest, "size:", artifactDesc.Size) return nil } From a1071bc423d56cff3365901beb2977d7318e38b6 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Thu, 8 Apr 2021 17:19:45 +0800 Subject: [PATCH 32/69] make install better Signed-off-by: Shiwei Zhang --- Makefile | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index fd6130dab..b22e5aed7 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,10 @@ endef .PHONY: all all: build -bin/%: cmd/% +.PHONY: FORCE +FORCE: + +bin/%: cmd/% FORCE $(BUILD_BINARY) .PHONY: build @@ -31,6 +34,16 @@ fix-encoding: vendor: GO111MODULE=on go mod vendor +.PHONY: install +install: install-nv2 install-docker-plugins + +.PHONY: install-nv2 +install-nv2: bin/nv2 + cp $< ~/bin/ + +.PHONY: install-docker-% +install-docker-%: bin/docker-% + cp $< ~/.docker/cli-plugins/ + .PHONY: install-docker-plugins -install-docker-plugins: $(addprefix bin/,$(DOCKER_PLUGINS)) - cp $(addprefix bin/,$(DOCKER_PLUGINS)) ~/.docker/cli-plugins/ +install-docker-plugins: $(addprefix install-,$(DOCKER_PLUGINS)) From b72e867e28a44f8f8801cd4ff2cba01893d9deaf Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Thu, 8 Apr 2021 17:21:43 +0800 Subject: [PATCH 33/69] update notary library Signed-off-by: Shiwei Zhang --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index eaa1145bb..6572da856 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,6 @@ require ( ) replace ( - github.com/notaryproject/notary/v2 => github.com/shizhMSFT/notary/v2 v2.0.0-20210331100429-b6fe3e90e3d0 + github.com/notaryproject/notary/v2 => github.com/shizhMSFT/notary/v2 v2.0.0-20210408090825-ba2c890acb93 github.com/opencontainers/artifacts => github.com/aviral26/artifacts v0.0.0-20210331072334-fac4f3a4da4e ) diff --git a/go.sum b/go.sum index b299a5357..533fdf37a 100644 --- a/go.sum +++ b/go.sum @@ -102,8 +102,8 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shizhMSFT/notary/v2 v2.0.0-20210331100429-b6fe3e90e3d0 h1:kYLJZAnD46wvFuW4N0TJMETM6VDFYSUXZ7De0TQhWVU= -github.com/shizhMSFT/notary/v2 v2.0.0-20210331100429-b6fe3e90e3d0/go.mod h1:isC0iSkBJFffROJ/A2gYQPL0c0SWEzrdCWWFo4i/1F0= +github.com/shizhMSFT/notary/v2 v2.0.0-20210408090825-ba2c890acb93 h1:b1i9Yi8xUKEDGJovM99oG7uRDmhyw9HUCBf7XHZabEg= +github.com/shizhMSFT/notary/v2 v2.0.0-20210408090825-ba2c890acb93/go.mod h1:isC0iSkBJFffROJ/A2gYQPL0c0SWEzrdCWWFo4i/1F0= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= From e9282194e2c81188efa112625082d58dcd5113be Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Wed, 14 Apr 2021 11:27:00 +0800 Subject: [PATCH 34/69] update dependencies Signed-off-by: Shiwei Zhang --- go.mod | 7 ++----- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 6572da856..3f5b12d17 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/docker/docker v20.10.5+incompatible // indirect github.com/docker/docker-credential-helpers v0.6.3 // indirect github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 - github.com/notaryproject/notary/v2 v2.0.0-00010101000000-000000000000 + github.com/notaryproject/notary/v2 v2.0.0-20210414032403-d1367cc13db7 github.com/opencontainers/artifacts v0.0.0-20210209205009-a282023000bd github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.1 @@ -17,7 +17,4 @@ require ( gotest.tools/v3 v3.0.3 // indirect ) -replace ( - github.com/notaryproject/notary/v2 => github.com/shizhMSFT/notary/v2 v2.0.0-20210408090825-ba2c890acb93 - github.com/opencontainers/artifacts => github.com/aviral26/artifacts v0.0.0-20210331072334-fac4f3a4da4e -) +replace github.com/opencontainers/artifacts => github.com/notaryproject/artifacts v0.0.0-20210414030140-c7c701eff45d diff --git a/go.sum b/go.sum index 533fdf37a..4b20c2b7e 100644 --- a/go.sum +++ b/go.sum @@ -5,8 +5,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/aviral26/artifacts v0.0.0-20210331072334-fac4f3a4da4e h1:PpLNjTpAp5mTxkuUdM2vCPckrXBPszurJQFvdFUaV1A= -github.com/aviral26/artifacts v0.0.0-20210331072334-fac4f3a4da4e/go.mod h1:IBQOjhxIKxb9G4h9NiWAJLGBgKPlIy27tcpPDTAfUQw= github.com/aws/aws-sdk-go v1.34.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -79,6 +77,10 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/notaryproject/artifacts v0.0.0-20210414030140-c7c701eff45d h1:GtjfjCO9nJX0zBaJ5bRtGjEFKflmdtYcn7sr7hgllHE= +github.com/notaryproject/artifacts v0.0.0-20210414030140-c7c701eff45d/go.mod h1:IBQOjhxIKxb9G4h9NiWAJLGBgKPlIy27tcpPDTAfUQw= +github.com/notaryproject/notary/v2 v2.0.0-20210414032403-d1367cc13db7 h1:4MWG4IZ4wMBfLs9BD1v7LpeGu+0uQTFwdQjtzZMsmgY= +github.com/notaryproject/notary/v2 v2.0.0-20210414032403-d1367cc13db7/go.mod h1:ZBxNIEYm11y1i6dTk4toLEcHhhNh4GOJjys/KIyWq7Q= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= @@ -102,8 +104,6 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shizhMSFT/notary/v2 v2.0.0-20210408090825-ba2c890acb93 h1:b1i9Yi8xUKEDGJovM99oG7uRDmhyw9HUCBf7XHZabEg= -github.com/shizhMSFT/notary/v2 v2.0.0-20210408090825-ba2c890acb93/go.mod h1:isC0iSkBJFffROJ/A2gYQPL0c0SWEzrdCWWFo4i/1F0= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= From ffe6cdc00785b7791ed605626d4a69736e9cce94 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Thu, 15 Apr 2021 10:52:31 +0800 Subject: [PATCH 35/69] Multiple signatures support (#52) Signed-off-by: Shiwei Zhang --- cmd/docker-nv2/config/path.go | 59 +++++++++++++++++++++++++++++++++-- cmd/docker-nv2/notary_sign.go | 3 +- cmd/docker-nv2/push.go | 40 +++++++++++++++--------- 3 files changed, 84 insertions(+), 18 deletions(-) diff --git a/cmd/docker-nv2/config/path.go b/cmd/docker-nv2/config/path.go index f94a16ce4..92a67a491 100644 --- a/cmd/docker-nv2/config/path.go +++ b/cmd/docker-nv2/config/path.go @@ -1,7 +1,9 @@ package config import ( + "os" "path/filepath" + "strings" "github.com/docker/cli/cli/config" "github.com/opencontainers/go-digest" @@ -25,11 +27,62 @@ var ( SignatureStoreDirPath = filepath.Join(config.Dir(), SignatureStoreDirName) ) -// SignaturePath returns the path of a signature for a manifest -func SignaturePath(manifestDigest digest.Digest) string { +// SignatureRootPath returns the root path of signatures for a manifest +func SignatureRootPath(manifestDigest digest.Digest) string { return filepath.Join( SignatureStoreDirPath, manifestDigest.Algorithm().String(), - manifestDigest.Encoded()+SignatureExtension, + manifestDigest.Encoded(), + ) +} + +// SignaturePath returns the path of a signature for a manifest +func SignaturePath(manifestDigest, signatureDigest digest.Digest) string { + return filepath.Join( + SignatureRootPath(manifestDigest), + signatureDigest.Algorithm().String(), + signatureDigest.Encoded()+SignatureExtension, ) } + +// SignatureDigests returns the digest of signatures for a manifest +func SignatureDigests(manifestDigest digest.Digest) ([]digest.Digest, error) { + rootPath := SignatureRootPath(manifestDigest) + algorithmEntries, err := os.ReadDir(rootPath) + if err != nil { + if os.IsNotExist(err) { + return nil, nil + } + return nil, err + } + + var digests []digest.Digest + for _, algorithmEntry := range algorithmEntries { + if !algorithmEntry.Type().IsDir() { + continue + } + + algorithm := algorithmEntry.Name() + signatureEntries, err := os.ReadDir(filepath.Join(rootPath, algorithm)) + if err != nil { + return nil, err + } + + for _, signatureEntry := range signatureEntries { + if !signatureEntry.Type().IsRegular() { + continue + } + encoded := signatureEntry.Name() + if !strings.HasSuffix(encoded, SignatureExtension) { + continue + } + encoded = strings.TrimSuffix(encoded, SignatureExtension) + digest := digest.NewDigestFromEncoded(digest.Algorithm(algorithm), encoded) + if err := digest.Validate(); err != nil { + return nil, err + } + digests = append(digests, digest) + } + } + return digests, nil +} diff --git a/cmd/docker-nv2/notary_sign.go b/cmd/docker-nv2/notary_sign.go index 31213ea76..2102eabe9 100644 --- a/cmd/docker-nv2/notary_sign.go +++ b/cmd/docker-nv2/notary_sign.go @@ -7,6 +7,7 @@ import ( "github.com/notaryproject/nv2/cmd/docker-nv2/crypto" "github.com/notaryproject/nv2/cmd/docker-nv2/docker" ios "github.com/notaryproject/nv2/internal/os" + "github.com/opencontainers/go-digest" "github.com/urfave/cli/v2" ) @@ -57,7 +58,7 @@ func notarySign(ctx *cli.Context) error { if err != nil { return err } - sigPath := config.SignaturePath(desc.Digest) + sigPath := config.SignaturePath(desc.Digest, digest.FromBytes(sig)) if err := ios.WriteFile(sigPath, sig); err != nil { return err } diff --git a/cmd/docker-nv2/push.go b/cmd/docker-nv2/push.go index ddbdd84e7..7d93038c9 100644 --- a/cmd/docker-nv2/push.go +++ b/cmd/docker-nv2/push.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "os" "os/exec" "strconv" @@ -37,29 +36,42 @@ func pushImage(ctx *cli.Context) error { } fmt.Println("Pushing signature") - sigPath := config.SignaturePath(desc.Digest) - sig, err := ioutil.ReadFile(sigPath) + sigDigests, err := config.SignatureDigests(desc.Digest) if err != nil { - if os.IsNotExist(err) { - return errors.New("signature not found") - } return err } + if len(sigDigests) == 0 { + return errors.New("no signatures found") + } client, err := docker.GetSignatureRepository(ctx.Context, ctx.Args().First()) if err != nil { return err } - sigDesc, err := client.Put(ctx.Context, sig) - if err != nil { - return err - } + pushSignature := func(sigDigest digest.Digest) error { + sigPath := config.SignaturePath(desc.Digest, sigDigest) + sig, err := os.ReadFile(sigPath) + if err != nil { + return err + } - artifactDesc, err := client.Link(ctx.Context, desc, sigDesc) - if err != nil { - return err + sigDesc, err := client.Put(ctx.Context, sig) + if err != nil { + return err + } + + artifactDesc, err := client.Link(ctx.Context, desc, sigDesc) + if err != nil { + return err + } + fmt.Println("signature manifest digest:", artifactDesc.Digest, "size:", artifactDesc.Size) + return nil + } + for _, sigDigest := range sigDigests { + if err := pushSignature(sigDigest); err != nil { + return err + } } - fmt.Println("signature manifest digest:", artifactDesc.Digest, "size:", artifactDesc.Size) return nil } From 44d4614d4b05bbd19b653dbf21726b4604cb4660 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Tue, 20 Apr 2021 04:05:24 +0800 Subject: [PATCH 36/69] pull signatures when pulling images (#54) Signed-off-by: Shiwei Zhang --- cmd/docker-nv2/pull.go | 54 +++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/cmd/docker-nv2/pull.go b/cmd/docker-nv2/pull.go index 1b9545484..035ba173c 100644 --- a/cmd/docker-nv2/pull.go +++ b/cmd/docker-nv2/pull.go @@ -4,10 +4,13 @@ import ( "context" "errors" "fmt" + "os" "github.com/docker/distribution/reference" "github.com/notaryproject/notary/v2" + "github.com/notaryproject/nv2/cmd/docker-nv2/config" "github.com/notaryproject/nv2/cmd/docker-nv2/docker" + ios "github.com/notaryproject/nv2/internal/os" "github.com/opencontainers/go-digest" oci "github.com/opencontainers/image-spec/specs-go/v1" "github.com/urfave/cli/v2" @@ -62,11 +65,7 @@ func verifyRemoteImage(ctx context.Context, ref string) (string, error) { fmt.Println(manifestRef, "digest:", manifestDesc.Digest, "size:", manifestDesc.Size) fmt.Println("Looking up for signatures") - client, err := docker.GetSignatureRepository(ctx, ref) - if err != nil { - return "", err - } - sigDigests, err := client.Lookup(ctx, manifestDesc.Digest) + sigDigests, err := downloadSignatures(ctx, ref, manifestDesc.Digest) if err != nil { return "", err } @@ -77,13 +76,7 @@ func verifyRemoteImage(ctx context.Context, ref string) (string, error) { fmt.Println("Found", n, "signatures") } - sigDigest, originRefs, err := verifySignatures( - ctx, - service, - client, - sigDigests, - manifestDesc, - ) + sigDigest, originRefs, err := verifySignatures(ctx, service, sigDigests, manifestDesc) if err != nil { return "", fmt.Errorf("none of the signatures are valid: %v", err) } @@ -98,19 +91,48 @@ func verifyRemoteImage(ctx context.Context, ref string) (string, error) { return fmt.Sprintf("%s@%s", named.Name(), manifestDesc.Digest), nil } +func downloadSignatures(ctx context.Context, ref string, manifestDigest digest.Digest) ([]digest.Digest, error) { + client, err := docker.GetSignatureRepository(ctx, ref) + if err != nil { + return nil, err + } + sigDigests, err := client.Lookup(ctx, manifestDigest) + if err != nil { + return nil, err + } + + for _, sigDigest := range sigDigests { + sigPath := config.SignaturePath(manifestDigest, sigDigest) + if _, err := os.Stat(sigPath); err == nil { + continue + } else if !os.IsNotExist(err) { + return nil, err + } + + sig, err := client.Get(ctx, sigDigest) + if err != nil { + return nil, err + } + if err := ios.WriteFile(sigPath, sig); err != nil { + return nil, err + } + } + + return sigDigests, nil +} + func verifySignatures( ctx context.Context, service notary.SigningService, - client notary.SignatureRepository, digests []digest.Digest, desc oci.Descriptor, ) (digest.Digest, []string, error) { var lastError error for _, digest := range digests { - sig, err := client.Get(ctx, digest) + path := config.SignaturePath(desc.Digest, digest) + sig, err := os.ReadFile(path) if err != nil { - lastError = err - continue + return "", nil, err } references, err := service.Verify(ctx, desc, sig) From 5af426ee5545aff4eda77260f1f168d89d88eec1 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Tue, 27 Apr 2021 04:48:15 +0800 Subject: [PATCH 37/69] Explicit add original references when signing (#57) Signed-off-by: Shiwei Zhang --- cmd/docker-nv2/notary_sign.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/cmd/docker-nv2/notary_sign.go b/cmd/docker-nv2/notary_sign.go index 2102eabe9..a3d7e00ab 100644 --- a/cmd/docker-nv2/notary_sign.go +++ b/cmd/docker-nv2/notary_sign.go @@ -29,6 +29,15 @@ var notarySignCommand = &cli.Command{ Usage: "signing cert", TakesFile: true, }, + &cli.StringSliceFlag{ + Name: "reference", + Aliases: []string{"r"}, + Usage: "original references", + }, + &cli.BoolFlag{ + Name: "origin", + Usage: "mark the current reference as a original reference", + }, }, Action: notarySign, } @@ -54,7 +63,12 @@ func notarySign(ctx *cli.Context) error { } fmt.Println("Signing", desc.Digest) - sig, err := service.Sign(ctx.Context, desc, reference) + var references []string + if ctx.Bool("origin") { + references = append(references, reference) + } + references = append(references, ctx.StringSlice("reference")...) + sig, err := service.Sign(ctx.Context, desc, references...) if err != nil { return err } From d589dd88c55fa70b27b4e8b523c4aab892e0d362 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Wed, 28 Apr 2021 08:26:28 +0800 Subject: [PATCH 38/69] create parent folders before create config file (#59) Signed-off-by: Shiwei Zhang --- cmd/docker-nv2/config/config.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmd/docker-nv2/config/config.go b/cmd/docker-nv2/config/config.go index 966cc4845..009028ad5 100644 --- a/cmd/docker-nv2/config/config.go +++ b/cmd/docker-nv2/config/config.go @@ -3,6 +3,7 @@ package config import ( "encoding/json" "os" + "path/filepath" ) // File reflects the config file @@ -21,6 +22,10 @@ func New() *File { // Save stores the config to file func (f *File) Save() error { + dir := filepath.Dir(FilePath) + if err := os.MkdirAll(dir, 0700); err != nil { + return err + } file, err := os.Create(FilePath) if err != nil { return err From 9ad12720128b6435a73b6b1a0b71cf6f990391dd Mon Sep 17 00:00:00 2001 From: Steve Lasker Date: Wed, 28 Apr 2021 12:52:53 -0700 Subject: [PATCH 39/69] Update demo script for prototype-2 (#53) * Update demo script for prototype-2 * Incorporate demo-script PR feedback * Add git clone steps to building.md Signed-off-by: Steve Lasker --- building.md | 34 +++ docs/nv2/README.md | 19 +- docs/nv2/demo-script-detailed.md | 380 ------------------------------- docs/nv2/demo-script.md | 300 +++++++++++++++--------- 4 files changed, 227 insertions(+), 506 deletions(-) create mode 100644 building.md delete mode 100644 docs/nv2/demo-script-detailed.md diff --git a/building.md b/building.md new file mode 100644 index 000000000..16cef244a --- /dev/null +++ b/building.md @@ -0,0 +1,34 @@ +# Building NV2 + +The nv2 repo contains the following: + +- `nv2` - A CLI for signing and verifying with Notary v2 +- `docker-generate` - Extends docker with `docker generate` to create locally persisted manifest for signing, without having to push to a registry. +- `docker-nv2` - Extends docker with `docker nv2 notary` to enable, sign and verify Notary v2 signatures on `docker pull` + +This plugin requires [golang](https://golang.org/dl/) with version `>= 1.16`. + +## Windows with WSL + +- Build the binaries, installing them to: + - `~/bin/nv2` + - `~/.docker/cli-plugins/docker-generate` + - `~/.docker/cli-plugins/docker-nv2` + ```shell + git clone https://github.com/notaryproject/nv2.git + cd nv2 + git checkout prototype-2 + make install + ``` +- Verify binaries are installed + ```bash + docker --help + # look for + Management Commands: + generate* Generate artifacts (github.com/shizhMSFT, 0.1.0) + nv2* Notary V2 Signature extension (Sajay Antony, Shiwei Zhang, 0.2.3) + + which nv2 + # output + /home/]/bin/nv2 + ``` diff --git a/docs/nv2/README.md b/docs/nv2/README.md index 987b78a04..b9252fb94 100644 --- a/docs/nv2/README.md +++ b/docs/nv2/README.md @@ -12,24 +12,7 @@ ### Build and Install -This plugin requires [golang](https://golang.org/dl/) with version `>= 1.16`. - -To build and install, run - -```shell -go install github.com/notaryproject/nv2/cmd/nv2 -``` - -To build and install to an optional path, run - -```shell -go build -o nv2 ./cmd/nv2 -``` - -Next, install optional components: - -- Install [docker-generate](https://github.com/shizhMSFT/docker-generate) for local Docker manifest generation and local signing. -- Install [OpenSSL](https://www.openssl.org/) for key generation. +`nv2`: see [building.md](/building.md) ### Self-signed certificate key generation diff --git a/docs/nv2/demo-script-detailed.md b/docs/nv2/demo-script-detailed.md deleted file mode 100644 index cdb8e8754..000000000 --- a/docs/nv2/demo-script-detailed.md +++ /dev/null @@ -1,380 +0,0 @@ -# Detailed Demo Steps - -The following demonstrates the underlying details of **prototype-2**. - -> At this point, this is a target experience, that is still being developed. - -## Demo Setup - -Perform the following steps prior to the demo: - -- Install [Docker Desktop](https://www.docker.com/products/docker-desktop) for local docker operations -- [Install and Build the nv2 Prerequisites](./README.md#prerequisites) -- Create an empty working directory: - ```bash - mkdir nv2-demo - cd nv2-demo/ - ``` -- Generate the Wabbit Networks Public and Private Keys: - ```bash - openssl req \ - -x509 \ - -sha256 \ - -nodes \ - -newkey rsa:2048 \ - -days 365 \ - -subj "/CN=registry.wabbit-networks.io/O=wabbit-networks inc/C=US/ST=Washington/L=Seattle" \ - -addext "subjectAltName=DNS:registry.wabbit-networks.io" \ - -keyout ./wabbit-networks.key \ - -out ./wabbit-networks.crt - ``` -- Start a local registry instance: - ```bash - # NOTE: the nv2-prototype-2 image does not yet exist - docker run -d -p 80:5000 --restart always --name registry notaryv2/registry:nv2-prototype-2 - ``` -- Add a `etc/hosts` entry to simulate pushing to registry.wabbit-networks.io - - If running on windows, _even if using wsl_, add the following entry to: `C:\Windows\System32\drivers\etc\hosts` - ```hosts - 127.0.0.1 registry.wabbit-networks.io - ``` - -## Demo Reset - -If iterating through the demo, these are the steps required to reset to a clean state: - -- Remove docker alias: - ```bash - unalias docker - ``` -- Reset the local registry: - ```bash - docker rm -f $(docker ps -a -q) - docker run -d -p 80:5000 --restart always --name registry notaryv2/registry:nv2-prototype-1 - ``` -- Remove the `net-monitor:v1` image: - ```bash - docker rmi -f registry.wabbit-networks.io/net-monitor:v1 - ``` -- Remove `wabbit-networks.crt` from `"verificationCerts"`: - ```bash - code ~/.docker/nv2.json - ``` - -## The End to End Experience - -![](../../media/notary-e2e-scenarios.svg) - -- Wabbit Networks is a small software company that produces network monitoring software. -- ACME Rockets wishes to acquire network monitoring software. -- ACME Rockets doesn't know about Wabbit Networks, but finds their [net-monitor software in Docker Hub](https://hub.docker.com/r/wabbitnetworks/net-monitor) -- Since they've never heard of Wabbit Networks, they're a little reluctant to run network software without some validations. -- ACME Rockets has a policy to only import Docker Hub certified software, or approved vendors. -- Wabbit Networks works with Docker Hub to get certified, to help with their customer confidence. -- ACME Rockets will only deploy software that's been scanned and approved by the ACME Rockets security team. They know it's been approved because all approved software has been signed by the ACME Rockets security team. - -## Wabbit Networks Build, Sign, Promote Process - -Let's walk through the sequence of operations Wabbit Networks takes to build, sign and promote their software. - -Within the automation of Wabbit Networks, the following steps are completed: - -1. Build the container image -1. Sign the container image -1. Create an SBoM -1. Sign the SBoM -1. Push the image, sbom, and the associated signatures to the registry - -### Summary of artifacts - -The following graph of artifacts will be created and pushed to the registry - -![](../../media/net-monitor-sbom-signed-detailed.svg) - -- the `net-monitor:v1` image - - the blob content of the `net-monitor:v1` image -- a wabbit-networks signature of the `net-monitor:v1` image - - the blob content of the signature -- an SBoM for the `net-monitor:v1` image - - the blob content of the sbom -- a wabbit-networks signature of the `net-monitor:v1 sbom` - - the blob content of the signature for the sbom - -![](../../media/net-monitor-sbom-signed-artifacts.svg) - -Viewed with less detail, the above image represents 4 artifacts connected through linked manifests: - -1. the `net-monitor:v1` image -1. a wabbit-networks signature of the `net-monitor:v1` image -1. an SBoM for the `net-monitor:v1` image -1. a wabbit-networks signature of the `net-monitor:v1 sbom` - -### Build the `net-monitor` image - - ```bash - docker build \ - -t registry.wabbit-networks.io/net-monitor:v1 \ - https://github.com/wabbit-networks/net-monitor.git#main - ``` - -### Generate the manifest - -Notary v2 signs the manifests of the content as they're represented within a registry. In normal docker operations, the image manifest is a hidden element the user doesn't have to deal with. For the sake full transparency, we'll highlight the full workflow by generating the manifest to sign the digest. - -```bash -docker generate manifest registry.wabbit-networks.io/net-monitor:v1 \ - > net-monitor_v1-manifest.json - -# view the manifest -cat ./net-monitor_v1-manifest.json -``` - -### Acquire the private key - -> TODO: Add any key management prototype steps here: - -- As a best practice, we'll always build on an ephemeral client, with no previous state. -- The ephemeral client will retrieve the private signing key from the companies secured key vault provider. - -These specific steps are product/cloud specific, so we'll assume these steps have been completed and we have the required keys. - -### Sign and Push - -Using the private key, we'll sign the `net-monitor:v1` image. Note, we're signing the image with a registry name that we haven't yet pushed to. This enables offline signing scenarios. This is important as the image will eventually be published on `registry.wabbit-networks.io/`, however their internal staging and promotion process may publish to internal registries before promotion to the public registry. - -- Generates an [nv2 signature][nv2-signature], persisted locally as `net-monitor_v1-signature.jwt` - - ```shell - nv2 sign -m x509 \ - -o net-monitor_v1-signature.jwt \ - -k ~/.ssh/wabbit-networks.key \ - -r registry.wabbit-networks.io/net-monitor:v1 \ - file:./net-monitor_v1-manifest.json - - # view the signature - cat ./net-monitor_v1-signature.jwt - ``` - -- Push the container image - - ```bash - docker push registry.wabbit-networks.io/net-monitor:v1 - ``` - -- Push the `net-monitor:v1` signature to the registry using ORAS - - ```bash - # implies a new means to push an artifact to a repo, without a tag - # need a good design for how to declare content is pushed, where the digest is computed by ORAS, or the underlying tool - # linked-manifest uses digests to assure links are established to the specific artifact, avoiding conflicts to updating tags - # artifact-type replaces - oras push registry.wabbit-networks.io/net-monitor \ - --push-as-digest \ - --artifact-type application/vnd.cncf.notary.v2 \ - --manifest-type application/vnd.oci.artifact.manifest.v1 \ - --manifests registry.wabbit-networks.io/net-monitor@sha256:12as1201... \ - --plain-http \ - ./net-monitor_v1.signature.jwt - ``` - -## Generate an SBoM - -This demo focuses on the signing of additional content, including an SBoM. It doesn't focus on a specific SBoM format. As a result, we'll generate the most basic, and _admittedly_ useless SBoM document: - -```bash -echo '{"version": "0.0.0.0", "image": "registry.wabbit-networks.io/net-monitor:v1", "contents": "good"}' > sbom_v1.json -``` - -### Sign the SBoM - -This is where some of the Notary v2 signature and persistance formats come through. Notary v2 signs a _**Registry Manifest**_. Registry manifests are things that describe the content that's persisted in the registry. There are two manifest formats today: [image-manifest][oci-image-manifest] and [image-index][oci-image-index]. These manifests describe self-contained content, for container images. Since Notary v2 signatures are enhancements to exiting content, we need a way to describe self-contained content that references existing content. An SBoM is yet another type of reference content. The [oci.artifact.manifest][oci-artifact-manifest] provides the ability to describe self-contained content, and link to existing content. - -To enable a Notary v2 signature of an [oci.artifact.manifest][oci-artifact-manifest], we first need to generate that manifest. In the container scenarios, we used the [docker-generate][docker-generate] plug-in to generate a manifest for container images. - -- For non-container images, we'll use the [ORAS cli][oras] to generate an [oci.artifact.manifest][oci-artifact-manifest]. - ```bash - oras generate-manifest \ - --manifest-type application/vnd.oci.artifact.manifest.v1 \ - --artifact-type application/vnd.example.sbom.v0 \ - --manifests oci://registry.wabbit-networks.io/net-monitor@sha256:1a0a0a89a \ - --output sbom_v1-manifest.json \ - ./sbom_v1.json - - # view the manifest - cat sbom_v1-manifest.json - ``` - -- Sign the manifest that represents the SBoM. - - ```bash - nv2 sign -m x509 \ - -k ~/.ssh/wabbit-networks.key \ - -r registry.wabbit-networks.io/net-monitor:v1 \ - -o net-monitor_v1-sbom.signature.jwt \ - file:sbom_v1-manifest.json - - # view the signature - cat ./net-monitor_v1-sbom.signature.jwt - ``` - -- Push the `net-monitor:v1` **sbom** to the registry using ORAS - - ```bash - oras push registry.wabbit-networks.io/net-monitor \ - --push-as-digest \ - --artifact-type application/vnd.example.sbom.v0 \ - --manifest-type application/vnd.oci.artifact.manifest.v1 \ - --manifests oci://registry.wabbit-networks.io/net-monitor@sha256:1a0a0a89a \ - --plain-http \ - ./sbom_v1-manifest.json - # Note: need to capture the digest of the pushed SBoM, for the linkage of the signature - ``` - -- Push the `net-monitor:v1` **sbom signature** to the registry using ORAS - - ```bash - oras push registry.wabbit-networks.io/net-monitor \ - --push-as-digest \ - --artifact-type application/vnd.cncf.notary.v2 \ - --manifest-type application/vnd.oci.artifact.manifest.v1 \ - --manifests oci://registry.wabbit-networks.io/net-monitor@${NET_MONITOR_SBOM_DIGEST} \ - --plain-http \ - ./net-monitor_v1-sbom.signature.jwt - ``` - -## Pulling Validated Content - -To represent a deployed, ephemeral node, we'll pull the `net-monitor:v1` image, validating the signature of the image and the sbom. - -### Clear the build content - -To simulate another client, we'll clear out the `net-monitor:v1` image and signature, simulating a new environment. - -> Note: The public and private keys are maintained, deferring to key management prototypes for how keys should be acquired. - -```bash -docker rmi -f registry.wabbit-networks.io/net-monitor:v1 -rm *.jwt -rm *.json -``` - -### Attempt, and fail to pull the image - -Simulate a notary enabled client, which doesn't yet have the public keys configured. - -- Get the digest for the `net-monitor:v1` image: - ```bash - NET_MONITOR_DIGEST=$(curl -v -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \ - registry.wabbit-networks.io/v2/net-monitor/manifests/v1 2>&1 | \ - grep -i 'Docker-Content-Digest:' | \ - awk '{print $3}') - ``` -- Query for Notary v2 linked artifacts - ```bash - curl -v -H "Accept: artifactType=application/vnd.cncf.notary.v2" \ - registry.wabbit-networks.io/v2/_ext/oci-artifacts/net-monitor/manifests/${NET_MONITOR_DIGEST}/links - NET_MONITOR_SIG_DIGEST=^ - ``` -- Retrieve the `net-monitor:v1` notary v2 signature - ```bash - oras pull registry.wabbit-networks.io/net-monitor@sha256:${NET_MONITOR_SIG_DIGEST} \ - --plain-http - ``` -- Validate the signature - ```bash - nv2 verify \ - -c ./wabbit-networks.crt \ - -f net-monitor_v1.signature.jwt \ - oci://registry.wabbit-networks.io/net-monitor:v1 - ``` - The above validation will fail, as we haven't yet configured notary to find the `wabbit-networks.crt` public key. -- Configure Notary access to the wabbit-networks key - ```bash - code ~/.docker/nv2.json - ``` -- Add the path to the cert: - ```json - "verificationCerts": [ - "/home/stevelas/nv2-demo/wabbit-networks.crt" - ] - ``` -- Validate the signature - ```bash - nv2 verify \ - -c ./wabbit-networks.crt \ - -f net-monitor_v1.signature.jwt \ - oci://registry.wabbit-networks.io/net-monitor:v1 - ``` - -- Pull the image, as the signature validation succeeded - ```bash - docker pull $image - ``` - -## Appendix - -### Convert the tag to a digest - -```bash -curl -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -vvv -k registry.wabbit-networks.io/v2/net-monitor/manifests/v1 -curl -H "Accept: application/vnd.oci.image.manifest.v2+json" -vvv -k registry.wabbit-networks.io/v2/net-monitor/manifests/v1 -curl -vvv -k registry.wabbit-networks.io/v2/net-monitor/manifests/v1 - -curl -v -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \ - https://mcr.microsoft.com/v2/aks/hcp/etcd-azure/manifests/v3.1.19 2>&1 | \ - grep -i 'Docker-Content-Digest:' | \ - awk '{print $3}' -curl -v -H "Accept: application/vnd.oci.image.manifest.v2+json" \ - https://mcr.microsoft.com/v2/aks/hcp/etcd-azure/manifests/v3.1.19 2>&1 | \ - grep -i 'Docker-Content-Digest:' | \ - awk '{print $3}' - -curl -v -H "Accept: application/vnd.oci.image.manifest.v2+json" \ - https://mcr.microsoft.com/v2/aks/hcp/etcd-azure/manifests/v3.1.19 2>&1 | \ - grep -i 'Docker-Content-Digest:' | \ - awk '{print $3}' - - - -curl -v -H "Accept: application/vnd.oci.image.manifest.v2+json" \ - registry.wabbit-networks.io/v2/net-monitor/manifests/v1 2>&1 | \ - grep -i 'Docker-Content-Digest:' | \ - awk '{print $3}' -``` - -### Query for linked artifacts - -```bash -GET /v2/_ext/{repository}/manifests/{digest}/links?artifactType=application/vnd.oci.notary.v2.config+json&n=10 -GET registry.wabbit-networks.io/v2/_ext/net-monitor/manifests/{digest}/links?artifactType=application/vnd.oci.notary.v2.config+json - -``` - -#### Validate the image - -To validate an image, we need the signature, which can be pulled prior to the image. We want to avoid pulling images we haven't validated, as this could be a trojan horse type exploit. - -```bash -oras pull registry.wabbit-networks.io/net-monitor:v1-signature -a --plain-http -``` -> TODO: Fix CN validation -```bash -nv2 verify \ - -c ~/.ssh/wabbit-networks.crt \ - -f net-monitor_v1.signature.jwt \ - file:net-monitor_v1-manifest.json - -nv2 verify \ - -c ~/.ssh/wabbit-networks.crt \ - -f net-monitor_v1.signature.jwt \ - oci://registry.wabbit-networks.io/net-monitor:v1 - -2021/03/02 14:27:38 verification failure: x509: certificate relies on legacy Common Name field, use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0 -``` - -[docker-generate]: https://github.com/shizhMSFT/docker-generate -[nv2-signature]: ../signature/README.md -[oci-image-manifest]: https://github.com/opencontainers/image-spec/blob/master/manifest.md -[oci-image-index]: https://github.com/opencontainers/image-spec/blob/master/image-index.md -[oci-artifact-manifest]: https://github.com/opencontainers/artifacts/blob/3e34f029537052639eed59b469cb6c43706ac3d0/artifact-manifest.md -[oras]: https://github.com/deislabs/oras \ No newline at end of file diff --git a/docs/nv2/demo-script.md b/docs/nv2/demo-script.md index 66b867b87..1aa71abf9 100644 --- a/docs/nv2/demo-script.md +++ b/docs/nv2/demo-script.md @@ -1,18 +1,27 @@ -# nv2 Demo Script +# Demo Steps -The following is a summary when presenting a demo of Notary v2 - prototype-2. +The following demonstrates the capabilities of [Notary v2 - Prototype-2][nv2-prototype-2]. ## Demo Setup Perform the following steps prior to the demo: - Install [Docker Desktop](https://www.docker.com/products/docker-desktop) for local docker operations -- [Install and Build the nv2 Prerequisites](./README.md#prerequisites) -- Create an empty working directory: +- [Install and Build nv2](../../building.md) +- [Install and Build the ORAS Prototype-2 branch](https://github.com/deislabs/oras/blob/prototype-2/docs/artifact-manifest.md) +- Generate the `~/.docker/nv2.json` config file ```bash - mkdir nv2-demo - cd nv2-demo/ + docker nv2 notary --enabled ``` +- Setup names and variables with `localhost:5000` + >**NOTE:** See [Simulating a Registry DNS Name](#simulating-a-registry-dns-name) for using `registry.wabbit-networks.io` + ```bash + export PORT=5000 + export REGISTRY=localhost:${PORT} + export REPO=${REGISTRY}/net-monitor + export IMAGE=${REPO}:v1 + ``` + - Generate the Wabbit Networks Public and Private Keys: ```bash openssl req \ @@ -21,48 +30,17 @@ Perform the following steps prior to the demo: -nodes \ -newkey rsa:2048 \ -days 365 \ - -subj "/CN=registry.wabbit-networks.io/O=wabbit-networks inc/C=US/ST=Washington/L=Seattle" \ - -addext "subjectAltName=DNS:registry.wabbit-networks.io" \ + -subj "/CN=${REGISTRY}/O=wabbit-networks inc/C=US/ST=Washington/L=Seattle" \ + -addext "subjectAltName=DNS:${REGISTRY}" \ -keyout ./wabbit-networks.key \ -out ./wabbit-networks.crt ``` -- Start a local registry instance: - ```bash - docker run -d -p 80:5000 --restart always --name registry notaryv2/registry:nv2-prototype-1 - ``` -- Add a `etc/hosts` entry to simulate pushing to registry.wabbit-networks.io - - If running on windows, _even if using wsl_, add the following entry to: `C:\Windows\System32\drivers\etc\hosts` - ```hosts - 127.0.0.1 registry.wabbit-networks.io - ``` - -## Demo Reset - -If iterating through the demo, these are the steps required to reset to a clean state: - -- Remove docker alias: - ```bash - unalias docker - ``` -- Reset the local registry: - ```bash - docker rm -f $(docker ps -a -q) - docker run -d -p 80:5000 --restart always --name registry notaryv2/registry:nv2-prototype-1 - ``` -- Remove the `net-monitor:v1` image: +### Start a Local Registry Instance ```bash - docker rmi -f registry.wabbit-networks.io/net-monitor:v1 + docker run -d -p ${PORT}:5000 notaryv2/registry:nv2-prototype-2 ``` -- Remove `wabbit-networks.crt` from `"verificationCerts"`: - ```bash - code ~/.docker/nv2.json - ``` - -## Demo Steps -### Explain the end to end experience being presented - -![](../../media/notary-e2e-scenarios.svg) +## Demo The End to End Experience - Wabbit Networks is a small software company that produces network monitoring software. - ACME Rockets wishes to acquire network monitoring software. @@ -72,40 +50,14 @@ If iterating through the demo, these are the steps required to reset to a clean - Wabbit Networks works with Docker Hub to get certified, to help with their customer confidence. - ACME Rockets will only deploy software that's been scanned and approved by the ACME Rockets security team. They know it's been approved because all approved software has been signed by the ACME Rockets security team. -### Show Notary Extension - -To demonstrate a clean end to end experience, using the docker cli, we're using the [docker-generate][docker-generate] extension. - -To see the extension capabilities, review the `Management Commands:`: - -```bash -docker --help - -Management Commands: - ... - generate* Generate artifacts (github.com/shizhMSFT, 0.1.0) - nv2* Notary V2 Signature extension (Sajay Antony, Shiwei Zhang, 0.1.0) - -``` - -To see the sub commands of `nv2` and `nv2 notary`: - -```bash -docker nv2 --help -docker nv2 notary --help -``` - -To avoid having to type `docker nv2` each time, we'll create an alias to mask over this: - -```bash -alias docker="docker nv2" -``` +![](../../media/notary-e2e-scenarios.svg) -To avoid having to type the fully qualified registry name, we'll create an environment variable: +### Alias `nv2` Commands -```bash -export image=registry.wabbit-networks.io/net-monitor:v1 -``` +- To avoid having to type `docker nv2` each time, create an alias: + ```bash + alias docker="docker nv2" + ``` ## Wabbit Networks Build, Sign, Promote Process @@ -113,13 +65,20 @@ Let's walk through the sequence of operations Wabbit Networks takes to build, si Within the automation of Wabbit Networks, the following steps are completed: +1. Building the `net-monitor` image +1. Sign the `net-monitor` image +1. Push the image and signature +1. Create and push a signed SBoM + ### Build the `net-monitor` image -```bash -docker build \ - -t $image \ +- Build the image, directly from GitHub to simplify the sequence. + ```bash + docker build \ + -t $IMAGE \ https://github.com/wabbit-networks/net-monitor.git#main -``` + ``` + _To represent an ephemeral client in an air-gapped environment, git clone, then build with `.` as the context_ ### Acquire the private key @@ -128,44 +87,42 @@ docker build \ These specific steps are product/cloud specific, so we'll assume these steps have been completed. -### Sign the image +### Sign and Push the Image and Signature -Using the private key, we'll sign the net-monitor image. Note, we're signing the image with a registry name that we haven't yet pushed to. This enables offline signing scenarios. This is important as the image will eventually be published on `registry.wabbit-networks.io/`, however their internal staging and promotion process may publish to internal registries before promotion to the public registry. +Using the private key, we'll sign the `net-monitor:v1` image. Note, we're signing the image with a registry name that we haven't yet pushed to. This enables offline signing scenarios. This is important as the image will eventually be published on `registry.wabbit-networks.io/`, however their internal staging and promotion process may publish to internal registries before promotion to the public registry. -- Generate an [nv2 signature][nv2-signature], persisted locally as `net-monitor_v1.signature.config.jwt` +- Generate an [nv2 signature][nv2-signature], persisted locally as `net-monitor_v1.signature.jwt` +- Enable notary, for the nv2 extension to account for signing and verification steps ```shell docker notary --enabled - + ``` +- Generate an [nv2 signature][nv2-signature], persisted within the `/.docker/nv2/sha256/` directory: + ```shell docker notary sign \ --key ./wabbit-networks.key \ --cert ./wabbit-networks.crt \ - $image + $IMAGE ``` -- view the signature referenced from docker notary sign +- Push the image, with the signature ```bash - cat + docker push $IMAGE ``` - -- View the manifest the signature is based upon: +- View the output, which includes pushing the signature as a reference: ```bash - docker generate manifest $image + The push refers to repository [registry.wabbit-networks.io/net-monitor] + 8ea3b23f387b: Preparing + 8ea3b23f387b: Pushed + v1: digest: sha256:31c6d76b9a0af8d2c0a7fc16b43b7d8d9b324aa5ac3ef8c84dc48ab5ba5c0f49 size: 527 + Pushing signature + signature manifest: digest: sha256:8eb7394c8f287ebd0e84a4659f37a2688c6e07e39906933ccb83d9011fb29034 size: 2534 + refers to manifests: digest: sha256:31c6d76b9a0af8d2c0a7fc16b43b7d8d9b324aa5ac3ef8c84dc48ab5ba5c0f49 size: 527 ``` - -### Push the image & signature to the registry - -Push the image, and its signature in one user gesture. Note the push links the signature to the image for later retrevial by a `:tag` or `digest`. - -```shell -docker push $image -``` - -### Clear the local image - -- To simulate another client, we'll clear out the `net-monitor:v1` image +- Discover the references using the [oras prototype-2 branch](https://github.com/deislabs/oras/tree/prototype-2). ```bash - docker rmi -f registry.wabbit-networks.io/net-monitor:v1 - rm ~/.docker/nv2/sha256/*.* + oras discover \ + --plain-http \ + $IMAGE ``` ### Validate the image @@ -174,7 +131,7 @@ To validate an image, `docker pull` with `docker notary --enabled` will attempt - Attempt to pull the `net-monitor:v1` image: ```bash - docker pull $image + docker pull $IMAGE ``` - The above command will fail, as we haven't configured the `nv2` client access to the public keys. @@ -194,14 +151,14 @@ To validate an image, `docker pull` with `docker notary --enabled` will attempt { "enabled": true, "verificationCerts": [ - "/home/stevelas/nv2-demo/wabbit-networks.crt" + "/home//nv2-demo/wabbit-networks.crt" ] } ``` - Pull the `net-monitor:v1` image, using the public key for verification: ```bash - docker pull $image + docker pull $IMAGE ``` - The validated pull can be seen: ```bash @@ -217,7 +174,134 @@ To validate an image, `docker pull` with `docker notary --enabled` will attempt registry.wabbit-networks.io/net-monitor@sha256:48575dfb9ef2ebb9d67c6ed3cfbd784d635fcfae8ec820235ffa24968b3474dc ``` -This shows the target experience we're shooting for, within various build and container runtime tooling. +### Create a Software Bill of Materials + +- Create an overly simplistic SBoM + ```bash + echo '{"version": "0.0.0.0", "artifact": "net-monitor:v1", "contents": "good"}' > sbom.json + ``` +- Push the SBoM with ORAS, saving the manifest for signing + ```bash + oras push $REPO \ + --artifact-type application/x.example.sbom.v0 \ + --artifact-reference $IMAGE \ + --export-manifest sbom-manifest.json \ + --plain-http \ + ./sbom.json:application/tar + ``` +- View the references with `oras discover`: + ```bash + oras discover \ + --plain-http \ + $IMAGE + ``` + +### Sign the SBoM + +In the above case, the SBoM has already been pushed to the registry. To sign it before pushing, we could have used `oras push` with the `--dry-run` and `--export-manifest` options. + +- For non-container images, we'll use the `nv2` cli to sign and the `oras` cli to push to a registry. We'll use the `oras discover` cli to find the sbom digest the signature will reference. + ```bash + nv2 sign \ + -m x509 \ + -k wabbit-networks.key \ + -c wabbit-networks.crt \ + --plain-http \ + --push \ + --push-reference oci://${REPO}@$(oras discover \ + --artifact-type application/x.example.sbom.v0 \ + --output-json \ + --plain-http \ + $IMAGE | jq -r .references[0].digest) \ + file:sbom-manifest.json + ``` +- Dynamically get the SBoM digest + ```bash + DIGEST=$(oras discover \ + --artifact-type application/x.example.sbom.v0 \ + --output-json \ + --plain-http \ + $IMAGE | jq -r .references[0].digest) +- Discover referenced artifacts of the SBoM + ```bash + oras discover \ + --plain-http \ + ${REPO}@${DIGEST} + ``` +- Generates: + ```bash + Discovered 1 artifacts referencing localhost:5000/net-monitor@sha256:adfe3a3c50838fc2a19d5d7e73119dcadad7ad8e4e98f1e0fd100dd9d2278b71 + Digest: sha256:adfe3a3c50838fc2a19d5d7e73119dcadad7ad8e4e98f1e0fd100dd9d2278b71 + + Artifact Type Digest + application/vnd.cncf.notary.v2 sha256:b7fc5fdb81f2ada359d0a709004360d1f08c9d2ac8a80630b152d1c6fb35460e + ``` + +The above workflow demonstrates the **Notary v2, prototype-2** target experience. + +## Optional Steps + +Some optional steps: + +## Demo Reset + +If iterating through the demo, these are the steps required to reset to a clean state: + +- Remove docker alias: + ```bash + unalias docker + ``` +- Reset the local registry: + ```bash + docker rm -f $(docker ps -a -q) + docker run -d -p ${PORT}:5000 notaryv2/registry:nv2-prototype-2 + ``` +- Remove the `net-monitor:v1` image: + ```bash + docker rmi -f ${REGISTRY}/net-monitor:v1 + ``` +- Remove `wabbit-networks.crt` from `"verificationCerts"` in the `nv2.json` configuration file: + ```bash + code ~/.docker/nv2.json + ``` +- Remove previous signatures: + ```bash + rm -r ~/.docker/nv2/sha256/ + ``` + +### Simulating a Registry DNS Name + +Configure the additional steps to simulate a fully qualified dns name for wabbit-networks. -[nv2-signature]: ../signature/README.md -[docker-generate]: https://github.com/shizhMSFT/docker-generate \ No newline at end of file +- Setup names and variables with `registry.wabbit-networks.io` + ```bash + export PORT=80 + export REGISTRY=registry.wabbit-networks.io + export REPO=${REGISTRY}/net-monitor + export IMAGE=${REPO}:v1 + ``` +- Edit the `~/.docker/nv2.json` file to support local, insecure registries + ```json + { + "enabled": true, + "verificationCerts": [ + ], + "insecureRegistries": [ + "registry.wabbit-networks.io" + ] + } + ``` +- Add a `etc/hosts` entry to simulate pushing to registry.wabbit-networks.io + - If running on windows, _even if using wsl_, add the following entry to: `C:\Windows\System32\drivers\etc\hosts` + ```hosts + 127.0.0.1 registry.wabbit-networks.io + ``` +- Continue with [Start a Local Registry Instance](#start-a-local-registry-instance) + +[docker-generate]: https://github.com/notaryproject/nv2/tree/prototype-2 +[nv2-signature]: ../signature/README.md +[oci-image-manifest]: https://github.com/opencontainers/image-spec/blob/master/manifest.md +[oci-image-index]: https://github.com/opencontainers/image-spec/blob/master/image-index.md +[oci-artifact-manifest]: https://github.com/SteveLasker/artifacts/blob/oci-artifact-manifest/artifact-manifest.md +[oras]: https://github.com/deislabs/oras/tree/prototype-2 +[nv2-prototype-2]: https://github.com/notaryproject/notaryproject/issues/53 From 9c9f68bb0b28fa19e877e16c14fbc8a42d656165 Mon Sep 17 00:00:00 2001 From: Marco Franssen Date: Sat, 8 May 2021 05:23:34 +0200 Subject: [PATCH 40/69] Ci 2 (#49) * Add basic workflow that compiles the binary Signed-off-by: Marco Franssen * Add dependabot for Go dependencies Signed-off-by: Marco Franssen * Add dependabot for github-actions Signed-off-by: Marco Franssen * Update workflow to use Makefile Signed-off-by: Marco Franssen * Include .editorconfig compatible with go fmt Signed-off-by: Marco Franssen * Run CI on go 1.16 Since go 1.16 some ioutil functions are deprecated and moved into the io package. Therefore can't build with previous versions of Go anymore Signed-off-by: Marco Franssen * Add help task to Makefile Signed-off-by: Marco Franssen * Add CI status badge Signed-off-by: Marco Franssen --- .editorconfig | 22 ++++++++++++++++++ .github/dependabot.yml | 18 +++++++++++++++ .github/workflows/golang.yml | 43 ++++++++++++++++++++++++++++++++++++ Makefile | 26 +++++++++++++++------- README.md | 8 ++++--- 5 files changed, 106 insertions(+), 11 deletions(-) create mode 100644 .editorconfig create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/golang.yml diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..02a97839c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,22 @@ +root = true + +[*] +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +end_of_line = lf +indent_style = space +indent_size = 2 +tab_width = 2 + +[*.go] +indent_size = 4 +tab_width = 4 +indent_style = tab +# required for multiline strings in test cases +trim_trailing_whitespace = false + +[Makefile] +indent_size = 4 +tab_width = 4 +indent_style = tab diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..715f5b432 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,18 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "gomod" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" + + - package-ecosystem: "github-actions" + # Workflow files stored in the + # default location of `.github/workflows` + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/golang.yml b/.github/workflows/golang.yml new file mode 100644 index 000000000..c7ccef2b7 --- /dev/null +++ b/.github/workflows/golang.yml @@ -0,0 +1,43 @@ +name: Go CI + +on: + push: + pull_request: + +jobs: + build: + runs-on: ubuntu-20.04 + + name: Continuous Integration + if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository + + strategy: + matrix: + go-version: [1.16] + + fail-fast: true + + steps: + - name: Set up Go ${{ matrix.go-version }} + uses: actions/setup-go@v2.1.3 + with: + go-version: ${{ matrix.go-version }} + + - name: Check out code + uses: actions/checkout@v2.3.4 + + - name: Cache Go modules + uses: actions/cache@v2.1.4 + id: go-mod-cache + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Get dependencies + run: make download + + - name: Build + run: | + make build diff --git a/Makefile b/Makefile index b22e5aed7..cb386d446 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -GO_BUILD_FLAGS = +GO_BUILD_FLAGS = DOCKER_PLUGINS = docker-generate docker-nv2 COMMANDS = nv2 $(DOCKER_PLUGINS) @@ -6,6 +6,11 @@ define BUILD_BINARY = go build $(GO_BUILD_FLAGS) -o $@ ./$< endef +.PHONY: help + +help: + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-25s\033[0m %s\n", $$1, $$2}' + .PHONY: all all: build @@ -15,23 +20,27 @@ FORCE: bin/%: cmd/% FORCE $(BUILD_BINARY) +.PHONY: download +download: ## download dependencies via go mod + go mod download + .PHONY: build -build: $(addprefix bin/,$(COMMANDS)) +build: $(addprefix bin/,$(COMMANDS)) ## builds binaries .PHONY: clean clean: git status --ignored --short | grep '^!! ' | sed 's/!! //' | xargs rm -rf -.PHONY: check-encoding -check-encoding: +.PHONY: check-line-endings +check-line-endings: ## check line endings ! find cmd pkg internal -name "*.go" -type f -exec file "{}" ";" | grep CRLF -.PHONY: fix-encoding -fix-encoding: +.PHONY: fix-line-endings +fix-line-endings: ## fix line endings find cmd pkg internal -type f -name "*.go" -exec sed -i -e "s/\r//g" {} + .PHONY: vendor -vendor: +vendor: ## vendores the go modules GO111MODULE=on go mod vendor .PHONY: install @@ -46,4 +55,5 @@ install-docker-%: bin/docker-% cp $< ~/.docker/cli-plugins/ .PHONY: install-docker-plugins -install-docker-plugins: $(addprefix install-,$(DOCKER_PLUGINS)) +install-docker-plugins: $(addprefix install-,$(DOCKER_PLUGINS)) ## installs the docker plugins + cp $(addprefix bin/,$(DOCKER_PLUGINS)) ~/.docker/cli-plugins/ diff --git a/README.md b/README.md index 2997124dd..3609b6707 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Notary V2 (nv2) - Prototype +[![Go CI](https://github.com/notaryproject/nv2/actions/workflows/golang.yml/badge.svg)](https://github.com/notaryproject/nv2/actions/workflows/golang.yml) + nv2 is an incubation and prototype for the [Notary v2][notary-v2] efforts, securing artifacts stored in [distribution-spec][distribution-spec] based registries. The `nv2` prototype covers the scenarios outlined in [notaryproject/requirements](https://github.com/notaryproject/requirements/blob/master/scenarios.md#scenarios). It also follows the [prototyping approach described here](https://github.com/stevelasker/nv2#prototyping-approach). @@ -34,7 +36,7 @@ Public registries generally have two cateogires of content: #### End to End Experience -The user works for ACME Rockets. They build `FROM` and use certified content from docker hub. +The user works for ACME Rockets. They build `FROM` and use certified content from docker hub. Their environemt is configured to only trust content from `docker.io` and `acme-rockets.io` #### Public Certified Content @@ -53,8 +55,8 @@ Their environemt is configured to only trust content from `docker.io` and `acme- 1. The image fails to run as the user has `trust-required` enabled, and doesn't have the wabbit-networks key.The docker cli produces an error with a url for acquiring the wabbit-networks key. - The user can disable `trust-requried`, or acquire the required key. 1. The user acquires the wabbit-networks key, saves it in their local store -1. The user again runs: - - `docker run docker.io/wabbit-networks/net-monitor:latest` +1. The user again runs: + - `docker run docker.io/wabbit-networks/net-monitor:latest` and the image is sucessfully run ### Key acquisition From 2f199a5ba462ae1821483f5325f48bd184407221 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Mon, 28 Jun 2021 17:06:17 +0800 Subject: [PATCH 41/69] upgrade to prototype-3 Signed-off-by: Shiwei Zhang --- go.mod | 5 ++++- go.sum | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 3f5b12d17..fd427a773 100644 --- a/go.mod +++ b/go.mod @@ -17,4 +17,7 @@ require ( gotest.tools/v3 v3.0.3 // indirect ) -replace github.com/opencontainers/artifacts => github.com/notaryproject/artifacts v0.0.0-20210414030140-c7c701eff45d +replace ( + github.com/notaryproject/notary/v2 => github.com/shizhMSFT/notary/v2 v2.0.0-20210628085455-9ffe654b1d61 + github.com/opencontainers/artifacts => github.com/aviral26/artifacts v0.0.3 +) diff --git a/go.sum b/go.sum index 4b20c2b7e..fea5958be 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/aviral26/artifacts v0.0.3 h1:F+XBw93sXm9H7iajUEl0DhbbvCg2e/k6e4lVY2EYhC4= +github.com/aviral26/artifacts v0.0.3/go.mod h1:IBQOjhxIKxb9G4h9NiWAJLGBgKPlIy27tcpPDTAfUQw= github.com/aws/aws-sdk-go v1.34.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -77,10 +79,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= -github.com/notaryproject/artifacts v0.0.0-20210414030140-c7c701eff45d h1:GtjfjCO9nJX0zBaJ5bRtGjEFKflmdtYcn7sr7hgllHE= -github.com/notaryproject/artifacts v0.0.0-20210414030140-c7c701eff45d/go.mod h1:IBQOjhxIKxb9G4h9NiWAJLGBgKPlIy27tcpPDTAfUQw= -github.com/notaryproject/notary/v2 v2.0.0-20210414032403-d1367cc13db7 h1:4MWG4IZ4wMBfLs9BD1v7LpeGu+0uQTFwdQjtzZMsmgY= -github.com/notaryproject/notary/v2 v2.0.0-20210414032403-d1367cc13db7/go.mod h1:ZBxNIEYm11y1i6dTk4toLEcHhhNh4GOJjys/KIyWq7Q= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= @@ -104,6 +102,8 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/shizhMSFT/notary/v2 v2.0.0-20210628085455-9ffe654b1d61 h1:zjKRGTeC9IucYK1TJZch8dHnNld3t6D87n0t4falB1U= +github.com/shizhMSFT/notary/v2 v2.0.0-20210628085455-9ffe654b1d61/go.mod h1:9TYSlVNAiZqhzs/nkZMNJ8vXx9X9YTTOpuTCk8c5s1A= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= From e304503e232f79b378af73dce0f92461dfbf74bd Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Mon, 30 Aug 2021 15:43:48 +0800 Subject: [PATCH 42/69] Notation CLI Alpha Signed-off-by: Shiwei Zhang --- .github/ISSUE_TEMPLATE/config.yml | 2 +- .github/workflows/golang.yml | 2 +- .github/workflows/release-github.yml | 30 + .goreleaser.yml | 59 ++ Makefile | 28 +- cmd/docker-generate/manifest.go | 2 +- cmd/docker-generate/metadata.go | 15 +- .../crypto/service.go | 12 +- .../docker/credential.go | 0 .../docker/manifest.go | 36 +- .../docker/network.go | 2 +- .../docker/signature.go | 10 +- cmd/{docker-nv2 => docker-notation}/main.go | 2 +- cmd/docker-notation/metadata.go | 27 + cmd/docker-notation/notation.go | 43 + cmd/{docker-nv2 => docker-notation}/pull.go | 18 +- cmd/{docker-nv2 => docker-notation}/push.go | 28 +- .../sign.go} | 16 +- cmd/{docker-nv2 => docker-notation}/util.go | 20 +- cmd/docker-nv2/config/config.go | 51 - cmd/docker-nv2/metadata.go | 25 - cmd/docker-nv2/notary.go | 40 - cmd/docker-nv2/nv2.go | 32 - cmd/notation/cache.go | 232 +++++ cmd/notation/cert.go | 192 ++++ cmd/notation/cert_gen.go | 133 +++ cmd/{nv2 => notation}/common.go | 15 +- cmd/notation/key.go | 227 +++++ cmd/{nv2 => notation}/main.go | 10 +- cmd/notation/manifest.go | 72 ++ cmd/notation/pull.go | 137 +++ cmd/notation/push.go | 98 ++ cmd/notation/registry.go | 22 + cmd/{nv2 => notation}/sign.go | 108 +- cmd/notation/verify.go | 195 ++++ cmd/nv2/manifest.go | 74 -- cmd/nv2/pull.go | 108 -- cmd/nv2/push.go | 83 -- cmd/nv2/registry.go | 31 - cmd/nv2/verify.go | 119 --- .../persistance-discovery-options.md | 934 ------------------ docs/docker-plugins/README.md | 6 - docs/docker-plugins/docker-generate.md | 51 - docs/docker-plugins/docker-nv2.md | 54 - docs/nv2/README.md | 271 ----- docs/nv2/demo-script.md | 307 ------ docs/signature/README.md | 239 ----- docs/signature/examples/x509_kid.nv2.jwt | 1 - docs/signature/examples/x509_x5c.nv2.jwt | 1 - go.mod | 32 +- go.sum | 43 +- internal/docker/plugin.go | 14 + internal/os/file.go | 27 +- internal/version/version.go | 17 + media/acme-rockets-cert.png | Bin 17157 -> 0 bytes media/example-cert.png | Bin 18030 -> 0 bytes media/net-monitor-sbom-signed-artifacts.svg | 1 - media/net-monitor-sbom-signed-detailed.svg | 1 - media/notary-e2e-scenarios.svg | 1 - media/nv2-client-components.png | Bin 26127 -> 0 bytes ...ture-as-index-signing-multi-arch-index.png | Bin 144312 -> 0 bytes media/signature-as-index.png | Bin 41901 -> 0 bytes media/signature-as-manifest-via-index.png | Bin 67354 -> 0 bytes media/signature-as-manifest.png | Bin 40394 -> 0 bytes pkg/config/config.go | 76 ++ pkg/config/once.go | 20 + {cmd/docker-nv2 => pkg}/config/path.go | 64 +- pkg/config/set.go | 48 + {cmd/docker-nv2 => pkg}/config/util.go | 10 +- pkg/docker/schema2.go | 6 +- pkg/registry/descriptor.go | 8 +- pkg/registry/manifest.go | 53 +- pkg/registry/reference.go | 13 +- 73 files changed, 1989 insertions(+), 2665 deletions(-) create mode 100644 .github/workflows/release-github.yml create mode 100644 .goreleaser.yml rename cmd/{docker-nv2 => docker-notation}/crypto/service.go (71%) rename cmd/{docker-nv2 => docker-notation}/docker/credential.go (100%) rename cmd/{docker-nv2 => docker-notation}/docker/manifest.go (69%) rename cmd/{docker-nv2 => docker-notation}/docker/network.go (89%) rename cmd/{docker-nv2 => docker-notation}/docker/signature.go (72%) rename cmd/{docker-nv2 => docker-notation}/main.go (92%) create mode 100644 cmd/docker-notation/metadata.go create mode 100644 cmd/docker-notation/notation.go rename cmd/{docker-nv2 => docker-notation}/pull.go (87%) rename cmd/{docker-nv2 => docker-notation}/push.go (73%) rename cmd/{docker-nv2/notary_sign.go => docker-notation/sign.go} (80%) rename cmd/{docker-nv2 => docker-notation}/util.go (55%) delete mode 100644 cmd/docker-nv2/config/config.go delete mode 100644 cmd/docker-nv2/metadata.go delete mode 100644 cmd/docker-nv2/notary.go delete mode 100644 cmd/docker-nv2/nv2.go create mode 100644 cmd/notation/cache.go create mode 100644 cmd/notation/cert.go create mode 100644 cmd/notation/cert_gen.go rename cmd/{nv2 => notation}/common.go (68%) create mode 100644 cmd/notation/key.go rename cmd/{nv2 => notation}/main.go (65%) create mode 100644 cmd/notation/manifest.go create mode 100644 cmd/notation/pull.go create mode 100644 cmd/notation/push.go create mode 100644 cmd/notation/registry.go rename cmd/{nv2 => notation}/sign.go (51%) create mode 100644 cmd/notation/verify.go delete mode 100644 cmd/nv2/manifest.go delete mode 100644 cmd/nv2/pull.go delete mode 100644 cmd/nv2/push.go delete mode 100644 cmd/nv2/registry.go delete mode 100644 cmd/nv2/verify.go delete mode 100644 docs/distribution/persistance-discovery-options.md delete mode 100644 docs/docker-plugins/README.md delete mode 100644 docs/docker-plugins/docker-generate.md delete mode 100644 docs/docker-plugins/docker-nv2.md delete mode 100644 docs/nv2/README.md delete mode 100644 docs/nv2/demo-script.md delete mode 100644 docs/signature/README.md delete mode 100644 docs/signature/examples/x509_kid.nv2.jwt delete mode 100644 docs/signature/examples/x509_x5c.nv2.jwt create mode 100644 internal/docker/plugin.go create mode 100644 internal/version/version.go delete mode 100644 media/acme-rockets-cert.png delete mode 100644 media/example-cert.png delete mode 100644 media/net-monitor-sbom-signed-artifacts.svg delete mode 100644 media/net-monitor-sbom-signed-detailed.svg delete mode 100644 media/notary-e2e-scenarios.svg delete mode 100644 media/nv2-client-components.png delete mode 100644 media/signature-as-index-signing-multi-arch-index.png delete mode 100644 media/signature-as-index.png delete mode 100644 media/signature-as-manifest-via-index.png delete mode 100644 media/signature-as-manifest.png create mode 100644 pkg/config/config.go create mode 100644 pkg/config/once.go rename {cmd/docker-nv2 => pkg}/config/path.go (54%) create mode 100644 pkg/config/set.go rename {cmd/docker-nv2 => pkg}/config/util.go (65%) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 9dec782aa..918773a9f 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: true contact_links: - name: Ask a question - url: https://github.com/notaryproject/nv2/discussions + url: https://github.com/notaryproject/notation/discussions about: Ask questions and discuss with other community members \ No newline at end of file diff --git a/.github/workflows/golang.yml b/.github/workflows/golang.yml index c7ccef2b7..b5157365c 100644 --- a/.github/workflows/golang.yml +++ b/.github/workflows/golang.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: - go-version: [1.16] + go-version: [1.17] fail-fast: true diff --git a/.github/workflows/release-github.yml b/.github/workflows/release-github.yml new file mode 100644 index 000000000..70a3401f6 --- /dev/null +++ b/.github/workflows/release-github.yml @@ -0,0 +1,30 @@ +name: release-github + +on: + push: + tags: + - v* + +jobs: + build: + name: Release Notation Binaries + runs-on: ubuntu-20.04 + strategy: + matrix: + go-version: [1.17] + fail-fast: true + steps: + - name: Set up Go ${{ matrix.go-version }} + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + - name: Checkout + uses: actions/checkout@v2 + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v2 + with: + distribution: goreleaser + version: latest + args: release --rm-dist + env: + GITHUB_TOKEN: ${{ secrets.RELEASE_GITHUB_USER_TOKEN }} diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 000000000..4409cda36 --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,59 @@ +builds: + - main: ./cmd/notation + id: notation + binary: notation + env: + - CGO_ENABLED=0 + goos: + - linux + - darwin + - windows + goarch: + - amd64 + - arm64 + ignore: + - goos: windows + goarch: arm64 + ldflags: + - -s -w -X {{.ModulePath}}/internal/version.Version={{.Version}} -X {{.ModulePath}}/internal/version.BuildMetadata= + - main: ./cmd/docker-notation + id: docker-notation + binary: docker-notation + env: + - CGO_ENABLED=0 + goos: + - linux + - darwin + - windows + goarch: + - amd64 + - arm64 + ignore: + - goos: windows + goarch: arm64 + ldflags: + - -s -w -X {{.ModulePath}}/internal/version.Version={{.Version}} -X {{.ModulePath}}/internal/version.BuildMetadata= + - main: ./cmd/docker-generate + id: docker-generate + binary: docker-generate + env: + - CGO_ENABLED=0 + goos: + - linux + - darwin + - windows + goarch: + - amd64 + - arm64 + ignore: + - goos: windows + goarch: arm64 + ldflags: + - -s -w +archives: + - format: tar.gz + format_overrides: + - goos: windows + format: zip + files: + - LICENSE diff --git a/Makefile b/Makefile index cb386d446..a691e2c89 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,17 @@ -GO_BUILD_FLAGS = -DOCKER_PLUGINS = docker-generate docker-nv2 -COMMANDS = nv2 $(DOCKER_PLUGINS) - -define BUILD_BINARY = - go build $(GO_BUILD_FLAGS) -o $@ ./$< -endef +MODULE = github.com/notaryproject/notation +DOCKER_PLUGINS = docker-generate docker-notation +COMMANDS = notation $(DOCKER_PLUGINS) +GIT_TAG = $(shell git describe --tags --abbrev=0 --exact-match 2>/dev/null) +BUILD_METADATA = +ifeq ($(GIT_TAG),) # unreleased build + GIT_COMMIT = $(shell git rev-parse HEAD) + GIT_STATUS = $(shell test -n "`git status --porcelain`" && echo "dirty" || echo "unreleased") + BUILD_METADATA = $(GIT_COMMIT).$(GIT_STATUS) +endif +LDFLAGS = -X $(MODULE)/internal/version.BuildMetadata=$(BUILD_METADATA) +GO_BUILD_FLAGS = --ldflags="$(LDFLAGS)" .PHONY: help - help: @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-25s\033[0m %s\n", $$1, $$2}' @@ -18,7 +22,7 @@ all: build FORCE: bin/%: cmd/% FORCE - $(BUILD_BINARY) + go build $(GO_BUILD_FLAGS) -o $@ ./$< .PHONY: download download: ## download dependencies via go mod @@ -44,10 +48,10 @@ vendor: ## vendores the go modules GO111MODULE=on go mod vendor .PHONY: install -install: install-nv2 install-docker-plugins +install: install-notation install-docker-plugins ## install the notation cli and docker plugins -.PHONY: install-nv2 -install-nv2: bin/nv2 +.PHONY: install-notation +install-notation: bin/notation ## installs the notation cli cp $< ~/bin/ .PHONY: install-docker-% diff --git a/cmd/docker-generate/manifest.go b/cmd/docker-generate/manifest.go index c593c14ae..c93a33b9c 100644 --- a/cmd/docker-generate/manifest.go +++ b/cmd/docker-generate/manifest.go @@ -5,7 +5,7 @@ import ( "os" "os/exec" - "github.com/notaryproject/nv2/pkg/docker" + "github.com/notaryproject/notation/pkg/docker" "github.com/urfave/cli/v2" ) diff --git a/cmd/docker-generate/metadata.go b/cmd/docker-generate/metadata.go index 9ddc8f16d..66750d8de 100644 --- a/cmd/docker-generate/metadata.go +++ b/cmd/docker-generate/metadata.go @@ -4,19 +4,20 @@ import ( "encoding/json" "os" + "github.com/notaryproject/notation/internal/docker" "github.com/urfave/cli/v2" ) -var pluginMetadata = map[string]interface{}{ - "SchemaVersion": "0.1.0", - "Vendor": "github.com/shizhMSFT", - "Version": "0.1.0", - "ShortDescription": "Generate artifacts", - "Experimental": true, +var pluginMetadata = docker.PluginMetadata{ + SchemaVersion: "0.1.0", + Vendor: "github.com/shizhMSFT", + Version: "0.1.0", + ShortDescription: "Generate artifacts", + Experimental: true, } var metadataCommand = &cli.Command{ - Name: "docker-cli-plugin-metadata", + Name: docker.PluginMetadataCommandName, Action: func(ctx *cli.Context) error { writer := json.NewEncoder(os.Stdout) return writer.Encode(pluginMetadata) diff --git a/cmd/docker-nv2/crypto/service.go b/cmd/docker-notation/crypto/service.go similarity index 71% rename from cmd/docker-nv2/crypto/service.go rename to cmd/docker-notation/crypto/service.go index 5e9617128..784bd14cd 100644 --- a/cmd/docker-nv2/crypto/service.go +++ b/cmd/docker-notation/crypto/service.go @@ -4,13 +4,13 @@ import ( "crypto/x509" "github.com/docker/libtrust" - "github.com/notaryproject/notary/v2" - x509nv2 "github.com/notaryproject/notary/v2/signature/x509" - "github.com/notaryproject/notary/v2/simple" + "github.com/notaryproject/notation-go-lib" + x509n "github.com/notaryproject/notation-go-lib/signature/x509" + "github.com/notaryproject/notation-go-lib/simple" ) // GetSigningService returns a signing service -func GetSigningService(keyPath string, certPaths ...string) (notary.SigningService, error) { +func GetSigningService(keyPath string, certPaths ...string) (notation.SigningService, error) { var ( key libtrust.PrivateKey commonCerts []*x509.Certificate @@ -18,7 +18,7 @@ func GetSigningService(keyPath string, certPaths ...string) (notary.SigningServi err error ) if keyPath != "" { - key, err = x509nv2.ReadPrivateKeyFile(keyPath) + key, err = x509n.ReadPrivateKeyFile(keyPath) if err != nil { return nil, err } @@ -26,7 +26,7 @@ func GetSigningService(keyPath string, certPaths ...string) (notary.SigningServi if len(certPaths) != 0 { rootCerts = x509.NewCertPool() for _, certPath := range certPaths { - certs, err := x509nv2.ReadCertificateFile(certPath) + certs, err := x509n.ReadCertificateFile(certPath) if err != nil { return nil, err } diff --git a/cmd/docker-nv2/docker/credential.go b/cmd/docker-notation/docker/credential.go similarity index 100% rename from cmd/docker-nv2/docker/credential.go rename to cmd/docker-notation/docker/credential.go diff --git a/cmd/docker-nv2/docker/manifest.go b/cmd/docker-notation/docker/manifest.go similarity index 69% rename from cmd/docker-nv2/docker/manifest.go rename to cmd/docker-notation/docker/manifest.go index 05ec9cb8d..952e61db9 100644 --- a/cmd/docker-nv2/docker/manifest.go +++ b/cmd/docker-notation/docker/manifest.go @@ -9,11 +9,11 @@ import ( "strconv" "strings" - "github.com/docker/distribution/manifest/schema2" - "github.com/notaryproject/nv2/cmd/docker-nv2/config" - "github.com/notaryproject/nv2/pkg/docker" + "github.com/distribution/distribution/v3/manifest/schema2" + "github.com/notaryproject/notation/pkg/config" + "github.com/notaryproject/notation/pkg/docker" "github.com/opencontainers/go-digest" - oci "github.com/opencontainers/image-spec/specs-go/v1" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) // GenerateManifest generate manifest from docker save @@ -36,12 +36,12 @@ func GenerateManifest(reference string) ([]byte, error) { } // GenerateManifestOCIDescriptor generate manifest descriptor from docker save -func GenerateManifestOCIDescriptor(reference string) (oci.Descriptor, error) { +func GenerateManifestOCIDescriptor(reference string) (ocispec.Descriptor, error) { manifest, err := GenerateManifest(reference) if err != nil { - return oci.Descriptor{}, err + return ocispec.Descriptor{}, err } - return oci.Descriptor{ + return ocispec.Descriptor{ MediaType: schema2.MediaTypeManifest, Digest: digest.FromBytes(manifest), Size: int64(len(manifest)), @@ -49,10 +49,10 @@ func GenerateManifestOCIDescriptor(reference string) (oci.Descriptor, error) { } // GetManifestOCIDescriptor get manifest descriptor from remote registry -func GetManifestOCIDescriptor(ctx context.Context, hostname, repository, ref string) (oci.Descriptor, error) { +func GetManifestOCIDescriptor(ctx context.Context, hostname, repository, ref string) (ocispec.Descriptor, error) { tr, err := Transport(hostname) if err != nil { - return oci.Descriptor{}, err + return ocispec.Descriptor{}, err } scheme := "https" @@ -70,42 +70,42 @@ func GetManifestOCIDescriptor(ctx context.Context, hostname, repository, ref str ) req, err := http.NewRequest(http.MethodHead, url, nil) if err != nil { - return oci.Descriptor{}, err + return ocispec.Descriptor{}, err } req.Header.Set("Connection", "close") req.Header.Set("Accept", schema2.MediaTypeManifest) resp, err := tr.RoundTrip(req) if err != nil { - return oci.Descriptor{}, fmt.Errorf("%v: %v", url, err) + return ocispec.Descriptor{}, fmt.Errorf("%v: %v", url, err) } resp.Body.Close() if resp.StatusCode != http.StatusOK { - return oci.Descriptor{}, fmt.Errorf("%v: %s", url, resp.Status) + return ocispec.Descriptor{}, fmt.Errorf("%v: %s", url, resp.Status) } header := resp.Header mediaType := header.Get("Content-Type") if mediaType != schema2.MediaTypeManifest { - return oci.Descriptor{}, fmt.Errorf("%v: media type mismatch: %s", url, mediaType) + return ocispec.Descriptor{}, fmt.Errorf("%v: media type mismatch: %s", url, mediaType) } contentDigest := header.Get("Docker-Content-Digest") if contentDigest == "" { - return oci.Descriptor{}, fmt.Errorf("%v: missing Docker-Content-Digest", url) + return ocispec.Descriptor{}, fmt.Errorf("%v: missing Docker-Content-Digest", url) } parsedDigest, err := digest.Parse(contentDigest) if err != nil { - return oci.Descriptor{}, fmt.Errorf("%v: invalid Docker-Content-Digest: %s", url, contentDigest) + return ocispec.Descriptor{}, fmt.Errorf("%v: invalid Docker-Content-Digest: %s", url, contentDigest) } length := header.Get("Content-Length") if length == "" { - return oci.Descriptor{}, fmt.Errorf("%v: missing Content-Length", url) + return ocispec.Descriptor{}, fmt.Errorf("%v: missing Content-Length", url) } size, err := strconv.ParseInt(length, 10, 64) if err != nil { - return oci.Descriptor{}, fmt.Errorf("%v: invalid Content-Length", url) + return ocispec.Descriptor{}, fmt.Errorf("%v: invalid Content-Length", url) } - return oci.Descriptor{ + return ocispec.Descriptor{ MediaType: schema2.MediaTypeManifest, Digest: parsedDigest, Size: size, diff --git a/cmd/docker-nv2/docker/network.go b/cmd/docker-notation/docker/network.go similarity index 89% rename from cmd/docker-nv2/docker/network.go rename to cmd/docker-notation/docker/network.go index b2f65c95b..5ed12ad48 100644 --- a/cmd/docker-nv2/docker/network.go +++ b/cmd/docker-notation/docker/network.go @@ -3,7 +3,7 @@ package docker import ( "net/http" - "github.com/notaryproject/nv2/pkg/registry" + "github.com/notaryproject/notation/pkg/registry" ) // Transport returns the configured round tripper for a host diff --git a/cmd/docker-nv2/docker/signature.go b/cmd/docker-notation/docker/signature.go similarity index 72% rename from cmd/docker-nv2/docker/signature.go rename to cmd/docker-notation/docker/signature.go index a84b4362b..6f38c1e2f 100644 --- a/cmd/docker-nv2/docker/signature.go +++ b/cmd/docker-notation/docker/signature.go @@ -4,14 +4,14 @@ import ( "context" "net" - "github.com/docker/distribution/reference" - "github.com/notaryproject/notary/v2" - "github.com/notaryproject/notary/v2/registry" - "github.com/notaryproject/nv2/cmd/docker-nv2/config" + "github.com/distribution/distribution/v3/reference" + "github.com/notaryproject/notation-go-lib" + "github.com/notaryproject/notation-go-lib/registry" + "github.com/notaryproject/notation/pkg/config" ) // GetSignatureRepository returns a signature repository -func GetSignatureRepository(ctx context.Context, ref string) (notary.SignatureRepository, error) { +func GetSignatureRepository(ctx context.Context, ref string) (notation.SignatureRepository, error) { named, err := reference.ParseNamed(ref) if err != nil { return nil, err diff --git a/cmd/docker-nv2/main.go b/cmd/docker-notation/main.go similarity index 92% rename from cmd/docker-nv2/main.go rename to cmd/docker-notation/main.go index fbb240feb..cf38128a1 100644 --- a/cmd/docker-nv2/main.go +++ b/cmd/docker-notation/main.go @@ -11,7 +11,7 @@ func main() { app := &cli.App{ Name: "docker", Commands: []*cli.Command{ - nv2Command, + notationCommand, metadataCommand, }, } diff --git a/cmd/docker-notation/metadata.go b/cmd/docker-notation/metadata.go new file mode 100644 index 000000000..c093f61c7 --- /dev/null +++ b/cmd/docker-notation/metadata.go @@ -0,0 +1,27 @@ +package main + +import ( + "encoding/json" + "os" + + "github.com/notaryproject/notation/internal/docker" + "github.com/notaryproject/notation/internal/version" + "github.com/urfave/cli/v2" +) + +var pluginMetadata = docker.PluginMetadata{ + SchemaVersion: "0.1.0", + Vendor: "Sajay Antony, Shiwei Zhang", + Version: version.GetVersion(), + ShortDescription: "Manage signatures on Docker images", + URL: "https://github.com/notaryproject/notation", +} + +var metadataCommand = &cli.Command{ + Name: docker.PluginMetadataCommandName, + Action: func(ctx *cli.Context) error { + writer := json.NewEncoder(os.Stdout) + return writer.Encode(pluginMetadata) + }, + Hidden: true, +} diff --git a/cmd/docker-notation/notation.go b/cmd/docker-notation/notation.go new file mode 100644 index 000000000..c5f02a14b --- /dev/null +++ b/cmd/docker-notation/notation.go @@ -0,0 +1,43 @@ +package main + +import ( + "os" + + "github.com/notaryproject/notation/pkg/config" + "github.com/urfave/cli/v2" +) + +var notationCommand = &cli.Command{ + Name: "notation", + Usage: pluginMetadata.ShortDescription, + Subcommands: []*cli.Command{ + pullCommand, + pushCommand, + signCommand, + }, + Flags: []cli.Flag{ + notationEnabledFlag, + }, + Action: setNotation, +} + +var notationEnabledFlag = &cli.BoolFlag{ + Name: "enabled", + Usage: "Enable Notation support", +} + +func setNotation(ctx *cli.Context) error { + if !ctx.IsSet(notationEnabledFlag.Name) { + return cli.ShowCommandHelp(ctx, ctx.Command.Name) + } + + cfg, err := config.Load() + if err != nil { + if !os.IsNotExist(err) { + return err + } + cfg = config.New() + } + cfg.Enabled = ctx.Bool(notationEnabledFlag.Name) + return cfg.Save() +} diff --git a/cmd/docker-nv2/pull.go b/cmd/docker-notation/pull.go similarity index 87% rename from cmd/docker-nv2/pull.go rename to cmd/docker-notation/pull.go index 035ba173c..4d2206614 100644 --- a/cmd/docker-nv2/pull.go +++ b/cmd/docker-notation/pull.go @@ -6,13 +6,13 @@ import ( "fmt" "os" - "github.com/docker/distribution/reference" - "github.com/notaryproject/notary/v2" - "github.com/notaryproject/nv2/cmd/docker-nv2/config" - "github.com/notaryproject/nv2/cmd/docker-nv2/docker" - ios "github.com/notaryproject/nv2/internal/os" + "github.com/distribution/distribution/v3/reference" + "github.com/notaryproject/notation-go-lib" + "github.com/notaryproject/notation/cmd/docker-notation/docker" + ios "github.com/notaryproject/notation/internal/os" + "github.com/notaryproject/notation/pkg/config" "github.com/opencontainers/go-digest" - oci "github.com/opencontainers/image-spec/specs-go/v1" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/urfave/cli/v2" ) @@ -24,7 +24,7 @@ var pullCommand = &cli.Command{ } func pullImage(ctx *cli.Context) error { - if err := passThroughIfNotaryDisabled(ctx); err != nil { + if err := passThroughIfNotationDisabled(ctx); err != nil { return err } @@ -123,9 +123,9 @@ func downloadSignatures(ctx context.Context, ref string, manifestDigest digest.D func verifySignatures( ctx context.Context, - service notary.SigningService, + service notation.SigningService, digests []digest.Digest, - desc oci.Descriptor, + desc ocispec.Descriptor, ) (digest.Digest, []string, error) { var lastError error for _, digest := range digests { diff --git a/cmd/docker-nv2/push.go b/cmd/docker-notation/push.go similarity index 73% rename from cmd/docker-nv2/push.go rename to cmd/docker-notation/push.go index 7d93038c9..8c84a8a14 100644 --- a/cmd/docker-nv2/push.go +++ b/cmd/docker-notation/push.go @@ -10,11 +10,11 @@ import ( "strconv" "strings" - "github.com/docker/distribution/manifest/schema2" - "github.com/notaryproject/nv2/cmd/docker-nv2/config" - "github.com/notaryproject/nv2/cmd/docker-nv2/docker" + "github.com/distribution/distribution/v3/manifest/schema2" + "github.com/notaryproject/notation/cmd/docker-notation/docker" + "github.com/notaryproject/notation/pkg/config" "github.com/opencontainers/go-digest" - oci "github.com/opencontainers/image-spec/specs-go/v1" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/urfave/cli/v2" ) @@ -26,7 +26,7 @@ var pushCommand = &cli.Command{ } func pushImage(ctx *cli.Context) error { - if err := passThroughIfNotaryDisabled(ctx); err != nil { + if err := passThroughIfNotationDisabled(ctx); err != nil { return err } @@ -76,44 +76,44 @@ func pushImage(ctx *cli.Context) error { return nil } -func pushImageAndGetOCIDescriptor(ctx *cli.Context) (oci.Descriptor, error) { +func pushImageAndGetOCIDescriptor(ctx *cli.Context) (ocispec.Descriptor, error) { args := append([]string{"push"}, ctx.Args().Slice()...) cmd := exec.Command("docker", args...) cmd.Stdin = os.Stdin cmd.Stderr = os.Stderr stdout, err := cmd.StdoutPipe() if err != nil { - return oci.Descriptor{}, err + return ocispec.Descriptor{}, err } scanner := bufio.NewScanner(io.TeeReader(stdout, os.Stdout)) if err := cmd.Start(); err != nil { - return oci.Descriptor{}, err + return ocispec.Descriptor{}, err } var lastLine string for scanner.Scan() { lastLine = scanner.Text() } if err := scanner.Err(); err != nil { - return oci.Descriptor{}, err + return ocispec.Descriptor{}, err } if err := cmd.Wait(); err != nil { - return oci.Descriptor{}, err + return ocispec.Descriptor{}, err } parts := strings.Split(lastLine, " ") if len(parts) != 5 { - return oci.Descriptor{}, fmt.Errorf("invalid docker pull result: %s", lastLine) + return ocispec.Descriptor{}, fmt.Errorf("invalid docker pull result: %s", lastLine) } digest, err := digest.Parse(parts[2]) if err != nil { - return oci.Descriptor{}, fmt.Errorf("invalid digest: %s", lastLine) + return ocispec.Descriptor{}, fmt.Errorf("invalid digest: %s", lastLine) } size, err := strconv.ParseInt(parts[4], 10, 64) if err != nil { - return oci.Descriptor{}, fmt.Errorf("invalid size: %s", lastLine) + return ocispec.Descriptor{}, fmt.Errorf("invalid size: %s", lastLine) } - return oci.Descriptor{ + return ocispec.Descriptor{ MediaType: schema2.MediaTypeManifest, Digest: digest, Size: size, diff --git a/cmd/docker-nv2/notary_sign.go b/cmd/docker-notation/sign.go similarity index 80% rename from cmd/docker-nv2/notary_sign.go rename to cmd/docker-notation/sign.go index a3d7e00ab..44bd98153 100644 --- a/cmd/docker-nv2/notary_sign.go +++ b/cmd/docker-notation/sign.go @@ -3,15 +3,15 @@ package main import ( "fmt" - "github.com/notaryproject/nv2/cmd/docker-nv2/config" - "github.com/notaryproject/nv2/cmd/docker-nv2/crypto" - "github.com/notaryproject/nv2/cmd/docker-nv2/docker" - ios "github.com/notaryproject/nv2/internal/os" + "github.com/notaryproject/notation/cmd/docker-notation/crypto" + "github.com/notaryproject/notation/cmd/docker-notation/docker" + ios "github.com/notaryproject/notation/internal/os" + "github.com/notaryproject/notation/pkg/config" "github.com/opencontainers/go-digest" "github.com/urfave/cli/v2" ) -var notarySignCommand = &cli.Command{ +var signCommand = &cli.Command{ Name: "sign", Usage: "Sign a docker image", ArgsUsage: "[]", @@ -39,11 +39,11 @@ var notarySignCommand = &cli.Command{ Usage: "mark the current reference as a original reference", }, }, - Action: notarySign, + Action: signImage, } -func notarySign(ctx *cli.Context) error { - if err := config.CheckNotaryEnabled(); err != nil { +func signImage(ctx *cli.Context) error { + if err := config.CheckNotationEnabled(); err != nil { return err } diff --git a/cmd/docker-nv2/util.go b/cmd/docker-notation/util.go similarity index 55% rename from cmd/docker-nv2/util.go rename to cmd/docker-notation/util.go index 6ae917b4c..a3e7b0804 100644 --- a/cmd/docker-nv2/util.go +++ b/cmd/docker-notation/util.go @@ -4,18 +4,18 @@ import ( "os" "os/exec" - "github.com/notaryproject/notary/v2" - "github.com/notaryproject/nv2/cmd/docker-nv2/config" - "github.com/notaryproject/nv2/cmd/docker-nv2/crypto" + "github.com/notaryproject/notation-go-lib" + "github.com/notaryproject/notation/cmd/docker-notation/crypto" + "github.com/notaryproject/notation/pkg/config" "github.com/urfave/cli/v2" ) -func passThroughIfNotaryDisabled(ctx *cli.Context) error { - err := config.CheckNotaryEnabled() +func passThroughIfNotationDisabled(ctx *cli.Context) error { + err := config.CheckNotationEnabled() if err == nil { return nil } - if err != config.ErrNotaryDisabled { + if err != config.ErrNotationDisabled { return err } @@ -41,10 +41,14 @@ func runCommand(command string, args ...string) error { return nil } -func getVerificationService() (notary.SigningService, error) { +func getVerificationService() (notation.SigningService, error) { cfg, err := config.Load() if err != nil { return nil, err } - return crypto.GetSigningService("", cfg.VerificationCerts...) + var certPaths []string + for _, cert := range cfg.VerificationCertificates.Certificates { + certPaths = append(certPaths, cert.Path) + } + return crypto.GetSigningService("", certPaths...) } diff --git a/cmd/docker-nv2/config/config.go b/cmd/docker-nv2/config/config.go deleted file mode 100644 index 009028ad5..000000000 --- a/cmd/docker-nv2/config/config.go +++ /dev/null @@ -1,51 +0,0 @@ -package config - -import ( - "encoding/json" - "os" - "path/filepath" -) - -// File reflects the config file -type File struct { - Enabled bool `json:"enabled"` - VerificationCerts []string `json:"verificationCerts"` - InsecureRegistries []string `json:"insecureRegistries"` -} - -// New creates a new config file -func New() *File { - return &File{ - VerificationCerts: []string{}, - } -} - -// Save stores the config to file -func (f *File) Save() error { - dir := filepath.Dir(FilePath) - if err := os.MkdirAll(dir, 0700); err != nil { - return err - } - file, err := os.Create(FilePath) - if err != nil { - return err - } - defer file.Close() - encoder := json.NewEncoder(file) - encoder.SetIndent("", "\t") - return encoder.Encode(f) -} - -// Load reads the config from file -func Load() (*File, error) { - file, err := os.Open(FilePath) - if err != nil { - return nil, err - } - defer file.Close() - var config *File - if err := json.NewDecoder(file).Decode(&config); err != nil { - return nil, err - } - return config, nil -} diff --git a/cmd/docker-nv2/metadata.go b/cmd/docker-nv2/metadata.go deleted file mode 100644 index 2c91673e3..000000000 --- a/cmd/docker-nv2/metadata.go +++ /dev/null @@ -1,25 +0,0 @@ -package main - -import ( - "encoding/json" - "os" - - "github.com/urfave/cli/v2" -) - -var pluginMetadata = map[string]interface{}{ - "SchemaVersion": "0.1.0", - "Vendor": "Sajay Antony, Shiwei Zhang", - "Version": "0.2.3", - "ShortDescription": "Notary V2 Signature extension", - "URL": "https://github.com/notaryproject/nv2", -} - -var metadataCommand = &cli.Command{ - Name: "docker-cli-plugin-metadata", - Action: func(ctx *cli.Context) error { - writer := json.NewEncoder(os.Stdout) - return writer.Encode(pluginMetadata) - }, - Hidden: true, -} diff --git a/cmd/docker-nv2/notary.go b/cmd/docker-nv2/notary.go deleted file mode 100644 index 4b3851f5a..000000000 --- a/cmd/docker-nv2/notary.go +++ /dev/null @@ -1,40 +0,0 @@ -package main - -import ( - "os" - - "github.com/notaryproject/nv2/cmd/docker-nv2/config" - "github.com/urfave/cli/v2" -) - -var notaryCommand = &cli.Command{ - Name: "notary", - Subcommands: []*cli.Command{ - notarySignCommand, - }, - Flags: []cli.Flag{ - notaryEnabledFlag, - }, - Action: setNotary, -} - -var notaryEnabledFlag = &cli.BoolFlag{ - Name: "enabled", - Usage: "Enable Notary support", -} - -func setNotary(ctx *cli.Context) error { - if !ctx.IsSet(notaryEnabledFlag.Name) { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - - cfg, err := config.Load() - if err != nil { - if !os.IsNotExist(err) { - return err - } - cfg = config.New() - } - cfg.Enabled = ctx.Bool(notaryEnabledFlag.Name) - return cfg.Save() -} diff --git a/cmd/docker-nv2/nv2.go b/cmd/docker-nv2/nv2.go deleted file mode 100644 index 31b7d6732..000000000 --- a/cmd/docker-nv2/nv2.go +++ /dev/null @@ -1,32 +0,0 @@ -package main - -import ( - "os" - "os/exec" - - "github.com/urfave/cli/v2" -) - -var nv2Command = &cli.Command{ - Name: "nv2", - Subcommands: []*cli.Command{ - notaryCommand, - pullCommand, - pushCommand, - }, - Action: delegateToDocker, -} - -func delegateToDocker(ctx *cli.Context) error { - cmd := exec.Command("docker", ctx.Args().Slice()...) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - if err, ok := err.(*exec.ExitError); ok { - os.Exit(err.ExitCode()) - } - return err - } - return nil -} diff --git a/cmd/notation/cache.go b/cmd/notation/cache.go new file mode 100644 index 000000000..4455030ed --- /dev/null +++ b/cmd/notation/cache.go @@ -0,0 +1,232 @@ +package main + +import ( + "errors" + "fmt" + "io/fs" + "os" + "path/filepath" + "strings" + + "github.com/notaryproject/notation/pkg/config" + "github.com/notaryproject/notation/pkg/registry" + "github.com/opencontainers/go-digest" + "github.com/urfave/cli/v2" +) + +var ( + cacheCommand = &cli.Command{ + Name: "cache", + Usage: "Manage signature cache", + Subcommands: []*cli.Command{ + cacheListCommand, + cachePruneCommand, + cacheRemoveCommand, + }, + } + + cacheListCommand = &cli.Command{ + Name: "list", + Usage: "List signatures in cache", + Aliases: []string{"ls"}, + Flags: []cli.Flag{ + localFlag, + usernameFlag, + passwordFlag, + plainHTTPFlag, + }, + ArgsUsage: "[reference|manifest_digest]", + Action: listCachedSignatures, + } + + cachePruneCommand = &cli.Command{ + Name: "prune", + Usage: "Prune signature from cache", + ArgsUsage: "[reference|manifest_digest] ...", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "all", + Aliases: []string{"a"}, + Usage: "prune all cached signatures", + }, + &cli.BoolFlag{ + Name: "force", + Aliases: []string{"f"}, + Usage: "prune entire directory, combined with --all", + }, + localFlag, + usernameFlag, + passwordFlag, + plainHTTPFlag, + }, + Action: pruneCachedSignatures, + } + + cacheRemoveCommand = &cli.Command{ + Name: "remove", + Usage: "Remove signature from cache", + Aliases: []string{"rm"}, + ArgsUsage: " ...", + Flags: []cli.Flag{ + localFlag, + usernameFlag, + passwordFlag, + plainHTTPFlag, + }, + Action: removeCachedSignatures, + } +) + +func listCachedSignatures(ctx *cli.Context) error { + if !ctx.Args().Present() { + return listManifestsWithCachedSignature() + } + + manifestDigest, err := getManifestDigestFromContext(ctx, ctx.Args().First()) + if err != nil { + return err + } + + fmt.Println("SIGNATURE") + return walkCachedSignatureTree( + config.SignatureRootPath(manifestDigest), + func(algorithm string, value fs.DirEntry) error { + if strings.HasSuffix(value.Name(), config.SignatureExtension) { + encoded := strings.TrimSuffix(value.Name(), config.SignatureExtension) + fmt.Printf("%s:%s\n", algorithm, encoded) + } + return nil + }) +} + +func listManifestsWithCachedSignature() error { + fmt.Println("MANIFEST") + return walkCachedSignatureTree( + config.SignatureStoreDirPath, + func(algorithm string, value fs.DirEntry) error { + if value.IsDir() { + fmt.Printf("%s:%s\n", algorithm, value.Name()) + } + return nil + }) +} + +func pruneCachedSignatures(ctx *cli.Context) error { + if ctx.Bool("all") { + if err := walkCachedSignatureTree( + config.SignatureStoreDirPath, + func(algorithm string, value fs.DirEntry) error { + if !value.IsDir() { + return nil + } + manifestDigest := digest.NewDigestFromEncoded(digest.Algorithm(algorithm), value.Name()) + if err := os.RemoveAll(config.SignatureRootPath(manifestDigest)); err != nil { + return err + } + + // write out + fmt.Println(manifestDigest) + return nil + }, + ); err != nil { + return err + } + if ctx.Bool("force") { + return os.RemoveAll(config.SignatureStoreDirPath) + } + return nil + } + + if !ctx.Args().Present() { + return errors.New("nothing to prune") + } + for _, ref := range ctx.Args().Slice() { + manifestDigest, err := getManifestDigestFromContext(ctx, ref) + if err != nil { + return err + } + if err := os.RemoveAll(config.SignatureRootPath(manifestDigest)); err != nil { + return err + } + + // write out + fmt.Println(manifestDigest) + + } + return nil +} + +func removeCachedSignatures(ctx *cli.Context) error { + // initialize + sigDigests := ctx.Args().Slice() + if len(sigDigests) == 0 { + return errors.New("missing target manifest") + } + sigDigests = sigDigests[1:] + if len(sigDigests) == 0 { + return errors.New("no signature specified") + } + + manifestDigest, err := getManifestDigestFromContext(ctx, ctx.Args().First()) + if err != nil { + return err + } + + // core process + for _, sigDigest := range sigDigests { + path := config.SignaturePath(manifestDigest, digest.Digest(sigDigest)) + if err := os.Remove(path); err != nil { + return err + } + + // write out + fmt.Println(sigDigest) + } + + return nil +} + +func walkCachedSignatureTree(root string, fn func(algorithm string, encodedEntry fs.DirEntry) error) error { + algorithms, err := os.ReadDir(root) + if err != nil { + if os.IsNotExist(err) { + return nil + } + return err + } + for _, alg := range algorithms { + if !alg.IsDir() { + continue + } + encodedEntries, err := os.ReadDir(filepath.Join(root, alg.Name())) + if err != nil { + return err + } + for _, encodedEntry := range encodedEntries { + if err := fn(alg.Name(), encodedEntry); err != nil { + return err + } + } + } + return nil +} + +func getManifestDigestFromContext(ctx *cli.Context, ref string) (manifestDigest digest.Digest, err error) { + manifestDigest, err = digest.Parse(ref) + if err == nil { + return + } + + reference := registry.ParseReference(ref) + manifestDigest, err = reference.Digest() + if err == nil { + return + } + + manifest, err := getManifestFromContextWithReference(ctx, ref) + if err != nil { + return + } + manifestDigest = digest.Digest(manifest.Digest) + return +} diff --git a/cmd/notation/cert.go b/cmd/notation/cert.go new file mode 100644 index 000000000..0b0a969f4 --- /dev/null +++ b/cmd/notation/cert.go @@ -0,0 +1,192 @@ +package main + +import ( + "errors" + "fmt" + "path/filepath" + "time" + + "github.com/notaryproject/notation-go-lib/signature/x509" + "github.com/notaryproject/notation/pkg/config" + "github.com/urfave/cli/v2" +) + +var ( + certCommand = &cli.Command{ + Name: "certificate", + Aliases: []string{"cert"}, + Usage: "Manage certificates used for verification", + Subcommands: []*cli.Command{ + certAddCommand, + certListCommand, + certRemoveCommand, + certGenerateTestCommand, + }, + } + + certAddCommand = &cli.Command{ + Name: "add", + Usage: "Add certificate to verification list", + ArgsUsage: "", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "name", + Aliases: []string{"n"}, + Usage: "certificate name", + }, + }, + Action: addCert, + } + + certListCommand = &cli.Command{ + Name: "list", + Usage: "List certificates used for verification", + Aliases: []string{"ls"}, + Action: listCerts, + } + + certRemoveCommand = &cli.Command{ + Name: "remove", + Usage: "Remove certificate from verification list", + Aliases: []string{"rm"}, + ArgsUsage: " ...", + Action: removeCerts, + } + + certGenerateTestCommand = &cli.Command{ + Name: "generate-test", + Usage: "Generates a test RSA key and a corresponding self-signed certificate", + ArgsUsage: " ...", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "name", + Aliases: []string{"n"}, + Usage: "key and certificate name", + }, + &cli.IntFlag{ + Name: "bits", + Usage: "RSA key bits", + Aliases: []string{"b"}, + Value: 2048, + }, + &cli.DurationFlag{ + Name: "expiry", + Aliases: []string{"e"}, + Usage: "certificate expiry", + Value: 365 * 24 * time.Hour, + }, + keyDefaultFlag, + }, + Action: generateTestCert, + } +) + +func addCert(ctx *cli.Context) error { + // initialize + path := ctx.Args().First() + if path == "" { + return errors.New("missing certificate path") + } + path, err := filepath.Abs(path) + if err != nil { + return err + } + name := ctx.String("name") + if name == "" { + name = nameFromPath(path) + } + + // check if the target path is a cert + if _, err := x509.ReadCertificateFile(path); err != nil { + return err + } + + // core process + cfg, err := config.LoadOrDefault() + if err != nil { + return err + } + if err := addCertCore(cfg, name, path); err != nil { + return err + } + if err := cfg.Save(); err != nil { + return err + } + + // write out + fmt.Println(name) + return nil +} + +func addCertCore(cfg *config.File, name, path string) error { + if ok := cfg.VerificationCertificates.Certificates.Append(name, path); !ok { + return errors.New(name + ": already exists") + } + return nil +} + +func listCerts(ctx *cli.Context) error { + // core process + cfg, err := config.LoadOrDefault() + if err != nil { + return err + } + + // write out + printCertificateSet(cfg.VerificationCertificates.Certificates) + return nil +} + +func removeCerts(ctx *cli.Context) error { + // initialize + names := ctx.Args().Slice() + if len(names) == 0 { + return errors.New("missing certificate names") + } + + // core process + cfg, err := config.LoadOrDefault() + if err != nil { + return err + } + + var removedNames []string + for _, name := range names { + if ok := cfg.VerificationCertificates.Certificates.Remove(name); !ok { + return errors.New(name + ": not found") + } + removedNames = append(removedNames, name) + } + if err := cfg.Save(); err != nil { + return err + } + + // write out + for _, name := range removedNames { + fmt.Println(name) + } + return nil +} + +func printCertificateSet(s config.FileSet) { + maxNameSize := 0 + for _, ref := range s { + if len(ref.Name) > maxNameSize { + maxNameSize = len(ref.Name) + } + } + format := fmt.Sprintf("%%-%ds\t%%s\n", maxNameSize) + fmt.Printf(format, "NAME", "PATH") + for _, ref := range s { + fmt.Printf(format, ref.Name, ref.Path) + } +} + +func nameFromPath(path string) string { + base := filepath.Base(path) + name := base[:len(base)-len(filepath.Ext(base))] + if name == "" { + return base + } + return name +} diff --git a/cmd/notation/cert_gen.go b/cmd/notation/cert_gen.go new file mode 100644 index 000000000..b968ad8ce --- /dev/null +++ b/cmd/notation/cert_gen.go @@ -0,0 +1,133 @@ +package main + +import ( + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "errors" + "fmt" + "math/big" + "net" + "time" + + "github.com/notaryproject/notation/internal/os" + "github.com/notaryproject/notation/pkg/config" + "github.com/urfave/cli/v2" +) + +func generateTestCert(ctx *cli.Context) error { + // initialize + hosts := ctx.Args().Slice() + if len(hosts) == 0 { + return errors.New("missing certificate hosts") + } + name := ctx.String("name") + if name == "" { + name = hosts[0] + } + + // generate RSA private key + bits := ctx.Int("bits") + fmt.Println("generating RSA Key with", bits, "bits") + key, keyBytes, err := generateTestKey(bits) + if err != nil { + return err + } + + // generate self-signed certificate + cert, certBytes, err := generateTestSelfSignedCert(key, hosts, ctx.Duration("expiry")) + if err != nil { + return err + } + fmt.Println("generated certificates expiring on", cert.NotAfter.Format(time.RFC3339)) + + // write private key + keyPath := config.KeyPath(name) + if err := os.WriteFileWithPermission(keyPath, keyBytes, 0600, false); err != nil { + return fmt.Errorf("failed to write key file: %v", err) + } + fmt.Println("wrote key:", keyPath) + + // write self-signed certificate + certPath := config.CertificatePath(name) + if err := os.WriteFileWithPermission(certPath, certBytes, 0644, false); err != nil { + return fmt.Errorf("failed to write certificate file: %v", err) + } + fmt.Println("wrote certificate:", certPath) + + // update config + cfg, err := config.LoadOrDefault() + if err != nil { + return err + } + isDefaultKey, err := addKeyCore(cfg, name, keyPath, ctx.Bool(keyDefaultFlag.Name)) + if err != nil { + return err + } + if err := addCertCore(cfg, name, certPath); err != nil { + return err + } + if err := cfg.Save(); err != nil { + return err + } + + // write out + fmt.Printf("%s: added to key and certificate lists\n", name) + if isDefaultKey { + fmt.Printf("%s: marked as default\n", name) + } + return nil +} + +func generateTestKey(bits int) (crypto.Signer, []byte, error) { + key, err := rsa.GenerateKey(rand.Reader, bits) + if err != nil { + return nil, nil, err + } + keyBytes, err := x509.MarshalPKCS8PrivateKey(key) + if err != nil { + return nil, nil, err + } + keyPEM := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes}) + return key, keyPEM, nil +} + +func generateTestSelfSignedCert(key crypto.Signer, hosts []string, expiry time.Duration) (*x509.Certificate, []byte, error) { + now := time.Now() + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + if err != nil { + return nil, nil, fmt.Errorf("failed to generate serial number: %v", err) + } + template := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + CommonName: hosts[0], + }, + NotBefore: now, + NotAfter: now.Add(expiry), + KeyUsage: x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning}, + BasicConstraintsValid: true, + } + for _, host := range hosts { + if ip := net.ParseIP(host); ip != nil { + template.IPAddresses = append(template.IPAddresses, ip) + } else { + template.DNSNames = append(template.DNSNames, host) + } + } + certBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, key.Public(), key) + if err != nil { + return nil, nil, fmt.Errorf("failed to create certificate: %v", err) + } + cert, err := x509.ParseCertificate(certBytes) + if err != nil { + return nil, nil, fmt.Errorf("generated invalid certificate: %v", err) + } + certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certBytes}) + return cert, certPEM, nil +} diff --git a/cmd/nv2/common.go b/cmd/notation/common.go similarity index 68% rename from cmd/nv2/common.go rename to cmd/notation/common.go index 42d8a1ec4..bd1d552f3 100644 --- a/cmd/nv2/common.go +++ b/cmd/notation/common.go @@ -7,13 +7,13 @@ var ( Name: "username", Aliases: []string{"u"}, Usage: "username for generic remote access", - EnvVars: []string{"NV2_USERNAME"}, + EnvVars: []string{"NOTATION_USERNAME"}, } passwordFlag = &cli.StringFlag{ Name: "password", Aliases: []string{"p"}, Usage: "password for generic remote access", - EnvVars: []string{"NV2_PASSWORD"}, + EnvVars: []string{"NOTATION_PASSWORD"}, } plainHTTPFlag = &cli.BoolFlag{ Name: "plain-http", @@ -29,4 +29,15 @@ var ( Aliases: []string{"o"}, Usage: "write signature to a specific path", } + localFlag = &cli.BoolFlag{ + Name: "local", + Aliases: []string{"l"}, + Usage: "reference is a local file", + } + signatureFlag = &cli.StringSliceFlag{ + Name: "signature", + Aliases: []string{"s", "f"}, + Usage: "signature files", + TakesFile: true, + } ) diff --git a/cmd/notation/key.go b/cmd/notation/key.go new file mode 100644 index 000000000..9ea969313 --- /dev/null +++ b/cmd/notation/key.go @@ -0,0 +1,227 @@ +package main + +import ( + "errors" + "fmt" + "path/filepath" + + "github.com/notaryproject/notation-go-lib/signature/x509" + "github.com/notaryproject/notation/pkg/config" + "github.com/urfave/cli/v2" +) + +var ( + keyCommand = &cli.Command{ + Name: "key", + Usage: "Manage keys used for signing", + Subcommands: []*cli.Command{ + keyAddCommand, + keyUpdateCommand, + keyListCommand, + keyRemoveCommand, + }, + } + + keyDefaultFlag = &cli.BoolFlag{ + Name: "default", + Aliases: []string{"d"}, + Usage: "mark as default", + } + + keyAddCommand = &cli.Command{ + Name: "add", + Usage: "Add key to signing key list", + ArgsUsage: "", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "name", + Aliases: []string{"n"}, + Usage: "key name", + }, + keyDefaultFlag, + }, + Action: addKey, + } + + keyUpdateCommand = &cli.Command{ + Name: "update", + Usage: "Update key in signing key list", + Aliases: []string{"set"}, + ArgsUsage: "", + Flags: []cli.Flag{ + keyDefaultFlag, + }, + Action: updateKey, + } + + keyListCommand = &cli.Command{ + Name: "list", + Usage: "List keys used for signing", + Aliases: []string{"ls"}, + Action: listKeys, + } + + keyRemoveCommand = &cli.Command{ + Name: "remove", + Usage: "Remove key from signing key list", + Aliases: []string{"rm"}, + ArgsUsage: "[name] ...", + Action: removeKeys, + } +) + +func addKey(ctx *cli.Context) error { + // initialize + path := ctx.Args().First() + if path == "" { + return errors.New("missing key path") + } + path, err := filepath.Abs(path) + if err != nil { + return err + } + name := ctx.String("name") + if name == "" { + name = nameFromPath(path) + } + + // check if the target path is a key + if _, err := x509.ReadPrivateKeyFile(path); err != nil { + return err + } + + // core process + cfg, err := config.LoadOrDefault() + if err != nil { + return err + } + isDefault, err := addKeyCore(cfg, name, path, ctx.Bool(keyDefaultFlag.Name)) + if err != nil { + return err + } + if err := cfg.Save(); err != nil { + return err + } + + // write out + if isDefault { + fmt.Printf("%s: marked as default\n", name) + } else { + fmt.Println(name) + } + return nil +} + +func addKeyCore(cfg *config.File, name, path string, markDefault bool) (bool, error) { + if ok := cfg.SigningKeys.Keys.Append(name, path); !ok { + return false, errors.New(name + ": already exists") + } + if markDefault { + cfg.SigningKeys.Default = name + } + return cfg.SigningKeys.Default == name, nil +} + +func updateKey(ctx *cli.Context) error { + // initialize + name := ctx.Args().First() + if name == "" { + return errors.New("missing key name") + } + + // core process + cfg, err := config.LoadOrDefault() + if err != nil { + return err + } + if _, ok := cfg.SigningKeys.Keys.Get(name); !ok { + return errors.New(name + ": not found") + } + if !ctx.Bool(keyDefaultFlag.Name) { + return nil + } + if cfg.SigningKeys.Default != name { + cfg.SigningKeys.Default = name + if err := cfg.Save(); err != nil { + return err + } + } + + // write out + fmt.Printf("%s: marked as default\n", name) + return nil +} + +func listKeys(ctx *cli.Context) error { + // core process + cfg, err := config.LoadOrDefault() + if err != nil { + return err + } + + // write out + printKeySet(cfg.SigningKeys.Default, cfg.SigningKeys.Keys) + return nil +} + +func removeKeys(ctx *cli.Context) error { + // initialize + names := ctx.Args().Slice() + if len(names) == 0 { + return errors.New("missing key names") + } + + // core process + cfg, err := config.LoadOrDefault() + if err != nil { + return err + } + + prevDefault := cfg.SigningKeys.Default + var removedNames []string + for _, name := range names { + if ok := cfg.SigningKeys.Keys.Remove(name); !ok { + return errors.New(name + ": not found") + } + removedNames = append(removedNames, name) + if prevDefault == name { + cfg.SigningKeys.Default = "" + } + } + if err := cfg.Save(); err != nil { + return err + } + + // write out + for _, name := range removedNames { + if prevDefault == name { + fmt.Printf("%s: unmarked as default\n", name) + } else { + fmt.Println(name) + } + } + return nil +} + +func printKeySet(target string, s config.FileSet) { + if len(s) == 0 { + fmt.Println("NAME\tPATH") + return + } + + maxNameSize := 0 + for _, ref := range s { + if len(ref.Name) > maxNameSize { + maxNameSize = len(ref.Name) + } + } + format := fmt.Sprintf("%%c %%-%ds\t%%s\n", maxNameSize) + fmt.Printf(format, ' ', "NAME", "PATH") + for _, ref := range s { + mark := ' ' + if ref.Name == target { + mark = '*' + } + fmt.Printf(format, mark, ref.Name, ref.Path) + } +} diff --git a/cmd/nv2/main.go b/cmd/notation/main.go similarity index 65% rename from cmd/nv2/main.go rename to cmd/notation/main.go index 2f4a7b4af..b2a5c195a 100644 --- a/cmd/nv2/main.go +++ b/cmd/notation/main.go @@ -4,14 +4,15 @@ import ( "log" "os" + "github.com/notaryproject/notation/internal/version" "github.com/urfave/cli/v2" ) func main() { app := &cli.App{ - Name: "nv2", - Usage: "Notary V2 - Prototype", - Version: "0.4.0", + Name: "notation", + Usage: "Notation - Notary V2", + Version: version.GetVersion(), Authors: []*cli.Author{ { Name: "Shiwei Zhang", @@ -23,6 +24,9 @@ func main() { verifyCommand, pushCommand, pullCommand, + certCommand, + keyCommand, + cacheCommand, }, } if err := app.Run(os.Args); err != nil { diff --git a/cmd/notation/manifest.go b/cmd/notation/manifest.go new file mode 100644 index 000000000..c5b290bb0 --- /dev/null +++ b/cmd/notation/manifest.go @@ -0,0 +1,72 @@ +package main + +import ( + "errors" + "io" + "math" + "os" + + "github.com/notaryproject/notation-go-lib/signature" + "github.com/notaryproject/notation/pkg/registry" + "github.com/opencontainers/go-digest" + "github.com/urfave/cli/v2" +) + +func getManifestFromContext(ctx *cli.Context) (signature.Manifest, error) { + ref := ctx.Args().First() + if ref == "" { + return signature.Manifest{}, errors.New("missing reference") + } + return getManifestFromContextWithReference(ctx, ref) +} + +func getManifestFromContextWithReference(ctx *cli.Context, ref string) (signature.Manifest, error) { + if ctx.Bool(localFlag.Name) { + mediaType := ctx.String(mediaTypeFlag.Name) + if ref == "-" { + return getManifestFromReader(os.Stdin, mediaType) + } + return getManifestsFromFile(ref, mediaType) + } + + return getManifestsFromReference(ctx, ref) +} + +func getManifestsFromReference(ctx *cli.Context, ref string) (signature.Manifest, error) { + remote := registry.NewClient( + registry.NewAuthtransport( + nil, + ctx.String(usernameFlag.Name), + ctx.String(passwordFlag.Name), + ), + ctx.Bool(plainHTTPFlag.Name), + ) + return remote.GetManifestMetadata(ref) +} + +func getManifestsFromFile(path, mediaType string) (signature.Manifest, error) { + file, err := os.Open(path) + if err != nil { + return signature.Manifest{}, err + } + defer file.Close() + return getManifestFromReader(file, mediaType) +} + +func getManifestFromReader(r io.Reader, mediaType string) (signature.Manifest, error) { + lr := &io.LimitedReader{ + R: r, + N: math.MaxInt64, + } + digest, err := digest.SHA256.FromReader(lr) + if err != nil { + return signature.Manifest{}, err + } + return signature.Manifest{ + Descriptor: signature.Descriptor{ + MediaType: mediaType, + Digest: digest.String(), + Size: math.MaxInt64 - lr.N, + }, + }, nil +} diff --git a/cmd/notation/pull.go b/cmd/notation/pull.go new file mode 100644 index 000000000..92e9024f4 --- /dev/null +++ b/cmd/notation/pull.go @@ -0,0 +1,137 @@ +package main + +import ( + "errors" + "fmt" + "path/filepath" + + "github.com/notaryproject/notation-go-lib" + "github.com/notaryproject/notation/internal/os" + "github.com/notaryproject/notation/pkg/config" + "github.com/notaryproject/notation/pkg/registry" + "github.com/opencontainers/go-digest" + "github.com/urfave/cli/v2" +) + +var pullCommand = &cli.Command{ + Name: "pull", + Usage: "Pull signatures from remote", + ArgsUsage: "", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "peek", + Usage: "view signatures without pulling", + }, + &cli.BoolFlag{ + Name: "strict", + Usage: "strict pull without lookup", + }, + outputFlag, + usernameFlag, + passwordFlag, + plainHTTPFlag, + }, + Action: runPull, +} + +func runPull(ctx *cli.Context) error { + // initialize + if !ctx.Args().Present() { + return errors.New("no reference specified") + } + + reference := ctx.Args().First() + sigRepo, err := getSignatureRepository(ctx, reference) + if err != nil { + return err + } + + // core process + if ctx.Bool("strict") { + return pullSignatureStrict(ctx, sigRepo, reference) + } + + manifest, err := getManifestsFromReference(ctx, reference) + if err != nil { + return err + } + manifestDesc := registry.OCIDescriptorFromNotation(manifest.Descriptor) + + sigDigests, err := sigRepo.Lookup(ctx.Context, manifestDesc.Digest) + if err != nil { + return fmt.Errorf("lookup signature failure: %v", err) + } + + path := ctx.String(outputFlag.Name) + for _, sigDigest := range sigDigests { + if !ctx.Bool("peek") { + sig, err := sigRepo.Get(ctx.Context, sigDigest) + if err != nil { + return fmt.Errorf("get signature failure: %v: %v", sigDigest, err) + } + var outputPath string + if path == "" { + outputPath = config.SignaturePath(manifestDesc.Digest, sigDigest) + } else { + outputPath = filepath.Join(path, sigDigest.Encoded()+config.SignatureExtension) + } + if err := os.WriteFile(outputPath, sig); err != nil { + return fmt.Errorf("fail to write signature: %v: %v", sigDigest, err) + } + } + + // write out + fmt.Println(sigDigest) + } + + return nil +} + +func pullSignatureStrict(ctx *cli.Context, sigRepo notation.SignatureRepository, reference string) error { + sigDigest, err := registry.ParseReference(reference).Digest() + if err != nil { + return fmt.Errorf("invalid signature digest: %v", err) + } + + if !ctx.Bool("peek") { + sig, err := sigRepo.Get(ctx.Context, sigDigest) + if err != nil { + return fmt.Errorf("get signature failure: %v: %v", sigDigest, err) + } + outputPath := ctx.String(outputFlag.Name) + if outputPath == "" { + outputPath = sigDigest.Encoded() + config.SignatureExtension + } + if err := os.WriteFile(outputPath, sig); err != nil { + return fmt.Errorf("fail to write signature: %v: %v", sigDigest, err) + } + } + + // write out + fmt.Println(sigDigest) + return nil +} + +func pullSignatures(ctx *cli.Context, manifestDigest digest.Digest) error { + reference := ctx.Args().First() + sigRepo, err := getSignatureRepository(ctx, reference) + if err != nil { + return err + } + + sigDigests, err := sigRepo.Lookup(ctx.Context, manifestDigest) + if err != nil { + return fmt.Errorf("lookup signature failure: %v", err) + } + for _, sigDigest := range sigDigests { + sig, err := sigRepo.Get(ctx.Context, sigDigest) + if err != nil { + return fmt.Errorf("get signature failure: %v: %v", sigDigest, err) + } + outputPath := config.SignaturePath(manifestDigest, sigDigest) + if err := os.WriteFile(outputPath, sig); err != nil { + return fmt.Errorf("fail to write signature: %v: %v", sigDigest, err) + } + } + return nil +} diff --git a/cmd/notation/push.go b/cmd/notation/push.go new file mode 100644 index 000000000..5990b6b5b --- /dev/null +++ b/cmd/notation/push.go @@ -0,0 +1,98 @@ +package main + +import ( + "errors" + "fmt" + "os" + + "github.com/notaryproject/notation/pkg/config" + "github.com/notaryproject/notation/pkg/registry" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/urfave/cli/v2" +) + +var pushCommand = &cli.Command{ + Name: "push", + Usage: "Push signature to remote", + ArgsUsage: "", + Flags: []cli.Flag{ + signatureFlag, + usernameFlag, + passwordFlag, + plainHTTPFlag, + }, + Action: runPush, +} + +func runPush(ctx *cli.Context) error { + // initialize + if !ctx.Args().Present() { + return errors.New("no reference specified") + } + ref := ctx.Args().First() + manifest, err := getManifestsFromReference(ctx, ref) + if err != nil { + return err + } + manifestDesc := registry.OCIDescriptorFromNotation(manifest.Descriptor) + sigPaths := ctx.StringSlice(signatureFlag.Name) + if len(sigPaths) == 0 { + sigDigests, err := config.SignatureDigests(manifestDesc.Digest) + if err != nil { + return err + } + for _, sigDigest := range sigDigests { + sigPaths = append(sigPaths, config.SignaturePath(manifestDesc.Digest, sigDigest)) + } + } + + // core process + sigRepo, err := getSignatureRepository(ctx, ref) + if err != nil { + return err + } + for _, path := range sigPaths { + sig, err := os.ReadFile(path) + if err != nil { + return err + } + sigDesc, err := sigRepo.Put(ctx.Context, sig) + if err != nil { + return fmt.Errorf("push signature failure: %v", err) + } + desc, err := sigRepo.Link(ctx.Context, manifestDesc, sigDesc) + if err != nil { + return fmt.Errorf("link signature failure: %v", err) + } + + // write out + fmt.Println(desc.Digest) + } + + return nil +} + +func pushSignature(ctx *cli.Context, ref string, sig []byte) (ocispec.Descriptor, error) { + // initialize + sigRepo, err := getSignatureRepository(ctx, ref) + if err != nil { + return ocispec.Descriptor{}, err + } + manifest, err := getManifestsFromReference(ctx, ref) + if err != nil { + return ocispec.Descriptor{}, err + } + manifestDesc := registry.OCIDescriptorFromNotation(manifest.Descriptor) + + // core process + sigDesc, err := sigRepo.Put(ctx.Context, sig) + if err != nil { + return ocispec.Descriptor{}, fmt.Errorf("push signature failure: %v", err) + } + desc, err := sigRepo.Link(ctx.Context, manifestDesc, sigDesc) + if err != nil { + return ocispec.Descriptor{}, fmt.Errorf("link signature failure: %v", err) + } + + return desc, nil +} diff --git a/cmd/notation/registry.go b/cmd/notation/registry.go new file mode 100644 index 000000000..ad861dc7e --- /dev/null +++ b/cmd/notation/registry.go @@ -0,0 +1,22 @@ +package main + +import ( + "github.com/notaryproject/notation-go-lib" + registryn "github.com/notaryproject/notation-go-lib/registry" + "github.com/notaryproject/notation/pkg/registry" + "github.com/urfave/cli/v2" +) + +func getSignatureRepository(ctx *cli.Context, reference string) (notation.SignatureRepository, error) { + ref := registry.ParseReference(reference) + remote := registryn.NewClient( + registry.NewAuthtransport( + nil, + ctx.String(usernameFlag.Name), + ctx.String(passwordFlag.Name), + ), + ref.Registry, + ctx.Bool(plainHTTPFlag.Name), + ) + return remote.Repository(ctx.Context, ref.Repository), nil +} diff --git a/cmd/nv2/sign.go b/cmd/notation/sign.go similarity index 51% rename from cmd/nv2/sign.go rename to cmd/notation/sign.go index da4c9db70..be25b991b 100644 --- a/cmd/nv2/sign.go +++ b/cmd/notation/sign.go @@ -1,41 +1,44 @@ package main import ( + "errors" "fmt" - "strings" "time" - "github.com/notaryproject/notary/v2/signature" - "github.com/notaryproject/notary/v2/signature/x509" - "github.com/notaryproject/nv2/internal/os" + "github.com/notaryproject/notation-go-lib/signature" + "github.com/notaryproject/notation-go-lib/signature/x509" + "github.com/notaryproject/notation/internal/os" + "github.com/notaryproject/notation/pkg/config" + "github.com/opencontainers/go-digest" "github.com/urfave/cli/v2" ) -const signerID = "nv2" - var signCommand = &cli.Command{ Name: "sign", - Usage: "signs OCI Artifacts", - ArgsUsage: "[]", + Usage: "Signs artifacts", + ArgsUsage: "", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "method", - Aliases: []string{"m"}, - Usage: "signing method", - Required: true, + Name: "key", + Aliases: []string{"k"}, + Usage: "signing key name", }, &cli.StringFlag{ - Name: "key", - Aliases: []string{"k"}, - Usage: "signing key file [x509]", + Name: "key-file", + Usage: "signing key file", TakesFile: true, }, &cli.StringFlag{ - Name: "cert", - Aliases: []string{"c"}, - Usage: "signing cert [x509]", + Name: "cert", + Aliases: []string{"c"}, + Usage: "signing certificate name", + }, + &cli.StringFlag{ + Name: "cert-file", + Usage: "signing certificate file", TakesFile: true, }, + localFlag, &cli.DurationFlag{ Name: "expiry", Aliases: []string{"e"}, @@ -50,6 +53,7 @@ var signCommand = &cli.Command{ &cli.BoolFlag{ Name: "push", Usage: "push after successful signing", + Value: true, }, &cli.StringFlag{ Name: "push-reference", @@ -75,30 +79,28 @@ func runSign(ctx *cli.Context) error { if err != nil { return err } - sig, err := scheme.Sign(signerID, claims) + sig, err := scheme.Sign("", claims) if err != nil { return err } // write out path := ctx.String(outputFlag.Name) - if path != "" || !ctx.Bool("push") { - if path == "" { - path = strings.Split(claims.Manifest.Digest, ":")[1] + ".jwt" - } - if err := os.WriteFile(path, []byte(sig)); err != nil { - return err - } + if path == "" { + path = config.SignaturePath(digest.Digest(claims.Manifest.Digest), digest.FromString(sig)) + } + if err := os.WriteFile(path, []byte(sig)); err != nil { + return err } if ctx.Bool("push") { - uri := ctx.String("push-reference") - if uri == "" { - uri = ctx.Args().First() + ref := ctx.String("push-reference") + if ref == "" { + ref = ctx.Args().First() } - if _, err := pushSignature(ctx, uri, []byte(sig)); err != nil { + if _, err := pushSignature(ctx, ref, []byte(sig)); err != nil { return fmt.Errorf("fail to push signature to %q: %v: %v", - uri, + ref, claims.Manifest.Digest, err, ) @@ -130,20 +132,44 @@ func prepareClaimsForSigning(ctx *cli.Context) (signature.Claims, error) { } func getSchemeForSigning(ctx *cli.Context) (*signature.Scheme, error) { - var ( - signer signature.Signer - err error - ) - switch method := ctx.String("method"); method { - case "x509": - signer, err = x509.NewSignerFromFiles(ctx.String("key"), ctx.String("cert")) - default: - return nil, fmt.Errorf("unsupported signing method: %s", method) + keyPath := ctx.String("key-file") + if keyPath == "" { + cfg, err := config.LoadOrDefaultOnce() + if err != nil { + return nil, err + } + name := ctx.String("key") + if name == "" { + name = cfg.SigningKeys.Default + } + path, ok := cfg.SigningKeys.Keys.Get(name) + if !ok { + return nil, errors.New("signing key not found") + } + keyPath = path } + + certPath := ctx.String("cert-file") + if certPath == "" { + name := ctx.String("cert") + if name != "" { + cfg, err := config.LoadOrDefaultOnce() + if err != nil { + return nil, err + } + path, ok := cfg.VerificationCertificates.Certificates.Get(name) + if !ok { + return nil, errors.New("certificate not found") + } + certPath = path + } + } + + signer, err := x509.NewSignerFromFiles(keyPath, certPath) scheme := signature.NewScheme() if err != nil { return nil, err } - scheme.RegisterSigner(signerID, signer) + scheme.RegisterSigner("", signer) return scheme, nil } diff --git a/cmd/notation/verify.go b/cmd/notation/verify.go new file mode 100644 index 000000000..199d71f95 --- /dev/null +++ b/cmd/notation/verify.go @@ -0,0 +1,195 @@ +package main + +import ( + "crypto/x509" + "errors" + "fmt" + "os" + + "github.com/notaryproject/notation-go-lib/signature" + x509n "github.com/notaryproject/notation-go-lib/signature/x509" + "github.com/notaryproject/notation/pkg/config" + "github.com/opencontainers/go-digest" + "github.com/urfave/cli/v2" +) + +var verifyCommand = &cli.Command{ + Name: "verify", + Usage: "Verifies OCI Artifacts", + ArgsUsage: "", + Flags: []cli.Flag{ + signatureFlag, + &cli.StringSliceFlag{ + Name: "cert", + Aliases: []string{"c"}, + Usage: "certificate names for verification", + }, + &cli.StringSliceFlag{ + Name: "cert-file", + Usage: "certificate files for verification", + TakesFile: true, + }, + &cli.StringSliceFlag{ + Name: "ca-cert", + Usage: "CA certificate names for verification", + }, + &cli.StringSliceFlag{ + Name: "ca-cert-file", + Usage: "CA certificate files for verification", + TakesFile: true, + }, + &cli.BoolFlag{ + Name: "pull", + Usage: "pull remote signatures before verification", + Value: true, + }, + localFlag, + usernameFlag, + passwordFlag, + plainHTTPFlag, + mediaTypeFlag, + }, + Action: runVerify, +} + +func runVerify(ctx *cli.Context) error { + // initialize + scheme, err := getSchemeForVerification(ctx) + if err != nil { + return err + } + manifest, err := getManifestFromContext(ctx) + if err != nil { + return err + } + + sigPaths := ctx.StringSlice(signatureFlag.Name) + if len(sigPaths) == 0 { + if !ctx.Bool(localFlag.Name) && ctx.Bool("pull") { + if err := pullSignatures(ctx, digest.Digest(manifest.Digest)); err != nil { + return err + } + } + manifestDigest := digest.Digest(manifest.Digest) + sigDigests, err := config.SignatureDigests(manifestDigest) + if err != nil { + return err + } + for _, sigDigest := range sigDigests { + sigPaths = append(sigPaths, config.SignaturePath(manifestDigest, sigDigest)) + } + } + + // core process + if err := verifySignatures(scheme, manifest, sigPaths); err != nil { + return err + } + + // write out + fmt.Println(manifest.Digest) + return nil +} + +func verifySignatures(scheme *signature.Scheme, manifest signature.Manifest, sigPaths []string) error { + if len(sigPaths) == 0 { + return errors.New("verification failure: no signatures found") + } + + var lastErr error + for _, path := range sigPaths { + sig, err := os.ReadFile(path) + if err != nil { + return err + } + claims, err := scheme.Verify(string(sig)) + if err != nil { + lastErr = fmt.Errorf("verification failure: %v", err) + continue + } + if manifest.Descriptor != claims.Manifest.Descriptor { + lastErr = fmt.Errorf("verification failure: %s", manifest.Digest) + continue + } + return nil + } + return lastErr +} + +func getSchemeForVerification(ctx *cli.Context) (*signature.Scheme, error) { + scheme := signature.NewScheme() + + // add x509 verifier + verifier, err := getX509Verifier(ctx) + if err != nil { + return nil, err + } + scheme.RegisterVerifier(verifier) + + return scheme, nil +} + +func getX509Verifier(ctx *cli.Context) (signature.Verifier, error) { + // resolve paths + certPaths := ctx.StringSlice("cert-file") + certPaths, err := appendCertPathFromName(certPaths, ctx.StringSlice("cert")) + if err != nil { + return nil, err + } + caCertPath := ctx.StringSlice("ca-cert-file") + caCertPath, err = appendCertPathFromName(caCertPath, ctx.StringSlice("ca-cert")) + if err != nil { + return nil, err + } + if len(certPaths) == 0 && len(caCertPath) == 0 { + cfg, err := config.LoadOrDefaultOnce() + if err != nil { + return nil, err + } + if len(cfg.VerificationCertificates.Certificates) == 0 { + return nil, errors.New("trust certificate not specified") + } + for _, ref := range cfg.VerificationCertificates.Certificates { + certPaths = append(certPaths, ref.Path) + } + } + + // read cert files + var certs []*x509.Certificate + roots := x509.NewCertPool() + for _, path := range certPaths { + bundledCerts, err := x509n.ReadCertificateFile(path) + if err != nil { + return nil, err + } + certs = append(certs, bundledCerts...) + for _, cert := range bundledCerts { + roots.AddCert(cert) + } + } + for _, path := range caCertPath { + bundledCerts, err := x509n.ReadCertificateFile(path) + if err != nil { + return nil, err + } + for _, cert := range bundledCerts { + roots.AddCert(cert) + } + } + + return x509n.NewVerifier(certs, roots) +} + +func appendCertPathFromName(paths, names []string) ([]string, error) { + for _, name := range names { + cfg, err := config.LoadOrDefaultOnce() + if err != nil { + return nil, err + } + path, ok := cfg.VerificationCertificates.Certificates.Get(name) + if !ok { + return nil, errors.New("verification certificate not found: " + name) + } + paths = append(paths, path) + } + return paths, nil +} diff --git a/cmd/nv2/manifest.go b/cmd/nv2/manifest.go deleted file mode 100644 index 6b5e2ac53..000000000 --- a/cmd/nv2/manifest.go +++ /dev/null @@ -1,74 +0,0 @@ -package main - -import ( - "fmt" - "io" - "math" - "net/url" - "os" - "strings" - - "github.com/notaryproject/notary/v2/signature" - "github.com/notaryproject/nv2/pkg/registry" - "github.com/opencontainers/go-digest" - "github.com/urfave/cli/v2" -) - -func getManifestFromContext(ctx *cli.Context) (signature.Manifest, error) { - if uri := ctx.Args().First(); uri != "" { - parsed, err := url.Parse(uri) - if err != nil { - return signature.Manifest{}, err - } - return getManfestsFromURI(ctx, parsed) - } - return getManifestFromReader(os.Stdin, ctx.String(mediaTypeFlag.Name)) -} - -func getManifestFromReader(r io.Reader, mediaType string) (signature.Manifest, error) { - lr := &io.LimitedReader{ - R: r, - N: math.MaxInt64, - } - digest, err := digest.SHA256.FromReader(lr) - if err != nil { - return signature.Manifest{}, err - } - return signature.Manifest{ - Descriptor: signature.Descriptor{ - MediaType: mediaType, - Digest: digest.String(), - Size: math.MaxInt64 - lr.N, - }, - }, nil -} - -func getManfestsFromURI(ctx *cli.Context, uri *url.URL) (signature.Manifest, error) { - var r io.Reader - switch strings.ToLower(uri.Scheme) { - case "file": - path := uri.Path - if uri.Opaque != "" { - path = uri.Opaque - } - file, err := os.Open(path) - if err != nil { - return signature.Manifest{}, err - } - defer file.Close() - r = file - case "docker", "oci": - remote := registry.NewClient( - registry.NewAuthtransport( - nil, - ctx.String(usernameFlag.Name), - ctx.String(passwordFlag.Name), - ), - ctx.Bool(plainHTTPFlag.Name), - ) - return remote.GetManifestMetadata(uri) - default: - return signature.Manifest{}, fmt.Errorf("unsupported URI scheme: %s", uri.Scheme) - } - return getManifestFromReader(r, ctx.String(mediaTypeFlag.Name)) -} diff --git a/cmd/nv2/pull.go b/cmd/nv2/pull.go deleted file mode 100644 index 6583739de..000000000 --- a/cmd/nv2/pull.go +++ /dev/null @@ -1,108 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "net/url" - "path/filepath" - - "github.com/notaryproject/nv2/internal/os" - "github.com/notaryproject/nv2/pkg/registry" - "github.com/urfave/cli/v2" -) - -var pullCommand = &cli.Command{ - Name: "pull", - Usage: "pull signatures from remote", - ArgsUsage: "", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "peek", - Usage: "view signatures without pulling", - }, - &cli.BoolFlag{ - Name: "strict", - Usage: "struct pull without lookup", - }, - outputFlag, - usernameFlag, - passwordFlag, - plainHTTPFlag, - }, - Action: runPull, -} - -func runPull(ctx *cli.Context) error { - // initialize - if !ctx.Args().Present() { - return errors.New("no reference specified") - } - - uri, err := url.Parse(ctx.Args().First()) - if err != nil { - return err - } - sigRepo, err := getSignatureRepositoryFromURI(ctx, uri) - if err != nil { - return err - } - - // core process - if ctx.Bool("strict") { - sigDigest, err := registry.ParseReferenceFromURL(uri).Digest() - if err != nil { - return fmt.Errorf("invalid signature digest: %v", err) - } - - if !ctx.Bool("peek") { - sig, err := sigRepo.Get(ctx.Context, sigDigest) - if err != nil { - return fmt.Errorf("get signature failure: %v: %v", sigDigest, err) - } - outputPath := ctx.String(outputFlag.Name) - if outputPath == "" { - outputPath = sigDigest.Encoded() + ".jwt" - } - if err := os.WriteFile(outputPath, sig); err != nil { - return fmt.Errorf("fail to write signature: %v: %v", sigDigest, err) - } - } - - // write out - fmt.Println(sigDigest) - return nil - } - - manifest, err := getManfestsFromURI(ctx, uri) - if err != nil { - return err - } - manifestDesc := registry.OCIDescriptorFromNotary(manifest.Descriptor) - - sigDigests, err := sigRepo.Lookup(ctx.Context, manifestDesc.Digest) - if err != nil { - return fmt.Errorf("lookup signature failure: %v", err) - } - - path := ctx.String(outputFlag.Name) - if path == "" { - path = manifestDesc.Digest.Encoded() - } - for _, sigDigest := range sigDigests { - if !ctx.Bool("peek") { - sig, err := sigRepo.Get(ctx.Context, sigDigest) - if err != nil { - return fmt.Errorf("get signature failure: %v: %v", sigDigest, err) - } - outputPath := filepath.Join(path, sigDigest.Encoded()+".jwt") - if err := os.WriteFile(outputPath, sig); err != nil { - return fmt.Errorf("fail to write signature: %v: %v", sigDigest, err) - } - } - - // write out - fmt.Println(sigDigest) - } - - return nil -} diff --git a/cmd/nv2/push.go b/cmd/nv2/push.go deleted file mode 100644 index 5eefd7270..000000000 --- a/cmd/nv2/push.go +++ /dev/null @@ -1,83 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "net/url" - "os" - - "github.com/notaryproject/nv2/pkg/registry" - oci "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/urfave/cli/v2" -) - -var pushCommand = &cli.Command{ - Name: "push", - Usage: "push signature to remote", - ArgsUsage: "", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "signature", - Aliases: []string{"s", "f"}, - Usage: "signature file", - Required: true, - TakesFile: true, - }, - usernameFlag, - passwordFlag, - plainHTTPFlag, - }, - Action: runPush, -} - -func runPush(ctx *cli.Context) error { - // initialize - if !ctx.Args().Present() { - return errors.New("no reference specified") - } - uri := ctx.Args().First() - sig, err := os.ReadFile(ctx.String("signature")) - if err != nil { - return err - } - - // core process - desc, err := pushSignature(ctx, uri, sig) - if err != nil { - return err - } - - // write out - fmt.Println(desc.Digest) - return nil -} - -func pushSignature(ctx *cli.Context, uri string, sig []byte) (oci.Descriptor, error) { - // initialize - parsedURI, err := url.Parse(uri) - if err != nil { - return oci.Descriptor{}, err - } - sigRepo, err := getSignatureRepositoryFromURI(ctx, parsedURI) - if err != nil { - return oci.Descriptor{}, err - } - manifest, err := getManfestsFromURI(ctx, parsedURI) - if err != nil { - return oci.Descriptor{}, err - } - manifestDesc := registry.OCIDescriptorFromNotary(manifest.Descriptor) - - // core process - sigDesc, err := sigRepo.Put(ctx.Context, sig) - if err != nil { - return oci.Descriptor{}, fmt.Errorf("push signature failure: %v", err) - } - - desc, err := sigRepo.Link(ctx.Context, manifestDesc, sigDesc) - if err != nil { - return oci.Descriptor{}, fmt.Errorf("link signature failure: %v", err) - } - - return desc, nil -} diff --git a/cmd/nv2/registry.go b/cmd/nv2/registry.go deleted file mode 100644 index bb643a63b..000000000 --- a/cmd/nv2/registry.go +++ /dev/null @@ -1,31 +0,0 @@ -package main - -import ( - "fmt" - "net/url" - "strings" - - "github.com/notaryproject/notary/v2" - notaryregistry "github.com/notaryproject/notary/v2/registry" - "github.com/notaryproject/nv2/pkg/registry" - "github.com/urfave/cli/v2" -) - -func getSignatureRepositoryFromURI(ctx *cli.Context, uri *url.URL) (notary.SignatureRepository, error) { - switch strings.ToLower(uri.Scheme) { - case "docker", "oci": - ref := registry.ParseReferenceFromURL(uri) - remote := notaryregistry.NewClient( - registry.NewAuthtransport( - nil, - ctx.String(usernameFlag.Name), - ctx.String(passwordFlag.Name), - ), - ref.Registry, - ctx.Bool(plainHTTPFlag.Name), - ) - return remote.Repository(ctx.Context, ref.Repository), nil - default: - return nil, fmt.Errorf("unsupported URI scheme: %s", uri.Scheme) - } -} diff --git a/cmd/nv2/verify.go b/cmd/nv2/verify.go deleted file mode 100644 index 7f67dac25..000000000 --- a/cmd/nv2/verify.go +++ /dev/null @@ -1,119 +0,0 @@ -package main - -import ( - "crypto/x509" - "fmt" - "os" - - "github.com/notaryproject/notary/v2/signature" - x509nv2 "github.com/notaryproject/notary/v2/signature/x509" - "github.com/urfave/cli/v2" -) - -var verifyCommand = &cli.Command{ - Name: "verify", - Usage: "verifies OCI Artifacts", - ArgsUsage: "[]", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "signature", - Aliases: []string{"s", "f"}, - Usage: "signature file", - Required: true, - TakesFile: true, - }, - &cli.StringSliceFlag{ - Name: "cert", - Aliases: []string{"c"}, - Usage: "certs for verification [x509]", - TakesFile: true, - }, - &cli.StringSliceFlag{ - Name: "ca-cert", - Usage: "CA certs for verification [x509]", - TakesFile: true, - }, - usernameFlag, - passwordFlag, - plainHTTPFlag, - mediaTypeFlag, - }, - Action: runVerify, -} - -func runVerify(ctx *cli.Context) error { - // initialize - scheme, err := getSchemeForVerification(ctx) - if err != nil { - return err - } - sig, err := readSignatrueFile(ctx.String("signature")) - if err != nil { - return err - } - - // core process - claims, err := scheme.Verify(sig) - if err != nil { - return fmt.Errorf("verification failure: %v", err) - } - manifest, err := getManifestFromContext(ctx) - if err != nil { - return err - } - if manifest.Descriptor != claims.Manifest.Descriptor { - return fmt.Errorf("verification failure: %s", manifest.Digest) - } - - // write out - fmt.Println(manifest.Digest) - return nil -} - -func readSignatrueFile(path string) (string, error) { - bytes, err := os.ReadFile(path) - if err != nil { - return "", err - } - return string(bytes), nil -} - -func getSchemeForVerification(ctx *cli.Context) (*signature.Scheme, error) { - scheme := signature.NewScheme() - - // add x509 verifier - verifier, err := getX509Verifier(ctx) - if err != nil { - return nil, err - } - scheme.RegisterVerifier(verifier) - - return scheme, nil -} - -func getX509Verifier(ctx *cli.Context) (signature.Verifier, error) { - roots := x509.NewCertPool() - - var certs []*x509.Certificate - for _, path := range ctx.StringSlice("cert") { - bundledCerts, err := x509nv2.ReadCertificateFile(path) - if err != nil { - return nil, err - } - certs = append(certs, bundledCerts...) - for _, cert := range bundledCerts { - roots.AddCert(cert) - } - } - for _, path := range ctx.StringSlice("ca-cert") { - bundledCerts, err := x509nv2.ReadCertificateFile(path) - if err != nil { - return nil, err - } - for _, cert := range bundledCerts { - roots.AddCert(cert) - } - } - - return x509nv2.NewVerifier(certs, roots) -} diff --git a/docs/distribution/persistance-discovery-options.md b/docs/distribution/persistance-discovery-options.md deleted file mode 100644 index be3c1d3f8..000000000 --- a/docs/distribution/persistance-discovery-options.md +++ /dev/null @@ -1,934 +0,0 @@ -# OCI Distribution - Notary v2 Signature Persistance & Discovery Options - -> This document explores the various options that were considered for the prototype. The current implementation is documented under the [README.md](./README.md) document. - -To support [Notary v2 goals][notaryv2-goals], upload, persistence and discovery of signatures must be supported. - -To minimize the complexity of registry operators and projects to adopt Notary v2, a balance between leveraging what already exists and new patterns to support secure discovery are explored. - -## Table of Contents - -* [Signature Persistence](#signature-Persistence) -* [Signature Push](#signature-push) -* [Signature Discovery](#signature-discovery) -* [Signature Pull](#signature-pull) -* [Example Artifacts](#example-artifacts) - -## Signature Persistence - -Several options for how to persist a signature were explored. We measure these options against the [goals of Notary v2][notaryv2-goals], specifically: - -* Maintain the original artifact digest and collection of associated tags, supporting existing dev through deployment workflows -* Multiple signatures per artifact, enabling the originating vendor signature, public registry certification and user/environment signatures -* Native Persistence within an OCI Artifact enabled, distribution spec based registry -* Artifact and signature copying within and across OCI Artifact enabled, distribution spec based registries -* Support multi-tenant registries enabling cloud providers and enterprises to support managed services at scale -* Support private registries, where public content may be copied to, and new content originated within -* Air-gapped environments, where the originating registry of content is not accessible - -To support the above requirements, signatures are stored as separate [OCI Artifacts][oci-artifacts]. They are maintained as any other artifact in a registry, supporting standard operations such as listing, deleting, garbage collection and any other content addressable operations within a registry. - -Following the [OCI Artifacts][oci-artifacts] design, signatures are identified with: `config.mediaType: "application/vnd.cncf.notary.config.v2+jwt"`. -The config object contains the signature and signed content. See [nv2-signature-spec][nv2-signature-spec] for details. - -Storing a signature as a separate artifact enables the above goals, most importantly the ability to maintain the existing tag and and digest for a given artifact. - -### Persistence as Manifest or Index - -A typical signing workflow would involve: - -1. An artifact (`net-monitor:v1` container image) is pushed to a registry -1. Signature artifacts are pushed to the same registry using a set of new [OCI distribution][oci-distribution] capabilities - -It's presumed artifact clients like docker, oras, buildkit would support these new workflows. The question is what oci schema they are pushed with: - -* [Option 1: oci-manifest](#signature-Persistence---option-1-oci-manifest) -* [Option 2: oci-index](#signature-Persistence---option-2-oci-index) -* [Option 3: oci-manifest-linked through index](#signature-Persistence---option-3-oci-manifest-linked-through-oci-index) - -### Signature Persistence - Option 1: oci-manifest - -The challenge with using oci-manifest is how the registry tracks the linkage between the signature and the original artifact. - - - -Example **manifests** for a container image (`net-monitor:v1`) and two signatures (**wabbit-networks**, **acme-rockets**): - -1. **manifest digest for the `net-monitor:v1` image:** `sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m"` - - ```JSON - { - "schemaVersion": 2, - "mediaType": "application/vnd.oci.image.manifest.v2+json", - "config": { - "mediaType": "application/vnd.oci.image.config.v1+json", - "digest": "sha256:111ca3788f3464fd9a06386c4d7a8e3018b525278ac4b9da872943d4cfea111c", - "size": 1906 - }, - "layers": [ - { - "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", - "digest": "sha256:9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0", - "size": 32654 - }, - { - "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", - "digest": "sha256:ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736", - "size": 73109 - } - ] - } - ``` - -2. **manifest digest for the wabbit-networks signature** `sha256:222mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222m` - - ```json - { - "schemaVersion": 2, - "mediaType": "application/vnd.oci.image.manifest.v2+json", - "config": { - "mediaType": "application/vnd.cncf.notary.config.v2+jwt", - "digest": "sha256:222cb130c152895905abe66279dd9feaa68091ba55619f5b900f2ebed38b222c", - "size": 1906 - }, - "layers": [] - } - ``` - - The `manifest.config` contains the following signature information: - - ```json - { - "signed": { - "mediaType": "application/vnd.oci.image.manifest.v2+json", - "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", - "size": 528, - "references": [ - "registry.wabbit-networks.com/net-monitor:v1" - ], - "exp": 1627555319, - "nbf": 1596019319, - "iat": 1596019319 - }, - "signature": { - "typ": "x509", - "sig": "UFqN24K2fLj...", - "alg": "RS256", - "x5c": [ - "MIIDszCCApugAwIBAgIUL1anEU/..." - ] - } - } - ``` - -3. **manifest digest for the acme-rockets signature** `sha256:333mc0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333m` - - ```json - { - "schemaVersion": 2, - "mediaType": "application/vnd.oci.image.manifest.v2+json", - "config": { - "mediaType": "application/vnd.cncf.notary.config.v2+jwt", - "digest": "sha256:333cc44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b785c333c", - "size": 1906 - }, - "layers": [] - } - ``` - - The `manifest.config` contains the following signature information: - - ```json - { - "signed": { - "mediaType": "application/vnd.oci.image.manifest.v2+json", - "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", - "size": 528, - "references": [ - "registry.acme-rockets.com/net-monitor:v1" - ], - "exp": 1627555319, - "nbf": 1596019319, - "iat": 1596019319 - }, - "signature": { - "typ": "x509", - "sig": "UFqN24K2fLj...", - "alg": "RS256", - "x5c": [ - "MIIDszCCApugAwIBAgIUL1anEU/..." - ] - } - } - ``` - -**Pros with this approach:** - -* OCI Artifacts already supports manifest based artifacts, through the `manifest.config.mediaType` - -**Cons with this approach:** - -* Manifests have no means to reference other artifacts. -* An alternative is required to link a target artifact with it's signature. Either through parsing the signature `manifest.config` object, or [a separate API for linking objects](#linking-signatures-to-artifacts). - -### Signature Persistence - Option 2: oci-index - -> **Note:** this is our working prototype/preferred method: See OCI image-spec issue: [Add Index Support for Artifact Type #806](https://github.com/opencontainers/image-spec/issues/806) - -This option is similar to using oci-manifest. However, instead of parsing the signature object to determine the linkage between an artifact and signature, the `index.manifests` collection is utilized. - - - -Example **manifests** for a container image (`net-monitor:v1`) and two signatures (**wabbit-networks**, **acme-rockets**). The signatures are persisted as OCI Indexes, with a new `index.config` object: - -1. **manifest digest for the `net-monitor:v1` image:** `sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m"` - - ```JSON - { - "schemaVersion": 2, - "mediaType": "application/vnd.oci.image.manifest.v2+json", - "config": { - "mediaType": "application/vnd.oci.image.config.v1+json", - "digest": "sha256:111ca3788f3464fd9a06386c4d7a8e3018b525278ac4b9da872943d4cfea111c", - "size": 1906 - }, - "layers": [ - { - "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", - "digest": "sha256:9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0", - "size": 32654 - }, - { - "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", - "digest": "sha256:ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736", - "size": 73109 - } - ] - } - ``` - -2. **index digest for the wabbit-networks signature** `sha256:222ibbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222i` - - ```json - { - "schemaVersion": 2, - "mediaType": "application/vnd.oci.image.index.v2+json", - "config": { - "mediaType": "application/vnd.cncf.notary.config.v2+jwt", - "digest": "sha256:222cb130c152895905abe66279dd9feaa68091ba55619f5b900f2ebed38b222c", - "size": 1906 - }, - "manifests": [ - { - "mediaType": "application/vnd.oci.image.manifest.v1+json", - "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", - "size": 7023, - "platform": { - "architecture": "ppc64le", - "os": "linux" - } - } - ] - } - ``` - - The `index.config` contains the following signature information: - - ```json - { - "signed": { - "mediaType": "application/vnd.oci.image.manifest.v2+json", - "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", - "size": 528, - "references": [ - "registry.wabbit-networks.com/net-monitor:v1" - ], - "exp": 1627555319, - "nbf": 1596019319, - "iat": 1596019319 - }, - "signature": { - "typ": "x509", - "sig": "UFqN24K2fLj...", - "alg": "RS256", - "x5c": [ - "MIIDszCCApugAwIBAgIUL1anEU/..." - ] - } - } - ``` - -3. **index digest for the acme-rockets signature** `sha256:333ic0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333i` - - ```json - { - "schemaVersion": 2, - "mediaType": "application/vnd.oci.image.index.v2+json", - "config": { - "mediaType": "application/vnd.cncf.notary.config.v2+jwt", - "digest": "sha256:333cc44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b785c333c", - "size": 1906 - }, - "manifests": [ - { - "mediaType": "application/vnd.oci.image.manifest.v1+json", - "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", - "size": 7023, - "platform": { - "architecture": "ppc64le", - "os": "linux" - } - } - ] - } - ``` - - The `manifest.config` contains the following signature information: - - ```json - { - "signed": { - "mediaType": "application/vnd.oci.image.manifest.v2+json", - "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", - "size": 528, - "references": [ - "registry.acme-rockets.com/net-monitor:v1" - ], - "exp": 1627555319, - "nbf": 1596019319, - "iat": 1596019319 - }, - "signature": { - "typ": "x509", - "sig": "UFqN24K2fLj...", - "alg": "RS256", - "x5c": [ - "MIIDszCCApugAwIBAgIUL1anEU/..." - ] - } - } - ``` - -**Pros with this approach:** - -* Utilize the existing `index.manifests` collection for linking artifacts -* Registries that support oci index already have infrastructure for tracking `index.manifests`, including delete operations and garbage collection -* Existing distribution-spec upload APIs are utilized -* Unlike the manifest proposal, no additional artifact handler would be required to parse the config object for linking artifacts -* Based on the artifact type: `manifest.config.mediaType: "application/vnd.cncf.notary.config.v2+jwt"`, role check may be done to confirm the identity has a signer role -* As registry operators may offer role checking for different artifact types, Notary v2 Signatures are just one of many types they may want to authorize - -**Cons with this approach:** - -* OCI index does not yet support the [OCI config descriptor][oci-descriptor]. This would require a schema change to oci-index, with a version bump. - * This has been a [desired item for OCI Artifacts][oci-artifacts-index] to support other artifact types which would base on Index. -* Registries that wish to implement role based authorization would implement and additional role check, based on the artifact type. Also noted as a pro as registry operators may want to utilize this for other artifact types, making it a consistent model. This likely minimizes this as a con-but noted for completeness. - -### Signature Persistence - Option 2a: oci-index signing a multi-arch manifest - -Takin the above scenario further, a signature can be associated with an individual manifest, or a signature can be applied to an index. The index could be a multi-arch index (windows & linux), or the index might represent a [CNAB][cnab]. - -In the below case, the `net-monitor` software is available as windows (`net-monitor:v1-win`) and linux (`net-monitor:v1-lin`) images, as well as a multi-arch index (`net-monitor:v1`) -The platform specific images, and the multi-arch index are all signed by **wabbit-networks** and **acme-rockets**. - - - - -### Signature Persistence - Option 3: oci-manifest linked through oci-index - -This model is a hybrid of the 1 & 2, but moves the Persistence of the signature from the config object to a layer of an additional manifest. - - - -1. **manifest digest for the `net-monitor:v1` image:** `sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m"` - - ```JSON - { - "schemaVersion": 2, - "mediaType": "application/vnd.oci.image.manifest.v2+json", - "config": { - "mediaType": "application/vnd.oci.image.config.v1+json", - "digest": "sha256:111ca3788f3464fd9a06386c4d7a8e3018b525278ac4b9da872943d4cfea111c", - "size": 1906 - }, - "layers": [ - { - "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", - "digest": "sha256:9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0", - "size": 32654 - }, - { - "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", - "digest": "sha256:ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736", - "size": 73109 - } - ] - } - ``` - -2. **index digest for the wabbit-networks signature of the `net-monitor:v1` image** `sha256:222ibbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222i` - - ```json - { - "schemaVersion": 2, - "mediaType": "application/vnd.oci.image.index.v2+json", - "config": { - "mediaType": "application/vnd.cncf.notary.index.config.v2+jwt", - "digest": "sha256:222cb130c152895905abe66279dd9feaa68091ba55619f5b900f2ebed38b222c", - "size": 1906 - }, - "manifests": [ - { - "mediaType": "application/vnd.oci.image.manifest.v1+json", - "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", - "size": 7023, - "platform": { - "architecture": "ppc64le", - "os": "linux" - } - }, - { - "mediaType": "application/vnd.oci.image.manifest.v1+json", - "digest": "sha256:222mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222m", - "size": 7023, - "config_mediaType": "application/vnd.cncf.notary.config.v2+jwt" - } - ] - } - ``` - -3. **manifest digest for the wabbit-networks signature** `sha256:222mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222m` - - ```json - { - "schemaVersion": 2, - "mediaType": "application/vnd.oci.image.manifest.v2+json", - "config": { - "mediaType": "application/vnd.cncf.notary.config.v2+jwt", - "digest": "sha256:222cb130c152895905abe66279dd9feaa68091ba55619f5b900f2ebed38b222c", - "size": 1906 - }, - "layers": [] - } - ``` - - The `manifest.config` contains the following signature information: - - ```json - { - "signed": { - "mediaType": "application/vnd.oci.image.manifest.v2+json", - "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", - "size": 528, - "references": [ - "registry.wabbit-networks.com/net-monitor:v1" - ], - "exp": 1627555319, - "nbf": 1596019319, - "iat": 1596019319 - }, - "signature": { - "typ": "x509", - "sig": "UFqN24K2fLj...", - "alg": "RS256", - "x5c": [ - "MIIDszCCApugAwIBAgIUL1anEU/..." - ] - } - } - ``` - -4. **index digest for the acme-rockets signature** `sha256:333ic0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333i` - - ```json - { - "schemaVersion": 2, - "mediaType": "application/vnd.oci.image.index.v2+json", - "config": { - "mediaType": "application/vnd.cncf.notary.index.config.v2+jwt", - "digest": "sha256:333cc44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b785c333c", - "size": 1906 - }, - "manifests": [ - { - "mediaType": "application/vnd.oci.image.manifest.v1+json", - "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", - "size": 7023, - "platform": { - "architecture": "ppc64le", - "os": "linux" - } - }, - { - "mediaType": "application/vnd.oci.image.manifest.v1+json", - "digest": "sha256:333mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb333m", - "size": 7023, - "config_mediaType": "application/vnd.cncf.notary.config.v2+jwt" - } - ] - } - ``` - -5. **manifest digest for the acme-rockets signature** `sha256:333mc0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333m` - - ```json - { - "schemaVersion": 2, - "mediaType": "application/vnd.oci.image.manifest.v2+json", - "config": { - "mediaType": "application/vnd.cncf.notary.config.v2+jwt", - "digest": "sha256:333cc44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b785c333c", - "size": 1906 - }, - "layers": [] - } - ``` - - The `manifest.config` contains the following signature information: - - ```json - { - "signed": { - "mediaType": "application/vnd.oci.image.manifest.v2+json", - "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", - "size": 528, - "references": [ - "registry.acme-rockets.com/net-monitor:v1" - ], - "exp": 1627555319, - "nbf": 1596019319, - "iat": 1596019319 - }, - "signature": { - "typ": "x509", - "sig": "UFqN24K2fLj...", - "alg": "RS256", - "x5c": [ - "MIIDszCCApugAwIBAgIUL1anEU/..." - ] - } - } - ``` - -**Pros with this approach:** - -* Conforms to norms of indexes as collections of manifests with no config data - -**Cons with this approach:** - -* An additional indirection between the original artifact being signed and the individual signatures. -* An `index.config.mediaType` is still required to identify the type of index being something other than a multi-arch index. - -The implied benefit is the signature is moved from the `index.config` to a layer within a manifest. However, config objects are [oci descriptors][oci-descriptor] pointing to blobs. Whether the signature is stored within a config or a layer is little difference. Since we'll need an `index.config.mediaType` to differentiate a signature index from a multi-arch index, are we justifying additional round trips to get a list of signatures? - -## Linking Signatures to Artifacts - -A signature is only interesting if it's linked to the object it's signing. The question is how. - -If manifest is used, we must choose between options 1-3. -If index is used, option 4 defers the linking to existing Index linking capabilities - -1. [Option 1: Parse the config object](#linking-signatures---option-1-parse-the-config-object) -1. [Option 2: Distinct Linking API](#linking-signatures---option-2-distinct-linking-api) -1. [Option 3: Signature Upload API](#linking-signatures---option-3-signature-upload-api) -1. [Option 4: Utilize OCI Index PUT](#linking-signatures---option-4-utilize-oci-index-put) - -### Linking Signatures - Option 1: Parse the config object - -Upon [manifest put][oci-dist-spec-manifest-put], perform the following steps: - -* The [proposed nv2 signature specification][nv2-signature-spec] identifies the referenced artifact by its digest and optional tags. -* As the registry receives artifacts, the artifact type is parsed, evaluating the `manifest.config.mediaType` of `"application/vnd.cncf.notary.config.v2+jwt"` -* A role check is performed, confirming the identity of the PUT has **signer** rights -* The registry uses the config objects reference to link the signature with signed digest. This would enable registry tracking for garbage collection - -Partial config object, referring to the digest and tag of the `net-monitor:v1` container image: - -```json -{ - "signed": { - "mediaType": "application/vnd.oci.image.manifest.v2+json", - "digest": "sha256:2235d2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49cc77c", - "size": 528, - "references": [ - "registry.acme-rockets.com/net-monitor:v1" - ] - } -} -``` - -**Pros with this approach:** - -* Existing [distribution-spec manifest put APIs][oci-dist-spec-manifest-put] are utilized for the manifest PUT -* Rather than add a new linking API, an artifact handler would be added to registries. Many already parse the config objects to understand which platform and architectures they support. - -**Cons with this approach:** - -* An artifact handler is required that must parse the signature object for the linked artifact -* New code for tracking dependency linking is required through a config object handler -* Based on the unique artifact type: `manifest.config.mediaType: "application/vnd.cncf.notary.config.v2+jwt"`, a role check may be done to confirm the identity has a signer role. - -### Linking Signatures - Option 2: Distinct Linking API - -Similar to the manifest or index options, the client pushes the artifact and signatures through standard oci-distribution PUT apis. -However, no linkage is made between the signature object and the signed artifact. Rather a signature linking api is added: - -1. Push all artifacts to the registry: - * Push `net-monitor:v1` container image: `sha256:2235d2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49cc77c` - * Push **acme-rockets** signature artifact `sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b` -1. Link **acme-rockets** signature to the `net-monitor:v1` container image - -```HTTP -PUT https://localhost:6000/v2/net-monitor/manifests/sha256:2235d2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49cc77c/signatures/sha256:007170c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75a153b -``` - -**Pros with this approach:** - -* Using a unique API enables RBAC to the API, without having to parse the content to determine the role check. - -**Cons with this approach:** - -* A new linking api, unique to signatures -* The client must make two calls to achieve a single operation of uploading a signature object, which by definition has the linking information -* If the signature linking API fails, additional garbage collection of a signature manifest must be cleaned up - -### Linking Signatures - Option 3: Signature Upload API - -In this option the signature artifact (manifest or index) is uploaded through a new signature API. - -**Pros with this approach:** - -* The signature artifact upload and role check are coupled to a signature API - -**Cons with this approach:** - -* Signature upload, which is just another artifact type, is uploaded differently than other artifacts. - -### Linking Signatures - Option 4: Utilize OCI Index PUT - -Utilizing the OCI Index, the manifest list is used to track dependencies. - -**Pros with this approach:** - -* Existing Index parsing logic is used to track despondencies -* No additional distribution-spec APIs are required - -**Cons with this approach:** - -* OCI Index would need to support a config object: [Add Index Support for Artifact Type #806](https://github.com/opencontainers/image-spec/issues/) - -## Signature Discovery - -Once a signature artifact is in a registry and linked to its target artifact, how is it retrieved? - -The following options are offered: - -1. [Option 1: Signature Listing API](#signature-discovery---option-1-rest-api-standard-paging) -1. [Option 2: Generic Reference Listing API](#signature-discovery---option-2-generic-reference-listing-api) - -### Signature Discovery - Option 1: Signature Listing API - -Similar to the [_tags api][tags-api], a new signatures API is proposed. The signatures API uses the digest as the path to find all signatures related to said digest. -In the below example, the `net-monitor:v1` tag has a digest of: `sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m` - -```HTTP -GET /v2//manifests/sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m/signatures/ -``` - -The response will be in the following format: - -```HTTP -200 OK -Content-Type: application/json -{ - "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", - "mediaType": "application/vnd.oci.image.manifest.v1+json", - "size": "1331", - "signatures": [ - { - "digest": "sha256:222ibbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222i", - "mediaType": "application/vnd.oci.image.index.v1+json", - "size": "1024", - "signature-typ": "x509" - }, - { - "digest": "sha256:333ic0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333i", - "mediaType": "application/vnd.oci.image.index.v1+json", - "size": "1025", - "signature-typ": "x509" - } - ] -} -``` - -### Signature Discovery - Option 2: Generic Reference Listing API - -A slight alternative to the signatures API is to provide a generic reference listing API, where a paged collection of references are returned. The intent is to provide a broader usage API, beyond the signature type. For example, returning any multi-arch index references. - - - -Using the diagram above, the `net-monitor:v1` manifest tag (4) has a digest of: `sha256:11wma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a11wm`. When requesting the referenced objects, we see 2 signature objects being returned (wabbit-networks (6) & acme-rockets(7)), and an OCI multi-arch index (1). - -```HTTP -GET /v2//manifests/sha256:11wma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a11wm/references/ -``` - -The response could be in the following format. Note the additional `config-mediaType` to identify the specific artifact type in the results. - -```HTTP -200 OK -Content-Type: application/json -{ - "digest": "sha256:11wma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a11wm", - "references": [ - { - "digest": "sha256:222mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222m", - "mediaType": "application/vnd.oci.image.index.v1+json", - "size": "1024", - "config-mediaType": "application/vnd.cncf.notary.config.v2+jwt" - }, - { - "digest": "sha256:333mc0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333m", - "mediaType": "application/vnd.oci.image.index.v1+json", - "size": "1025", - "config-mediaType": "application/vnd.cncf.notary.config.v2+jwt" - }, - { - "digest": "sha256:111ia2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111i", - "mediaType": "application/vnd.oci.image.index.v1+json", - "size": "1025", - "config-mediaType": "application/vnd.oci.image.index.v1+json" - } - ] -} -``` - -### Paging Results - -There are three identified patterns for paging results: - -1. [OCI distribution-spec Tag Listing](#distribution-spec---tags-listing-api) -1. [Google API Design Guidelines](#google-paging-api) -1. [Microsoft API Design Guidelines](https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md#98-pagination) - -#### Distribution Spec - Tags Listing API - -The [OCI distribution-spec][distribution-spec-paging] identifies paging with `n` and `last` parameters: -[distribution-spec-paging] - -Get a list of paginated signatures from the registry. The response will include an opaque URL that can be followed to obtain the next page of results. - -Paginated tag results can be retrieved by adding an `n` parameter to the request URL, declaring that the response SHOULD be limited to `n` results. Starting a paginated flow MAY begin as follows: - -```HTTP -GET /v2//manifests/sha256:11wma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a11wm/references/list?n= -``` - -The above specifies that a tags response SHOULD be returned, from the start of the result set, ordered lexically, limiting the number of results to `n`. The response to such a request would look as follows: - -```HTTP -200 OK -Content-Type: application/json -Link: <?n=&last=>; rel="next" -{ - "digest": "sha256:11wma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a11wm", - "@nextLink": "{opaqueUrl}", - "references": [ - { - "digest": "sha256:222mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222m", - "mediaType": "application/vnd.oci.image.index.v1+json", - "size": "1024", - "config-mediaType": "application/vnd.cncf.notary.config.v2+jwt" - }, - { - "digest": "sha256:333mc0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333m", - "mediaType": "application/vnd.oci.image.index.v1+json", - "size": "1025", - "config-mediaType": "application/vnd.cncf.notary.config.v2+jwt" - }, - { - "digest": "sha256:111ia2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111i", - "mediaType": "application/vnd.oci.image.index.v1+json", - "size": "1025", - "config-mediaType": "application/vnd.oci.image.index.v1+json" - } - ] -} -``` - -To get the _next_ `n` entries, one can create a URL where the argument `last` has the value from `references[len(tags)-1]`. -If there are indeed more results, the URL for the next block is encoded in an [RFC5988](https://tools.ietf.org/html/rfc5988) `Link` header, as a "next" relation. - -The presence of the `Link` header communicates to the client that the entire result set has not been returned and another request MAY be issued. -If the header is not present, the client can assume that all results have been received. - -> __NOTE:__ In the request template above, note that the brackets are required. For example, if the url is `http://example.com//manifests/sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042/references/list?n=20&last=b`, the value of the header would be `http://example.com//manifests/sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042/references/list?n=20&last=b>; rel="next"`. -> Please see [RFC5988](https://tools.ietf.org/html/rfc5988) for details. - -Compliant client implementations SHOULD always use the `Link` header value when proceeding through results linearly. The client MAY construct URLs to skip forward in the list of tags. - -To get the next result set, a client would issue the request as follows, using the URL encoded in the described `Link` header: - -```HTTP -GET /v2//manifests/sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042/references/list?n=&last= -``` - -The above process should then be repeated until the `Link` header is no longer set in the response. - -The tag list result set is represented abstractly as a lexically sorted list, where the position in that list can be specified by the query term `last`. The entries in the response start _after_ the term specified by `last`, up to `n` -entries. - -#### Google Paging API - -From [Google API Design Guides][google-paging-api] - -To support pagination (returning list results in pages) in a List method, the API shall: - -* define `a string` field `page_token` in the `List` method's request message. The client uses this field to request a specific page of the list results. -* define an `int32` field `page_size` in the `List` method's request message. Clients use this field to specify the maximum number of results to be returned by the server. The server **may** further constrain the maximum number of results returned in a single page. If the `page_size` is `0`, the server will decide the number of results to be returned. -* define a `string` field `next_page_token` in the `List` method's response message. This field represents the pagination token to retrieve the next page of results. If the value is `""`, it means no further results for the request. -To retrieve the next page of results, client **shall** pass the value of response's `next_page_token` in the subsequent `List` method call (in the request message's `page_token` field): - -```HTTP -GET /v2//manifests/sha256:11wma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a11wm/references/list?page_token=1&page_size=10&next_page_token= -``` - -The above specifies that a tags response SHOULD be returned, from the start of the result set, ordered lexically, limiting the number of results to `n`. The response to such a request would look as follows: - -```json -{ - "digest": "sha256:11wma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a11wm", - "@next_page_token": "{opaqueUrl}", - "references": [ - { - "digest": "sha256:222mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222m", - "mediaType": "application/vnd.oci.image.index.v1+json", - "size": "1024", - "config-mediaType": "application/vnd.cncf.notary.config.v2+jwt" - }, - { - "digest": "sha256:333mc0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333m", - "mediaType": "application/vnd.oci.image.index.v1+json", - "size": "1025", - "config-mediaType": "application/vnd.cncf.notary.config.v2+jwt" - }, - { - "digest": "sha256:111ia2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111i", - "mediaType": "application/vnd.oci.image.index.v1+json", - "size": "1025", - "config-mediaType": "application/vnd.oci.image.index.v1+json" - } - ] -} -``` - -## Signature Pull - -Using one of the options from the [Signature Discovery](#signature-discovery) section, a specific digest is resolved. A signature shall be pulled using the distribution spec [GET Manifest][distribution-spec-get-manifest] API. - -## Example Artifacts - -The following are references used in the examples below. - -These assume: - -* The original net-monitors image was sourced from `registry.wabbit-networks.com/net-monitor:v1`. -* Wabbit Networks signed the original image -* ACME Rockets imported the net-monitor image into `registry.acme-rockets.com/net-monitor:v1` -* The Wabbit Networks signature was copied into `registry.acme-rockets.com/net-monitor:v1` -* ACME Rockets added a verification signature. -* Signature objects do NOT have tags. However, they are placed in the same repo as the artifact they reference. -* Per the design options, a signature object may be persisted as an OCI Manifest or OCI Index. - -### Artifacts submitted to a registry - -The following are artifacts that represent container images and signature artifacts. Depending on the example above, the signatures are represented as an oci manifest or oci index. Some tags are re-used to represent platform neutral examples. For instance, `net-monitor:v1` is represented as both a default linux image manifest, and a multi-arch index. In some examples, the platform is removed from the tag for brevity and focus on the topic at hand. _It is not suggested `:v1` tags can point to multiple things at the same time._ - -|Artifact |`config.mediaType` | Digest | -|------------------------------------------|-------------------------------------------|-------------------------------------------------------------------------| -|`net-monitor:v1` image **manifest** |`application/vnd.oci.image.config.v1+json` |`sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m`| -|`net-monitor:v1-linux` image **manifest** |`application/vnd.oci.image.config.v1+json` |`sha256:11lma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a11lm`| -|`net-monitor:v1-win` image **manifest** |`application/vnd.oci.image.config.v1+json` |`sha256:11wma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a11wm`| -|`net-monitor:v1` multi-arch **index** |`application/vnd.oci.image.config.v1+json` |`sha256:111ia2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111i`| -|wabbit-networks signature **manifest** |`application/vnd.cncf.notary.config.v2+jwt`|`sha256:222mbbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222m`| -|wabbit-networks signature **index** |`application/vnd.cncf.notary.config.v2+jwt`|`sha256:222ibbf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cb222i`| -|acme-rockets signature **manifest** |`application/vnd.cncf.notary.config.v2+jwt`|`sha256:333mc0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333m`| -|acme-rockets signature **index** |`application/vnd.cncf.notary.config.v2+jwt`|`sha256:333ic0c33ebc4a74a0a554c86ac2b28ddf3454a5ad9cf90ea8cea9f9e75c333i`| - -### Config Objects - referenced by manifests - -The following are descriptors, representing config objects within a manifest and/or index - -| Config Object | Config Digest | -|-|-| -|net-monitor image |`sha256:111ca3788f3464fd9a06386c4d7a8e3018b525278ac4b9da872943d4cfea111c`| -|wabbit-networks signature |`sha256:222cb130c152895905abe66279dd9feaa68091ba55619f5b900f2ebed38b222c`| -|acme-rockets signature |`sha256:333cc44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b785c333c`| - -### Example manifest for the platform agnostic **container image**: `registry.acme-rockets.com/net-monitor:v1` - -```json -{ - "schemaVersion": 2, - "mediaType": "application/vnd.oci.image.manifest.v2+json", - "config": { - "mediaType": "application/vnd.oci.image.config.v1+json", - "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", - "size": 1906 - }, - "layers": [ - { - "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", - "digest": "sha256:9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0", - "size": 32654 - }, - { - "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", - "digest": "sha256:ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736", - "size": 73109 - } - ] -} -``` - -### Example **config object** for the **Notary v2 signature artifact** - -See [nv2 signature spec][nv2-signature-spec] for more details. - -```json -{ - "signed": { - "digest": "sha256:111ma2d22ae5ef400769fa51c84717264cd1520ac8d93dc071374c1be49a111m", - "size": 528, - "references": [ - "registry.acme-rockets.com/net-monitor:v1" - ], - "exp": 1627555319, - "nbf": 1596019319, - "iat": 1596019319 - }, - "signature": { - "typ": "x509", - "sig": "UFqN24K2fLj7/h2slM68PLTfF9CDhrEVGuMQ8m3kkQJ4SKusj9fNxYV78tTiedqB+E8SqVH66mZbdlTrVQFJAd7aL2c3NZFfo92pE9SaHnqEDqnnGWXGRVjtBRM13YyRDm2wD8aRyuL5jEDUkTw7jBLY0+LfKHMDuYCsOOzvedof7aiaFc3qA+qKiW53jn2uEGCFfAs0LmsNafGfAtVmdGSO4zX4fdnQFAGT8sbUmL71uXl9W1B6tGeLfx5nBoQUvtplQipHly/yMQvWw7qMXsaAsf/BbGDmivN06CRahSb7VOwNq6K7Py4zYeiW40hEFVz9L7/5xT5XI1unKPZDuw==", - "alg": "RS256", - "x5c": [ - "MIIDszCCApugAwIBAgIUL1anEU/yJy67VJTbHkNX0bBNAnEwDQYJKoZIhvcNAQELBQAwaTEdMBsGA1UEAwwUcmVnaXN0cnkuZXhhbXBsZS5jb20xFDASBgNVBAoMC2V4YW1wbGUgaW5jMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTAeFw0yMDA3MjcxNDQzNDZaFw0yMTA3MjcxNDQzNDZaMGkxHTAbBgNVBAMMFHJlZ2lzdHJ5LmV4YW1wbGUuY29tMRQwEgYDVQQKDAtleGFtcGxlIGluYzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkKwAcV44psjN8nno1eZ3zv1ZKUhJAoxwBOIGfIxIe+iHtpXLvFFVwk5Jbxu+Pkig2N4B3Ilrj/Vryi0hxp4mag02M733bXLRENSOFONRkslpO8zHUN5pYdnhTSwYTLap1+1bgcFSuUXLWieqZB6qc7kiv3bj3SPaf42+s48V49t/OpXxLtgiWL9XkuDTZctpJJA4vHHk6Ou0bcg7iGm+L1xwIfb8Ml4oWvT0SF35fgW08bbLXZ2v1XCLRsrWUgbq4U+KxtEpG3XIYcYhKx1rIrUhfEJkuHzgPglM11gG5W+Cyfg+wfOJig5q6axIKWzIf6C8m8lmy6bM+N5EsD9SvAgMBAAGjUzBRMB0GA1UdDgQWBBTf1hM6/ibGF+u/SVAK88FUMjzRoTAfBgNVHSMEGDAWgBTf1hM6/ibGF+u/SVAK88FUMjzRoTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBgvVau5+2wAuCsmOyyG28h1zyC4IPmMmpRZTDOp/pLdwXeHjJr8kEC3l92qJEvc+WAboJ1RoucHycUe7RWh2C6ZF/WPCBLyWGwnlyqGyRM9/j86UJ1OgiuZl7kl9zxwWoaxPBCmHa0RHowdQB7AVlpqg1c7FhKjhUCBmGT4Ve8tV0hdZtrZoQV+6xHPbUd37KV1B1Bmfo3o4ekoJKhUu99Eo03OpE3JLtM13A1HxABEuQGHTI0tycDBBdRn3b03HoIhU0VnqjvpV1KPvsrgYi/0VStLNezZPgGe0fG3Xgy8yekdB9NMUn+zZLATI4+z8j4QH5Wj5ZPaUkyoAD2oUJO" - ] - } -} -``` - -[cnab]: https://cnab.io -[distribution-spec-paging]: https://github.com/opencontainers/distribution-spec/blob/master/spec.md#listing-image-tags -[distribution-spec-get-manifest]: https://github.com/opencontainers/distribution-spec/blob/master/spec.md#get-manifest -[google-paging-api]: https://cloud.google.com/apis/design/design_patterns#list_pagination -[notaryv2-goals]: https://github.com/notaryproject/requirements/blob/52c1ba2f5696a98b317aff84288d3564b4041ad5/README.md#goals -[nv2-signature-spec]: https://github.com/notaryproject/nv2/blob/efe151ddf6a7fd3848fea340cab7553d0a7d295b/docs/signature/README.md -[oci-artifacts]: https://github.com/opencontainers/artifacts -[oci-artifacts-index]: https://github.com/opencontainers/artifacts/issues/25 -[oci-index]: https://github.com/opencontainers/image-spec/blob/master/image-index.md -[oci-descriptor]: https://github.com/opencontainers/image-spec/blob/master/descriptor.md -[oci-distribution]: https://github.com/opencontainers/distribution-spec -[oci-manifest]: https://github.com/opencontainers/image-spec/blob/master/manifest.md -[oras]: https://github.com/deislabs/oras -[oci-dist-spec-manifest-put]: https://github.com/opencontainers/distribution-spec/blob/master/spec.md#put-manifest diff --git a/docs/docker-plugins/README.md b/docs/docker-plugins/README.md deleted file mode 100644 index 234aba0d9..000000000 --- a/docs/docker-plugins/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Docker Plugins - -Multiple docker plugins are provided for `nv2` scenarios. - -- [docker-generate](docker-generate.md) -- [docker-nv2](docker-nv2.md) \ No newline at end of file diff --git a/docs/docker-plugins/docker-generate.md b/docs/docker-plugins/docker-generate.md deleted file mode 100644 index e55afbde4..000000000 --- a/docs/docker-plugins/docker-generate.md +++ /dev/null @@ -1,51 +0,0 @@ -# docker-generate -Docker CLI plugin to generate metadata **offline**. - -## Build and Install -This plugin requires [golang](https://golang.org/dl/) with version `>= 1.16`. - -To build and install, run -``` -go build -o ~/.docker/cli-plugins/docker-generate ./cmd/docker-generate -``` -Finally, follow the [documentation](https://docs.docker.com/engine/reference/commandline/cli/#experimental-features) to enable experimental features for Docker CLI. - -## Instructions -### Generate manifest -To generate a manifest of an image referenced by ``, run -``` -docker generate manifest -``` -For example, -``` -docker build -t myapp:1.0 . -docker generate manifest myapp:1.0 -``` - -#### Output to files -If a file is desired instead of standard output, try -``` -docker generate manifest > manifest.json -``` -or -``` -docker generate manifest -o manifest.json -``` - -#### From `docker save` -Manifest is also possible to be generated from a tar file saved via `docker save`. -``` -docker save > save.tar -cat save.tar | docker generate manifest -``` -Basically, -``` -docker save | docker generate manifest -``` -is equivalent to -``` -docker generate manifest -``` - -## Known Limitation -The current version of this plugin can only accept one `reference` at a time. diff --git a/docs/docker-plugins/docker-nv2.md b/docs/docker-plugins/docker-nv2.md deleted file mode 100644 index 9c0c0aa7b..000000000 --- a/docs/docker-plugins/docker-nv2.md +++ /dev/null @@ -1,54 +0,0 @@ -# docker-nv2 -Docker CLI plugin to demonstrate Notary v2 integration with Docker CLI, leveraging the [notary v2 library](https://github.com/notaryproject/notary). - -## Build and Install -This plugin requires [golang](https://golang.org/dl/) with version `>= 1.16`. - -To build and install, run -``` -go build -o ~/.docker/cli-plugins/docker-nv2 ./cmd/docker-nv2 -``` - -## Instructions -### Create Alias -For better demonstration experience, it is suggested to create the following alias in your shell: -```bash -alias docker="docker nv2" -``` -or if you are using PowerShell on Windows, -```powershell -function docker { cmd /c docker nv2 $args } -``` - -### Example Run -On the producer machine: -```bash -docker notary --enabled -docker build -t $image . -docker notary sign --key identity.pem --cert identity.crt $image -docker push $image -``` - -On the consumer machine: -```bash -docker notary --enabled -docker pull $image -``` -It may fail since the producer machine may use a self-signed certificate, or invalid certificates detected. -See [configurations](#configurations) for more details. - -## Configurations -The config file for notary is default at `~/.docker/nv2.json`. -The intermediate signatures are stored at `~/.docker/nv2/`. - -The config file looks like -```json -{ - "enabled": true, - "verificationCerts": [ - "path/to/the/certs/for/verification" - ] -} -``` -To pull images properly, certification paths are required to be provided at `verificationCerts`. -It is suggested to use absolute paths. diff --git a/docs/nv2/README.md b/docs/nv2/README.md deleted file mode 100644 index b9252fb94..000000000 --- a/docs/nv2/README.md +++ /dev/null @@ -1,271 +0,0 @@ -# Notary V2 (nv2) - Prototype - -`nv2` is a command line tool for signing and verifying [OCI Artifacts]. This implementation supports `x509` signing mechanisms. - -## Table of Contents - -- [Prerequisites](#prerequisites) -- [CLI Overview](#cli-overview) -- [Offline signing & verification](#offline-signing-and-verification) - -## Prerequisites - -### Build and Install - -`nv2`: see [building.md](/building.md) - -### Self-signed certificate key generation - -To generate a `x509` self-signed certificate key pair `example.key` and `example.crt`, run - -``` shell -openssl req \ - -x509 \ - -sha256 \ - -nodes \ - -newkey rsa:2048 \ - -days 365 \ - -subj "/CN=registry.wabbit-networks.io/O=wabbit-networks inc/C=US/ST=Washington/L=Seattle" \ - -keyout wabbit-networks.key \ - -out wabbit-networks.crt -``` - -When generating the certificate, make sure that the Common Name (`CN`) is set properly in the `Subject` field. The Common Name will be verified against the registry name within the signature. - -## Offline Signing - -Offline signing is accomplished with the `nv2 sign` command. - -### nv2 sign options - -```shell -NAME: - nv2 sign - signs OCI Artifacts - -USAGE: - nv2 sign [command options] [] - -OPTIONS: - --method value, -m value signing method - --key value, -k value signing key file [x509] - --cert value, -c value signing cert [x509] - --expiry value, -e value expire duration (default: 0s) - --reference value, -r value original references - --output value, -o value write signature to a specific path - --username value, -u value username for generic remote access - --password value, -p value password for generic remote access - --plain-http remote access via plain HTTP (default: false) - --media-type value specify the media type of the manifest read from file or stdin (default: "application/vnd.docker.distribution.manifest.v2+json") - --help, -h show help (default: false) -``` - -Signing and verification are based on [OCI manifests](https://github.com/opencontainers/image-spec/blob/master/manifest.md), [docker-generate](https://github.com/shizhMSFT/docker-generate) is used to generate the manifest, which is exactly the same manifest as the `docker push` produces. - -### Generating a manifest - -Notary v2 signing is accomplished by signing the OCI manifest representing the artifact. When building docker images, the manifest is not generated until the image is pushed to a registry. To accomplish offline/local signing, the manifest must first exist. - -- Build the sample `net-monitor` image - - ``` shell - docker build \ - -f Dockerfile \ - -t registry.wabbit-networks.io/net-monitor:v1 \ - https://github.com/wabbit-networks/net-monitor.git#main - ``` - -- Generate a manifest, saving it as `net-monitor_v1-manifest.json` - - ``` shell - docker generate manifest registry.wabbit-networks.io/net-monitor:v1 > net-monitor_v1-manifest.json - ``` - -### Signing using `x509` - -To sign the manifest `net-monitor_v1-manifest.json` using the `--key` from the `x509` `--cert` with the Common Name `registry.wabbit-networks.io`, run: - -```shell -./nv2 sign --method x509 \ - -k wabbit-networks.key \ - -c wabbit-networks.crt \ - -r registry.wabbit-networks.io/net-monitor:v1 \ - -o net-monitor_v1.signature.config.jwt \ - file:net-monitor_v1-manifest.json -``` - -The formatted x509 signature: `net-monitor_v1.signature.config.jwt` is: - -``` json -{ - "typ": "x509", - "alg": "RS256", - "x5c": [ - "MIIDJzCCAg+gAwIBAgIUMwVg7bpx8QmWaFzRcgpRFBN6JoQwDQYJKoZIhvcNAQELBQAwIzEhMB8GA1UEAwwYcmVnaXN0cnkuYWNtZS1yb2NrZXRzLmlvMB4XDTIwMDcyOTExMDIzMloXDTIxMDcyOTExMDIzMlowIzEhMB8GA1UEAwwYcmVnaXN0cnkuYWNtZS1yb2NrZXRzLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2mXqcXqkllwxj7S12WhVDsIu6y4ebZ/CwVwwime44yDcd0bcpdJExqIH/Qy6axQd/1zmLCHPeOXGFq48Ul0oS4Bawj1GEeLvB7VFvqB0KaBeAdxrZAvdKXCXIDH5qyFSGnOmvkja1BuR8XrH7tts5u56i+U3KEDBZg5tfx4cQuKKt0DfXZAL+4RZkNh1LoO77X0ThaBThFoRsg6aZA/cEpttoWmvnO6uUkK73oZEVgZNKGGIZZKzhUjnydRSTphp9GmZzbqUHlOiMvbzdtsQYC0qeQeNqua38HN93Ur3p+oH7oSrBWxX1Xlx933oVb+4G6h5oz0aZvMQ0G6gCLzjwIDAQABo1MwUTAdBgNVHQ4EFgQU8l2F7avSjFZ9TvnpHackunxSFcswHwYDVR0jBBgwFoAU8l2F7avSjFZ9TvnpHackunxSFcswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAwECYhttcbCbqyi7DvOTHw5bixmxplbgD0AmMvE6Ci4P/MrooBququlkri/Jcp58GBaMjxItE4qVsaWwFCEvZEfP2xN4DAbr+rdrIFy9VYuwEIBs5l0ZLRH2H2N3HlqBzhYOjVzNlYfIqnqHUDip2VsUKqhcVFkCmb3cpJ1VNAgjQU2N60JUW28L0XrGyBctBIiicLvdP4NMhHP/hhN2vr2VGIyyo5XtP+QHFi/Uwa48BJ+c9bbVpXeghOMOPMeSJmJ2b/qlp95e/YHlSCfxDXyxZ70N2vBGecrc8ly4tD9KGLb9y3Q7RBgsagOFe7cGQ2db/t60AwTIxP0a9bIyJMg==" - ] -}.{ - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "digest": "sha256:24a74900a4e749ef31295e5aabde7093e3244b119582bd6e64b1a88c71c410d0", - "size": 3056, - "references": [ - "registry.wabbit-networks.io/net-monitor:v1" - ], - "iat": 1597053936 -}.[Signature] -``` - -If the embedded cert chain `x5c` is not desired, it can be replaced by a key ID `kid` by omitting the `-c` option. - -```shell -./nv2 sign -m x509 \ - -k wabbit-networks.key \ - -r registry.wabbit-networks.io/net-monitor:v1 \ - -o net-monitor_v1.signature.config.jwt \ - file:net-monitor_v1-manifest.json -``` - -The formatted x509, without the `x5c` chain signature: `net-monitor_v1.signature.config.jwt` is: - -```json -{ - "typ": "x509", - "alg": "RS256", - "kid": "RQGT:OPJI:IABT:DFXB:52VS:FNOJ:4XBS:H4KY:WHGM:HQMC:WSMN:LKXM" -}.{ - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "digest": "sha256:24a74900a4e749ef31295e5aabde7093e3244b119582bd6e64b1a88c71c410d0", - "size": 3056, - "references": [ - "registry.wabbit-networks.io/net-monitor:v1" - ], - "iat": 1597053992 -}.[Signature] -``` - -The detailed signature specification is [available](../signature/README.md). - -### Offline Verification - -Notary v2 verification can be accomplished with the `nv2 verify` command. - -```shell -NAME: - nv2 verify - verifies OCI Artifacts - -USAGE: - nv2 verify [command options] [] - -OPTIONS: - --signature value, -s value, -f value signature file - --cert value, -c value certs for verification [x509] - --ca-cert value CA certs for verification [x509] - --username value, -u value username for generic remote access - --password value, -p value password for generic remote access - --plain-http remote access via plain HTTP (default: false) - --media-type value specify the media type of the manifest read from file or stdin (default: "application/vnd.docker.distribution.manifest.v2+json") - --help, -h show help (default: false) -``` - -To verify a manifest `example.json` with a signature file `example.nv2`, run - -Since the manifest was signed by a self-signed certificate, that certificate `cert.pem` is required to be provided to `nv2`. - -```shell -./nv2 verify \ - -f net-monitor_v1.signature.config.jwt \ - -c wabbit-networks.crt \ - file:net-monitor_v1-manifest.json -``` - -If the cert isn't self-signed, you can omit the `-c` parameter. - -``` shell -./nv2 verify \ - -f net-monitor_v1.signature.config.jwt \ - file:net-monitor_v1-manifest.json - -sha256:3351c53952446db17d21b86cfe5829ae70f823aff5d410fbf09dff820a39ab55 -``` - -On successful verification, the `sha256` digest of the manifest is printed. Otherwise, `nv2` prints error messages and returns non-zero values. - -The command `nv2 verify` takes care of all signing methods. - -## Remote Manifests - -With `nv2`, it is also possible to sign and verify a manifest or a manifest list in a remote registry where the registry can be a docker registry or an OCI registry. - -### Docker Registry - -Here is an example to sign and verify the image `hello-world` in DockerHub, i.e. `docker.io/library/hello-world:latest`, using `x509`. - -``` shell -nv2 sign -m x509 \ - -k key.key \ - -o hello-world_latest.signature.config.jwt \ - docker://docker.io/library/hello-world:latest - -sha256:49a1c8800c94df04e9658809b006fd8a686cab8028d33cfba2cc049724254202 - -nv2 verify \ - -c cert.crt \ - -f hello-world_latest.signature.config.jwt \ - docker://docker.io/library/hello-world:latest - -sha256:49a1c8800c94df04e9658809b006fd8a686cab8028d33cfba2cc049724254202 -``` - -It is possible to use `digest` in the reference. For instance: - -``` shell -docker.io/library/hello-world@sha256:49a1c8800c94df04e9658809b006fd8a686cab8028d33cfba2cc049724254202 -``` - -If neither `tag` nor `digest` is specified, the default tag `latest` is used. - -### OCI Registry - -OCI registry works the same as Docker but with the scheme `oci`. - -```shell -nv2 sign -m x509 \ - -k key.key \ - -o hello-world_latest.signature.config.jwt \ - oci://docker.io/library/hello-world:latest - -sha256:0ebe6f409b373c8baf39879fccee6cae5e718003ec3167ded7d54cb2b5da2946 - -nv2 verify \ - -c cert.crt \ - -f hello-world_latest.signature.config.jwt \ - oci://docker.io/library/hello-world:latest - -sha256:0ebe6f409b373c8baf39879fccee6cae5e718003ec3167ded7d54cb2b5da2946 -``` - -**Note** The digest of the OCI manifest is different from the Docker manifest for the same image since their format is different. Therefore, the signer should be careful with the manifest type when signing. - -### Plain-HTTP Registries - -To sign and verify images from registries accessed via `HTTP`, such as `localhost`, the option `--plain-http` is required. - -``` shell -docker tag example localhost:5000/example -docker push localhost:5000/example -The push refers to repository [localhost:5000/example] -50644c29ef5a: Pushed -latest: digest: sha256:3351c53952446db17d21b86cfe5829ae70f823aff5d410fbf09dff820a39ab55 size: 528 -nv2 verify -f example.nv2 --plain-http docker://localhost:5000/example - -sha256:3351c53952446db17d21b86cfe5829ae70f823aff5d410fbf09dff820a39ab55 -``` - -### Secure Image Pulling - -Since the tag might be changed during the verification process, it is required to pull by digest after verification. - -```shell -digest=$(nv2 verify -f hello-world_latest.signature.config.jwt -c cert.crt docker://docker.io/library/hello-world:latest) -if [ $? -eq 0 ]; then - docker pull docker.io/library/hello-world@$digest -fi -``` diff --git a/docs/nv2/demo-script.md b/docs/nv2/demo-script.md deleted file mode 100644 index 1aa71abf9..000000000 --- a/docs/nv2/demo-script.md +++ /dev/null @@ -1,307 +0,0 @@ -# Demo Steps - -The following demonstrates the capabilities of [Notary v2 - Prototype-2][nv2-prototype-2]. - -## Demo Setup - -Perform the following steps prior to the demo: - -- Install [Docker Desktop](https://www.docker.com/products/docker-desktop) for local docker operations -- [Install and Build nv2](../../building.md) -- [Install and Build the ORAS Prototype-2 branch](https://github.com/deislabs/oras/blob/prototype-2/docs/artifact-manifest.md) -- Generate the `~/.docker/nv2.json` config file - ```bash - docker nv2 notary --enabled - ``` -- Setup names and variables with `localhost:5000` - >**NOTE:** See [Simulating a Registry DNS Name](#simulating-a-registry-dns-name) for using `registry.wabbit-networks.io` - ```bash - export PORT=5000 - export REGISTRY=localhost:${PORT} - export REPO=${REGISTRY}/net-monitor - export IMAGE=${REPO}:v1 - ``` - -- Generate the Wabbit Networks Public and Private Keys: - ```bash - openssl req \ - -x509 \ - -sha256 \ - -nodes \ - -newkey rsa:2048 \ - -days 365 \ - -subj "/CN=${REGISTRY}/O=wabbit-networks inc/C=US/ST=Washington/L=Seattle" \ - -addext "subjectAltName=DNS:${REGISTRY}" \ - -keyout ./wabbit-networks.key \ - -out ./wabbit-networks.crt - ``` -### Start a Local Registry Instance - ```bash - docker run -d -p ${PORT}:5000 notaryv2/registry:nv2-prototype-2 - ``` - -## Demo The End to End Experience - -- Wabbit Networks is a small software company that produces network monitoring software. -- ACME Rockets wishes to acquire network monitoring software. -- ACME Rockets doesn't know about Wabbit Networks, but finds their [net-monitor software in Docker Hub](https://hub.docker.com/r/wabbitnetworks/net-monitor) -- Since they've never heard of Wabbit Networks, they're a little reluctant to run network software without some validations. -- ACME Rockets has a policy to only import Docker Hub certified software, or approved vendors. -- Wabbit Networks works with Docker Hub to get certified, to help with their customer confidence. -- ACME Rockets will only deploy software that's been scanned and approved by the ACME Rockets security team. They know it's been approved because all approved software has been signed by the ACME Rockets security team. - -![](../../media/notary-e2e-scenarios.svg) - -### Alias `nv2` Commands - -- To avoid having to type `docker nv2` each time, create an alias: - ```bash - alias docker="docker nv2" - ``` - -## Wabbit Networks Build, Sign, Promote Process - -Let's walk through the sequence of operations Wabbit Networks takes to build, sign and promote their software. - -Within the automation of Wabbit Networks, the following steps are completed: - -1. Building the `net-monitor` image -1. Sign the `net-monitor` image -1. Push the image and signature -1. Create and push a signed SBoM - -### Build the `net-monitor` image - -- Build the image, directly from GitHub to simplify the sequence. - ```bash - docker build \ - -t $IMAGE \ - https://github.com/wabbit-networks/net-monitor.git#main - ``` - _To represent an ephemeral client in an air-gapped environment, git clone, then build with `.` as the context_ - -### Acquire the private key - -- As a best practice, we'll always build on an ephemeral client, with no previous state. -- The ephemeral client will retrieve the private signing key from the companies secured key vault provider. - -These specific steps are product/cloud specific, so we'll assume these steps have been completed. - -### Sign and Push the Image and Signature - -Using the private key, we'll sign the `net-monitor:v1` image. Note, we're signing the image with a registry name that we haven't yet pushed to. This enables offline signing scenarios. This is important as the image will eventually be published on `registry.wabbit-networks.io/`, however their internal staging and promotion process may publish to internal registries before promotion to the public registry. - -- Generate an [nv2 signature][nv2-signature], persisted locally as `net-monitor_v1.signature.jwt` - -- Enable notary, for the nv2 extension to account for signing and verification steps - ```shell - docker notary --enabled - ``` -- Generate an [nv2 signature][nv2-signature], persisted within the `/.docker/nv2/sha256/` directory: - ```shell - docker notary sign \ - --key ./wabbit-networks.key \ - --cert ./wabbit-networks.crt \ - $IMAGE - ``` -- Push the image, with the signature - ```bash - docker push $IMAGE - ``` -- View the output, which includes pushing the signature as a reference: - ```bash - The push refers to repository [registry.wabbit-networks.io/net-monitor] - 8ea3b23f387b: Preparing - 8ea3b23f387b: Pushed - v1: digest: sha256:31c6d76b9a0af8d2c0a7fc16b43b7d8d9b324aa5ac3ef8c84dc48ab5ba5c0f49 size: 527 - Pushing signature - signature manifest: digest: sha256:8eb7394c8f287ebd0e84a4659f37a2688c6e07e39906933ccb83d9011fb29034 size: 2534 - refers to manifests: digest: sha256:31c6d76b9a0af8d2c0a7fc16b43b7d8d9b324aa5ac3ef8c84dc48ab5ba5c0f49 size: 527 - ``` -- Discover the references using the [oras prototype-2 branch](https://github.com/deislabs/oras/tree/prototype-2). - ```bash - oras discover \ - --plain-http \ - $IMAGE - ``` - -### Validate the image - -To validate an image, `docker pull` with `docker notary --enabled` will attempt to validate the image, based on the local keys. - -- Attempt to pull the `net-monitor:v1` image: - ```bash - docker pull $IMAGE - ``` - -- The above command will fail, as we haven't configured the `nv2` client access to the public keys. - ```bash - Looking up for signatures - Found 1 signatures - 2021/03/02 18:34:47 none of the signatures are valid: verification failure: x509: certificate signed by unknown authority - ``` - -- Open the `nv2.json` configuration file: - ```bash - code ~/.docker/nv2.json - ``` - -- Add the wabbit networks public key: - ```json - { - "enabled": true, - "verificationCerts": [ - "/home//nv2-demo/wabbit-networks.crt" - ] - } - ``` - -- Pull the `net-monitor:v1` image, using the public key for verification: - ```bash - docker pull $IMAGE - ``` -- The validated pull can be seen: - ```bash - v1 digest: sha256:48575dfb9ef2ebb9d67c6ed3cfbd784d635fcfae8ec820235ffa24968b3474dc size: 527 - Looking up for signatures - Found 1 signatures - Found valid signature: sha256:282f5475ac4788f5c0ce3c0c44995726192385c2cae85d0f04da12595707a73f - The image is originated from: - - registry.wabbit-networks.io/net-monitor:v1 - registry.wabbit-networks.io/net-monitor@sha256:48575dfb9ef2ebb9d67c6ed3cfbd784d635fcfae8ec820235ffa24968b3474dc: Pulling from net-monitor - Digest: sha256:48575dfb9ef2ebb9d67c6ed3cfbd784d635fcfae8ec820235ffa24968b3474dc - Status: Downloaded newer image for registry.wabbit-networks.io/net-monitor@sha256:48575dfb9ef2ebb9d67c6ed3cfbd784d635fcfae8ec820235ffa24968b3474dc - registry.wabbit-networks.io/net-monitor@sha256:48575dfb9ef2ebb9d67c6ed3cfbd784d635fcfae8ec820235ffa24968b3474dc - ``` - -### Create a Software Bill of Materials - -- Create an overly simplistic SBoM - ```bash - echo '{"version": "0.0.0.0", "artifact": "net-monitor:v1", "contents": "good"}' > sbom.json - ``` -- Push the SBoM with ORAS, saving the manifest for signing - ```bash - oras push $REPO \ - --artifact-type application/x.example.sbom.v0 \ - --artifact-reference $IMAGE \ - --export-manifest sbom-manifest.json \ - --plain-http \ - ./sbom.json:application/tar - ``` -- View the references with `oras discover`: - ```bash - oras discover \ - --plain-http \ - $IMAGE - ``` - -### Sign the SBoM - -In the above case, the SBoM has already been pushed to the registry. To sign it before pushing, we could have used `oras push` with the `--dry-run` and `--export-manifest` options. - -- For non-container images, we'll use the `nv2` cli to sign and the `oras` cli to push to a registry. We'll use the `oras discover` cli to find the sbom digest the signature will reference. - ```bash - nv2 sign \ - -m x509 \ - -k wabbit-networks.key \ - -c wabbit-networks.crt \ - --plain-http \ - --push \ - --push-reference oci://${REPO}@$(oras discover \ - --artifact-type application/x.example.sbom.v0 \ - --output-json \ - --plain-http \ - $IMAGE | jq -r .references[0].digest) \ - file:sbom-manifest.json - ``` -- Dynamically get the SBoM digest - ```bash - DIGEST=$(oras discover \ - --artifact-type application/x.example.sbom.v0 \ - --output-json \ - --plain-http \ - $IMAGE | jq -r .references[0].digest) -- Discover referenced artifacts of the SBoM - ```bash - oras discover \ - --plain-http \ - ${REPO}@${DIGEST} - ``` -- Generates: - ```bash - Discovered 1 artifacts referencing localhost:5000/net-monitor@sha256:adfe3a3c50838fc2a19d5d7e73119dcadad7ad8e4e98f1e0fd100dd9d2278b71 - Digest: sha256:adfe3a3c50838fc2a19d5d7e73119dcadad7ad8e4e98f1e0fd100dd9d2278b71 - - Artifact Type Digest - application/vnd.cncf.notary.v2 sha256:b7fc5fdb81f2ada359d0a709004360d1f08c9d2ac8a80630b152d1c6fb35460e - ``` - -The above workflow demonstrates the **Notary v2, prototype-2** target experience. - -## Optional Steps - -Some optional steps: - -## Demo Reset - -If iterating through the demo, these are the steps required to reset to a clean state: - -- Remove docker alias: - ```bash - unalias docker - ``` -- Reset the local registry: - ```bash - docker rm -f $(docker ps -a -q) - docker run -d -p ${PORT}:5000 notaryv2/registry:nv2-prototype-2 - ``` -- Remove the `net-monitor:v1` image: - ```bash - docker rmi -f ${REGISTRY}/net-monitor:v1 - ``` -- Remove `wabbit-networks.crt` from `"verificationCerts"` in the `nv2.json` configuration file: - ```bash - code ~/.docker/nv2.json - ``` -- Remove previous signatures: - ```bash - rm -r ~/.docker/nv2/sha256/ - ``` - -### Simulating a Registry DNS Name - -Configure the additional steps to simulate a fully qualified dns name for wabbit-networks. - -- Setup names and variables with `registry.wabbit-networks.io` - ```bash - export PORT=80 - export REGISTRY=registry.wabbit-networks.io - export REPO=${REGISTRY}/net-monitor - export IMAGE=${REPO}:v1 - ``` -- Edit the `~/.docker/nv2.json` file to support local, insecure registries - ```json - { - "enabled": true, - "verificationCerts": [ - ], - "insecureRegistries": [ - "registry.wabbit-networks.io" - ] - } - ``` -- Add a `etc/hosts` entry to simulate pushing to registry.wabbit-networks.io - - If running on windows, _even if using wsl_, add the following entry to: `C:\Windows\System32\drivers\etc\hosts` - ```hosts - 127.0.0.1 registry.wabbit-networks.io - ``` -- Continue with [Start a Local Registry Instance](#start-a-local-registry-instance) - -[docker-generate]: https://github.com/notaryproject/nv2/tree/prototype-2 -[nv2-signature]: ../signature/README.md -[oci-image-manifest]: https://github.com/opencontainers/image-spec/blob/master/manifest.md -[oci-image-index]: https://github.com/opencontainers/image-spec/blob/master/image-index.md -[oci-artifact-manifest]: https://github.com/SteveLasker/artifacts/blob/oci-artifact-manifest/artifact-manifest.md -[oras]: https://github.com/deislabs/oras/tree/prototype-2 -[nv2-prototype-2]: https://github.com/notaryproject/notaryproject/issues/53 diff --git a/docs/signature/README.md b/docs/signature/README.md deleted file mode 100644 index 76bca766a..000000000 --- a/docs/signature/README.md +++ /dev/null @@ -1,239 +0,0 @@ -# Notary V2 Signature Specification - -This section defines the signature file, which is a [JWT](https://tools.ietf.org/html/rfc7519) variant. - -## Signature Goals - -- Offline signature creation -- Persistence within an [OCI Artifact][oci-artifacts] enabled, [distribution-spec][distribution-spec] based registry -- Artifact and signature copying within and across [OCI Artifact][oci-artifacts] enabled, [distribution-spec][distribution-spec] based registries -- Support public registry acquisition of content - where the public registry may host certified content as well as public, non-certified content -- Support private registries, where public content may be copied to, and new content originated within -- Air-gapped environments, where the originating registry of content is not accessible -- Multiple signatures per artifact, enabling the originating vendor signature, public registry certification and user/environment signatures -- Maintain the original artifact digest and collection of associated tags, supporting dev/ops deployment definitions - -## Signature - -A Notary v2 signature is clear-signed signature of manifest metadata, including but not limited to - -- [OCI Image Index](https://github.com/opencontainers/image-spec/blob/master/image-index.md) -- [OCI Image Manifest](https://github.com/opencontainers/image-spec/blob/master/manifest.md) -- [Docker Image Manifest List](https://docs.docker.com/registry/spec/manifest-v2-2/#manifest-list) -- [Docker Image Manifest](https://docs.docker.com/registry/spec/manifest-v2-2/#image-manifest) - -### Signing an Artifact Manifest - -For any [OCI Artifact][oci-artifacts] submitted to a registry, an [OCI Manifest][oci-manifest] and an optional [OCI Manifest List/Index][oci-manifest-list] is required. - -The nv2 prototype signs a combination of: - -- Key properties -- The target artifact manifest digest -- *optional:* list of associated tags - -#### Generating a self-signed x509 cert - -``` shell -openssl req \ - -x509 \ - -sha256 \ - -nodes \ - -newkey rsa:2048 \ - -days 365 \ - -subj "/CN=registry.example.com/O=example inc/C=US/ST=Washington/L=Seattle" \ - -keyout example.key \ - -out example.crt -``` - -An nv2 client would generate the following header and claims to be signed. - -The header would be a base64 URL encoded string without paddings: - -``` -eyJ0eXAiOiJ4NTA5IiwiYWxnIjoiUlMyNTYiLCJ4NWMiOlsiTUlJRHN6Q0NBcHVnQXdJQkFnSVVMMWFuRVUveUp5NjdWSlRiSGtOWDBiQk5BbkV3RFFZSktvWklodmNOQVFFTEJRQXdhVEVkTUJzR0ExVUVBd3dVY21WbmFYTjBjbmt1WlhoaGJYQnNaUzVqYjIweEZEQVNCZ05WQkFvTUMyVjRZVzF3YkdVZ2FXNWpNUXN3Q1FZRFZRUUdFd0pWVXpFVE1CRUdBMVVFQ0F3S1YyRnphR2x1WjNSdmJqRVFNQTRHQTFVRUJ3d0hVMlZoZEhSc1pUQWVGdzB5TURBM01qY3hORFF6TkRaYUZ3MHlNVEEzTWpjeE5EUXpORFphTUdreEhUQWJCZ05WQkFNTUZISmxaMmx6ZEhKNUxtVjRZVzF3YkdVdVkyOXRNUlF3RWdZRFZRUUtEQXRsZUdGdGNHeGxJR2x1WXpFTE1Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBZ01DbGRoYzJocGJtZDBiMjR4RURBT0JnTlZCQWNNQjFObFlYUjBiR1V3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRRGtLd0FjVjQ0cHNqTjhubm8xZVozenYxWktVaEpBb3h3Qk9JR2ZJeEllK2lIdHBYTHZGRlZ3azVKYnh1K1BraWcyTjRCM0lscmovVnJ5aTBoeHA0bWFnMDJNNzMzYlhMUkVOU09GT05Sa3NscE84ekhVTjVwWWRuaFRTd1lUTGFwMSsxYmdjRlN1VVhMV2llcVpCNnFjN2tpdjNiajNTUGFmNDIrczQ4VjQ5dC9PcFh4THRnaVdMOVhrdURUWmN0cEpKQTR2SEhrNk91MGJjZzdpR20rTDF4d0lmYjhNbDRvV3ZUMFNGMzVmZ1cwOGJiTFhaMnYxWENMUnNyV1VnYnE0VStLeHRFcEczWElZY1loS3gxcklyVWhmRUprdUh6Z1BnbE0xMWdHNVcrQ3lmZyt3Zk9KaWc1cTZheElLV3pJZjZDOG04bG15NmJNK041RXNEOVN2QWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJUZjFoTTYvaWJHRit1L1NWQUs4OEZVTWp6Um9UQWZCZ05WSFNNRUdEQVdnQlRmMWhNNi9pYkdGK3UvU1ZBSzg4RlVNanpSb1RBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFCZ3ZWYXU1KzJ3QXVDc21PeXlHMjhoMXp5QzRJUG1NbXBSWlRET3AvcExkd1hlSGpKcjhrRUMzbDkycUpFdmMrV0Fib0oxUm91Y0h5Y1VlN1JXaDJDNlpGL1dQQ0JMeVdHd25seXFHeVJNOS9qODZVSjFPZ2l1Wmw3a2w5enh3V29heFBCQ21IYTBSSG93ZFFCN0FWbHBxZzFjN0ZoS2poVUNCbUdUNFZlOHRWMGhkWnRyWm9RVis2eEhQYlVkMzdLVjFCMUJtZm8zbzRla29KS2hVdTk5RW8wM09wRTNKTHRNMTNBMUh4QUJFdVFHSFRJMHR5Y0RCQmRSbjNiMDNIb0loVTBWbnFqdnBWMUtQdnNyZ1lpLzBWU3RMTmV6WlBnR2UwZkczWGd5OHlla2RCOU5NVW4relpMQVRJNCt6OGo0UUg1V2o1WlBhVWt5b0FEMm9VSk8iXX0 -``` - -The parsed and formatted header would be: - -```json -{ - "typ": "x509", - "alg": "RS256", - "x5c": [ - "MIIDszCCApugAwIBAgIUL1anEU/yJy67VJTbHkNX0bBNAnEwDQYJKoZIhvcNAQELBQAwaTEdMBsGA1UEAwwUcmVnaXN0cnkuZXhhbXBsZS5jb20xFDASBgNVBAoMC2V4YW1wbGUgaW5jMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTAeFw0yMDA3MjcxNDQzNDZaFw0yMTA3MjcxNDQzNDZaMGkxHTAbBgNVBAMMFHJlZ2lzdHJ5LmV4YW1wbGUuY29tMRQwEgYDVQQKDAtleGFtcGxlIGluYzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkKwAcV44psjN8nno1eZ3zv1ZKUhJAoxwBOIGfIxIe+iHtpXLvFFVwk5Jbxu+Pkig2N4B3Ilrj/Vryi0hxp4mag02M733bXLRENSOFONRkslpO8zHUN5pYdnhTSwYTLap1+1bgcFSuUXLWieqZB6qc7kiv3bj3SPaf42+s48V49t/OpXxLtgiWL9XkuDTZctpJJA4vHHk6Ou0bcg7iGm+L1xwIfb8Ml4oWvT0SF35fgW08bbLXZ2v1XCLRsrWUgbq4U+KxtEpG3XIYcYhKx1rIrUhfEJkuHzgPglM11gG5W+Cyfg+wfOJig5q6axIKWzIf6C8m8lmy6bM+N5EsD9SvAgMBAAGjUzBRMB0GA1UdDgQWBBTf1hM6/ibGF+u/SVAK88FUMjzRoTAfBgNVHSMEGDAWgBTf1hM6/ibGF+u/SVAK88FUMjzRoTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBgvVau5+2wAuCsmOyyG28h1zyC4IPmMmpRZTDOp/pLdwXeHjJr8kEC3l92qJEvc+WAboJ1RoucHycUe7RWh2C6ZF/WPCBLyWGwnlyqGyRM9/j86UJ1OgiuZl7kl9zxwWoaxPBCmHa0RHowdQB7AVlpqg1c7FhKjhUCBmGT4Ve8tV0hdZtrZoQV+6xHPbUd37KV1B1Bmfo3o4ekoJKhUu99Eo03OpE3JLtM13A1HxABEuQGHTI0tycDBBdRn3b03HoIhU0VnqjvpV1KPvsrgYi/0VStLNezZPgGe0fG3Xgy8yekdB9NMUn+zZLATI4+z8j4QH5Wj5ZPaUkyoAD2oUJO" - ] -} -``` - -The claims would be a base64 URL encoded string without paddings: - -``` -eyJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiZGlnZXN0Ijoic2hhMjU2OmM0NTE2YjhhMzExZTg1ZjFmMmE2MDU3M2FiZjRjNmI3NDBjYTNhZGU0MTI3ZTI5YjA1NjE2ODQ4ZGU0ODdkMzQiLCJzaXplIjo1MjgsInJlZmVyZW5jZXMiOlsicmVnaXN0cnkuZXhhbXBsZS5jb20vZXhhbXBsZTpsYXRlc3QiLCJyZWdpc3RyeS5leGFtcGxlLmNvbS9leGFtcGxlOnYxLjAiXSwiZXhwIjoxNjI4NTg3MTE5LCJpYXQiOjE1OTcwNTExMTksIm5iZiI6MTU5NzA1MTExOX0 -``` - -The parsed and formatted claims would be: - -``` JSON -{ - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "digest": "sha256:c4516b8a311e85f1f2a60573abf4c6b740ca3ade4127e29b05616848de487d34", - "size": 528, - "references": [ - "registry.example.com/example:latest", - "registry.example.com/example:v1.0" - ], - "exp": 1628587119, - "iat": 1597051119, - "nbf": 1597051119 -} -``` - -The signature of the above would be represented as a base64 URL encoded string without paddings: - -``` -MtQBOL2FERM2fMSikruHOMQdHuEXAE1wf6J6TfDY2W_7PfQQllBKbJJE0HqJ5ENAbuqNYHNZeIeKUCYFrNx2XgtrKuTe7WCa1ZZKDtp5bmANp484ekdl6lW23YB8r_SRtseJuibqjI3HuiMyELj9uYV1CdRYaD2BIZ_qxraYH1fMpjDWjehU4RYLI37hsSuDQ90o09BwaNfzbQXYPsGmkSUSmej7rOFPDnuwhNy4WcUed3kRKYEW8eIjO9OUBGQq3PWvhDjxZi3QF4QFDoiKBOXL70AjaiVIveQRkJI9-xHZSYwje9OFEMioeNWB5ceZR-r4L7VzDcU-Fxqjxn79Fw -``` - -Putting everything together: - -``` -eyJ0eXAiOiJ4NTA5IiwiYWxnIjoiUlMyNTYiLCJ4NWMiOlsiTUlJRHN6Q0NBcHVnQXdJQkFnSVVMMWFuRVUveUp5NjdWSlRiSGtOWDBiQk5BbkV3RFFZSktvWklodmNOQVFFTEJRQXdhVEVkTUJzR0ExVUVBd3dVY21WbmFYTjBjbmt1WlhoaGJYQnNaUzVqYjIweEZEQVNCZ05WQkFvTUMyVjRZVzF3YkdVZ2FXNWpNUXN3Q1FZRFZRUUdFd0pWVXpFVE1CRUdBMVVFQ0F3S1YyRnphR2x1WjNSdmJqRVFNQTRHQTFVRUJ3d0hVMlZoZEhSc1pUQWVGdzB5TURBM01qY3hORFF6TkRaYUZ3MHlNVEEzTWpjeE5EUXpORFphTUdreEhUQWJCZ05WQkFNTUZISmxaMmx6ZEhKNUxtVjRZVzF3YkdVdVkyOXRNUlF3RWdZRFZRUUtEQXRsZUdGdGNHeGxJR2x1WXpFTE1Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBZ01DbGRoYzJocGJtZDBiMjR4RURBT0JnTlZCQWNNQjFObFlYUjBiR1V3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRRGtLd0FjVjQ0cHNqTjhubm8xZVozenYxWktVaEpBb3h3Qk9JR2ZJeEllK2lIdHBYTHZGRlZ3azVKYnh1K1BraWcyTjRCM0lscmovVnJ5aTBoeHA0bWFnMDJNNzMzYlhMUkVOU09GT05Sa3NscE84ekhVTjVwWWRuaFRTd1lUTGFwMSsxYmdjRlN1VVhMV2llcVpCNnFjN2tpdjNiajNTUGFmNDIrczQ4VjQ5dC9PcFh4THRnaVdMOVhrdURUWmN0cEpKQTR2SEhrNk91MGJjZzdpR20rTDF4d0lmYjhNbDRvV3ZUMFNGMzVmZ1cwOGJiTFhaMnYxWENMUnNyV1VnYnE0VStLeHRFcEczWElZY1loS3gxcklyVWhmRUprdUh6Z1BnbE0xMWdHNVcrQ3lmZyt3Zk9KaWc1cTZheElLV3pJZjZDOG04bG15NmJNK041RXNEOVN2QWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJUZjFoTTYvaWJHRit1L1NWQUs4OEZVTWp6Um9UQWZCZ05WSFNNRUdEQVdnQlRmMWhNNi9pYkdGK3UvU1ZBSzg4RlVNanpSb1RBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFCZ3ZWYXU1KzJ3QXVDc21PeXlHMjhoMXp5QzRJUG1NbXBSWlRET3AvcExkd1hlSGpKcjhrRUMzbDkycUpFdmMrV0Fib0oxUm91Y0h5Y1VlN1JXaDJDNlpGL1dQQ0JMeVdHd25seXFHeVJNOS9qODZVSjFPZ2l1Wmw3a2w5enh3V29heFBCQ21IYTBSSG93ZFFCN0FWbHBxZzFjN0ZoS2poVUNCbUdUNFZlOHRWMGhkWnRyWm9RVis2eEhQYlVkMzdLVjFCMUJtZm8zbzRla29KS2hVdTk5RW8wM09wRTNKTHRNMTNBMUh4QUJFdVFHSFRJMHR5Y0RCQmRSbjNiMDNIb0loVTBWbnFqdnBWMUtQdnNyZ1lpLzBWU3RMTmV6WlBnR2UwZkczWGd5OHlla2RCOU5NVW4relpMQVRJNCt6OGo0UUg1V2o1WlBhVWt5b0FEMm9VSk8iXX0.eyJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiZGlnZXN0Ijoic2hhMjU2OmM0NTE2YjhhMzExZTg1ZjFmMmE2MDU3M2FiZjRjNmI3NDBjYTNhZGU0MTI3ZTI5YjA1NjE2ODQ4ZGU0ODdkMzQiLCJzaXplIjo1MjgsInJlZmVyZW5jZXMiOlsicmVnaXN0cnkuZXhhbXBsZS5jb20vZXhhbXBsZTpsYXRlc3QiLCJyZWdpc3RyeS5leGFtcGxlLmNvbS9leGFtcGxlOnYxLjAiXSwiZXhwIjoxNjI4NTg3MTE5LCJpYXQiOjE1OTcwNTExMTksIm5iZiI6MTU5NzA1MTExOX0.MtQBOL2FERM2fMSikruHOMQdHuEXAE1wf6J6TfDY2W_7PfQQllBKbJJE0HqJ5ENAbuqNYHNZeIeKUCYFrNx2XgtrKuTe7WCa1ZZKDtp5bmANp484ekdl6lW23YB8r_SRtseJuibqjI3HuiMyELj9uYV1CdRYaD2BIZ_qxraYH1fMpjDWjehU4RYLI37hsSuDQ90o09BwaNfzbQXYPsGmkSUSmej7rOFPDnuwhNy4WcUed3kRKYEW8eIjO9OUBGQq3PWvhDjxZi3QF4QFDoiKBOXL70AjaiVIveQRkJI9-xHZSYwje9OFEMioeNWB5ceZR-r4L7VzDcU-Fxqjxn79Fw -``` - -### Signature Persisted within an OCI Artifact Enabled Registry - -All values are persisted in a `signature.jwt` file. The file would be submitted to a registry as an Artifact with null layers. -The `signature.jwt` would be persisted within the `manifest.config` object - -``` SHELL -oras push \ - registry.example.com/hello-world:v1.0 \ - --manifest-config signature.json:application/vnd.cncf.notary.config.v2+jwt -``` - -Would push the following manifest: - -``` JSON -{ - "schemaVersion": 2, - "config": { - "mediaType": "application/vnd.cncf.notary.config.v2+jwt", - "size": 1906, - "digest": "sha256:c7848182f2c817415f0de63206f9e4220012cbb0bdb750c2ecf8020350239814" - }, - "layers": [] -} -``` - -## *Signature* Property Descriptions - -### Header - -- **`typ`** *string* - - This REQUIRED property identifies the signature type. Implementations MUST support at least the following types - - - `x509`: X.509 public key certificates. Implementations MUST verify that the certificate of the signing key has the `digitalSignature` `Key Usage` extension ([RFC 5280 Section 4.2.1.3](https://tools.ietf.org/html/rfc5280#section-4.2.1.3)). - - Implementations MAY support the following types - - - `tuf`: [The update framework](https://theupdateframework.io/). - - Although the signature file is a JWT, type `JWT` is not used as it is not an authentication or authorization token. - -- **`alg`** *string* - - This REQUIRED property for the `x509` type identifies the cryptographic algorithm used to sign the content. This field is based on [RFC 7515 Section 4.1.1](https://tools.ietf.org/html/rfc7515#section-4.1.1). - -- **`x5c`** *array of strings* - - This OPTIONAL property for the `x509` type contains the X.509 public key certificate or certificate chain corresponding to the key used to digitally sign the content. The certificates are encoded in base64. This field is based on [RFC 7515 Section 4.1.6](https://tools.ietf.org/html/rfc7515#section-4.1.6). - -- **`kid`** *string* - - This OPTIONAL property for the `x509` type is a hint (key ID) indicating which key was used to sign the content. This field is based on [RFC 7515 Section 4.1.4](https://tools.ietf.org/html/rfc7515#section-4.1.4). - -### Claims - -- **`iat`** *integer* - - This OPTIONAL property identities the time at which the manifests were presented to the notary. This field is based on [RFC 7519 Section 4.1.6](https://tools.ietf.org/html/rfc7519#section-4.1.6). When used, it does not imply the issue time of any signature in the `signatures` property. - -- **`nbf`** *integer* - - This OPTIONAL property identifies the time before which the signed content MUST NOT be accepted for processing. This field is based on [RFC 7519 Section 4.1.5](https://tools.ietf.org/html/rfc7519#section-4.1.5). - -- **`exp`** *integer* - - This OPTIONAL property identifies the expiration time on or after which the signed content MUST NOT be accepted for processing. This field is based on [RFC 7519 Section 4.1.4](https://tools.ietf.org/html/rfc7519#section-4.1.4). - -- **`mediaType`** *string* - - This REQUIRED property contains the media type of the referenced content. Values MUST comply with [RFC 6838][rfc6838], including the [naming requirements in its section 4.2][rfc6838-s4.2]. - -- **`digest`** *string* - - This REQUIRED property is the *digest* of the target manifest, conforming to the requirements outlined in [Digests](https://github.com/opencontainers/image-spec/blob/master/descriptor.md#digests). If the actual content is fetched according to the *digest*, implementations MUST verify the content against the *digest*. - -- **`size`** *integer* - - This REQUIRED property is the *size* of the target manifest. If the actual content is fetched according the *digest*, implementations MUST verify the content against the *size*. - -- **`references`** *array of strings* - - This OPTIONAL property claims the manifest references of its origin. The format of the value MUST matches the [*reference* grammar](https://github.com/docker/distribution/blob/master/reference/reference.go). With used, the `x509` signatures are valid only if the domain names of all references match the Common Name (`CN`) in the `Subject` field of the certificate. - -## Example Signatures - -### x509 Signature - -Example showing a formatted `x509` signature file [examples/x509_x5c.nv2.jwt](examples/x509_x5c.nv2.jwt) with certificates provided by `x5c`: - -```json -{ - "typ": "x509", - "alg": "RS256", - "x5c": [ - "MIIDszCCApugAwIBAgIUL1anEU/yJy67VJTbHkNX0bBNAnEwDQYJKoZIhvcNAQELBQAwaTEdMBsGA1UEAwwUcmVnaXN0cnkuZXhhbXBsZS5jb20xFDASBgNVBAoMC2V4YW1wbGUgaW5jMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTAeFw0yMDA3MjcxNDQzNDZaFw0yMTA3MjcxNDQzNDZaMGkxHTAbBgNVBAMMFHJlZ2lzdHJ5LmV4YW1wbGUuY29tMRQwEgYDVQQKDAtleGFtcGxlIGluYzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkKwAcV44psjN8nno1eZ3zv1ZKUhJAoxwBOIGfIxIe+iHtpXLvFFVwk5Jbxu+Pkig2N4B3Ilrj/Vryi0hxp4mag02M733bXLRENSOFONRkslpO8zHUN5pYdnhTSwYTLap1+1bgcFSuUXLWieqZB6qc7kiv3bj3SPaf42+s48V49t/OpXxLtgiWL9XkuDTZctpJJA4vHHk6Ou0bcg7iGm+L1xwIfb8Ml4oWvT0SF35fgW08bbLXZ2v1XCLRsrWUgbq4U+KxtEpG3XIYcYhKx1rIrUhfEJkuHzgPglM11gG5W+Cyfg+wfOJig5q6axIKWzIf6C8m8lmy6bM+N5EsD9SvAgMBAAGjUzBRMB0GA1UdDgQWBBTf1hM6/ibGF+u/SVAK88FUMjzRoTAfBgNVHSMEGDAWgBTf1hM6/ibGF+u/SVAK88FUMjzRoTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBgvVau5+2wAuCsmOyyG28h1zyC4IPmMmpRZTDOp/pLdwXeHjJr8kEC3l92qJEvc+WAboJ1RoucHycUe7RWh2C6ZF/WPCBLyWGwnlyqGyRM9/j86UJ1OgiuZl7kl9zxwWoaxPBCmHa0RHowdQB7AVlpqg1c7FhKjhUCBmGT4Ve8tV0hdZtrZoQV+6xHPbUd37KV1B1Bmfo3o4ekoJKhUu99Eo03OpE3JLtM13A1HxABEuQGHTI0tycDBBdRn3b03HoIhU0VnqjvpV1KPvsrgYi/0VStLNezZPgGe0fG3Xgy8yekdB9NMUn+zZLATI4+z8j4QH5Wj5ZPaUkyoAD2oUJO" - ] -}.{ - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "digest": "sha256:c4516b8a311e85f1f2a60573abf4c6b740ca3ade4127e29b05616848de487d34", - "size": 528, - "references": [ - "registry.example.com/example:latest", - "registry.example.com/example:v1.0" - ], - "exp": 1628587119, - "iat": 1597051119, - "nbf": 1597051119 -}.[Signature] -``` - -Example showing a formatted `x509` signature file [examples/x509_kid.nv2.jwt](examples/x509_kid.nv2.jwt) with certificates referenced by `kid`: - -```json -{ - "typ": "x509", - "alg": "RS256", - "kid": "XP5O:Y7W2:PRB6:O355:56CC:P3A6:CBDV:EDMN:QZCK:W5PO:QMV3:T2LX" -}.{ - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "digest": "sha256:c4516b8a311e85f1f2a60573abf4c6b740ca3ade4127e29b05616848de487d34", - "size": 528, - "references": [ - "registry.example.com/example:latest", - "registry.example.com/example:v1.0" - ], - "exp": 1628587341, - "iat": 1597051341, - "nbf": 1597051341 -}.[Signature] -``` - -[distribution-spec]: https://github.com/opencontainers/distribution-spec -[oci-artifacts]: https://github.com/opencontainers/artifacts -[oci-manifest]: https://github.com/opencontainers/image-spec/blob/master/manifest.md -[oci-manifest-list]: https://github.com/opencontainers/image-spec/blob/master/image-index.md - diff --git a/docs/signature/examples/x509_kid.nv2.jwt b/docs/signature/examples/x509_kid.nv2.jwt deleted file mode 100644 index 444cd2790..000000000 --- a/docs/signature/examples/x509_kid.nv2.jwt +++ /dev/null @@ -1 +0,0 @@ -eyJ0eXAiOiJ4NTA5IiwiYWxnIjoiUlMyNTYiLCJraWQiOiJYUDVPOlk3VzI6UFJCNjpPMzU1OjU2Q0M6UDNBNjpDQkRWOkVETU46UVpDSzpXNVBPOlFNVjM6VDJMWCJ9.eyJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiZGlnZXN0Ijoic2hhMjU2OmM0NTE2YjhhMzExZTg1ZjFmMmE2MDU3M2FiZjRjNmI3NDBjYTNhZGU0MTI3ZTI5YjA1NjE2ODQ4ZGU0ODdkMzQiLCJzaXplIjo1MjgsInJlZmVyZW5jZXMiOlsicmVnaXN0cnkuZXhhbXBsZS5jb20vZXhhbXBsZTpsYXRlc3QiLCJyZWdpc3RyeS5leGFtcGxlLmNvbS9leGFtcGxlOnYxLjAiXSwiZXhwIjoxNjI4NTg3MzQxLCJpYXQiOjE1OTcwNTEzNDEsIm5iZiI6MTU5NzA1MTM0MX0.cr9C_Py-IJcgIUXtHAQ9dFmZO4JBEOedPdg67Fm-Av8vMQBHrs7kHZOqZhF33OYR7tuG94v760RlrCrBl1OhUpk5umLjeCOk1-RBqSWUhM7GxwfeIWEIC10gzmolHVI55nb27QQxq0pTqhAC9Nof6QljFG8kyqYqjn0cr3X1zt23ppyJ1CYkcdXdDL0QD8-1EnngHAYcssun8A9dKveld-O-dMq94wk2FkSuKz6WSOM1I5E-thbq6NltB7dzLuZAkU4LXAqODCJ7fTQgUvtapzyEMvV6cQwAG1sUV1yEST0A6t6U_0Tt-X32_kciptVuzbtRLYuOW8Wzv7E41ryU6w \ No newline at end of file diff --git a/docs/signature/examples/x509_x5c.nv2.jwt b/docs/signature/examples/x509_x5c.nv2.jwt deleted file mode 100644 index 78ff07e12..000000000 --- a/docs/signature/examples/x509_x5c.nv2.jwt +++ /dev/null @@ -1 +0,0 @@ -eyJ0eXAiOiJ4NTA5IiwiYWxnIjoiUlMyNTYiLCJ4NWMiOlsiTUlJRHN6Q0NBcHVnQXdJQkFnSVVMMWFuRVUveUp5NjdWSlRiSGtOWDBiQk5BbkV3RFFZSktvWklodmNOQVFFTEJRQXdhVEVkTUJzR0ExVUVBd3dVY21WbmFYTjBjbmt1WlhoaGJYQnNaUzVqYjIweEZEQVNCZ05WQkFvTUMyVjRZVzF3YkdVZ2FXNWpNUXN3Q1FZRFZRUUdFd0pWVXpFVE1CRUdBMVVFQ0F3S1YyRnphR2x1WjNSdmJqRVFNQTRHQTFVRUJ3d0hVMlZoZEhSc1pUQWVGdzB5TURBM01qY3hORFF6TkRaYUZ3MHlNVEEzTWpjeE5EUXpORFphTUdreEhUQWJCZ05WQkFNTUZISmxaMmx6ZEhKNUxtVjRZVzF3YkdVdVkyOXRNUlF3RWdZRFZRUUtEQXRsZUdGdGNHeGxJR2x1WXpFTE1Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBZ01DbGRoYzJocGJtZDBiMjR4RURBT0JnTlZCQWNNQjFObFlYUjBiR1V3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRRGtLd0FjVjQ0cHNqTjhubm8xZVozenYxWktVaEpBb3h3Qk9JR2ZJeEllK2lIdHBYTHZGRlZ3azVKYnh1K1BraWcyTjRCM0lscmovVnJ5aTBoeHA0bWFnMDJNNzMzYlhMUkVOU09GT05Sa3NscE84ekhVTjVwWWRuaFRTd1lUTGFwMSsxYmdjRlN1VVhMV2llcVpCNnFjN2tpdjNiajNTUGFmNDIrczQ4VjQ5dC9PcFh4THRnaVdMOVhrdURUWmN0cEpKQTR2SEhrNk91MGJjZzdpR20rTDF4d0lmYjhNbDRvV3ZUMFNGMzVmZ1cwOGJiTFhaMnYxWENMUnNyV1VnYnE0VStLeHRFcEczWElZY1loS3gxcklyVWhmRUprdUh6Z1BnbE0xMWdHNVcrQ3lmZyt3Zk9KaWc1cTZheElLV3pJZjZDOG04bG15NmJNK041RXNEOVN2QWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJUZjFoTTYvaWJHRit1L1NWQUs4OEZVTWp6Um9UQWZCZ05WSFNNRUdEQVdnQlRmMWhNNi9pYkdGK3UvU1ZBSzg4RlVNanpSb1RBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFCZ3ZWYXU1KzJ3QXVDc21PeXlHMjhoMXp5QzRJUG1NbXBSWlRET3AvcExkd1hlSGpKcjhrRUMzbDkycUpFdmMrV0Fib0oxUm91Y0h5Y1VlN1JXaDJDNlpGL1dQQ0JMeVdHd25seXFHeVJNOS9qODZVSjFPZ2l1Wmw3a2w5enh3V29heFBCQ21IYTBSSG93ZFFCN0FWbHBxZzFjN0ZoS2poVUNCbUdUNFZlOHRWMGhkWnRyWm9RVis2eEhQYlVkMzdLVjFCMUJtZm8zbzRla29KS2hVdTk5RW8wM09wRTNKTHRNMTNBMUh4QUJFdVFHSFRJMHR5Y0RCQmRSbjNiMDNIb0loVTBWbnFqdnBWMUtQdnNyZ1lpLzBWU3RMTmV6WlBnR2UwZkczWGd5OHlla2RCOU5NVW4relpMQVRJNCt6OGo0UUg1V2o1WlBhVWt5b0FEMm9VSk8iXX0.eyJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiZGlnZXN0Ijoic2hhMjU2OmM0NTE2YjhhMzExZTg1ZjFmMmE2MDU3M2FiZjRjNmI3NDBjYTNhZGU0MTI3ZTI5YjA1NjE2ODQ4ZGU0ODdkMzQiLCJzaXplIjo1MjgsInJlZmVyZW5jZXMiOlsicmVnaXN0cnkuZXhhbXBsZS5jb20vZXhhbXBsZTpsYXRlc3QiLCJyZWdpc3RyeS5leGFtcGxlLmNvbS9leGFtcGxlOnYxLjAiXSwiZXhwIjoxNjI4NTg3MTE5LCJpYXQiOjE1OTcwNTExMTksIm5iZiI6MTU5NzA1MTExOX0.MtQBOL2FERM2fMSikruHOMQdHuEXAE1wf6J6TfDY2W_7PfQQllBKbJJE0HqJ5ENAbuqNYHNZeIeKUCYFrNx2XgtrKuTe7WCa1ZZKDtp5bmANp484ekdl6lW23YB8r_SRtseJuibqjI3HuiMyELj9uYV1CdRYaD2BIZ_qxraYH1fMpjDWjehU4RYLI37hsSuDQ90o09BwaNfzbQXYPsGmkSUSmej7rOFPDnuwhNy4WcUed3kRKYEW8eIjO9OUBGQq3PWvhDjxZi3QF4QFDoiKBOXL70AjaiVIveQRkJI9-xHZSYwje9OFEMioeNWB5ceZR-r4L7VzDcU-Fxqjxn79Fw \ No newline at end of file diff --git a/go.mod b/go.mod index fd427a773..30fa816bf 100644 --- a/go.mod +++ b/go.mod @@ -1,23 +1,29 @@ -module github.com/notaryproject/nv2 +module github.com/notaryproject/notation -go 1.16 +go 1.17 require ( - github.com/docker/cli v20.10.5+incompatible - github.com/docker/distribution v0.0.0-20210206161202-6200038bc715 - github.com/docker/docker v20.10.5+incompatible // indirect - github.com/docker/docker-credential-helpers v0.6.3 // indirect + github.com/distribution/distribution/v3 v3.0.0-20210804104954-38ab4c606ee3 + github.com/docker/cli v20.10.8+incompatible github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 - github.com/notaryproject/notary/v2 v2.0.0-20210414032403-d1367cc13db7 - github.com/opencontainers/artifacts v0.0.0-20210209205009-a282023000bd + github.com/notaryproject/notation-go-lib v0.0.0 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.1 + github.com/oras-project/artifacts-spec v0.0.0-20210827194259-6e52c5a2ed3d github.com/urfave/cli/v2 v2.3.0 - golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 // indirect - gotest.tools/v3 v3.0.3 // indirect ) -replace ( - github.com/notaryproject/notary/v2 => github.com/shizhMSFT/notary/v2 v2.0.0-20210628085455-9ffe654b1d61 - github.com/opencontainers/artifacts => github.com/aviral26/artifacts v0.0.3 +require ( + github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect + github.com/docker/docker v20.10.8+incompatible // indirect + github.com/docker/docker-credential-helpers v0.6.4 // indirect + github.com/docker/go v1.5.1-1 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/russross/blackfriday/v2 v2.0.1 // indirect + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + github.com/sirupsen/logrus v1.8.1 // indirect + golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect + gotest.tools/v3 v3.0.3 // indirect ) + +replace github.com/notaryproject/notation-go-lib => github.com/shizhMSFT/notation-go-lib v0.0.0-20210830093102-4cf866d49e92 diff --git a/go.sum b/go.sum index fea5958be..7eeb11acc 100644 --- a/go.sum +++ b/go.sum @@ -5,34 +5,33 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/aviral26/artifacts v0.0.3 h1:F+XBw93sXm9H7iajUEl0DhbbvCg2e/k6e4lVY2EYhC4= -github.com/aviral26/artifacts v0.0.3/go.mod h1:IBQOjhxIKxb9G4h9NiWAJLGBgKPlIy27tcpPDTAfUQw= github.com/aws/aws-sdk-go v1.34.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/distribution/distribution/v3 v3.0.0-20210804104954-38ab4c606ee3 h1:rEK0juuU5idazw//KzUcL3yYwUU3DIe2OnfJwjDBqno= +github.com/distribution/distribution/v3 v3.0.0-20210804104954-38ab4c606ee3/go.mod h1:gt38b7cvVKazi5XkHvINNytZXgTEntyhtyM3HQz46Nk= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/docker/cli v20.10.5+incompatible h1:bjflayQbWg+xOkF2WPEAOi4Y7zWhR7ptoPhV/VqLVDE= -github.com/docker/cli v20.10.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/distribution v0.0.0-20210206161202-6200038bc715 h1:oN+Mw/t1Ua4huewY/20wTTZ0Nvye+9BJVYoCl//3tcQ= -github.com/docker/distribution v0.0.0-20210206161202-6200038bc715/go.mod h1:j0+FEax3zYG2pUod5Nc0npkx8p9I3HrKgf2TvKDc5LE= -github.com/docker/docker v20.10.5+incompatible h1:o5WL5onN4awYGwrW7+oTn5x9AF2prw7V0Ox8ZEkoCdg= -github.com/docker/docker v20.10.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ= -github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/cli v20.10.8+incompatible h1:/zO/6y9IOpcehE49yMRTV9ea0nBpb8OeqSskXLNfH1E= +github.com/docker/cli v20.10.8+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/docker v20.10.8+incompatible h1:RVqD337BgQicVCzYrrlhLDWhq6OAD2PJDUg2LsEUvKM= +github.com/docker/docker v20.10.8+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.4 h1:axCks+yV+2MR3/kZhAmy07yC56WZ2Pwu/fKWtKuZB0o= +github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c= github.com/docker/go v1.5.1-1 h1:hr4w35acWBPhGBXlzPoHpmZ/ygPjnmFVxGxxGnMyP7k= github.com/docker/go v1.5.1-1/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= @@ -63,8 +62,6 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -83,6 +80,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/oras-project/artifacts-spec v0.0.0-20210827194259-6e52c5a2ed3d h1:fnJDGYyP6INkpdty1iJzXS3jI6n9RaLK0JN+glIPmsE= +github.com/oras-project/artifacts-spec v0.0.0-20210827194259-6e52c5a2ed3d/go.mod h1:Xch2aLzSwtkhbFFN6LUzTfLtukYvMMdXJ4oZ8O7BOdc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -102,13 +101,13 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shizhMSFT/notary/v2 v2.0.0-20210628085455-9ffe654b1d61 h1:zjKRGTeC9IucYK1TJZch8dHnNld3t6D87n0t4falB1U= -github.com/shizhMSFT/notary/v2 v2.0.0-20210628085455-9ffe654b1d61/go.mod h1:9TYSlVNAiZqhzs/nkZMNJ8vXx9X9YTTOpuTCk8c5s1A= +github.com/shizhMSFT/notation-go-lib v0.0.0-20210830093102-4cf866d49e92 h1:IkiOEbFLTEoQw6XMatJU3CfKSanzsYgGn/TNTrKz/0c= +github.com/shizhMSFT/notation-go-lib v0.0.0-20210830093102-4cf866d49e92/go.mod h1:KL5EBS/9X5UI7GnDC4NbYg2az6HVmoyH5M2Bv8a9E24= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -140,10 +139,11 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -156,7 +156,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3 h1:fvjTMHxHEw/mxHbtzPi3JCcKXQRAnQTBRo6YCJSVHKI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= diff --git a/internal/docker/plugin.go b/internal/docker/plugin.go new file mode 100644 index 000000000..4c0dfec23 --- /dev/null +++ b/internal/docker/plugin.go @@ -0,0 +1,14 @@ +package docker + +// PluginMetadataCommandName is the internal command name for docker CLI plugin metadata. +const PluginMetadataCommandName = "docker-cli-plugin-metadata" + +// PluginMetadata presents the plugin metadata to the docker CLI. +type PluginMetadata struct { + SchemaVersion string `json:"SchemaVersion,omitempty"` + Vendor string `json:"Vendor,omitempty"` + Version string `json:"Version,omitempty"` + ShortDescription string `json:"ShortDescription,omitempty"` + URL string `json:"URL,omitempty"` + Experimental bool `json:"Experimental,omitempty"` +} diff --git a/internal/os/file.go b/internal/os/file.go index 8199bb8bf..a239b0338 100644 --- a/internal/os/file.go +++ b/internal/os/file.go @@ -1,7 +1,7 @@ package os import ( - "io/ioutil" + "io/fs" "os" "path/filepath" ) @@ -11,5 +11,28 @@ func WriteFile(path string, data []byte) error { if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil { return err } - return ioutil.WriteFile(path, data, 0666) + return os.WriteFile(path, data, 0666) +} + +// WriteFileWithPermission writes to a path with all parent directories created. +func WriteFileWithPermission(path string, data []byte, perm fs.FileMode, overwrite bool) error { + if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil { + return err + } + flag := os.O_WRONLY | os.O_CREATE + if overwrite { + flag |= os.O_TRUNC + } else { + flag |= os.O_EXCL + } + file, err := os.OpenFile(path, flag, perm) + if err != nil { + return err + } + _, err = file.Write(data) + if err != nil { + file.Close() + return err + } + return file.Close() } diff --git a/internal/version/version.go b/internal/version/version.go new file mode 100644 index 000000000..7adc4bb7f --- /dev/null +++ b/internal/version/version.go @@ -0,0 +1,17 @@ +package version + +var ( + // Version shows the current notation version, optionally with pre-release. + Version = "0.5.0" + + // BuildMetadata stores the build metadata. + BuildMetadata = "unreleased" +) + +// GetVersion returns the version string in SemVer 2. +func GetVersion() string { + if BuildMetadata == "" { + return Version + } + return Version + "+" + BuildMetadata +} diff --git a/media/acme-rockets-cert.png b/media/acme-rockets-cert.png deleted file mode 100644 index 0c3e8cd3df8179b5e6bf25a2a92fe7411ed443c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17157 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 diff --git a/media/example-cert.png b/media/example-cert.png deleted file mode 100644 index 3f84aa20dbea5dbf1c6d4cc2e4850417e3d00175..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18030 zcmd74WmH_v)-Fmyf&_vF3l<0(+#M1mxD#B0Ly*SZ6134^jnlzHur%%s!97TDcWA7U z#^E;ae)qlmp6{IfedmmO#<@QjjILE{RjsO7&z$p_b1tBoitO`eFQ1{HpgfnClh!~% zd6bNT@)#8Z4cRgn9ejcOhv_7z=Zb=Y)A{iCD47L^9NCEOCa)}mzK%{xz>D(h$wbRv zO)|P}@7&#N04^xS<%4p_CTurkleDF)xr?onn=QZ*g%FeGHM0HLL%S5f$=k)&+Qto~ z6n9V<*^2X5tBa-SL)TYswhopkeCN2B$Sar+S2O`uZl0ztmMBI}_Yd8%{(88rtGT@? zva1V9U0Zb=vKix{S;y4H(bmx#rHyyQ?t@|f>?Q?paIkcALqQCJ zpvX3~hi+Q7ZuXWa-w(zZQBYo?$V3&N;Z)n5L zo0Tk=DBqa&9%s(|QdzX>awtK`YAW5TC^&OzY>8v0vh8)2h1GOSms^;(?g=Te*Pw?% zono4vSwV&aH{Q>5EV|-EJcBpOVRWe>A35m^?ZHdbjTdqti$3vMKW_^e?g}tLC)>Gii#AL6dz7XH0$Bal`9Uv&nsT{ zx938h2NYG-BZZZfF1nV_|8zx>?CkFsR97e2ju#TqhxxUf42z)5yNxS9-Je=mP}bAa z>#rODA6V}W+CAc_ZHo?MJiG2XDM}UheYbbb=ebo{R9BZ0Cvle=8TkymqgSMLAcf;3 z%H-y8-JG(wx3`P8fdTnp^9j!RqA$nB#)g}_JA5^Y!)2qN2nED$)UN}*`e5vT_92#1 z1mw5y=TFxF2Xt_%6;ZPuFgf*BK~J+#Nq#b(D(cK#Pmk>S{1AP)yy+k}Ki@)nSeCZc zu;*wcocj29fCH7&yc_!fdLIz<2$C)A{w&A<(31S)$B*V+DwX+`mKNqScHN(^yvqr; zTn^?N+}zwyj%q6WV`QR;ALUbw=gLG02HuG})@7veSX=q4_74o8H{Z|nLjr2|#1V$z zjMEXvR&ZT=|L41<&+)?LO5mzu%_6IttbrFgd$YndNpD|$^(>&JrA?cdnp$J>z@w$* zc4jJ$h=_1V(vp_$PlS&TQMPR*r}97NqrgdAWJy8cMG^j)U zSHZ{#d?xfDKH5ZDy8CN$qJjwk*L9QaTjlP6A7aLG*v+VuSJ{bFDNREX0HD?>KV4-4 zo_$X?;X~!zfr)WxK%ydgNi~0`M%p5rHwUc^8{I~bkU%j?G(!GEz>@(yO%jg#znwI*qQf_Ss zpSoP{l!@b&Fn+xJ-r1B%Ps{FbG;rg0j#RzQLLaOGn(gVmu(0s7R_jWMlTiNGx1y>1 z>dy8FW}HH0maY{}&g((lxz1OU8hy!{xdwWc^plI#tFV^iOoKK3xjT+oS%;g`STO8Kzo{D(03*#)E4`9k(Fnr z5&{AlygqDES+Fp#(UI{7CESr64`O)rm4Qz-6KojZ*I;giu z+c~p{QkAywgD`+r=w9@?Ds3QNxcN>yiHA|b+UlCCKQ8OrezH{a)hx`g*((iqaYkxp zaA)2N3_dZcN)@K=4fJ=b0a?J*%WUb&qG`42{wPCLmJsx*2 z3~8moB!;+@_XCZ=sOb{O&375qBA54Qq4zlFPrtQ9hmK6zeA0vXxO6enatm!FYawBQ zkJ!ZJh+`{7v$iFEXO3J?$eO`b)qilMBRrMISKNq^13oNqOEli!n5J&USz^y_we$-0 zjO~!1ua&@?eHb6Wb&AeeuFJTbU1QiVb; zkmP!@)?(m2>Shb#4T<p=_~TN-FIKG4}n!TKx}?^K&RuD^ZN6{`|L$n3a7)Y zmbj<~e%_wqO*{3ikf-0;$ah1Z=Q@SPBf0bfPG`ShRU~^3ozYLcnr68I%5pB{~o zVg@ZG^V^7j!~3*5hW7hp)ncLD%CR=-5bM$6*^{F+ZtUprrHxGsMf#R(zcoU9vW(W_ zkl$8rDB*9N(-G#wUu0@h70?u#(Mi+); z$BQ&;ZqTro*Fv$yw8Vd>&;Lt7lqY9pW#tj|d@ug~ zoyh}(mX=U^IREiazsuv%2y?CKx;he(C;0K04!`rcN0mA!Q>LZLbmLbt+~h4q4F!co zM0#X034xCM(tA0deUNh;>XdskibACtWCK~l!%tfe%hJkygd1i`2Niu}G%F*`P-04- zY||E8QVfc)HA_c=We%d(xQ4Ve)^V-%y4JaR+Ib!JR065JlTuRF0&}L@r$07l1;#r& z>dIRxit+9puPL!RuL7c>v1mth2Aoun)e{!99+?CVbdy9L3U4FCCG+c|SLdF0_`|Vm z-jR&?v1`5d=BhHh7#J8}<~ZF2#IVs1lN?E0;HXj``tA|&i)q}<#LW_{PK zf9HLm#b-`OPE*^Htt2aLGUTWs_9xBg7vRKLHNW^Ke)*Q1vY)prWqZ+M>66)3e2(SQ zx=sTb2CI{2yLBPlPrpJ%vNxS{NQ{i&SUbV|3ppIV(Im!R(U$x#EZyDa{F5XwB;-5i z|8%K(IUZp-@J|ZHz4r>waANDozStK=pFH1YJo-iu)|+ZM{?T8M1FmuyxAv z=8nX?H7i5mi5X@j-IBL^HC~ElLH6*+6=L$&s77w?PwP3v?j)24Q=O70oIQV3ZNJ%(*t_J1r$ZH;cqa6b4YqI|Fb)U`1akND_LL)k*@n&4nNY-wGax0~-sr`ffOl+6i%8K>4c8)bI`s~CA9i~pWMyX$ zA_XnnvmH$1A68a%Bf2)=(jbP#T_z5WEdLCOHVp)$HUVqQyKrt)*4yu=_L)Jmn&JFp>wk-OUd=)s!IXn z=L>f{t?u=Kh72b%F!9Gm$i)(CbG^h7w00V|lUTd7*E#fCt&v*nu_uH%>k;u1+>b9xwulg`pnouDE;rOn-RUJ9jacTov&!~%*KXp`P%GMU3@PS z;Uu0&A!esCKm&4xT|06Vi9+@%ReKtZL1NvW)XZD$$CUH%Q`1)8@%=vT1F!Y?LC?Vf z!=v?mx*v^eI~~oOAw9VuF~sBWhPb(bfol@+W5UMzxNGjNxm3v4y9;XXC%t@x?)K5Y z^bcN3?5s8kBwLGbMq3tv2V^hgr~I9GH7+oJPHL)Q({jIzc85)-We5O<>np3OTz@J1 zOHeU!0p zcq*NQR1z{nFaA@7@!n0cFH6KT)&fpTtMM(II>1YMfEunBY2v++9A7ReEq#2no~Rn@ zMVZHac3bN(_df3>K7QXyCy?;9ad`J%u14%)Hp@RJv$fR}Ng0gPUU)cCRWG6hG)Lsrr9U8foMci=g4-r@f-!u~uRBz(#7VcS#5Yf~f5H#9DQH^bU>3 zdZ-ZQ#<-!QlkW%J-F@oj?~>4PQnB%?foCwCCk5Gy=lVy9kmu$L*G=~2y`n5bzKSp9 zs^YnRcQtw`jIH3SWx*77lhtzc_a1lT`0;(ckKT{Ix&OWd0_keB~elm>0lE>tG{29{Q%)o%7P#I2@CPbOOv^Yw6m20ha&6|4r=%c%4@`|6DeufYecdx$r8V% z#Ov0q4tx{Gk9a1yhC;VAQ-*aRRn{sb`}IiW_(P+E$yj6OYW=l>0`}F_)y00gEDGv4 zFV`a_&Y=s>t5slo+a3=W#m98Cut$Y6B=<8YO4zS!mG`XC!-6e-aSw^d)`VT&%rj<+ zE$IDYcJD1gtM>g{Cgj)c(J?SV>|k*vim-RS>x4*W%>uEvV|cMgt67w!rm_2NOMydY zB&&VqKyfgWE4gY*9CduzMU}eBT6JS=OH3)lxW6DuEGb#JsNbEBfdP_)>JM)$Z*0sJ zL}#Pr{!GMIoOxTF=sm@nKf=4FNFf+KEfY91)^K{32G>UWn11@MvI!<^CjX_i1i8xf zW8>kbcy^?bWj#A-B>aS?Bf>a==->?QLx_jC_4NWaJ$zT!J$c7UZGx^8J6Lflt7#ki&A9ph&5d z^%B;{W2JY_wQAW#pbVZ#u_vP6CC10UPD)Q1`Nt`6{nLEeH;I~hO5a$=Y9{rDVKlF3 z2gbw93>4GYb0Rft^$Q(gH?&%*u{3P@nb~?l_|e~L6_c~$m~wRlG`eus_nopRqSs=D ziEWjYt*WB&MjjU9%CnDZUv{?hp1ht3P2R>} z$>52ptkj)K?KpP(oThEHDpU~=>vah!05T2@+bPLNcX|}i%Vb^!OlCH`4OA>>DU0!p zYaSRiq24;((LJB|bFx+C1t-znyrDI@Sta3O&Z#RB;FnvP3!j;aGR-bpKjG97zqR&} zkZ4aT=1KLa316%PjF}q_H6QCKr4iVbopx;rvt;-x-b|N`(+Zt9tP_ z0HQtYv>j`lgR8e&Jv?B)Cv9B=VtcnHLwlD!_gyotVAr)sgG(!Awx!bIjqVJ<#z|C) zH~jwQi^LI4iSqcN*eZ=5$~y_eKBru)8`1= z%BUKUyA;>Y*5>om0?G=;w+Bob<{ZY7WP21*y>d+ZY^zX0b};m->jH`3)rwv}dtkJ0 zmxG~yZB)XPNkPS$pboouSk`!cgoGm?rQrM?g8~9wJcKFUWGUpZCF6jY zzAYN=0_ue{^l44s~FroVGQ@7)R@J25$QP%b84wf8PPb}#L(b`Q+42| zE8>)S(MLpK=7zq0Ys6abM56Md17~oVzp$pYYr=D>`v#7i=3ANt3%D|O%y1=ISO8ZA z-aq;ll3jiq0=`EtH$a)v`IR;@Q2&vY;rPz2{PfqLhK(lC~{zQWrsMJ)po4>5VsJCp%mB+vI-^9O$aD5^AK*p`W8&o75(L_U#fmhXl^Xsfs zdB@7u%)xz+TW5S)i4w(~H-n*YM(+ML@Oex;+C1K&*e*R7~)hch^0iYLeUM z+mjHGUm>#RRHl9I_)6|9JAM5Q(irA6IC(5}*_j;R_cZfmynH`bffsJzD3#Fru9_*X z^EFMU)(lq;D0bVg=j6IavVon0OV|GW*;hPPkHNeGRp-B9N`Z$)Z;07fTWZfQZf?+( zSRS2lC#Aa9TfKX#6L6wPu_f_QMTph#v1|Xz>Sfhnni%2sz0|;o^?t^ccw-%q6B3nR zN(zY*#}g;mSz-!^r*Lv+QL|Ak-D`Y)=XIVy7-+t?bteKKfjb|sbcv>lHr6M=Cp%+j z4G5bi(9dIIP4r^(g3Q?k%ekgQ8M!BgqG|7rhwD@50sYrmTWLZh<)@G7ms5qKIyHNNP)+6x5$HEvBZ2xyHVy*; zjNoRNs-IpD^%#4ChoY!+azsu8JM`A2TU0;H%Q4Jnke1tpg4!fgy}DmQ%oWtIaZ-N_ z!{~O867=521Khx=$06=4*1kTeVgPpQI|SfzC-5eYl~1`G-6ytrX#UtcQ}|C`W~gI% z(T=!=8K&llJtk)!3w8vS#!}5!H7F zDp|#j6loDx9DAMQY>m;Y)YQ66@}>oxFBraIF;}oF)%m9e7v_}N^o!$AEVM|MD@L8}YnhQu8Wqldk9qn0YWZY(ksS~6cfo~mt=-=Sq4*4 zQ$A-8a5^xElHZ9T?lujc+@9z;o!O%l4mU??G74X;=PfxMrUy!_nYD;oh>hP&tDsOUQNj>zkj!c9$vJqL=utAfe)m*{Rff#=u`+mTry2?>0Ct zN2j2}Btc7;e=6$xVV26Aaz6{hng9m!TYYh<>SI0k;#}axV~*pc#e0zepNrSTLw+$n0l5rGC1GNBiuDEjzZfCUz$PpJcX zhgALI5Q)_Af*%`NA3ivrPJ!X0fMMs$Rr)v3-#t=%CR@e&jb(cM>fM5^c9V5M>2=D0@}2LA(A^b8h&5BE(-sx!w8nG&VMHz}-z#VA&8VotqqP_; zbXG8b*K#0ky^g%kWYq~<>eOIh9@_tuQGv1+ZySBeN?LQ zx@TxT&GtQD*5Bw7bwYZ+;D7k1|H5?sSIE=9x@W+XwIs!{JCL!ANXou^g6CdlTML{= zPk0~g=n@}yEfzUnvJgC9=EBBS4SEFTzCDN|H)kylIqKptMs4Nx|IJE3()x?thitbh zz=n`|-4L1&Gzm%K!0mt{7|c$%DxvRDVe(=rG_@1q?F(-^d1tz2O&L;hsHc7}uH}%j zcE|ex-e37sUmZ?g@MJF)!R?~yi8x{kfwt+=FXvI}$!SvyfitT;Y38a$(5K_Pw(zal zeq^NSJ3~Z9m|Up}(pe;Lxi#3sWC+ALAY0EPgl?xJZGezs&zL1#gZ_r-+R4NMI#KM5&_yeJ$?YkdU3;25a8e}6fS1xwvlD*-k7e|&q7`@s3 zFAUE@9)0-(A=Z6WMoz0~M5Yf2rqZcR<)H**A3D4E##t|KS(0vvuU%np@h8zQ-f0SO z-sNOc+X?-77sfWV#kY1jgt#1VTXgl~Pxy6Kk7g&f0rzI^zoz@?xFB3rQo^#PV_=XW zL?Pm_#|gdN2jJQ+$pz0nQSy|^4>Wbn!c46vAB?a~A97C((wnl^)0xWjUgBlG#?c5I zKBj$MI7gs)?4J8k(GYcasAkxnAJ!Hk%wry5yY-9rwUv}nFd1+P9L?97)kI?k{6l%I zk~NcAOl4=d(_?Lv!WK3`Xu)64)$Y(O*{^0&j(jOsuzys|9?)uB!+A zA5`nhg=S(v+mah#3RT-wIK{Gao$rZcioBJlyEe_&<>Y3!ePs@0 z;&h`eyrGYNO*E|nAHSOKT(k!>d!ok6p*jYAbRPw`$|Dl3Nm+jRqn6{Bio85p{(;MA z{SveOu zK3)E>lOso!L$e?Y@BKNiAxm2>O|}EqjbpxdC%bYa?8yws?9(0ZAHuWi_Bp21?0Xq} z*4(JqgpIrpJFbjT-aPXr+c+=IX%{CJLCC1`(+j>zvp=`Es3IdHGwgt5 zHl=q?g|Nc3K1W1!%AAkA@EHGTx5tn)sxf=J(@FlF1fT4KiUeCBbXq+cGj@bwc^t`S zYEZ;RZkVunV0T&io8^5i66oGZq#|^5>2`z~c#s->~7bHML-VB5Ud8?j+M(8|*r24tMGoL3K6jFHBR#qwx3g9z@ zQ>^<_9bbP1ur@^30cmAzCCA?}T2KPObJgd(Frk5yD&gW7q%-NNq-!%G4X{m|w)_ET z8}t-nFse3n8R!!ivbZC}Bfbz{7lVJKJ;gr!qYGxLlp{>v%&d124RCZdMCZ<~dM8n0 zKK@;a$r~}TgRh{&-_P~gqLr|Ph`T+<2%@(UshKF%z2VJ%vM>b#q7!ysNyq1j=Gd}( zXPt8)8isVO%1^j6M|PiV+1ze{%z8NKLX}Rfw&*-UE6pVvf#O2za#i#oh`9PXld4U+ ztK_7G+}fclONRiWTkBc;mNXz#$xMJ24Tu~iHX1*!K#owxio@xYfp>_H24)k0ws$pe z#p=q-K%Nyu0d^{$=E9cmf16&C{j=$_Tpr0$WovtkJ6>$}<^@L(R)?;lW_!(ZR-Ppj z(4Mn?6d-zGf#H5FE9z?U;#dy#z@jBs%!2b&u&V2)@K(csnn^nsNp9O3d9iLY45+M6 zDWWs^?o?7drC~UE92$k@8AzhBhXQ;4RKmsI;qg;gFSdzBk~NpCrvQffk!TD}H~ljg`@uZ}S`ungzBz4nc! zrR`X$_qbH2r?78{=#}1LYTCRq>-qXFLhN0ek!%(@ zhWMX*bZsGq6Y~C$U_HiIatqpaKZb$<&&sya@wykBT&C}Oxa904J_Cgi9Md#m3@^IGa_UMx5Scv zua^{9(D6uqr&9Sx$_QOzsEU&AZ|CUkhv%n}nOq&;ZgQO8Gp#8oGchCC+35a|1Tmdq z+~UXh`0;MBBg5`5{tiM|p8WV{2&02E&ovMj(Ob{6NySWz9}idjN6@AS`jBE3n?0iX z&zqJmx&{8eD|TnRh~yv7;#K4L&tmWYWsCG5xm^E~-DNyI>;95i*?);P{l|QP{}l`Q zzdRpeOH0eY2B7{c8|{Dc4gSw`Pa>{z>EMjiLmtu)i*&2eUG`5J%$uK)@vPg4Tl)X? zJ&k@u1O9AEdLh{rE6p8=cI5R~I*Ky9SCG>-QDIdw`{rdLNerHNM;oVK^o$?R^iv%Y zi+Fjs^#f3PKl!#@rGJO*P~iu&kde$ zcPo^R{C-&p(xDtAR^)?xc=v;i4P?`n$kp9>+zD&$G$42cE|7Wgd|4iJNTX-ie|!Pg z)u&~4_I@l4B+xZb6*P<+;5@qUvvrrj^eSBlpz)i$8e5~l(=4S=5nZ%FQS~$06^aB< zKVODl9C;HQYL?!u`+{o4%~LFDU3rccqUyNE`&HSiGGT^Xz-S(YH^ies;k&Q?;kMYO zS6^i5rQm9iX77Hy7awxRE4OwKCHsI5tof>xC>_k4RR>9%{vn*MOgL`eN&bLeMSJAs zp3e^-zj(;HX!eu5FqECflThK&P#m8{QAhqfE45K!1+-;(G~2;+I@fq@jh#a~A>zc8ZaLHm0FeHBjq=2M{Ued~9e{kR z&R;nkoiL0#myYu3Yy47UEFc&h$#~Q0!vl$_fpHm7?BqTX{qt2&r%*mm;Os``rG7DD zgDkOEFgHKpUHxJ*JXT`vSSk0xz(#Pb4#gkEW8{cIz_3rvPkTVE6?F_Ck1xKGeONo+ zFgdcCKA!>AaviD}4Bn%Km1H|zV8q*ymrd@E36reM}-RI8~(f=18a=|lEMl+m|^no^I)<>XEVfhyf3CZLEI?O9sy z&Uk`D<8(QZ;p&quB#4Uy%m;VVamO+h>k8ho-LA2A5`N)Ga`zT5EhB&M9kEpD^4J$E zx8s`d0qYnmnIhh{yvj;dVPa3k43`TE*?Y6qBE;H-D>rA9xVm(NO0@GG$&nTmpE`Np z*pHX76wVP53H@&uy9Y^f?FVx1*{5lpbFiiWWKPcR3(K*G+Fn~>HI|Qy*-~g?it}By zA+$(Ub^5J^Zz42fI-_jc2F2u+0&9b`jZ%$z<-7z;AscWxI~6J1jTeAjbIA z%C0AGF--V)GlojPo6Jdco7y_l>Bl_9+Naqrx2$2g6V{<%hL;zDs`tkbF$WH`hB|p6 zbcDnC%5P{)0#jbJe?ofhU)`OiKB!JFyv-lY5Z<=ai}e&kQrhBpS=`G94$+LS6g}l{ zz8sz&=C&^^@qrw^Q8kwWoD#X!4jt&mmSejpmZlc)+FQ}o>@#y~gl`|Aa>NX=eD~BF z4t5u?CZcP+Dm7A9ks#kSgZtJ}^cfbo^3^yB)Ra`Y&sjz>Bc1iI&G*fH7k(j`0sN&A zEsSBNKM}o=HwJH3?rx($*{FC|vKdgI;$YmDPwe~UO!ym}vDi@ImTAX7CWB3u@dyAG zGo3B1tr?N|&(tm}BAy59$vVcSNbXUJU8?*0S6p+|7_kL!8tQIM0X$|zULP_dQuDK9 z+BqWn>;J%h|EiE8&%9n$`(xLJf4^ZIXCG6eu6-iZ(BiS0Mtrk3x$gpFF81Zn2vDk;C<68<64rA7Tgzg0c?oPmeD?kdzx;sZ5WTbUP_vgoV5OX|a5}73G z+5eNs@Lxz~``@aZ{+TD8%=K!WhZ7ssgvmjMH>ih`Q}j`;3{WX(`uf}XTRM(J{$e`z z^*#WZtXr-@NTdN{(Kv;+c3Jm=qGBUOEs z?(f}8;!Am0_wsj4vMxA>&w{N&SWr%F#mA7@QX10>8@og5mHM}W64n<-`JLIC&Gh(3 zWTatnUu#%jD^gDCva-e7G%qFzPE8WV_8h`5$95wrWdrL>Fu*mfr-JC6FMe5z4gZD6 z3ar5Wyhox`)Z(hE{tB5rUf8xUR}c9@aKs4y&WmM z$WuL@-*q_H==b&4krw*(xovr{lbGFF-*;iT(olLRk@0$Yb5Cge{aZC*x@z_Nhna=r91V>s@tA=R| zF^dx?B(_LwOtDs?U5iLiKwI(A=@z-QAK;NUTqnFHg>TAT$c6mQo*r@MTl})>qFp8j z`dk+#9JEX&`IoVa%y34SsG%$SVIH7OGD-q#M-{&Ac2d^-3p}Ht^*sBc)pOX^5))%F z&)b3xc<$aV783M3`{Sl-0viL8U@&@KrbW)4{>k%g|XRtCi1=5Ldz{uy{eidtFd!P`1il2lwtHD7sf%7q5uVpcC2~_itbPnGh#N!aV zUs2iUt5^<_zk}qbdMd#`04*|*%KzWN^~{g&OWez=yN&IXOJzTYV@`=<|KgWOu^&5r zTC1BLmF(7fP*C{g)`~vA7hmrFQr;WVw%`roz@rBl((=|D$Ws{?HhJ5P!pLpP$_xLb zzd*_+urmp{Fp?KPa%SwUWNv5gxNsDsUXOla)wRKWhs?7iyahI_$^kw3YVsXYY5{Hl z!j;CC^mJ)X3=SHYmsd^s7}`bHPK-_b^UtMUwiE}qf;POS#+Mm{zGnXmVoM?so0ea6 z^^MIpaW0%h`#r&1dpX{3+_5s)GXEJ;Z?#oz$ZfvKDk*k9XY9H$f40K&Bc}l$z%5Qq zQv`m_az*W^>uVu%$3_H`!vFI-^Vq_mRuGK>@6M=r?ozV&x^Y+Mx4l8h2a7$<$ua|L z$Hiu$wf^B@6%dDs`1&u;gZVy|isoNPQYFkVY@L99*;$=BtkEh_z2$wVAF1!By`5pK zOU~@Z&vFoIWn^w^X{b?GtdvDarl9i|WZ?{w)kGjX-n@C^;#g%n&Y%#k)foN!fl4D2 zybzO=6t^q+5oXK*V0!|Z}47o2ij3ygWdy{;kc49D@ zpU<4GP0P5&EuvfeI4nqiuJ+NZE)Kg)9-_);`<=^!8%I3^%shf#!38ct-4ND($^(87a!-9y@TbHC+i#h{x z@(grVj_Z~&rCq9p?Li>A_X9y9j=9y)ebbMzNDyiriHQ$}b1^c)a1e1EsqqiV^}X%W zT|7|kG3hyPkqyxojknvRQ(H&hd!HV`8o1pC)4P5)&0 z_+kAxm2C~HUCvV|3-t58Wd9LAzm)r4%|IZ}5ImUG?Rt-3ArtiZiUzy{_a1(=n3b{Z zIB|YSQZ08+th3kf>wq9qKSw`@8|0%%29_p8e8Q7jrO{ zyPGhJhYa_>iFy+W)y-7fChEUQU_W#IvzpA6y`2f9OClCQA+u}dP48%_{2L$=zJdPp zl8XN!8vUo$75_g$(u}eA^5s58@cKjQu2BrKp6=1>bSW*Z({yWu! z|4Y-i>MUv{fy^B&G(}N<(Jj@hV%WM0yxR(-%0e2`(AznvSndW(ac});a)n>PG!4el z6|7>b#z;?Z21Azia{J(b3NHL_h?WM5rQvkGIic(e@!2!z>67H-WG!v&<4(mqqXxN^ zBrS^@;nplZIF_U32H^|8p&Ax-UG|%YPQ*TEb=~m<H9`TSsi%(WM&=eo|6p8R}&b9A2Qc-45i{xB`+ ziOUGj$Z3!3xfM=9l64H6#>4GG&?;svC;Zz`S5;HW80pe^d_T4RD)JqgI|-BH@J#xp zM1+qh4R|;a^gT1#9??yQ{>~qj6vMn)WqU)nA0cE{169>GSIb4RzP9f1dv&BouuESP zj)yX#BV;2SjKW~$BF+Q`(4VZ5>m4%ln=PTC%rzh`ku)h{mjN~ul89FPoF;NaIBinH z!7BgacHC=qMCs?b1@C=XJ+u0^WYou|0<4Yu>{c@8ggap}b>0n@rZ<8v-Bcw)wfjIDNS?XCIi8(7#hN;mzsGA|O?{!J9XX5m zlQE>Dn!{w0CxJmrcAka!TjU+V2AaxR`h{MspwFV@Q}#MjGe z>HRDktHdyZFRm>XM_7YfFKimzz_?FpvI^|S<{~OiP8khl0!a7Q5BV};eNF_l$ef2V zjh`Kc%=Ngit=d*2l`_!2uS7%*tH+C>M0Oqc;^#%xQQZtCApNbN)+uzH0mhb9W&eR z%Gl9v+)LBk5E4Acd% z1idNc>z=}ZZJ)*uoZBFhIEnNIEan-bWc?A`FjuCu7X-eAsohDT^Q&hrSd88*FIJzM z8GS$nEhMkCiY{7$d~!w-LeR7Vv5Wyv0inV|$Tgf`M@}6_x5s$Z$g#GYGjqBJL+qBG za0$LI3b_@8tXIaxu*?a1h_)W6g_r~PwaYgb>ETAk^K*ey;6Gv){J%DvG{K_2J3vOS zzh>o7$hCytUh2GFxo)hTm@{t(VeB6!8b?YGMEsq=G%VhQrr%%`t21H1sJ_2ZD3H6O z((&81WM!ArN?sxaj4WO#6_Kp|+SAJ}Ep!C349D8qsjWq0Jv*)AWpytE2qck)Re||h zx!$r7kwICF#65N1PeVqMy_@J2O-~lI9AjGy8=Ot{VzXs0hozE5H7=tKpMF3=c}nx} zT>vR<$N3)59|xNU7w=i9eV8WQ`6KA#4y>r{>YFMn16QO(wwI|6X6oYkJarNbt6W}R zXAkMh1ybOOJ+Tmqo$eOBvj5b8yT83G@*z3R+$6y#x{0StYY-GwAYvQ1{kYDXt#4kI(nyZ$0Vq;H`{|7>Aqv1Tlizx$gmoA|4eQ?O7a>+j+iHN}5d=J~(ZCMgJZ z_`SF&{u0UM_CEQ_Q>>+>6|Mb`lG1C%e^Y$=FS8o@7I?!%%dMAme<|CAV>$@Cx-TDU zFlKxBDnX1s@(TsF!mVP74SjRPZqU%RT*hIm3tL0r>j8ZPH}%aJxz&_Gc0d%>Wh02hQB{o@$U`J zzv}A>Z6AM3XV{TAKRX+pn(9FYTrYo-w5kp2S|;owzb%rVpFeFHAxCu=_{(1n6H9bZ S1^HPO6nPmH>2k@BU;Zy!4&}7~ diff --git a/media/net-monitor-sbom-signed-artifacts.svg b/media/net-monitor-sbom-signed-artifacts.svg deleted file mode 100644 index 2e4ec4ef5..000000000 --- a/media/net-monitor-sbom-signed-artifacts.svg +++ /dev/null @@ -1 +0,0 @@ -net-monitor:v1SBoMdocumentSBoMWabbit Networks signatureWabbit Networks signaturecontent (blobs) \ No newline at end of file diff --git a/media/net-monitor-sbom-signed-detailed.svg b/media/net-monitor-sbom-signed-detailed.svg deleted file mode 100644 index 7002954e2..000000000 --- a/media/net-monitor-sbom-signed-detailed.svg +++ /dev/null @@ -1 +0,0 @@ -signature content (blob)net-monitor:v1SBoMdocumentSBoMWabbit Networks signatureWabbit Networks signaturelayer1 (blob)layer2 (blob)config (blob)sbomcontent (blob)signature content (blob) \ No newline at end of file diff --git a/media/notary-e2e-scenarios.svg b/media/notary-e2e-scenarios.svg deleted file mode 100644 index 8ecd6896e..000000000 --- a/media/notary-e2e-scenarios.svg +++ /dev/null @@ -1 +0,0 @@ -WabbitNetworks2Public RegistryNotary v2 ScopeInteroperability with other projectsImageSBoMsrcIndexArtifact Build Environment14PolicyManagement5ContainerHost3Private RegistryImageSBoMsrcIndexImageSBoMIndexsrcDocker HubACME RocketsdeployImageSBoMIndexsrcArtifact PushArtifact ImportArtifact DeploymentImage \ No newline at end of file diff --git a/media/nv2-client-components.png b/media/nv2-client-components.png deleted file mode 100644 index 1f9ae294e1ac8cc535ecd9f82766770dbd91682e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26127 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 diff --git a/media/signature-as-index-signing-multi-arch-index.png b/media/signature-as-index-signing-multi-arch-index.png deleted file mode 100644 index bb89f2e70208e7d9f4d3ef85b510f1de51a7964b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 144312 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