Skip to content
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
37 changes: 33 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ parameters:
type: boolean
default: false
description: |
Sign every tag the skopeo YAML files govern at gsoci, not only the tags this run copies:
the one-off pass over tags mirrored before signing existed, and the repair of a run whose
signing failed. Idempotent. Trigger a pipeline on main with this parameter set to true.
Sign every tag the image files govern at gsoci (the skopeo YAML files and the renamed-images
files), not only the tags this run copies: the one-off pass over tags mirrored before signing
existed, and the repair of a run whose signing failed. Idempotent. Trigger a pipeline on main
with this parameter set to true.

jobs:
validate:
Expand Down Expand Up @@ -282,6 +283,15 @@ jobs:
default: 0
filename:
type: string
sign:
type: boolean
default: false
description: |
Sign every tag copied to gsoci right after its copy, with cosign keyless signing under
this job's CircleCI OIDC identity (README, "Signed images"); with the pipeline parameter
`sign-all`, also every tag this executor's share of the file governs. Needs the
`architect` context for the OIDC token. cosign reads the registry credentials
`docker login` stores.
steps:
- setup_remote_docker:
docker_layer_caching: true
Expand Down Expand Up @@ -319,11 +329,29 @@ jobs:
name: "Run retagger"
no_output_timeout: 1h
command: |
retagger run --log-level "<<parameters.log_level>>" \
set -o pipefail
retagger run --log-level "<<parameters.log_level>>" --sign=<<parameters.sign>> \
--executor-count <<parameters.executor_count>> --executor-id <<parameters.executor_id>> --filename <<parameters.filename>> | tee /tmp/retagger.log
- store_artifacts:
path: /tmp/retagger.log
destination: "retagger-<<parameters.filename>>-<<parameters.executor_id>>-of-<<parameters.executor_count>>.log"
- when:
condition:
and:
- <<parameters.sign>>
- <<pipeline.parameters.sign-all>>
steps:
- run:
name: Sign every governed image
no_output_timeout: 1h
command: |
# One worker: forty of these jobs share the registry's per-identity referrers rate limit.
set -o pipefail
retagger sign --sign-workers 1 \
--executor-count <<parameters.executor_count>> --executor-id <<parameters.executor_id>> <<parameters.filename>> | tee /tmp/retagger-sign.log
- store_artifacts:
path: /tmp/retagger-sign.log
destination: "retagger-<<parameters.filename>>-<<parameters.executor_id>>-of-<<parameters.executor_count>>-sign.log"

ping-heartbeat:
docker:
Expand Down Expand Up @@ -589,6 +617,7 @@ build_and_retag: &build_and_retag
requires:
- build-and-push-docker
executor_count: 5
sign: true
filters:
branches:
only:
Expand Down
30 changes: 17 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,26 +90,30 @@ attestors:
url: https://rekor.sigstore.dev
```

`retagger sign <skopeo yaml>` does the signing (see [`sign.go`](sign.go)): it lists
the tags the file governs the way `retagger filter` does, resolves each at the
registry and signs every digest that does not already verify against the job's
own identity, so it is idempotent. The `retag-registry` job runs it over the
`.filtered` file, the tags the run copied. The pipeline parameter `sign-all`
runs it over the unfiltered files instead, every tag they govern: that is the
one-off pass for tags mirrored before signing existed, and the repair of a run
whose signing failed. Trigger it on `main`:
`retagger sign <images file>` does the signing (see [`sign.go`](sign.go)): it lists
the tags the file governs (a skopeo file the way `retagger filter` does, a
[renamed images](#renamed-images) file from its rules the way `retagger run`
does), resolves each at the registry and signs every digest that does not
already verify against the job's own identity, so it is idempotent. The
`retag-registry` job runs it over the `.filtered` file, the tags the run copied;
the `retag-renamed-images` job runs `retagger run --sign`, which signs each tag
right after its copy. The pipeline parameter `sign-all` signs every tag the
files govern instead (the unfiltered skopeo files, and the renamed-images files
sharded by executor like the copies): that is the one-off pass for tags
mirrored before signing existed, and the repair of a run whose signing failed.
Trigger it on `main`:

```bash
curl -X POST -H "Circle-Token: $CIRCLE_TOKEN" -H "Content-Type: application/json" \
-d '{"branch": "main", "parameters": {"sign-all": true}}' \
https://circleci.com/api/v2/project/gh/giantswarm/retagger/pipeline
```

The copies in the Aliyun registry are not signed; the images renamed through
`retagger run` ([renamed images](#renamed-images)) are not signed yet either.
Mirrors in the Docker schema 1 manifest format (a few images from before 2019,
`etcd:v3.3` for one) cannot carry a cosign signature at all; `retagger sign`
reports them as unsignable and moves on.
The copies in the Aliyun registry are not signed, and neither are the Trivy
vulnerability databases the `retag-image-name` jobs copy: OCI artifacts no pod
runs. Mirrors in the Docker schema 1 manifest format (a few images from before
2019, `etcd:v3.3` for one) cannot carry a cosign signature at all; `retagger
sign` reports them as unsignable and moves on.

## Image list formats

Expand Down
Loading