Skip to content

Commit

Permalink
feat: add custom tags to created ECR repositories (estahn#191)
Browse files Browse the repository at this point in the history
This PR adds the ability to configure custom tags for created
repositories.

Co-authored-by: Enrico Stahn <enrico.stahn@gmail.com>
darkweaver87 and estahn authored Dec 16, 2022

Partially verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
We cannot verify signatures from co-authors, and some of the co-authors attributed to this commit require their commits to be signed.
1 parent cc534c1 commit 9849df2
Showing 6 changed files with 130 additions and 30 deletions.
7 changes: 4 additions & 3 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -25,12 +25,11 @@ import (
"context"
"fmt"
"net/http"
"os"
"os/signal"
"syscall"
"time"

"os"

"github.com/estahn/k8s-image-swapper/pkg/config"
"github.com/estahn/k8s-image-swapper/pkg/registry"
"github.com/estahn/k8s-image-swapper/pkg/secrets"
@@ -64,12 +63,14 @@ A mutating webhook for Kubernetes, pointing the images to a new location.`,
//metricsRec := metrics.NewPrometheus(promReg)
log.Trace().Interface("config", cfg).Msg("config")

rClient, err := registry.NewECRClient(cfg.Target.AWS.Region, cfg.Target.AWS.EcrDomain(), cfg.Target.AWS.AccountID, cfg.Target.AWS.Role, cfg.Target.AWS.AccessPolicy, cfg.Target.AWS.LifecyclePolicy)
rClient, err := registry.NewECRClient(cfg.Target.AWS.Region, cfg.Target.AWS.EcrDomain(), cfg.Target.AWS.AccountID, cfg.Target.AWS.Role, cfg.Target.AWS.ECROptions.AccessPolicy, cfg.Target.AWS.ECROptions.LifecyclePolicy)
if err != nil {
log.Err(err).Msg("error connecting to registry client")
os.Exit(1)
}

rClient.SetRepositoryTags(cfg.Target.AWS.ECROptions.Tags)

imageSwapPolicy, err := types.ParseImageSwapPolicy(cfg.ImageSwapPolicy)
if err != nil {
log.Err(err)
18 changes: 18 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
@@ -138,3 +138,21 @@ The AWS Account ID and Region is primarily used to construct the ECR domain `[AC
accountId: 123456789
region: ap-southeast-2
```

### ECR Options

#### Tags

This provides a way to add custom tags to newly created repositories. This may be useful while looking at AWS costs.
It's a slice of `Key` and `Value`.

!!! example
```yaml
target:
type: aws
aws:
ecrOptions:
tags:
- name: cluster
value: myCluster
```
32 changes: 27 additions & 5 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
@@ -54,11 +54,33 @@ type Target struct {
}

type AWS struct {
AccountID string `yaml:"accountId"`
Region string `yaml:"region"`
Role string `yaml:"role"`
AccessPolicy string `yaml:"accessPolicy"`
LifecyclePolicy string `yaml:"lifecyclePolicy"`
AccountID string `yaml:"accountId"`
Region string `yaml:"region"`
Role string `yaml:"role"`
ECROptions ECROptions `yaml:"ecrOptions"`
}

type ECROptions struct {
AccessPolicy string `yaml:"accessPolicy"`
LifecyclePolicy string `yaml:"lifecyclePolicy"`
Tags []Tag `yaml:"tags"`
ImageTagMutability string `yaml:"imageTagMutability"`
ImageScanningConfiguration ImageScanningConfiguration `yaml:"imageScanningConfiguration"`
EncryptionConfiguration EncryptionConfiguration `yaml:"encryptionConfiguration"`
}

type Tag struct {
Key string `yaml:"key"`
Value string `yaml:"value"`
}

type ImageScanningConfiguration struct {
ImageScanOnPush bool `yaml:"imageScanOnPush"`
}

type EncryptionConfiguration struct {
EncryptionType string `yaml:"encryptionType"`
KmsKey string `yaml:"kmsKey"`
}

func (a *AWS) EcrDomain() string {
38 changes: 38 additions & 0 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
@@ -37,6 +37,44 @@ source:
},
},
},
{
name: "should render tags config",
cfg: `
target:
type: aws
aws:
accountId: 123456789
region: ap-southeast-2
role: arn:aws:iam::123456789012:role/roleName
ecrOptions:
tags:
- key: CreatedBy
value: k8s-image-swapper
- key: A
value: B
`,
expCfg: Config{
Target: Target{
AWS: AWS{
AccountID: "123456789",
Region: "ap-southeast-2",
Role: "arn:aws:iam::123456789012:role/roleName",
ECROptions: ECROptions{
Tags: []Tag{
{
Key: "CreatedBy",
Value: "k8s-image-swapper",
},
{
Key: "A",
Value: "B",
},
},
},
},
},
},
},
}

for _, test := range tests {
25 changes: 19 additions & 6 deletions pkg/registry/ecr.go
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ import (
"github.com/aws/aws-sdk-go/service/ecr"
"github.com/aws/aws-sdk-go/service/ecr/ecriface"
"github.com/dgraph-io/ristretto"
"github.com/estahn/k8s-image-swapper/pkg/config"
"github.com/go-co-op/gocron"
"github.com/rs/zerolog/log"
)
@@ -28,6 +29,7 @@ type ECRClient struct {
targetAccount string
accessPolicy string
lifecyclePolicy string
tags []config.Tag
}

func (e *ECRClient) Credentials() string {
@@ -46,12 +48,7 @@ func (e *ECRClient) CreateRepository(name string) error {
},
ImageTagMutability: aws.String(ecr.ImageTagMutabilityMutable),
RegistryId: &e.targetAccount,
Tags: []*ecr.Tag{
{
Key: aws.String("CreatedBy"),
Value: aws.String("k8s-image-swapper"),
},
},
Tags: e.buildEcrTags(),
})

if err != nil {
@@ -102,6 +99,21 @@ func (e *ECRClient) CreateRepository(name string) error {
return nil
}

func (e *ECRClient) SetRepositoryTags(tags []config.Tag) {
e.tags = tags
}

func (e *ECRClient) buildEcrTags() []*ecr.Tag {
ecrTags := []*ecr.Tag{}

for _, t := range e.tags {
tag := ecr.Tag{Key: &t.Key, Value: &t.Value}
ecrTags = append(ecrTags, &tag)
}

return ecrTags
}

func (e *ECRClient) RepositoryExists() bool {
panic("implement me")
}
@@ -249,6 +261,7 @@ func NewMockECRClient(ecrClient ecriface.ECRAPI, region string, ecrDomain string
scheduler: nil,
targetAccount: targetAccount,
authToken: []byte("mock-ecr-client-fake-auth-token"),
tags: []config.Tag{{Key: "CreatedBy", Value: "k8s-image-swapper"}},
}

return client, nil
40 changes: 24 additions & 16 deletions pkg/webhook/image_swapper_test.go
Original file line number Diff line number Diff line change
@@ -246,10 +246,12 @@ func TestImageSwapper_Mutate(t *testing.T) {
ImageTagMutability: aws.String("MUTABLE"),
RepositoryName: aws.String("docker.io/library/init-container"),
RegistryId: aws.String("123456789"),
Tags: []*ecr.Tag{{
Key: aws.String("CreatedBy"),
Value: aws.String("k8s-image-swapper"),
}},
Tags: []*ecr.Tag{
{
Key: aws.String("CreatedBy"),
Value: aws.String("k8s-image-swapper"),
},
},
}).Return(mock.Anything)
ecrClient.On(
"CreateRepository",
@@ -260,10 +262,12 @@ func TestImageSwapper_Mutate(t *testing.T) {
ImageTagMutability: aws.String("MUTABLE"),
RepositoryName: aws.String("docker.io/library/nginx"),
RegistryId: aws.String("123456789"),
Tags: []*ecr.Tag{{
Key: aws.String("CreatedBy"),
Value: aws.String("k8s-image-swapper"),
}},
Tags: []*ecr.Tag{
{
Key: aws.String("CreatedBy"),
Value: aws.String("k8s-image-swapper"),
},
},
}).Return(mock.Anything)
ecrClient.On(
"CreateRepository",
@@ -274,10 +278,12 @@ func TestImageSwapper_Mutate(t *testing.T) {
ImageTagMutability: aws.String("MUTABLE"),
RepositoryName: aws.String("k8s.gcr.io/ingress-nginx/controller"),
RegistryId: aws.String("123456789"),
Tags: []*ecr.Tag{{
Key: aws.String("CreatedBy"),
Value: aws.String("k8s-image-swapper"),
}},
Tags: []*ecr.Tag{
{
Key: aws.String("CreatedBy"),
Value: aws.String("k8s-image-swapper"),
},
},
}).Return(mock.Anything)

registryClient, _ := registry.NewMockECRClient(ecrClient, "ap-southeast-2", "123456789.dkr.ecr.ap-southeast-2.amazonaws.com", "123456789", "arn:aws:iam::123456789:role/fakerole")
@@ -328,10 +334,12 @@ func TestImageSwapper_MutateWithImagePullSecrets(t *testing.T) {
ImageTagMutability: aws.String("MUTABLE"),
RegistryId: aws.String("123456789"),
RepositoryName: aws.String("docker.io/library/nginx"),
Tags: []*ecr.Tag{{
Key: aws.String("CreatedBy"),
Value: aws.String("k8s-image-swapper"),
}},
Tags: []*ecr.Tag{
{
Key: aws.String("CreatedBy"),
Value: aws.String("k8s-image-swapper"),
},
},
}).Return(mock.Anything)

registryClient, _ := registry.NewMockECRClient(ecrClient, "ap-southeast-2", "123456789.dkr.ecr.ap-southeast-2.amazonaws.com", "123456789", "arn:aws:iam::123456789:role/fakerole")

0 comments on commit 9849df2

Please sign in to comment.