Add lookaside and lookaside-staging, hide sigstore and sigstore-staging

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
Miloslav Trmač 2022-07-11 20:30:54 +02:00
parent c1a12dccd3
commit 3766acbf59
6 changed files with 92 additions and 68 deletions

View File

@ -1,14 +1,14 @@
docker: docker:
example.com: example.com:
sigstore: https://sigstore.example.com lookaside: https://lookaside.example.com
registry.test.example.com: registry.test.example.com:
sigstore: http://registry.test.example.com/sigstore lookaside: http://registry.test.example.com/lookaside
registry.test.example.com:8888: registry.test.example.com:8888:
sigstore: http://registry.test.example.com:8889/sigstore lookaside: http://registry.test.example.com:8889/lookaside
sigstore-staging: https://registry.test.example.com:8889/sigstore/specialAPIserverWhichDoesNotExist lookaside-staging: https://registry.test.example.com:8889/lookaside/specialAPIserverWhichDoesNotExist
localhost: localhost:
sigstore: file:///home/mitr/mydevelopment1 lookaside: file:///home/mitr/mydevelopment1
localhost:8080: localhost:8080:
sigstore: file:///home/mitr/mydevelopment2 lookaside: file:///home/mitr/mydevelopment2
localhost/invalid/url/test: localhost/invalid/url/test:
sigstore: ":emptyscheme" lookaside: ":emptyscheme"

View File

@ -1,12 +1,12 @@
default-docker: default-docker:
sigstore: file:///mnt/companywide/signatures/for/other/repositories lookaside: file:///mnt/companywide/signatures/for/other/repositories
docker: docker:
docker.io/contoso: docker.io/contoso:
sigstore: https://sigstore.contoso.com/fordocker lookaside: https://lookaside.contoso.com/fordocker
docker.io/centos: docker.io/centos:
sigstore: https://sigstore.centos.org/ lookaside: https://lookaside.centos.org/
docker.io/centos/mybetaproduct: docker.io/centos/mybetaproduct:
sigstore: http://localhost:9999/mybetaWIP/sigstore lookaside: http://localhost:9999/mybetaWIP/lookaside
sigstore-staging: file:///srv/mybetaWIP/sigstore lookaside-staging: file:///srv/mybetaWIP/lookaside
docker.io/centos/mybetaproduct:latest: docker.io/centos/mybetaproduct:latest:
sigstore: https://sigstore.centos.org/ lookaside: https://lookaside.centos.org/

View File

@ -47,8 +47,10 @@ type registryConfiguration struct {
// registryNamespace defines lookaside locations for a single namespace. // registryNamespace defines lookaside locations for a single namespace.
type registryNamespace struct { type registryNamespace struct {
SigStore string `json:"sigstore"` // For reading, and if SigStoreStaging is not present, for writing. Lookaside string `json:"lookaside"` // For reading, and if LookasideStaging is not present, for writing.
SigStoreStaging string `json:"sigstore-staging"` // For writing only. LookasideStaging string `json:"lookaside-staging"` // For writing only.
SigStore string `json:"sigstore"` // For compatibility, deprecated in favor of Lookaside.
SigStoreStaging string `json:"sigstore-staging"` // For compatibility, deprecated in favor of LookasideStaging.
UseCosignAttachments *bool `json:"use-cosign-attachments,omitempty"` UseCosignAttachments *bool `json:"use-cosign-attachments,omitempty"`
} }
@ -261,12 +263,22 @@ func (config *registryConfiguration) useCosignAttachments(ref dockerReference) b
// ns.signatureTopLevel returns an URL string configured in ns for ref, for write access if “write”. // ns.signatureTopLevel returns an URL string configured in ns for ref, for write access if “write”.
// or "" if nothing has been configured. // or "" if nothing has been configured.
func (ns registryNamespace) signatureTopLevel(write bool) string { func (ns registryNamespace) signatureTopLevel(write bool) string {
if write && ns.SigStoreStaging != "" { if write {
logrus.Debugf(` Using %s`, ns.SigStoreStaging) if ns.LookasideStaging != "" {
return ns.SigStoreStaging logrus.Debugf(` Using "lookaside-staging" %s`, ns.LookasideStaging)
return ns.LookasideStaging
}
if ns.SigStoreStaging != "" {
logrus.Debugf(` Using "sigstore-staging" %s`, ns.SigStoreStaging)
return ns.SigStoreStaging
}
}
if ns.Lookaside != "" {
logrus.Debugf(` Using "lookaside" %s`, ns.Lookaside)
return ns.Lookaside
} }
if ns.SigStore != "" { if ns.SigStore != "" {
logrus.Debugf(` Using %s`, ns.SigStore) logrus.Debugf(` Using "sigstore" %s`, ns.SigStore)
return ns.SigStore return ns.SigStore
} }
return "" return ""

View File

@ -45,7 +45,7 @@ func TestSignatureStorageBaseURL(t *testing.T) {
dockerRefFromString(t, "//example.com/my/project"), false) dockerRefFromString(t, "//example.com/my/project"), false)
assert.NoError(t, err) assert.NoError(t, err)
require.NotNil(t, base) require.NotNil(t, base)
assert.Equal(t, "https://sigstore.example.com/my/project", base.String()) assert.Equal(t, "https://lookaside.example.com/my/project", base.String())
} }
func TestRegistriesDirPath(t *testing.T) { func TestRegistriesDirPath(t *testing.T) {
@ -157,10 +157,10 @@ func TestLoadAndMergeConfig(t *testing.T) {
err = os.Mkdir(duplicateDefault, 0755) err = os.Mkdir(duplicateDefault, 0755)
require.NoError(t, err) require.NoError(t, err)
err = os.WriteFile(filepath.Join(duplicateDefault, "0.yaml"), err = os.WriteFile(filepath.Join(duplicateDefault, "0.yaml"),
[]byte("default-docker:\n sigstore: file:////tmp/something"), 0644) []byte("default-docker:\n lookaside: file:////tmp/something"), 0644)
require.NoError(t, err) require.NoError(t, err)
err = os.WriteFile(filepath.Join(duplicateDefault, "1.yaml"), err = os.WriteFile(filepath.Join(duplicateDefault, "1.yaml"),
[]byte("default-docker:\n sigstore: file:////tmp/different"), 0644) []byte("default-docker:\n lookaside: file:////tmp/different"), 0644)
require.NoError(t, err) require.NoError(t, err)
_, err = loadAndMergeConfig(duplicateDefault) _, err = loadAndMergeConfig(duplicateDefault)
assert.ErrorContains(t, err, "0.yaml") assert.ErrorContains(t, err, "0.yaml")
@ -171,10 +171,10 @@ func TestLoadAndMergeConfig(t *testing.T) {
err = os.Mkdir(duplicateNS, 0755) err = os.Mkdir(duplicateNS, 0755)
require.NoError(t, err) require.NoError(t, err)
err = os.WriteFile(filepath.Join(duplicateNS, "0.yaml"), err = os.WriteFile(filepath.Join(duplicateNS, "0.yaml"),
[]byte("docker:\n example.com:\n sigstore: file:////tmp/something"), 0644) []byte("docker:\n example.com:\n lookaside: file:////tmp/something"), 0644)
require.NoError(t, err) require.NoError(t, err)
err = os.WriteFile(filepath.Join(duplicateNS, "1.yaml"), err = os.WriteFile(filepath.Join(duplicateNS, "1.yaml"),
[]byte("docker:\n example.com:\n sigstore: file:////tmp/different"), 0644) []byte("docker:\n example.com:\n lookaside: file:////tmp/different"), 0644)
require.NoError(t, err) require.NoError(t, err)
_, err = loadAndMergeConfig(duplicateNS) _, err = loadAndMergeConfig(duplicateNS)
assert.ErrorContains(t, err, "0.yaml") assert.ErrorContains(t, err, "0.yaml")
@ -184,28 +184,28 @@ func TestLoadAndMergeConfig(t *testing.T) {
config, err = loadAndMergeConfig("fixtures/registries.d") config, err = loadAndMergeConfig("fixtures/registries.d")
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, &registryConfiguration{ assert.Equal(t, &registryConfiguration{
DefaultDocker: &registryNamespace{SigStore: "file:///mnt/companywide/signatures/for/other/repositories"}, DefaultDocker: &registryNamespace{Lookaside: "file:///mnt/companywide/signatures/for/other/repositories"},
Docker: map[string]registryNamespace{ Docker: map[string]registryNamespace{
"example.com": {SigStore: "https://sigstore.example.com"}, "example.com": {Lookaside: "https://lookaside.example.com"},
"registry.test.example.com": {SigStore: "http://registry.test.example.com/sigstore"}, "registry.test.example.com": {Lookaside: "http://registry.test.example.com/lookaside"},
"registry.test.example.com:8888": {SigStore: "http://registry.test.example.com:8889/sigstore", SigStoreStaging: "https://registry.test.example.com:8889/sigstore/specialAPIserverWhichDoesNotExist"}, "registry.test.example.com:8888": {Lookaside: "http://registry.test.example.com:8889/lookaside", LookasideStaging: "https://registry.test.example.com:8889/lookaside/specialAPIserverWhichDoesNotExist"},
"localhost": {SigStore: "file:///home/mitr/mydevelopment1"}, "localhost": {Lookaside: "file:///home/mitr/mydevelopment1"},
"localhost:8080": {SigStore: "file:///home/mitr/mydevelopment2"}, "localhost:8080": {Lookaside: "file:///home/mitr/mydevelopment2"},
"localhost/invalid/url/test": {SigStore: ":emptyscheme"}, "localhost/invalid/url/test": {Lookaside: ":emptyscheme"},
"docker.io/contoso": {SigStore: "https://sigstore.contoso.com/fordocker"}, "docker.io/contoso": {Lookaside: "https://lookaside.contoso.com/fordocker"},
"docker.io/centos": {SigStore: "https://sigstore.centos.org/"}, "docker.io/centos": {Lookaside: "https://lookaside.centos.org/"},
"docker.io/centos/mybetaproduct": { "docker.io/centos/mybetaproduct": {
SigStore: "http://localhost:9999/mybetaWIP/sigstore", Lookaside: "http://localhost:9999/mybetaWIP/lookaside",
SigStoreStaging: "file:///srv/mybetaWIP/sigstore", LookasideStaging: "file:///srv/mybetaWIP/lookaside",
}, },
"docker.io/centos/mybetaproduct:latest": {SigStore: "https://sigstore.centos.org/"}, "docker.io/centos/mybetaproduct:latest": {Lookaside: "https://lookaside.centos.org/"},
}, },
}, config) }, config)
} }
func TestRegistryConfigurationSignatureTopLevel(t *testing.T) { func TestRegistryConfigurationSignatureTopLevel(t *testing.T) {
config := registryConfiguration{ config := registryConfiguration{
DefaultDocker: &registryNamespace{SigStore: "=default", SigStoreStaging: "=default+w"}, DefaultDocker: &registryNamespace{Lookaside: "=default", LookasideStaging: "=default+w"},
Docker: map[string]registryNamespace{}, Docker: map[string]registryNamespace{},
} }
for _, ns := range []string{ for _, ns := range []string{
@ -217,7 +217,7 @@ func TestRegistryConfigurationSignatureTopLevel(t *testing.T) {
"example.com/ns1/ns2/repo", "example.com/ns1/ns2/repo",
"example.com/ns1/ns2/repo:notlatest", "example.com/ns1/ns2/repo:notlatest",
} { } {
config.Docker[ns] = registryNamespace{SigStore: ns, SigStoreStaging: ns + "+w"} config.Docker[ns] = registryNamespace{Lookaside: ns, LookasideStaging: ns + "+w"}
} }
for _, c := range []struct{ input, expected string }{ for _, c := range []struct{ input, expected string }{
@ -241,7 +241,7 @@ func TestRegistryConfigurationSignatureTopLevel(t *testing.T) {
config = registryConfiguration{ config = registryConfiguration{
Docker: map[string]registryNamespace{ Docker: map[string]registryNamespace{
"unmatched": {SigStore: "a", SigStoreStaging: "b"}, "unmatched": {Lookaside: "a", LookasideStaging: "b"},
}, },
} }
dr := dockerRefFromString(t, "//thisisnotmatched") dr := dockerRefFromString(t, "//thisisnotmatched")
@ -257,14 +257,24 @@ func TestRegistryNamespaceSignatureTopLevel(t *testing.T) {
forWriting bool forWriting bool
expected string expected string
}{ }{
{registryNamespace{SigStoreStaging: "a", SigStore: "b"}, true, "a"}, {registryNamespace{LookasideStaging: "a", Lookaside: "b"}, true, "a"},
{registryNamespace{SigStoreStaging: "a", SigStore: "b"}, false, "b"}, {registryNamespace{LookasideStaging: "a", Lookaside: "b"}, false, "b"},
{registryNamespace{SigStore: "b"}, true, "b"}, {registryNamespace{Lookaside: "b"}, true, "b"},
{registryNamespace{SigStore: "b"}, false, "b"}, {registryNamespace{Lookaside: "b"}, false, "b"},
{registryNamespace{SigStoreStaging: "a"}, true, "a"}, {registryNamespace{LookasideStaging: "a"}, true, "a"},
{registryNamespace{SigStoreStaging: "a"}, false, ""}, {registryNamespace{LookasideStaging: "a"}, false, ""},
{registryNamespace{}, true, ""}, {registryNamespace{}, true, ""},
{registryNamespace{}, false, ""}, {registryNamespace{}, false, ""},
{registryNamespace{LookasideStaging: "a", Lookaside: "b", SigStoreStaging: "c", SigStore: "d"}, true, "a"},
{registryNamespace{Lookaside: "b", SigStoreStaging: "c", SigStore: "d"}, true, "c"},
{registryNamespace{Lookaside: "b", SigStore: "d"}, true, "b"},
{registryNamespace{SigStore: "d"}, true, "d"},
{registryNamespace{LookasideStaging: "a", Lookaside: "b", SigStoreStaging: "c", SigStore: "d"}, false, "b"},
{registryNamespace{Lookaside: "b", SigStoreStaging: "c", SigStore: "d"}, false, "b"},
{registryNamespace{Lookaside: "b", SigStore: "d"}, false, "b"},
{registryNamespace{SigStore: "d"}, false, "d"},
} { } {
res := c.ns.signatureTopLevel(c.forWriting) res := c.ns.signatureTopLevel(c.forWriting)
assert.Equal(t, c.expected, res, fmt.Sprintf("%#v %v", c.ns, c.forWriting)) assert.Equal(t, c.expected, res, fmt.Sprintf("%#v %v", c.ns, c.forWriting))

View File

@ -73,16 +73,18 @@ If no `docker` section can be found for the container image, and no `default-doc
A single configuration section is selected for a container image using the process A single configuration section is selected for a container image using the process
described above. The configuration section is a YAML mapping, with the following keys: described above. The configuration section is a YAML mapping, with the following keys:
- `sigstore-staging` defines an URL of of the signature storage, used for editing it (adding or deleting signatures). <!-- `sigstore` and `sigstore-staging` are deprecated and intentionally not documented here. -->
This key is optional; if it is missing, `sigstore` below is used. - `lookaside-staging` defines an URL of of the signature storage, used for editing it (adding or deleting signatures).
- `sigstore` defines an URL of the signature storage. This key is optional; if it is missing, `lookaside` below is used.
- `lookaside` defines an URL of the signature storage.
This URL is used for reading existing signatures, This URL is used for reading existing signatures,
and if `sigstore-staging` does not exist, also for adding or removing them. and if `lookaside-staging` does not exist, also for adding or removing them.
This key is optional; if it is missing, no signature storage is defined (no signatures This key is optional; if it is missing, no signature storage is defined (no signatures
are download along with images, adding new signatures is possible only if `sigstore-staging` is defined). are download along with images, adding new signatures is possible only if `lookaside-staging` is defined).
- `use-cosign-attachments` specifies whether Cosign image attachments (signatures, attestations and the like) are going to be read/written along with the image. - `use-cosign-attachments` specifies whether Cosign image attachments (signatures, attestations and the like) are going to be read/written along with the image.
If disabled, the images are treated as if no attachments exist; attempts to write attachments fail. If disabled, the images are treated as if no attachments exist; attempts to write attachments fail.
@ -96,11 +98,11 @@ The following demonstrates how to to consume and run images from various registr
```yaml ```yaml
docker: docker:
registry.database-supplier.com: registry.database-supplier.com:
sigstore: https://sigstore.database-supplier.com lookaside: https://lookaside.database-supplier.com
distribution.great-middleware.org: distribution.great-middleware.org:
sigstore: https://security-team.great-middleware.org/sigstore lookaside: https://security-team.great-middleware.org/lookaside
docker.io/web-framework: docker.io/web-framework:
sigstore: https://sigstore.web-framework.io:8080 lookaside: https://lookaside.web-framework.io:8080
``` ```
### Developing and Signing Containers, Staging Signatures ### Developing and Signing Containers, Staging Signatures
@ -114,13 +116,13 @@ For developers in `example.com`:
```yaml ```yaml
docker: docker:
registry.example.com: registry.example.com:
sigstore: https://registry-sigstore.example.com lookaside: https://registry-lookaside.example.com
registry.example.com/mydepartment: registry.example.com/mydepartment:
sigstore: https://sigstore.mydepartment.example.com lookaside: https://lookaside.mydepartment.example.com
sigstore-staging: file:///mnt/mydepartment/sigstore-staging lookaside-staging: file:///mnt/mydepartment/lookaside-staging
registry.example.com/mydepartment/myproject:mybranch: registry.example.com/mydepartment/myproject:mybranch:
sigstore: http://localhost:4242/sigstore lookaside: http://localhost:4242/lookaside
sigstore-staging: file:///home/useraccount/webroot/sigstore lookaside-staging: file:///home/useraccount/webroot/lookaside
``` ```
### A Global Default ### A Global Default
@ -130,7 +132,7 @@ without listing each domain individually. This is expected to rarely happen, usu
```yaml ```yaml
default-docker: default-docker:
sigstore-staging: file:///mnt/company/common-sigstore-staging lookaside-staging: file:///mnt/company/common-lookaside-staging
``` ```
# AUTHORS # AUTHORS

View File

@ -26,13 +26,13 @@ a simple static web server serving a directory structure created by writing to a
e.g. a HTTP server reading signatures from a database.) e.g. a HTTP server reading signatures from a database.)
The usual workflow for producing and distributing images using the separate storage mechanism The usual workflow for producing and distributing images using the separate storage mechanism
is to configure the repository in `registries.d` with `sigstore-staging` URL pointing to a private is to configure the repository in `registries.d` with `lookaside-staging` URL pointing to a private
`file:///` staging area, and a `sigstore` URL pointing to a public web server. `file:///` staging area, and a `lookaside` URL pointing to a public web server.
To publish an image, the image author would sign the image as necessary (e.g. using `skopeo copy`), To publish an image, the image author would sign the image as necessary (e.g. using `skopeo copy`),
and then copy the created directory structure from the `file:///` staging area and then copy the created directory structure from the `file:///` staging area
to a subdirectory of a webroot of the public web server so that they are accessible using the public `sigstore` URL. to a subdirectory of a webroot of the public web server so that they are accessible using the public `lookaside` URL.
The author would also instruct consumers of the image to, or provide a `registries.d` configuration file to, The author would also instruct consumers of the image to, or provide a `registries.d` configuration file to,
set up a `sigstore` URL pointing to the public web server. set up a `lookaside` URL pointing to the public web server.
### Path structure ### Path structure
@ -63,15 +63,15 @@ and no way to download all of the signatures at once.
For a docker/distribution image available as `busybox@sha256:817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e` For a docker/distribution image available as `busybox@sha256:817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e`
(or as `busybox:latest` if the `latest` tag points to to a manifest with the same digest), (or as `busybox:latest` if the `latest` tag points to to a manifest with the same digest),
and with a `registries.d` configuration specifying a `sigstore` URL `https://example.com/sigstore` for the same image, and with a `registries.d` configuration specifying a `lookaside` URL `https://example.com/lookaside` for the same image,
the following URLs would be accessed to download all signatures: the following URLs would be accessed to download all signatures:
> - `https://example.com/sigstore/library/busybox@sha256=817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e/signature-1` > - `https://example.com/lookaside/library/busybox@sha256=817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e/signature-1`
> - `https://example.com/sigstore/library/busybox@sha256=817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e/signature-2` > - `https://example.com/lookaside/library/busybox@sha256=817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e/signature-2`
> - … > - …
For a docker/distribution image available as `example.com/ns1/ns2/ns3/repo@somedigest:digestvalue` and the same For a docker/distribution image available as `example.com/ns1/ns2/ns3/repo@somedigest:digestvalue` and the same
`sigstore` URL, the signatures would be available at `lookaside` URL, the signatures would be available at
> `https://example.com/sigstore/ns1/ns2/ns3/repo@somedigest=digestvalue/signature-1` > `https://example.com/lookaside/ns1/ns2/ns3/repo@somedigest=digestvalue/signature-1`
and so on. and so on.