diff --git a/charts/renew-ecr-k8s-creds/Chart.yaml b/charts/renew-ecr-k8s-creds/Chart.yaml new file mode 100644 index 00000000..52080155 --- /dev/null +++ b/charts/renew-ecr-k8s-creds/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +name: renew-ecr-k8s-creds +description: A Helm chart for updating AWS ECR secrets in Kubernetes +version: 0.1.0 + diff --git a/charts/renew-ecr-k8s-creds/README.md b/charts/renew-ecr-k8s-creds/README.md new file mode 100644 index 00000000..6ee93055 --- /dev/null +++ b/charts/renew-ecr-k8s-creds/README.md @@ -0,0 +1,45 @@ +# renew-ecr-k8s-cred + +A Helm chart for renewing AWS ECR credentials and updating them in a Kubernetes secret. + +## Introduction + +This Helm chart creates a CronJob in Kubernetes to periodically renew AWS Elastic Container Registry (ECR) credentials and update them in a Kubernetes secret. This is useful for ensuring that your ECR credentials are always up to date, especially in environments where long-running workloads need continuous access to private ECR repositories. + +## Prerequisites + +- Kubernetes 1.16+ +- Helm 3.0+ +- An AWS account with permissions to assume the specified role and access ECR +- The AWS CLI installed in the container image + +## Installation + +### Add the Helm Repository + +```sh +# AWS credentials configuration +aws: + accessKey: "your-aws-access-key" # AWS Access Key ID of IAM role for authentication + secretKey: "your-aws-secret-key" # AWS Secret Access Key of IAM role for authentication + region: "your-aws-region" # AWS region where your resources are located + roleArn: "your-aws-role-arn" # ARN of the AWS role to assume for getting temporary credentials + sessionName: "your-session-name" # Session name for the assumed role + +# Kubernetes configuration +kubernetes: + secretName: "your-secret-name" # Name of the Kubernetes secret to create or update with ECR credentials + +# ECR (Elastic Container Registry) configuration +ecr: + account: "your-aws-account" # AWS account ID where your ECR is located + region: "your-ecr-region" # AWS region of your ECR + +# CronJob configuration +cronjob: + schedule: "0 */12 * * *" # Cron schedule for the job to run (every 12 hours) + +# ServiceAccount configuration +serviceAccount: + name: "renew-ecr-k8s-creds-sa" # Name of the ServiceAccount to create or use +``` diff --git a/charts/renew-ecr-k8s-creds/templates/job.yaml b/charts/renew-ecr-k8s-creds/templates/job.yaml new file mode 100644 index 00000000..e19aab3c --- /dev/null +++ b/charts/renew-ecr-k8s-creds/templates/job.yaml @@ -0,0 +1,24 @@ +apiVersion: batch/v1 +kind: CronJob +metadata: + name: renew-ecr-k8s-creds + namespace: {{ .Release.Namespace }} +spec: + schedule: "{{ .Values.cronjob.schedule }}" + jobTemplate: + spec: + template: + spec: + serviceAccountName: {{ .Values.serviceAccount.name }} + containers: + - name: renew-ecr-k8s-creds + image: amazon/aws-cli:2.13.15 + command: ["/bin/bash", "/scripts/update-secret.sh"] + volumeMounts: + - name: script + mountPath: /scripts + restartPolicy: Never + volumes: + - name: script + configMap: + name: renew-ecr-k8s-creds-script diff --git a/charts/renew-ecr-k8s-creds/templates/role.yaml b/charts/renew-ecr-k8s-creds/templates/role.yaml new file mode 100644 index 00000000..0391634c --- /dev/null +++ b/charts/renew-ecr-k8s-creds/templates/role.yaml @@ -0,0 +1,9 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + namespace: {{ .Release.Namespace }} + name: renew-ecr-k8s-creds-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "create", "patch"] diff --git a/charts/renew-ecr-k8s-creds/templates/rolebinding.yaml b/charts/renew-ecr-k8s-creds/templates/rolebinding.yaml new file mode 100644 index 00000000..71740f0a --- /dev/null +++ b/charts/renew-ecr-k8s-creds/templates/rolebinding.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: renew-ecr-k8s-creds-rolebinding + namespace: {{ .Release.Namespace }} +subjects: +- kind: ServiceAccount + name: {{ .Values.serviceAccount.name }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: Role + name: renew-ecr-k8s-creds-role + apiGroup: rbac.authorization.k8s.io diff --git a/charts/renew-ecr-k8s-creds/templates/script-configmap.yaml b/charts/renew-ecr-k8s-creds/templates/script-configmap.yaml new file mode 100644 index 00000000..49aada5c --- /dev/null +++ b/charts/renew-ecr-k8s-creds/templates/script-configmap.yaml @@ -0,0 +1,56 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: renew-ecr-k8s-creds-script + namespace: {{ .Release.Namespace }} +data: + update-secret.sh: | + #!/bin/bash + + # Install kubectl + echo "Installing kubectl..." + curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl + + # Install jq + echo "Installing jq..." + yum install -y jq + + secret_exists() { + kubectl get secret "{{ .Values.kubernetes.secretName }}" --namespace="{{ .Release.Namespace }}" &> /dev/null + return $? + } + + echo "Aws Configure..." + aws configure set aws_access_key_id "{{ .Values.aws.accessKey }}" + aws configure set aws_secret_access_key "{{ .Values.aws.secretKey }}" + aws configure set region "{{ .Values.aws.region }}" + aws configure set output "json" + + echo "Assuming a Role..." + ROLE_OUTPUT=$(aws sts assume-role --role-arn "{{ .Values.aws.roleArn }}" --role-session-name "{{ .Values.aws.sessionName }}") + + echo "Now fetching the access_key, secret_key & session_token..." + AWS_ACCESS_KEY_ID=$(echo "$ROLE_OUTPUT" | jq -r '.Credentials.AccessKeyId') + AWS_SECRET_ACCESS_KEY=$(echo "$ROLE_OUTPUT" | jq -r '.Credentials.SecretAccessKey') + AWS_SESSION_TOKEN=$(echo "$ROLE_OUTPUT" | jq -r '.Credentials.SessionToken') + + export AWS_ACCESS_KEY_ID + export AWS_SECRET_ACCESS_KEY + export AWS_SESSION_TOKEN + + if secret_exists; then + echo "Secret already exists, patching the secret..." + kubectl patch secret "{{ .Values.kubernetes.secretName }}" --namespace="{{ .Release.Namespace }}" --type='json' -p='[{"op": "replace", "path": "/data/.dockerconfigjson", "value":"'$(echo -n "{\"auths\":{\"{{ .Values.ecr.account }}.dkr.ecr.{{ .Values.ecr.region }}.amazonaws.com\":{\"username\":\"AWS\",\"password\":\"$(aws ecr get-login-password)\"}}}" | base64 | tr -d '\n')'"}]' + else + echo "Secret does not exist, creating the secret..." + kubectl create secret docker-registry "{{ .Values.kubernetes.secretName }}" \ + --docker-server="{{ .Values.ecr.account }}.dkr.ecr.{{ .Values.ecr.region }}.amazonaws.com" \ + --docker-username=AWS \ + --docker-password="$(aws ecr get-login-password)" \ + --namespace="{{ .Release.Namespace }}" + fi + + unset AWS_ACCESS_KEY_ID + unset AWS_SECRET_ACCESS_KEY + unset AWS_SESSION_TOKEN diff --git a/charts/renew-ecr-k8s-creds/templates/serviceaccount.yaml b/charts/renew-ecr-k8s-creds/templates/serviceaccount.yaml new file mode 100644 index 00000000..8645420c --- /dev/null +++ b/charts/renew-ecr-k8s-creds/templates/serviceaccount.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.serviceAccount.name }} + namespace: {{ .Release.Namespace }} + diff --git a/charts/renew-ecr-k8s-creds/values.yaml b/charts/renew-ecr-k8s-creds/values.yaml new file mode 100644 index 00000000..341c61f0 --- /dev/null +++ b/charts/renew-ecr-k8s-creds/values.yaml @@ -0,0 +1,24 @@ +# AWS credentials configuration +aws: + accessKey: "your-aws-access-key" # AWS Access Key ID of IAM role for authentication + secretKey: "your-aws-secret-key" # AWS Secret Access Key of IAM role for authentication + region: "your-aws-region" # AWS region where your resources are located + roleArn: "your-aws-role-arn" # ARN of the AWS role to assume for getting temporary credentials + sessionName: "your-session-name" # Session name for the assumed role + +# Kubernetes configuration +kubernetes: + secretName: "your-secret-name" # Name of the Kubernetes secret to create or update with ECR credentials + +# ECR (Elastic Container Registry) configuration +ecr: + account: "your-aws-account" # AWS account ID where your ECR is located + region: "your-ecr-region" # AWS region of your ECR + +# CronJob configuration +cronjob: + schedule: "0 */12 * * *" # Cron schedule for the job to run (every 12 hours) + +# ServiceAccount configuration +serviceAccount: + name: "renew-ecr-k8s-creds-sa" # Name of the ServiceAccount to create or use