Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add custom tags to created ECR repositories #191

Merged
merged 6 commits into from
Dec 16, 2022
Merged
Show file tree
Hide file tree
Changes from 5 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
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
16 changes: 16 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,19 @@ The AWS Account ID and Region is primarily used to construct the ECR domain `[AC
accountId: 123456789
region: ap-southeast-2
```

### RepositoryTags
darkweaver87 marked this conversation as resolved.
Show resolved Hide resolved

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
darkweaver87 marked this conversation as resolved.
Show resolved Hide resolved
```
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