Dagger
Search

cosign

This module signs container images and OCI artefacts by digest with
Sigstore's cosign, attaches predicates such as a CycloneDX SBOM as signed
attestations, and verifies both against an OIDC issuer and an identity.

Signing is keyless: cosign gets a short-lived certificate from Fulcio for the
identity in an OIDC token, and the signature is recorded in Rekor. The token
is requested by the calling repository's own workflow and handed in as a
secret, so the identity in the certificate is that repository's workflow and
not a shared template's.

Verification needs no token and no local cosign install, so anyone can check
an artefact by hand.

Installation

dagger install github.com/stuttgart-things/dagger/cosign@v0.131.0

Entrypoint

Return Type
Cosign
Example
dagger -m github.com/stuttgart-things/dagger/cosign@13be045b822d23b5c6335452a4f4dc3c0b2283e7 call \
func (m *MyModule) Example() *dagger.Cosign  {
	return dag.
			Cosign()
}
@function
def example() -> dagger.Cosign:
	return (
		dag.cosign()
	)
@func()
example(): Cosign {
	return dag
		.cosign()
}

Types

Cosign 🔗

Cosign signs, attests and verifies OCI artefacts with a pinned cosign release

baseImage() 🔗

Base image the cosign binary is copied into. It needs a shell, which the registry login runs in.

Return Type
String !
Example
dagger -m github.com/stuttgart-things/dagger/cosign@13be045b822d23b5c6335452a4f4dc3c0b2283e7 call \
 base-image
func (m *MyModule) Example(ctx context.Context) string  {
	return dag.
			Cosign().
			Baseimage(ctx)
}
@function
async def example() -> str:
	return await (
		dag.cosign()
		.baseimage()
	)
@func()
async example(): Promise<string> {
	return dag
		.cosign()
		.baseImage()
}

attest() 🔗

Attest attaches predicate to the artefact at ref as a signed in-toto attestation of predicateType, e.g. a CycloneDX SBOM from the trivy module’s Sbom as “cyclonedx”. The token, the registry credentials and the digest requirement work as they do for Sign.

predicateType is one of cosign’s names (cyclonedx, spdxjson, slsaprovenance, vuln, openvex, custom, …) or a predicate type URI. It has no default: the type is a claim about what the predicate is.

An empty predicate is refused. Attested and signed, an empty SBOM is a signed claim that the image contains nothing.

cosign adds an attestation next to those already there. VerifyAttestation refuses to choose between attestations of one type that carry different predicates, so a job that may attest the same digest again, such as a re-run, should pass replace: it drops the earlier attestations of the same type before adding this one.

Return Type
String !
Arguments
NameTypeDefault ValueDescription
refString !-

Artefact to attest, pinned to a digest (repo@sha256:…)

predicateFile !-

Predicate document, e.g. a CycloneDX SBOM

predicateTypeString !-

cosign predicate type name (cyclonedx, spdxjson, slsaprovenance, …) or URI

identityTokenSecret !-

OIDC token with audience “sigstore” for the identity to sign as

replaceBoolean false

Replace earlier attestations of the same type on ref

registryString -

Registry to log in to; derived from ref when empty

registryUsernameString -No description provided
registryPasswordSecret -No description provided
cosignVersionString "2.6.5"

cosign release

Example
dagger -m github.com/stuttgart-things/dagger/cosign@13be045b822d23b5c6335452a4f4dc3c0b2283e7 call \
 attest --ref string --predicate file:path --predicate-type string --identity-token env:MYSECRET
func (m *MyModule) Example(ctx context.Context, ref string, predicate *dagger.File, predicateType string, identityToken *dagger.Secret) string  {
	return dag.
			Cosign().
			Attest(ctx, ref, predicate, predicateType, identityToken)
}
@function
async def example(ref: str, predicate: dagger.File, predicatetype: str, identitytoken: dagger.Secret) -> str:
	return await (
		dag.cosign()
		.attest(ref, predicate, predicatetype, identitytoken)
	)
@func()
async example(ref: string, predicate: File, predicateType: string, identityToken: Secret): Promise<string> {
	return dag
		.cosign()
		.attest(ref, predicate, predicateType, identityToken)
}

sign() 🔗

Sign signs the artefact at ref keylessly: cosign gets a short-lived certificate from Fulcio for the identity in identityToken, records the signature in Rekor and pushes it next to the artefact. It returns cosign’s report, which names the Rekor entry and where the signature went.

ref has to be pinned to a digest (repo@sha256:…). A signature on a tag is a signature on a name somebody can move, so a tag is refused rather than resolved here. Resolve it first with the crane module’s Digest; for a multi-arch release that is the index digest.

identityToken is an OIDC token with audience “sigstore”, requested by the workflow that calls this function. In GitHub Actions the job needs id-token: write, and Fulcio writes the calling workflow’s job_workflow_ref into the certificate, which is what Verify matches. Requested from a shared template’s workflow instead, every repository using that template would sign as one and the same identity.

The token reaches cosign as SIGSTORE_ID_TOKEN, never as an argument, and the credentials that request a token (ACTIONS_ID_TOKENREQUEST*) never enter the container. Without such a token nothing here works locally; Verify does.

The registry credentials need push access: the signature is stored in the artefact’s repository.

Return Type
String !
Arguments
NameTypeDefault ValueDescription
refString !-

Artefact to sign, pinned to a digest (repo@sha256:…)

identityTokenSecret !-

OIDC token with audience “sigstore” for the identity to sign as

registryString -

Registry to log in to; derived from ref when empty

registryUsernameString -No description provided
registryPasswordSecret -No description provided
cosignVersionString "2.6.5"

cosign release

Example
dagger -m github.com/stuttgart-things/dagger/cosign@13be045b822d23b5c6335452a4f4dc3c0b2283e7 call \
 sign --ref string --identity-token env:MYSECRET
func (m *MyModule) Example(ctx context.Context, ref string, identityToken *dagger.Secret) string  {
	return dag.
			Cosign().
			Sign(ctx, ref, identityToken)
}
@function
async def example(ref: str, identitytoken: dagger.Secret) -> str:
	return await (
		dag.cosign()
		.sign(ref, identitytoken)
	)
@func()
async example(ref: string, identityToken: Secret): Promise<string> {
	return dag
		.cosign()
		.sign(ref, identityToken)
}

verify() 🔗

Verify checks the signatures on ref against an OIDC issuer and exactly one of an identity or an identity regexp, and returns the verified payloads as cosign prints them (JSON). It is an error when no signature verifies.

There is no default identity. For GitHub Actions the issuer is https://token.actions.githubusercontent.com and the identity is the signing workflow, e.g. ^https://github.com///.github/workflows/.yaml@refs/ Anchor and escape a regexp, or it matches more repositories than yours.

No token and no local cosign install are needed, so this is also how to check an artefact by hand. A tag is accepted here and means whatever it points at right now.

A verification that has never refused anything cannot be told apart from one that cannot refuse. Pair it with VerifyRefuses.

Return Type
String !
Arguments
NameTypeDefault ValueDescription
refString !-

Artefact to verify, ideally pinned to a digest

certificateOidcIssuerString !-

OIDC issuer the certificate must name

certificateIdentityString -

Exact identity (certificate SAN) the signature must carry

certificateIdentityRegexpString -

Regexp the identity must match; anchor and escape it

registryString -

Registry to log in to; derived from ref when empty

registryUsernameString -No description provided
registryPasswordSecret -No description provided
cosignVersionString "2.6.5"

cosign release

Example
dagger -m github.com/stuttgart-things/dagger/cosign@13be045b822d23b5c6335452a4f4dc3c0b2283e7 call \
 verify --ref string --certificate-oidc-issuer string
func (m *MyModule) Example(ctx context.Context, ref string, certificateOidcIssuer string) string  {
	return dag.
			Cosign().
			Verify(ctx, ref, certificateOidcIssuer)
}
@function
async def example(ref: str, certificateoidcissuer: str) -> str:
	return await (
		dag.cosign()
		.verify(ref, certificateoidcissuer)
	)
@func()
async example(ref: string, certificateOidcIssuer: string): Promise<string> {
	return dag
		.cosign()
		.verify(ref, certificateOidcIssuer)
}

verifyAttestation() 🔗

VerifyAttestation checks the attestations of predicateType on ref against an OIDC issuer and an identity, as Verify does for signatures, and returns the predicate they carry, e.g. the CycloneDX document of a “cyclonedx” attestation.

When several attestations of that type verify and carry different predicates – a digest attested twice without replace – this is an error rather than a pick of one of them.

Return Type
File !
Arguments
NameTypeDefault ValueDescription
refString !-

Artefact to verify, ideally pinned to a digest

predicateTypeString !-

cosign predicate type name (cyclonedx, spdxjson, slsaprovenance, …) or URI

certificateOidcIssuerString !-

OIDC issuer the certificate must name

certificateIdentityString -

Exact identity (certificate SAN) the attestation must carry

certificateIdentityRegexpString -

Regexp the identity must match; anchor and escape it

registryString -

Registry to log in to; derived from ref when empty

registryUsernameString -No description provided
registryPasswordSecret -No description provided
cosignVersionString "2.6.5"

cosign release

Example
dagger -m github.com/stuttgart-things/dagger/cosign@13be045b822d23b5c6335452a4f4dc3c0b2283e7 call \
 verify-attestation --ref string --predicate-type string --certificate-oidc-issuer string
func (m *MyModule) Example(ref string, predicateType string, certificateOidcIssuer string) *dagger.File  {
	return dag.
			Cosign().
			Verifyattestation(ref, predicateType, certificateOidcIssuer)
}
@function
def example(ref: str, predicatetype: str, certificateoidcissuer: str) -> dagger.File:
	return (
		dag.cosign()
		.verifyattestation(ref, predicatetype, certificateoidcissuer)
	)
@func()
example(ref: string, predicateType: string, certificateOidcIssuer: string): File {
	return dag
		.cosign()
		.verifyAttestation(ref, predicateType, certificateOidcIssuer)
}

verifyRefuses() 🔗

VerifyRefuses proves that verification can refuse. It runs the check Verify runs (VerifyAttestation’s, when predicateType is set) with an identity that must NOT match, and succeeds only when cosign refuses it for that reason.

It is an error when the verification passes: the identity is broader than it looks, or the check is not a check. It is also an error when cosign fails for any other reason – an artefact with no signature at all, a registry that cannot be reached, a typo in the issuer – because none of those shows that a signature which does exist would be refused.

Use an identity that differs from the real one in the part that matters, such as another repository of the same organisation, with the same issuer.

Return Type
String !
Arguments
NameTypeDefault ValueDescription
refString !-

Artefact that is signed, by an identity other than the one below

certificateOidcIssuerString !-

OIDC issuer the real signature was made with

certificateIdentityString -

Exact identity that must not match

certificateIdentityRegexpString -

Identity regexp that must not match

predicateTypeString -

Check attestations of this type instead of signatures

registryString -

Registry to log in to; derived from ref when empty

registryUsernameString -No description provided
registryPasswordSecret -No description provided
cosignVersionString "2.6.5"

cosign release

Example
dagger -m github.com/stuttgart-things/dagger/cosign@13be045b822d23b5c6335452a4f4dc3c0b2283e7 call \
 verify-refuses --ref string --certificate-oidc-issuer string
func (m *MyModule) Example(ctx context.Context, ref string, certificateOidcIssuer string) string  {
	return dag.
			Cosign().
			Verifyrefuses(ctx, ref, certificateOidcIssuer)
}
@function
async def example(ref: str, certificateoidcissuer: str) -> str:
	return await (
		dag.cosign()
		.verifyrefuses(ref, certificateoidcissuer)
	)
@func()
async example(ref: string, certificateOidcIssuer: string): Promise<string> {
	return dag
		.cosign()
		.verifyRefuses(ref, certificateOidcIssuer)
}

version() 🔗

Version returns cosign version for the release the other functions use.

Return Type
String !
Arguments
NameTypeDefault ValueDescription
cosignVersionString "2.6.5"

cosign release

Example
dagger -m github.com/stuttgart-things/dagger/cosign@13be045b822d23b5c6335452a4f4dc3c0b2283e7 call \
 version
func (m *MyModule) Example(ctx context.Context) string  {
	return dag.
			Cosign().
			Version(ctx)
}
@function
async def example() -> str:
	return await (
		dag.cosign()
		.version()
	)
@func()
async example(): Promise<string> {
	return dag
		.cosign()
		.version()
}