Skip to content

Instantly share code, notes, and snippets.

@cablespaghetti
Last active May 24, 2024 06:14
Show Gist options
  • Save cablespaghetti/b5343b04dd5bdc68dcb62754986a34ed to your computer and use it in GitHub Desktop.
Save cablespaghetti/b5343b04dd5bdc68dcb62754986a34ed to your computer and use it in GitHub Desktop.
Automatic Updating Amazon ECR Credentials in Kubernetes
#!/bin/bash
# Get directory of script
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
if [[ $# -ne 1 ]]
then
echo "ERROR: This script expects the namespace name to be given as an argument"
echo "e.g. ./ecr-cred-updater.sh my-namespace"
exit 1
fi
# Steal the aws creds from the user's configuration for awscli
AWS_ACCESS_KEY_ID=`cat ~/.aws/credentials | grep aws_access_key_id | head -1 | cut -d'=' -f2 | sed 's/ //g'`
AWS_SECRET_ACCESS_KEY=`cat ~/.aws/credentials | grep aws_secret_access_key | head -1 | cut -d'=' -f2 | sed 's/ //g'`
if [ -z "$AWS_ACCESS_KEY_ID" ]
then
echo "ERROR: Failed to work out the AWS_ACCESS_KEY_ID"
exit 1
fi
if [ -z "$AWS_SECRET_ACCESS_KEY" ]
then
echo "ERROR: Failed to work out the AWS_SECRET_ACCESS_KEY"
exit 1
fi
# Fill in the variables in the yaml and run kubectl
cat $DIR/ecr-cred-updater.yaml | envsubst '$AWS_ACCESS_KEY_ID $AWS_SECRET_ACCESS_KEY' | kubectl apply -n ${1} -f -
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: ecr-cred-updater
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "create", "delete"]
- apiGroups: [""]
resources: ["serviceaccounts"]
verbs: ["get", "patch"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: ecr-cred-updater
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: ecr-cred-updater
subjects:
- kind: ServiceAccount
name: ecr-cred-updater
roleRef:
kind: Role
name: ecr-cred-updater
apiGroup: rbac.authorization.k8s.io
---
apiVersion: batch/v1
kind: Job
metadata:
name: ecr-cred-updater
spec:
backoffLimit: 4
template:
spec:
serviceAccountName: ecr-cred-updater
terminationGracePeriodSeconds: 0
restartPolicy: Never
containers:
- name: kubectl
image: xynova/aws-kubectl
command:
- "/bin/sh"
- "-c"
- |
AWS_ACCOUNT=YOUR_ACCOUNT_NUMBER_HERE
export AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
export AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
export AWS_REGION=us-east-1
DOCKER_REGISTRY_SERVER=https://${AWS_ACCOUNT}.dkr.ecr.${AWS_REGION}.amazonaws.com
DOCKER_USER=AWS
DOCKER_PASSWORD=`aws ecr get-login --region ${AWS_REGION} --registry-ids ${AWS_ACCOUNT} | cut -d' ' -f6`
kubectl delete secret aws-registry || true
kubectl create secret docker-registry aws-registry \
--docker-server=$DOCKER_REGISTRY_SERVER \
--docker-username=$DOCKER_USER \
--docker-password=$DOCKER_PASSWORD \
--docker-email=no@email.local
kubectl patch serviceaccount default -p '{"imagePullSecrets":[{"name":"aws-registry"}]}'
---
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: ecr-cred-updater
spec:
schedule: "* */8 * * *"
successfulJobsHistoryLimit: 1
failedJobsHistoryLimit: 1
jobTemplate:
spec:
backoffLimit: 4
template:
spec:
serviceAccountName: ecr-cred-updater
terminationGracePeriodSeconds: 0
restartPolicy: Never
containers:
- name: kubectl
image: xynova/aws-kubectl
command:
- "/bin/sh"
- "-c"
- |
AWS_ACCOUNT=YOUR_ACCOUNT_NUMBER_HERE
export AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
export AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
export AWS_REGION=us-east-1
DOCKER_REGISTRY_SERVER=https://${AWS_ACCOUNT}.dkr.ecr.${AWS_REGION}.amazonaws.com
DOCKER_USER=AWS
DOCKER_PASSWORD=`aws ecr get-login --region ${AWS_REGION} --registry-ids ${AWS_ACCOUNT} | cut -d' ' -f6`
kubectl delete secret aws-registry || true
kubectl create secret docker-registry aws-registry \
--docker-server=$DOCKER_REGISTRY_SERVER \
--docker-username=$DOCKER_USER \
--docker-password=$DOCKER_PASSWORD \
--docker-email=no@email.local
kubectl patch serviceaccount default -p '{"imagePullSecrets":[{"name":"aws-registry"}]}'
@SteveOnorato
Copy link

Thanks for sharing this! I needed to change lines 14 and 15 of ecr-cred-updater.sh to start with "export " to get it to work. (Otherwise envsubst just replaces AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY with nothing, since I don't have these variables defined outside of the script.)

@chriswiggins
Copy link

Thanks so much for this! ECR makes all these things a bit of a nightmare, however I feel that the extra pain is worth it for how cheap it is 😆

@ObviousDWest
Copy link

ObviousDWest commented Dec 17, 2018

I would suggest you store the AWS access keys in k8s secrets as well, instead of in the jobs (where they can be looked at using kuebctl describe). The secrets can be easily read using envFrom: and secretRef: and exposed as environment variable values.

@dimmg
Copy link

dimmg commented Jan 31, 2019

Thank you very much for sharing this! It worked flawlessly. ❤️
However instead of duplicating the manifest for Job, I've left only the one for CronJob and then triggered it manually.

cat ecr-cred-updater.yml < envsubst '$AWS_ACCESS_KEY_ID $AWS_SECRET_ACCESS_KEY' > kubectl apply -f - && \
kubect create job --from=cronjob/ecr-cred-updater ecr-cred-updater

@saurfangg
Copy link

I believe the cronjob's timing is off. The way you have it right now it would run at every minute past every 8th hour which means it'll run every minute at hours 8, 16, and 24(00). I think what you want instead is 0 */8 * * * which means it'll run at minute 0 past every 8th hour.

@DavidPerezIngeniero
Copy link

DavidPerezIngeniero commented Aug 30, 2022

I get AWS_ACCOUNT with:

aws sts get-caller-identity --query Account --output text:latest

The ecr-cred-updater.sh script could provide this value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment