Skip to content

Commit 7b91c23

Browse files
author
Geoff Flarity
committed
initial version
1 parent f2197b1 commit 7b91c23

28 files changed

+2348
-2
lines changed

.github/workflows/pr.yaml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: Build & Test
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- '**' # Triggers on all branches
7+
8+
jobs:
9+
build:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- name: Checkout code
14+
uses: actions/checkout@v2
15+
16+
- name: Set up QEMU
17+
uses: docker/setup-qemu-action@v2
18+
19+
- name: Set up Docker Buildx
20+
uses: docker/setup-buildx-action@v2
21+
22+
- name: Cache Docker layers
23+
uses: actions/cache@v2
24+
with:
25+
path: /tmp/.buildx-cache
26+
key: ${{ runner.os }}-buildx-${{ github.sha }}
27+
restore-keys: |
28+
${{ runner.os }}-buildx-
29+
30+
- name: Build Docker image
31+
uses: docker/build-push-action@v4
32+
with:
33+
context: .
34+
push: false
35+
tags: user/repo:latest
36+
platforms: linux/amd64,linux/arm64
37+
38+
test:
39+
runs-on: ubuntu-latest
40+
needs: build
41+
42+
steps:
43+
- name: Checkout code
44+
uses: actions/checkout@v2
45+
46+
- name: Set up Go
47+
uses: actions/setup-go@v2
48+
with:
49+
go-version: '^1.22'
50+
51+
- name: Run Go tests
52+
run: |
53+
go test ./...

.github/workflows/release.yaml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: Build and Push Docker Image
2+
3+
on:
4+
release:
5+
types: [published] # Triggers on release tagging
6+
7+
jobs:
8+
build:
9+
runs-on: ubuntu-latest
10+
# This job runs only if the tag_name starts with 'v', this avoids conflicts with helm
11+
# chart releases which have simple-sidecar-helm-chart-{{ .Version }} as the release name
12+
if: startsWith(github.event.release.tag_name, 'v')
13+
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@v2
17+
18+
- name: Set up QEMU
19+
uses: docker/setup-qemu-action@v2
20+
21+
- name: Set up Docker Buildx
22+
uses: docker/setup-buildx-action@v2
23+
24+
- name: Log in to GitHub Container Registry
25+
uses: docker/login-action@v2
26+
with:
27+
registry: ghcr.io
28+
username: ${{ github.actor }}
29+
password: ${{ secrets.GITHUB_TOKEN }}
30+
31+
- name: Cache Docker layers
32+
uses: actions/cache@v2
33+
with:
34+
path: /tmp/.buildx-cache
35+
key: ${{ runner.os }}-buildx-${{ github.sha }}
36+
restore-keys: |
37+
${{ runner.os }}-buildx-
38+
39+
- name: Convert repository name to lowercase
40+
id: lowercase_repo
41+
run: echo "::set-output name=lower_repo::$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')"
42+
43+
- name: Build and push Docker image
44+
uses: docker/build-push-action@v4
45+
with:
46+
context: .
47+
push: true
48+
tags: |
49+
ghcr.io/${{ steps.lowercase_repo.outputs.lower_repo }}:latest
50+
ghcr.io/${{ steps.lowercase_repo.outputs.lower_repo }}:${{ github.event.release.tag_name }}
51+
platforms: linux/amd64,linux/arm64
52+
53+
- name: Logout from GitHub Container Registry
54+
run: docker logout ghcr.io
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Release Helm Chart
2+
3+
on:
4+
# Triggers the workflow when Chart.yaml is updated on the main branch
5+
push:
6+
branches:
7+
- main
8+
paths:
9+
- "charts/ecr-anywhere/Chart.yaml"
10+
11+
# Allows you to manually trigger the workflow from GitHub's UI
12+
workflow_dispatch:
13+
14+
jobs:
15+
release_helm_chart:
16+
# Permissions required for the job. In this case, write access to the repository contents is needed.
17+
permissions:
18+
contents: write
19+
# Specifies the type of runner that the job will run on. Here, it's the latest version of Ubuntu.
20+
runs-on: ubuntu-latest
21+
steps:
22+
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
23+
- name: Checkout
24+
uses: actions/checkout@v4
25+
with:
26+
fetch-depth: 0
27+
28+
# Configures Git with the GitHub actor's name and email to make commits and tags
29+
- name: Configure Git
30+
run: |
31+
git config user.name "$GITHUB_ACTOR"
32+
git config user.email "[email protected]"
33+
34+
# Runs the chart-releaser action which turns your GitHub project into a self-hosted Helm
35+
# chart repo. It does this – during every push to main – by checking each chart in your
36+
# project, and whenever there's a new chart version, creates a corresponding GitHub release
37+
# named for the chart version, adds Helm chart artifacts to the release, and creates or
38+
# updates an index.yaml file with metadata about those releases,
39+
# which is then hosted on GitHub Pages
40+
- name: Run chart-releaser
41+
uses: helm/[email protected]
42+
env:
43+
# GitHub token used by the chart-releaser action
44+
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
45+
# Customizes the name of the chart release
46+
CR_RELEASE_NAME_TEMPLATE: "ecr-anywhere-helm-chart-{{ .Version }}"

Dockerfile

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Build the sidecar-injector binary
2+
FROM golang:1.22 as builder
3+
4+
WORKDIR /workspace
5+
# Copy the Go Modules manifests
6+
COPY go.mod go.mod
7+
COPY go.sum go.sum
8+
9+
# cache deps before building and copying source so that we don't need to re-download as much
10+
# and so that source changes don't invalidate our downloaded layer
11+
RUN go mod download
12+
13+
# Copy the go source
14+
COPY cmd/ cmd/
15+
COPY pkg/ pkg/
16+
17+
# Build
18+
RUN CGO_ENABLED=0 GOOS=linux GOARCH=${BUILDPLATFORM} go build -a -o ecr-anywhere-webhook ./cmd/webhook
19+
RUN CGO_ENABLED=0 GOOS=linux GOARCH=${BUILDPLATFORM} go build -a -o ecr-anywhere-refresher ./cmd/refresher
20+
21+
FROM alpine:latest
22+
23+
24+
WORKDIR /
25+
26+
# install binaries
27+
COPY --from=builder /workspace/ecr-anywhere-webhook .
28+
COPY --from=builder /workspace/ecr-anywhere-refresher .
29+
30+
USER 65532:65532
31+
32+
# webhook is the default entrypoint
33+
ENTRYPOINT ["/ecr-anywhere-webhook"]

README.md

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,39 @@
1-
# ecr-anywhere
2-
Pull from private ECR repos... anywhere
1+
# ECR Anywhere
2+
3+
## Description
4+
ECR Anywhere makes it easy use images hosted in private ECR repositories on any Kubernetes cluster, esspecially those hosted outside of AWS. It works via two components:
5+
6+
1) A Mutating Webhook that intercepts create/update verbs on labeled Kubernetes Secrets, injecting fresh ECR credentials which expire in 12 hours.
7+
2) A CronJob that periodically checks the specially labeled Kubernetes Secrets to see if they need to be refreshed. If they do, an annotation is updated, synchronously triggering a credential refresh by the Mutating Webhook.
8+
9+
The benefits of this approach are simplicity in implimentation and operations (monitoring/alerting).
10+
11+
From an operational perspective:
12+
13+
1) A properly labeled secret can not be created or updated unless ecr-anywhere is working as expected. There's immediate feedback during operational setup/maintenance.
14+
2) Any automation issues refreshing credentials are known immediately to operators with basic alerting on CronJob failures/pod failures.
15+
16+
17+
## Quick Start
18+
19+
Setup your values.yaml for the helm chart. Specifically include the AWS credentials using the standard AWS SDK environment variables. The easiest way to issue long lived AWS credentials, the most secure way is to use [AWS OIDC](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html) with [Spiffe](https://spiffe.io/). The best reference for AWS SDK environment variables seems to be in the [AWS CLI documentation](https://docs.aws.amazon.com/cli/v1/userguide/cli-configure-envvars.html).
20+
21+
```yaml
22+
23+
pod:
24+
container:
25+
env:
26+
- name: AWS_ACCESS_KEY_ID
27+
value: "EXAMPLE"
28+
- name: AWS_SECRET_ACCESS_KEY
29+
value: "EXAMPLE"
30+
- name: AWS_REGION
31+
#important, this must match the region in the image name
32+
value: "us-east-1"
33+
```
34+
35+
36+
```sh
37+
helm install ecr-anywhere ./charts/ecr-anywhere -f values.yaml
38+
```
39+

charts/ecr-anywhere/.helmignore

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Patterns to ignore when building packages.
2+
# This supports shell glob matching, relative path matching, and
3+
# negation (prefixed with !). Only one pattern per line.
4+
.DS_Store
5+
# Common VCS dirs
6+
.git/
7+
.gitignore
8+
.bzr/
9+
.bzrignore
10+
.hg/
11+
.hgignore
12+
.svn/
13+
# Common backup files
14+
*.swp
15+
*.bak
16+
*.tmp
17+
*.orig
18+
*~
19+
# Various IDEs
20+
.project
21+
.idea/
22+
*.tmproj
23+
.vscode/

charts/ecr-anywhere/Chart.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
apiVersion: v2
2+
name: ecr-anywhere
3+
description: A Helm chart for Kubernetes
4+
5+
# A chart can be either an 'application' or a 'library' chart.
6+
#
7+
# Application charts are a collection of templates that can be packaged into versioned archives
8+
# to be deployed.
9+
#
10+
# Library charts provide useful utilities or functions for the chart developer. They're included as
11+
# a dependency of application charts to inject those utilities and functions into the rendering
12+
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
13+
type: application
14+
15+
# This is the chart version. This version number should be incremented each time you make changes
16+
# to the chart and its templates, including the app version.
17+
# Versions are expected to follow Semantic Versioning (https://semver.org/)
18+
version: 1.0.0
19+
20+
# This is the version number of the application being deployed. This version number should be
21+
# incremented each time you make changes to the application. Versions are not expected to
22+
# follow Semantic Versioning. They should reflect the version the application is using.
23+
# It is recommended to use it with quotes.
24+
appVersion: "1.0.0"

charts/ecr-anywhere/templates/NOTES.txt

Whitespace-only changes.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
{{/*
2+
Expand the name of the chart.
3+
*/}}
4+
{{- define "simple-sidecar.name" -}}
5+
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
6+
{{- end }}
7+
8+
{{/*
9+
Create a default fully qualified app name.
10+
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
11+
If release name contains chart name it will be used as a full name.
12+
*/}}
13+
{{- define "simple-sidecar.fullname" -}}
14+
{{- if .Values.fullnameOverride }}
15+
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
16+
{{- else }}
17+
{{- $name := default .Chart.Name .Values.nameOverride }}
18+
{{- if contains $name .Release.Name }}
19+
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
20+
{{- else }}
21+
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
22+
{{- end }}
23+
{{- end }}
24+
{{- end }}
25+
26+
{{/*
27+
Create chart name and version as used by the chart label.
28+
*/}}
29+
{{- define "simple-sidecar.chart" -}}
30+
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
31+
{{- end }}
32+
33+
{{/*
34+
Common labels
35+
*/}}
36+
{{- define "simple-sidecar.labels" -}}
37+
helm.sh/chart: {{ include "simple-sidecar.chart" . }}
38+
{{ include "simple-sidecar.selectorLabels" . }}
39+
{{- if .Chart.AppVersion }}
40+
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
41+
{{- end }}
42+
app.kubernetes.io/managed-by: {{ .Release.Service }}
43+
{{- end }}
44+
45+
{{/*
46+
Selector labels
47+
*/}}
48+
{{- define "simple-sidecar.selectorLabels" -}}
49+
app.kubernetes.io/name: {{ include "simple-sidecar.name" . }}
50+
app.kubernetes.io/instance: {{ .Release.Name }}
51+
{{- end }}
52+
53+
{{/*
54+
Create the name of the service account to use
55+
*/}}
56+
{{- define "simple-sidecar.serviceAccountName" -}}
57+
{{- if .Values.serviceAccount.create }}
58+
{{- default (include "simple-sidecar.fullname" .) .Values.serviceAccount.name }}
59+
{{- else }}
60+
{{- default "default" .Values.serviceAccount.name }}
61+
{{- end }}
62+
{{- end }}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
kind: ClusterRole
2+
apiVersion: rbac.authorization.k8s.io/v1
3+
metadata:
4+
name: {{ .Values.name }}
5+
labels:
6+
app: {{ .Values.name }}
7+
rules:
8+
- apiGroups: [""]
9+
resources: ["secrets"]
10+
verbs: ["get", "list", "update"]
11+
- apiGroups: [""]
12+
resources: ["namespaces"]
13+
verbs: ["get", "list"]

0 commit comments

Comments
 (0)