Skip to content

Commit f1ac277

Browse files
authored
image-copy-{ecr,gcp}: optionally ignore referrers (#238)
If customers aren't familiar with cosign then the sea of `sha256-abcdef...` tags in the mirror repositories can be confusing and make it unnecessarily difficult to understand the available tags, especially if they have no intention of doing anything with the signatures and attestations. This change adds a variable (`ignore_referrers`) that disables the mirroring of signatures and attestations. I've updated the READMEs to document this variable. I've also lengthened the timeout on the `image-copy-ecr` Lambda. The default of 3 seconds is far too short and I was running into timeouts while testing this change.
1 parent 5bd8451 commit f1ac277

File tree

8 files changed

+100
-32
lines changed

8 files changed

+100
-32
lines changed

image-copy-ecr/README.md

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,52 @@ The Terraform does everything:
1212

1313
## Setup
1414

15+
Create a `.tfvars` file.
16+
17+
```
18+
cat << EOF > iac/terraform.tfvars
19+
# Required. The name of your Chainguard organization.
20+
group_name = "your.org"
21+
22+
# Required. The name of the destination repo where images should be copied to.
23+
# This repository will be created by the terraform and images will be copied to
24+
# '<dst_repo>/<image_name>'.
25+
dst_repo = "image-copy"
26+
27+
# Optional. Ignore signatures and attestations. This can help reduce cruft in
28+
# the mirror repositories if you aren't going to be verifying or using the
29+
# referrers.
30+
# ignore_referrers = true
31+
32+
# Optional. Enable immutable tags for the repositories created by the Lambda.
33+
# If enabled, then the Lambda will append a portion of the digest to the tags
34+
# it copies. For instance: 'latest-abcdef'
35+
# immutable_tags = true
36+
EOF
37+
```
38+
39+
Login to AWS and Chainguard.
40+
1541
```sh
1642
aws sso login --profile my-profile
1743
chainctl auth login
18-
terraform init
19-
terraform apply
2044
```
2145

22-
This will prompt for your group name and destination repo, and show you the resources it will create.
46+
Apply the terraform.
47+
48+
```sh
49+
cd iac/
50+
terraform init
51+
terraform apply -var-file=terraform.tfvars
52+
```
2353

24-
When the resources are created, any images that are pushed to your group will be mirrored to the ECR repository.
54+
When the resources are created, any images that are pushed to your group will
55+
be mirrored to the ECR repository.
2556

26-
The Lambda function has minimal permissions: it's only allowed to push images to the destination repo and its sub-repos.
57+
The Lambda function has minimal permissions: it's only allowed to push images
58+
to the destination repo and its sub-repos.
2759

28-
The Chainguard identity also has minimal permissions: it only has permission to pull from the source repo.
60+
The Chainguard identity also has minimal permissions: it only has permission to
61+
pull from the source repo.
2962

30-
To tear down resources, run `terraform destroy`.
63+
To tear down resources, run `terraform destroy -var-file=terraform.tfvars`.

image-copy-ecr/iac/lambda.tf

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -107,17 +107,20 @@ resource "aws_lambda_function" "lambda" {
107107
package_type = "Image"
108108
image_uri = ko_build.image.image_ref
109109

110+
timeout = 300
111+
110112
environment {
111113
variables = {
112-
GROUP_NAME = var.group_name
113-
GROUP = data.chainguard_group.group.id
114-
IDENTITY = chainguard_identity.aws.id
115-
ISSUER_URL = "https://issuer.enforce.dev"
116-
API_ENDPOINT = "https://console-api.enforce.dev"
117-
DST_REPO = var.dst_repo
118-
FULL_DST_REPO = aws_ecr_repository.repo.repository_url
119-
REGION = data.aws_region.current.name
120-
IMMUTABLE_TAGS = var.immutable_tags
114+
GROUP_NAME = var.group_name
115+
GROUP = data.chainguard_group.group.id
116+
IDENTITY = chainguard_identity.aws.id
117+
ISSUER_URL = "https://issuer.enforce.dev"
118+
API_ENDPOINT = "https://console-api.enforce.dev"
119+
DST_REPO = var.dst_repo
120+
FULL_DST_REPO = aws_ecr_repository.repo.repository_url
121+
REGION = data.aws_region.current.name
122+
IMMUTABLE_TAGS = var.immutable_tags
123+
IGNORE_REFERRERS = var.ignore_referrers
121124
}
122125
}
123126
}

image-copy-ecr/iac/variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,9 @@ variable "immutable_tags" {
1313
description = "Whether to enable immutable tags."
1414
default = false
1515
}
16+
17+
variable "ignore_referrers" {
18+
type = bool
19+
description = "Whether to ignore events for signatures and attestations."
20+
default = false
21+
}

image-copy-ecr/main.go

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,16 @@ import (
3434
var amazonKeychain authn.Keychain = authn.NewKeychainFromHelper(ecrcreds.NewECRHelper(ecrcreds.WithLogger(log.Writer())))
3535

3636
var env = struct {
37-
APIEndpoint string `envconfig:"API_ENDPOINT" required:"true"`
38-
Issuer string `envconfig:"ISSUER_URL" required:"true"`
39-
GroupName string `envconfig:"GROUP_NAME" required:"true"`
40-
Group string `envconfig:"GROUP" required:"true"`
41-
Identity string `envconfig:"IDENTITY" required:"true"`
42-
Region string `envconfig:"REGION" required:"true"`
43-
DstRepo string `envconfig:"DST_REPO" required:"true"`
44-
FullDstRepo string `envconfig:"FULL_DST_REPO" required:"true"`
45-
ImmutableTags bool `envconfig:"IMMUTABLE_TAGS" required:"true"`
37+
APIEndpoint string `envconfig:"API_ENDPOINT" required:"true"`
38+
Issuer string `envconfig:"ISSUER_URL" required:"true"`
39+
GroupName string `envconfig:"GROUP_NAME" required:"true"`
40+
Group string `envconfig:"GROUP" required:"true"`
41+
Identity string `envconfig:"IDENTITY" required:"true"`
42+
Region string `envconfig:"REGION" required:"true"`
43+
DstRepo string `envconfig:"DST_REPO" required:"true"`
44+
FullDstRepo string `envconfig:"FULL_DST_REPO" required:"true"`
45+
ImmutableTags bool `envconfig:"IMMUTABLE_TAGS" required:"true"`
46+
IgnoreReferrers bool `envconfig:"IGNORE_REFERRERS" required:"true"`
4647
}{}
4748

4849
func init() {
@@ -85,6 +86,7 @@ func handler(ctx context.Context, levent events.LambdaFunctionURLRequest) (resp
8586
// - It's a registry push event.
8687
// - It's not a push error.
8788
// - It's a tag push.
89+
// - Optionally, it's not a signature or attestation.
8890
if levent.Headers["ce-type"] != registry.PushedEventType {
8991
log.Printf("event type is %q, skipping", levent.Headers["ce-type"])
9092
return "", nil
@@ -102,6 +104,10 @@ func handler(ctx context.Context, levent events.LambdaFunctionURLRequest) (resp
102104
log.Printf("event body is not a tag push, skipping: %q %q", body.Tag, body.Type)
103105
return "", nil
104106
}
107+
if env.IgnoreReferrers && strings.HasPrefix(body.Tag, "sha256-") {
108+
log.Printf("tag is a referrer; skipping: %q", body.Tag)
109+
return "", nil
110+
}
105111

106112
// Resolve the repository ID to the name
107113
repoName, err := resolveRepositoryName(ctx, body.RepoID)

image-copy-gcp/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ module "image-copy" {
3434
3535
# Location of the Artifact Registry repository, and the Cloud Run subscriber.
3636
# location = "us-central1" (default)
37+
38+
# Don't copy referrers like signatures and attestations
39+
# ignore_referrers = true
3740
}
3841
```
3942

image-copy-gcp/iac/main.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ resource "google_cloud_run_service" "image-copy" {
9191
name = "DST_REPO"
9292
value = "${var.location}-docker.pkg.dev/${var.project_id}/${google_artifact_registry_repository.dst-repo.name}"
9393
}
94+
env {
95+
name = "IGNORE_REFERRERS"
96+
value = var.ignore_referrers
97+
}
9498
}
9599
}
96100
}

image-copy-gcp/iac/variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,9 @@ variable "dst_repo" {
2828
type = string
2929
description = "The destination repo where images should be copied to."
3030
}
31+
32+
variable "ignore_referrers" {
33+
type = bool
34+
description = "Whether to ignore events for signatures and attestations."
35+
default = false
36+
}

image-copy-gcp/main.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"fmt"
1111
"log"
1212
"net/http"
13+
"strings"
1314

1415
"chainguard.dev/sdk/events"
1516
"chainguard.dev/sdk/events/receiver"
@@ -28,13 +29,14 @@ import (
2829
)
2930

3031
type envConfig struct {
31-
APIEndpoint string `envconfig:"API_ENDPOINT" required:"true"`
32-
Issuer string `envconfig:"ISSUER_URL" required:"true"`
33-
GroupName string `envconfig:"GROUP_NAME" required:"true"`
34-
Group string `envconfig:"GROUP" required:"true"`
35-
Identity string `envconfig:"IDENTITY" required:"true"`
36-
Port int `envconfig:"PORT" default:"8080" required:"true"`
37-
DstRepo string `envconfig:"DST_REPO" required:"true"` // Almost fully qualified at this point, just needs the final component.
32+
APIEndpoint string `envconfig:"API_ENDPOINT" required:"true"`
33+
Issuer string `envconfig:"ISSUER_URL" required:"true"`
34+
GroupName string `envconfig:"GROUP_NAME" required:"true"`
35+
Group string `envconfig:"GROUP" required:"true"`
36+
Identity string `envconfig:"IDENTITY" required:"true"`
37+
Port int `envconfig:"PORT" default:"8080" required:"true"`
38+
DstRepo string `envconfig:"DST_REPO" required:"true"` // Almost fully qualified at this point, just needs the final component.
39+
IgnoreReferrers bool `envconfig:"IGNORE_REFERRERS" required:"true"`
3840
}
3941

4042
var location, sa string
@@ -78,6 +80,7 @@ func main() {
7880
// Check that the event is one we care about:
7981
// - It's not a push error.
8082
// - It's a tag push.
83+
// - Optionally, it's not a signature or attestation.
8184
if body.Error != nil {
8285
log.Printf("event body has error, skipping: %+v", body.Error)
8386
return nil
@@ -86,6 +89,10 @@ func main() {
8689
log.Printf("event body is not a tag push, skipping: %q %q", body.Tag, body.Type)
8790
return nil
8891
}
92+
if env.IgnoreReferrers && strings.HasPrefix(body.Tag, "sha256-") {
93+
log.Printf("tag is a referrer; skipping: %q", body.Tag)
94+
return nil
95+
}
8996

9097
// Resolve the repository ID to the name
9198
repoName, err := resolveRepositoryName(ctx, body.RepoID)

0 commit comments

Comments
 (0)