Skip to content

Commit

Permalink
feat: add custom tags to created ECR repositories (#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>
  • Loading branch information
darkweaver87 and estahn committed Dec 16, 2022
1 parent cc534c1 commit 9849df2
Show file tree
Hide file tree
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
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
Expand Down
18 changes: 18 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Up @@ -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 {
Expand Down
38 changes: 38 additions & 0 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
25 changes: 19 additions & 6 deletions pkg/registry/ecr.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand All @@ -28,6 +29,7 @@ type ECRClient struct {
targetAccount string
accessPolicy string
lifecyclePolicy string
tags []config.Tag
}

func (e *ECRClient) Credentials() string {
Expand All @@ -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 {
Expand Down Expand Up @@ -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")
}
Expand Down Expand Up @@ -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
Expand Down
40 changes: 24 additions & 16 deletions pkg/webhook/image_swapper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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")
Expand Down Expand Up @@ -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")
Expand Down

0 comments on commit 9849df2

Please sign in to comment.