Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix some bugs in the attestation support and add a formal spec. #561

Merged
merged 1 commit into from
Aug 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion cmd/cosign/cli/attest.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,10 @@ EXAMPLES
}
}

const intotoPayloadType = "application/vnd.in-toto+json"
const (
intotoPayloadType = "application/vnd.in-toto+json"
dssePayloadType = "application/vnd.dsse.envelope.v1+json"
)

func AttestCmd(ctx context.Context, ko KeyOpts, imageRef string, certPath string,
upload bool, predicatePath string, force bool, predicateType string) error {
Expand Down Expand Up @@ -179,6 +182,7 @@ func AttestCmd(ctx context.Context, ko KeyOpts, imageRef string, certPath string
Chain: sv.Chain,
DupeDetector: sv,
RemoteOpts: remoteOpts,
MediaType: dssePayloadType,
}

uploadTLog, err := shouldUploadToTlog(ref, force, ko.RekorURL)
Expand Down
4 changes: 2 additions & 2 deletions cmd/cosign/cli/verify_attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ func applyVerifyAttestationFlags(cmd *VerifyAttestationCommand, flagset *flag.Fl
flagset.BoolVar(&cmd.Sk, "sk", false, "whether to use a hardware security key")
flagset.StringVar(&cmd.Slot, "slot", "", "security key slot to use for generated key (default: signature) (authentication|signature|card-authentication|key-management)")
flagset.BoolVar(&cmd.CheckClaims, "check-claims", true, "whether to check the claims found")
flagset.StringVar(&cmd.Output, "output", "json", "output format for the signing image information (default JSON) (json|text)")
flagset.StringVar(&cmd.FulcioURL, "fulcio-url", "https://fulcio.sigstore.dev", "[EXPERIMENTAL] address of sigstore PKI server")
flagset.StringVar(&cmd.RekorURL, "rekor-url", "https://rekor.sigstore.dev", "[EXPERIMENTAL] address of rekor STL server")
}
Expand Down Expand Up @@ -155,7 +154,8 @@ func (c *VerifyAttestationCommand) Exec(ctx context.Context, args []string) (err
return err
}

PrintVerification(imageRef, verified, co, c.Output)
// The attestations are always JSON, so use the raw "text" mode for outputting them instead of conversion
PrintVerification(imageRef, verified, co, "text")
}

return nil
Expand Down
7 changes: 6 additions & 1 deletion pkg/cosign/remote/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,17 @@ type UploadOpts struct {
Bundle *Bundle
AdditionalAnnotations map[string]string
RemoteOpts []remote.Option
MediaType string
}

func UploadSignature(signature, payload []byte, dst name.Reference, opts UploadOpts) (uploadedSig []byte, err error) {
// Preserve the default
if opts.MediaType == "" {
opts.MediaType = SimpleSigningMediaType
}
l := &staticLayer{
b: payload,
mt: SimpleSigningMediaType,
mt: types.MediaType(opts.MediaType),
}

base, err := SignatureImage(dst, opts.RemoteOpts...)
Expand Down
54 changes: 54 additions & 0 deletions specs/ATTESTATION_SPEC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Cosign Attestation Specifications

This document aims to describe how `cosign` attaches `Attestations` to container images.

The goal is to specify the behavior well enough to promote other implementations and enable interoperability.
Attestations attached with `cosign` should be retrievable in other tools, and vice-versa.

This document focuses on the layout of attestations within an [OCI Image Manifest V1](https://github.com/opencontainers/image-spec/blob/master/manifest.md) object.

This document assumes you are using the In-Toto [Attestation](https://github.com/in-toto/attestation) format, serialized as a `DSSE` envelope
Other formats can be used, and the `mediaType` property should describe the format of a particular attestation, but implementations may not understand them.
The DSSE envelope format is defined [here](https://github.com/secure-systems-lab/dsse/blob/master/envelope.md#dsse-envelope) and uses the `mediaType`: `application/vnd.dsse.envelope.v1+json`.

Multiple Attestations may be "attached" to one image.
Each Attestation may refer to the entire image, or to a specific part of that image.
This is indicated via the `subject` field of the `Statement` inside the `Attestation`.

Attestations attached to a container image are generally assumed to refer to that image in some way.

## Overall Layout

An `Attestation` object is represented as an [OCI Image Manifest V1](https://github.com/opencontainers/image-spec/blob/master/manifest.md).

Each individual `Attestation` is represented as a `layer`, using a standard `descriptor`.
The `layers` list is ordered, but no order is assumed or important for the `Attestations`.

Here is an example manifest containing one `Attestation`:

```json
{
"schemaVersion": 2,
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"size": 233,
"digest": "sha256:83bd5fb5b39f65f28e50a86d48fa79c07880befc292d92eebdc18531054b070c"
},
"layers": [
{
"mediaType": "application/vnd.dsse.envelope.v1+json",
"size": 246,
"digest": "sha256:ed3ad03d3b87843b5419d7dce9d50a3e0f45554b2ba93bf378611cae6b450cff",
}
]
}
```

## Subject Verification

`Attestations` MAY refer to multiple `subjects`.

When verifying an attestation for a container image, implementations MUST verify the relationship between the `subject` field and the container image.
Attestations MAY reference the entire container image or a portion of it.

Implementations MUST support `Attestations` that reference the entire container image, other relationship types are optional.