diff --git a/.github/ci/ct.yaml b/.github/ci/ct.yaml new file mode 100644 index 000000000..e5206d409 --- /dev/null +++ b/.github/ci/ct.yaml @@ -0,0 +1,5 @@ +chart-dirs: + - deploy/charts +helm-extra-args: "--timeout=5m" +check-version-increment: false +target-branch: main diff --git a/.github/workflows/all.yml b/.github/workflows/all.yml index c09d531ca..67bb8cd97 100644 --- a/.github/workflows/all.yml +++ b/.github/workflows/all.yml @@ -7,8 +7,12 @@ on: - '*/*' # matches every branch containing a single '/' - '**' # matches every branch - '!main' # excludes main + paths-ignore: + - 'deploy/**' pull_request: branches: [ '!main' ] + paths-ignore: + - 'deploy/**' env: KUBEBUILDER_VERSION: 2.3.1 diff --git a/.github/workflows/helm.yml b/.github/workflows/helm.yml new file mode 100644 index 000000000..d50b78414 --- /dev/null +++ b/.github/workflows/helm.yml @@ -0,0 +1,55 @@ +name: Helm + +on: + push: + tags: + - '*' + paths: + - 'deploy/charts/**' + pull_request: + branches: main + paths: + - 'deploy/charts/**' + +jobs: + lint-and-test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Generate chart + run: | + make crds-to-chart + + - name: Set up Helm + uses: azure/setup-helm@v1 + with: + version: v3.4.2 + + - uses: actions/setup-python@v2 + with: + python-version: 3.7 + + - name: Set up chart-testing + uses: helm/chart-testing-action@v2.0.1 + + - name: Run chart-testing (list-changed) + id: list-changed + run: | + changed=$(ct list-changed --config=.github/ci/ct.yaml) + if [[ -n "$changed" ]]; then + echo "::set-output name=changed::true" + fi + + - name: Run chart-testing (lint) + run: ct lint --config=.github/ci/ct.yaml + + - name: Create kind cluster + uses: helm/kind-action@v1.1.0 + if: steps.list-changed.outputs.changed == 'true' + + - name: Run chart-testing (install) + run: ct install --config=.github/ci/ct.yaml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 41fac71ca..2df33648b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,8 +5,12 @@ on: branches: [ main ] tags: - '*' + paths-ignore: + - 'deploy/**' pull_request: branches: [ main ] + paths-ignore: + - 'deploy/**' env: KUBEBUILDER_VERSION: 2.3.1 diff --git a/.gitignore b/.gitignore index eb7ef50af..d967a5893 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,5 @@ bin # Code test output cover.out + +deploy/charts/external-secrets/templates/crds/*.yaml diff --git a/Makefile b/Makefile index 403b86e98..09e4cfc28 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,8 @@ SHELL := /bin/bash IMG ?= controller:latest # Produce CRDs that work back to Kubernetes 1.11 (no version conversion) CRD_OPTIONS ?= "crd:trivialVersions=true" +HELM_DIR ?= deploy/charts/external-secrets +CRD_DIR ?= config/crd/bases # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) ifeq (,$(shell go env GOBIN)) @@ -77,6 +79,16 @@ docker-build: test ## Build the docker image docker-push: ## Push the docker image docker push ${IMG} +helm-docs: ## Generate helm docs + cd $(HELM_DIR); \ + docker run --rm -v $(shell pwd)/$(HELM_DIR):/helm-docs -u $(shell id -u) jnorwood/helm-docs:latest + +crds-to-chart: # Copy crds to helm chart directory + cp $(CRD_DIR)/*.yaml $(HELM_DIR)/templates/crds/; \ + for i in $(HELM_DIR)/templates/crds/*.yaml; do \ + sed -i '1s/.*/{{- if .Values.installCRDs }}/;$$a{{- end }}' $$i; \ + done + # find or download controller-gen # download controller-gen if necessary controller-gen: diff --git a/deploy/charts/external-secrets/.helmignore b/deploy/charts/external-secrets/.helmignore new file mode 100644 index 000000000..855edc3fb --- /dev/null +++ b/deploy/charts/external-secrets/.helmignore @@ -0,0 +1,26 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ + +# CRD README.md +templates/crds/README.md diff --git a/deploy/charts/external-secrets/Chart.yaml b/deploy/charts/external-secrets/Chart.yaml new file mode 100644 index 000000000..ad13f1042 --- /dev/null +++ b/deploy/charts/external-secrets/Chart.yaml @@ -0,0 +1,14 @@ +apiVersion: v2 +name: external-secrets +description: External secret management for Kubernetes +type: application +version: "0.1.0" +appVersion: "0.1.0" +kubeVersion: ">= 1.11.0" +keywords: + - kubernetes-external-secrets + - secrets +home: https://github.com/external-secrets/external-secrets +maintainers: + - name: mcavoyk + email: kellinmcavoy@gmail.com diff --git a/deploy/charts/external-secrets/README.md b/deploy/charts/external-secrets/README.md new file mode 100644 index 000000000..c3ef4544f --- /dev/null +++ b/deploy/charts/external-secrets/README.md @@ -0,0 +1,63 @@ +# external-secrets + +[//]: # (README.md generated by gotmpl. DO NOT EDIT.) + +![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![AppVersion: 0.1.0](https://img.shields.io/badge/AppVersion-0.1.0-informational?style=flat-square) + +External secret management for Kubernetes + +## TL;DR +```bash +helm repo add external-secrets https://external-secrets.github.io/external-secrets +helm install external-secrets/external-secrets +``` + +## Installing the Chart +To install the chart with the release name `external-secrets`: +```bash +helm install external-secrets external-secrets/external-secrets +``` + +### Custom Resources +By default, the chart will install external-secrets CRDs, this can be controlled with `installCRDs` value. + +## Uninstalling the Chart +To uninstall the `external-secrets` deployment: +```bash +helm uninstall external-secrets +``` +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Configuration +Read through the external-secrets [values.yaml](https://github.com/external-secrets/external-secrets/blob/master/deploy/charts/external-secrets/values.yaml) +file. It has several commented out suggested values. + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | | +| extraArgs | object | `{}` | | +| extraEnv | list | `[]` | | +| fullnameOverride | string | `""` | | +| image.pullPolicy | string | `"IfNotPresent"` | | +| image.repository | string | `"ghcr.io/external-secrets/external-secrets"` | | +| image.tag | string | `""` | The image tag to use. The default is the chart appVersion. | +| imagePullSecrets | list | `[]` | | +| installCRDs | bool | `true` | If set, install and upgrade CRDs through helm chart. | +| leaderElect | bool | `true` | If true, external-secrets will perform leader election between instances to ensure no more than one instance of external-secrets operates at a time. | +| nameOverride | string | `""` | | +| nodeSelector | object | `{}` | | +| podAnnotations | object | `{}` | | +| podLabels | object | `{}` | | +| podSecurityContext | object | `{}` | | +| prometheus.enabled | bool | `false` | Specifies whether to expose Service resource for collecting Prometheus metrics | +| prometheus.service.port | int | `8080` | | +| rbac.create | bool | `true` | Specifies whether role and rolebinding resources should be created. | +| replicaCount | int | `1` | | +| resources | object | `{}` | | +| securityContext | object | `{}` | | +| serviceAccount.annotations | object | `{}` | Annotations to add to the service account. | +| serviceAccount.create | bool | `true` | Specifies whether a service account should be created. | +| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template. | +| tolerations | list | `[]` | | diff --git a/deploy/charts/external-secrets/README.md.gotmpl b/deploy/charts/external-secrets/README.md.gotmpl new file mode 100644 index 000000000..1762e4b1d --- /dev/null +++ b/deploy/charts/external-secrets/README.md.gotmpl @@ -0,0 +1,38 @@ +{{- $valuesYAML := "https://github.com/external-secrets/external-secrets/blob/master/deploy/charts/external-secrets/values.yaml" -}} +{{- $chartRepo := "https://external-secrets.github.io/external-secrets" -}} +{{- $org := "external-secrets" -}} +{{ template "chart.header" . }} + +[//]: # (README.md generated by gotmpl. DO NOT EDIT.) + +{{ template "chart.typeBadge" . }}{{ template "chart.versionBadge" . }}{{ template "chart.appVersionBadge" . }} + +{{ template "chart.description" . }} + +## TL;DR +```bash +helm repo add {{ $org }} {{ $chartRepo }} +helm install {{ $org }}/{{ template "chart.name" . }} +``` + +## Installing the Chart +To install the chart with the release name `{{ template "chart.name" . }}`: +```bash +helm install {{ template "chart.name" . }} {{ $org }}/{{ template "chart.name" . }} +``` + +### Custom Resources +By default, the chart will install external-secrets CRDs, this can be controlled with `installCRDs` value. + +## Uninstalling the Chart +To uninstall the `{{ template "chart.name" . }}` deployment: +```bash +helm uninstall {{ template "chart.name" . }} +``` +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Configuration +Read through the {{ template "chart.name" . }} [values.yaml]({{ $valuesYAML }}) +file. It has several commented out suggested values. + +{{ template "chart.valuesSection" . }} diff --git a/deploy/charts/external-secrets/ci/main-values.yaml b/deploy/charts/external-secrets/ci/main-values.yaml new file mode 100644 index 000000000..75eb234e3 --- /dev/null +++ b/deploy/charts/external-secrets/ci/main-values.yaml @@ -0,0 +1,2 @@ +image: + tag: main diff --git a/deploy/charts/external-secrets/templates/NOTES.txt b/deploy/charts/external-secrets/templates/NOTES.txt new file mode 100644 index 000000000..4fd716993 --- /dev/null +++ b/deploy/charts/external-secrets/templates/NOTES.txt @@ -0,0 +1,7 @@ +external-secrets has been deployed successfully! + +In order to begin using ExternalSecrets, you will need to set up a SecretStore +or ClusterSecretStore resource (for example, by creating a 'vault' SecretStore). + +More information on the different types of SecretStores and how to configure them +can be found in our Github: {{ .Chart.Home }} diff --git a/deploy/charts/external-secrets/templates/_helpers.tpl b/deploy/charts/external-secrets/templates/_helpers.tpl new file mode 100644 index 000000000..23c759fe2 --- /dev/null +++ b/deploy/charts/external-secrets/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "external-secrets.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "external-secrets.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "external-secrets.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "external-secrets.labels" -}} +helm.sh/chart: {{ include "external-secrets.chart" . }} +{{ include "external-secrets.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "external-secrets.selectorLabels" -}} +app.kubernetes.io/name: {{ include "external-secrets.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "external-secrets.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "external-secrets.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/deploy/charts/external-secrets/templates/crds/README.md b/deploy/charts/external-secrets/templates/crds/README.md new file mode 100644 index 000000000..6761190f7 --- /dev/null +++ b/deploy/charts/external-secrets/templates/crds/README.md @@ -0,0 +1,4 @@ +# CRD Template Directory +the CRDs are generated in pipeline during helm package. To install the CRDs please set `installCRDS: true`. + +The latest CRDs in the repository are located [here](../../../../../config/crd/bases) diff --git a/deploy/charts/external-secrets/templates/deployment.yaml b/deploy/charts/external-secrets/templates/deployment.yaml new file mode 100644 index 000000000..a54ca1700 --- /dev/null +++ b/deploy/charts/external-secrets/templates/deployment.yaml @@ -0,0 +1,74 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "external-secrets.fullname" . }} + labels: + {{- include "external-secrets.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "external-secrets.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "external-secrets.selectorLabels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "external-secrets.serviceAccountName" . }} + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: + {{- if .Values.leaderElect }} + - --enable-leader-election=true + {{- end }} + {{- range $key, $value := .Values.extraArgs }} + {{- if $value }} + - --{{ $key }}={{ $value }} + {{- else }} + - --{{ $key }} + {{- end }} + {{- end }} + ports: + - containerPort: {{ .Values.prometheus.service.port }} + protocol: TCP + {{- with .Values.extraEnv }} + env: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/deploy/charts/external-secrets/templates/rbac.yaml b/deploy/charts/external-secrets/templates/rbac.yaml new file mode 100644 index 000000000..a72568d6b --- /dev/null +++ b/deploy/charts/external-secrets/templates/rbac.yaml @@ -0,0 +1,101 @@ +{{- if .Values.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "external-secrets.fullname" . }}-controller + labels: + {{- include "external-secrets.labels" . | nindent 4 }} +rules: + - apiGroups: + - "external-secrets.io" + resources: + - "secretstores" + - "clustersecretstores" + - "externalsecrets" + verbs: + - "get" + - "list" + - "watch" + - apiGroups: + - "external-secrets.io" + resources: + - "externalsecrets" + - "externalsecrets/status" + verbs: + - "update" + - "patch" + - apiGroups: + - "" + resources: + - "secrets" + verbs: + - "get" + - "list" + - "watch" + - "create" + - "update" + - "delete" + - apiGroups: + - "" + resources: + - "events" + verbs: + - "create" + - "patch" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "external-secrets.fullname" . }}-controller + labels: + {{- include "external-secrets.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "external-secrets.fullname" . }}-controller +subjects: + - name: {{ include "external-secrets.serviceAccountName" . }} + namespace: {{ .Release.Namespace | quote }} + kind: ServiceAccount +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "external-secrets.fullname" . }}-leaderelection + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "external-secrets.labels" . | nindent 4 }} +rules: + - apiGroups: + - "" + resources: + - "configmaps" + resourceNames: + - "external-secrets-controller" + verbs: + - "get" + - "update" + - "patch" + - apiGroups: + - "" + resources: + - "configmaps" + verbs: + - "create" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "external-secrets.fullname" . }}-leaderelection + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "external-secrets.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "external-secrets.fullname" . }}-leaderelection +subjects: + - kind: ServiceAccount + name: {{ include "external-secrets.serviceAccountName" . }} + namespace: {{ .Release.Namespace | quote }} +{{- end }} diff --git a/deploy/charts/external-secrets/templates/service.yaml b/deploy/charts/external-secrets/templates/service.yaml new file mode 100644 index 000000000..6c95edd05 --- /dev/null +++ b/deploy/charts/external-secrets/templates/service.yaml @@ -0,0 +1,20 @@ +{{- if .Values.prometheus.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "external-secrets.fullname" . }}-metrics + labels: + {{- include "external-secrets.labels" . | nindent 4 }} + annotations: + prometheus.io/path: "/metrics" + prometheus.io/scrape: "true" + prometheus.io/port: {{ .Values.prometheus.service.port | quote }} +spec: + type: ClusterIP + ports: + - port: {{ .Values.prometheus.service.port }} + targetPort: {{ .Values.prometheus.service.port }} + protocol: TCP + selector: + {{- include "external-secrets.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/deploy/charts/external-secrets/templates/serviceaccount.yaml b/deploy/charts/external-secrets/templates/serviceaccount.yaml new file mode 100644 index 000000000..911638fb4 --- /dev/null +++ b/deploy/charts/external-secrets/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "external-secrets.serviceAccountName" . }} + labels: + {{- include "external-secrets.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/deploy/charts/external-secrets/values.yaml b/deploy/charts/external-secrets/values.yaml new file mode 100644 index 000000000..419b06473 --- /dev/null +++ b/deploy/charts/external-secrets/values.yaml @@ -0,0 +1,68 @@ +replicaCount: 1 + +image: + repository: ghcr.io/external-secrets/external-secrets + pullPolicy: IfNotPresent + # -- The image tag to use. The default is the chart appVersion. + tag: "" + +# -- If set, install and upgrade CRDs through helm chart. +installCRDs: true + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +# -- If true, external-secrets will perform leader election between instances to ensure no more +# than one instance of external-secrets operates at a time. +leaderElect: false + +serviceAccount: + # -- Specifies whether a service account should be created. + create: true + # -- Annotations to add to the service account. + annotations: {} + # -- The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template. + name: "" + +rbac: + # -- Specifies whether role and rolebinding resources should be created. + create: true + +## -- Extra environment variables to add to container. +extraEnv: [] + +## -- Map of extra arguments to pass to container. +extraArgs: {} + +podAnnotations: {} +podLabels: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +resources: {} + # requests: + # cpu: 10m + # memory: 32Mi + +prometheus: + # -- Specifies whether to expose Service resource for collecting Prometheus metrics + enabled: false + service: + port: 8080 + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/main.go b/main.go index f52a49e2e..17877e11b 100644 --- a/main.go +++ b/main.go @@ -57,7 +57,7 @@ func main() { MetricsBindAddress: metricsAddr, Port: 9443, LeaderElection: enableLeaderElection, - LeaderElectionID: "1fc40399.io", + LeaderElectionID: "external-secrets-controller", }) if err != nil { setupLog.Error(err, "unable to start manager")