cosign
This module signs container images and OCI artefacts by digest withSigstore'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.0Entrypoint
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-imagefunc (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
| Name | Type | Default Value | Description |
|---|---|---|---|
| ref | String ! | - | Artefact to attest, pinned to a digest (repo@sha256:…) |
| predicate | File ! | - | Predicate document, e.g. a CycloneDX SBOM |
| predicateType | String ! | - | cosign predicate type name (cyclonedx, spdxjson, slsaprovenance, …) or URI |
| identityToken | Secret ! | - | OIDC token with audience “sigstore” for the identity to sign as |
| replace | Boolean | false | Replace earlier attestations of the same type on ref |
| registry | String | - | Registry to log in to; derived from ref when empty |
| registryUsername | String | - | No description provided |
| registryPassword | Secret | - | No description provided |
| cosignVersion | String | "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:MYSECRETfunc (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
| Name | Type | Default Value | Description |
|---|---|---|---|
| ref | String ! | - | Artefact to sign, pinned to a digest (repo@sha256:…) |
| identityToken | Secret ! | - | OIDC token with audience “sigstore” for the identity to sign as |
| registry | String | - | Registry to log in to; derived from ref when empty |
| registryUsername | String | - | No description provided |
| registryPassword | Secret | - | No description provided |
| cosignVersion | String | "2.6.5" | cosign release |
Example
dagger -m github.com/stuttgart-things/dagger/cosign@13be045b822d23b5c6335452a4f4dc3c0b2283e7 call \
sign --ref string --identity-token env:MYSECRETfunc (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
| Name | Type | Default Value | Description |
|---|---|---|---|
| ref | String ! | - | Artefact to verify, ideally pinned to a digest |
| certificateOidcIssuer | String ! | - | OIDC issuer the certificate must name |
| certificateIdentity | String | - | Exact identity (certificate SAN) the signature must carry |
| certificateIdentityRegexp | String | - | Regexp the identity must match; anchor and escape it |
| registry | String | - | Registry to log in to; derived from ref when empty |
| registryUsername | String | - | No description provided |
| registryPassword | Secret | - | No description provided |
| cosignVersion | String | "2.6.5" | cosign release |
Example
dagger -m github.com/stuttgart-things/dagger/cosign@13be045b822d23b5c6335452a4f4dc3c0b2283e7 call \
verify --ref string --certificate-oidc-issuer stringfunc (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
| Name | Type | Default Value | Description |
|---|---|---|---|
| ref | String ! | - | Artefact to verify, ideally pinned to a digest |
| predicateType | String ! | - | cosign predicate type name (cyclonedx, spdxjson, slsaprovenance, …) or URI |
| certificateOidcIssuer | String ! | - | OIDC issuer the certificate must name |
| certificateIdentity | String | - | Exact identity (certificate SAN) the attestation must carry |
| certificateIdentityRegexp | String | - | Regexp the identity must match; anchor and escape it |
| registry | String | - | Registry to log in to; derived from ref when empty |
| registryUsername | String | - | No description provided |
| registryPassword | Secret | - | No description provided |
| cosignVersion | String | "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 stringfunc (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
| Name | Type | Default Value | Description |
|---|---|---|---|
| ref | String ! | - | Artefact that is signed, by an identity other than the one below |
| certificateOidcIssuer | String ! | - | OIDC issuer the real signature was made with |
| certificateIdentity | String | - | Exact identity that must not match |
| certificateIdentityRegexp | String | - | Identity regexp that must not match |
| predicateType | String | - | Check attestations of this type instead of signatures |
| registry | String | - | Registry to log in to; derived from ref when empty |
| registryUsername | String | - | No description provided |
| registryPassword | Secret | - | No description provided |
| cosignVersion | String | "2.6.5" | cosign release |
Example
dagger -m github.com/stuttgart-things/dagger/cosign@13be045b822d23b5c6335452a4f4dc3c0b2283e7 call \
verify-refuses --ref string --certificate-oidc-issuer stringfunc (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
| Name | Type | Default Value | Description |
|---|---|---|---|
| cosignVersion | String | "2.6.5" | cosign release |
Example
dagger -m github.com/stuttgart-things/dagger/cosign@13be045b822d23b5c6335452a4f4dc3c0b2283e7 call \
versionfunc (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()
}