diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..f7ecb60 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,48 @@ +name: release + +on: + push: + branches: + - main + +jobs: + build: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + + - uses: actions/cache@v2 + with: + path: ./bin + key: ${{ runner.os }}-bin + + - name: Build image + run: make docker-build + + - name: Export release name + run: | + echo "NEW_RELEASE=$(make get-new-release)" >> $GITHUB_ENV + - name: Login to quay.io/3scale + if: ${{ env.NEW_RELEASE != '' }} + uses: docker/login-action@v1 + with: + registry: quay.io + username: ${{ secrets.REGISTRY_USER }} + password: ${{ secrets.REGISTRY_PASSWORD }} + + - name: Push new operator image + if: ${{ env.NEW_RELEASE != '' }} + run: make docker-push + + - name: Publish new bundle image + if: ${{ env.NEW_RELEASE != '' }} + run: make bundle-publish + + - name: Create a new draft-release in github + if: ${{ env.NEW_RELEASE != '' }} + uses: "marvinpinto/action-automatic-releases@latest" + with: + repo_token: "${{ secrets.GITHUB_TOKEN }}" + automatic_release_tag: "${{ env.NEW_RELEASE }}" + title: "${{ env.NEW_RELEASE }}" + draft: true \ No newline at end of file diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..a649f22 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,20 @@ +name: test + +on: + pull_request: + branches: + - main + +jobs: + test: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + + - uses: actions/cache@v2 + with: + path: ./bin + key: ${{ runner.os }}-bin + + - name: Run test-e2e + run: make test-e2e \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a2b024c --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ + +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +bin + +# editor and IDE paraphernalia +.idea +*.swp +*.swo +*~ +kubeconfig +helm-charts/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..bcbd6a9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,7 @@ +# Build the manager binary +FROM quay.io/operator-framework/helm-operator:v1.15.0 + +ENV HOME=/opt/helm +COPY watches.yaml ${HOME}/watches.yaml +COPY helm-charts ${HOME}/helm-charts +WORKDIR ${HOME} diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c5fd9c7 --- /dev/null +++ b/Makefile @@ -0,0 +1,293 @@ +# VERSION defines the project version for the bundle. +# Update this value when you upgrade the version of your project. +# To re-generate a bundle for another specific version without changing the standard setup, you can: +# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2) +# - use environment variables to overwrite this value (e.g export VERSION=0.0.2) +VERSION ?= 0.3.8 + +# CHANNELS define the bundle channels used in the bundle. +# Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable") +# To re-generate a bundle for other specific channels without changing the standard setup, you can: +# - use the CHANNELS as arg of the bundle target (e.g make bundle CHANNELS=candidate,fast,stable) +# - use environment variables to overwrite this value (e.g export CHANNELS="candidate,fast,stable") +ifneq ($(origin CHANNELS), undefined) +BUNDLE_CHANNELS := --channels=$(CHANNELS) +endif + +# DEFAULT_CHANNEL defines the default channel used in the bundle. +# Add a new line here if you would like to change its default config. (E.g DEFAULT_CHANNEL = "stable") +# To re-generate a bundle for any other default channel without changing the default setup, you can: +# - use the DEFAULT_CHANNEL as arg of the bundle target (e.g make bundle DEFAULT_CHANNEL=stable) +# - use environment variables to overwrite this value (e.g export DEFAULT_CHANNEL="stable") +ifneq ($(origin DEFAULT_CHANNEL), undefined) +BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL) +endif +BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL) + +# IMAGE_TAG_BASE defines the docker.io namespace and part of the image name for remote images. +# This variable is used to construct full image tags for bundle and catalog images. +# +# For example, running 'make bundle-build bundle-push catalog-build catalog-push' will build and push both +# external-secrets.io/external-secrets-operator-bundle:$VERSION and external-secrets.io/external-secrets-operator-catalog:$VERSION. +IMAGE_TAG_BASE ?= quay.io/3scale/external-secrets-operator + +# BUNDLE_IMG defines the image:tag used for the bundle. +# You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=/:) +BUNDLE_IMG ?= $(IMAGE_TAG_BASE)-bundle:v$(VERSION) + +# Image URL to use all building/pushing image targets +IMG ?= $(IMAGE_TAG_BASE):v$(VERSION) + +all: docker-build + +##@ General + +# The help target prints out all targets with their descriptions organized +# beneath their categories. The categories are represented by '##@' and the +# target descriptions by '##'. The awk commands is responsible for reading the +# entire set of makefiles included in this invocation, looking for lines of the +# file as xyz: ## something, and then pretty-format the target and help. Then, +# if there's a line with ##@ something, that gets pretty-printed as a category. +# More info on the usage of ANSI control characters for terminal formatting: +# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters +# More info on the awk command: +# http://linuxcommand.org/lc3_adv_awk.php + +help: ## Display this help. + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +##@ Build + +run: download-helm-chart helm-operator ## Run against the configured Kubernetes cluster in ~/.kube/config + $(HELM_OPERATOR) run + +docker-build: download-helm-chart ## Build docker image with the manager. + docker build -t ${IMG} . + +docker-push: ## Push docker image with the manager. + docker push ${IMG} + +##@ Deployment + +install: kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. + $(KUSTOMIZE) build config/crd | kubectl apply -f - + +uninstall: kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. + $(KUSTOMIZE) build config/crd | kubectl delete -f - + +deploy: kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. + cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} + $(KUSTOMIZE) build config/default | kubectl apply -f - + +undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. + $(KUSTOMIZE) build config/default | kubectl delete -f - + +OS := $(shell uname -s | tr '[:upper:]' '[:lower:]') +ARCH := $(shell uname -m | sed 's/x86_64/amd64/') + +.PHONY: kustomize +KUSTOMIZE = $(shell pwd)/bin/kustomize +kustomize: ## Download kustomize locally if necessary. +ifeq (,$(wildcard $(KUSTOMIZE))) +ifeq (,$(shell which kustomize 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p $(dir $(KUSTOMIZE)) ;\ + curl -sSLo - https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v3.8.7/kustomize_v3.8.7_$(OS)_$(ARCH).tar.gz | \ + tar xzf - -C bin/ ;\ + } +else +KUSTOMIZE = $(shell which kustomize) +endif +endif + +.PHONY: helm-operator +HELM_OPERATOR = $(shell pwd)/bin/helm-operator +helm-operator: ## Download helm-operator locally if necessary, preferring the $(pwd)/bin path over global if both exist. +ifeq (,$(wildcard $(HELM_OPERATOR))) +ifeq (,$(shell which helm-operator 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p $(dir $(HELM_OPERATOR)) ;\ + curl -sSLo $(HELM_OPERATOR) https://github.com/operator-framework/operator-sdk/releases/download/v1.15.0/helm-operator_$(OS)_$(ARCH) ;\ + chmod +x $(HELM_OPERATOR) ;\ + } +else +HELM_OPERATOR = $(shell which helm-operator) +endif +endif + +.PHONY: bundle +bundle: operator-sdk kustomize ## Generate bundle manifests and metadata, then validate generated files. + $(OPERATOR_SDK) generate kustomize manifests -q + cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG) + $(KUSTOMIZE) build config/manifests | $(OPERATOR_SDK) generate bundle -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS) + $(OPERATOR_SDK) bundle validate ./bundle + +.PHONY: bundle-build +bundle-build: ## Build the bundle image. + docker build -f bundle.Dockerfile -t $(BUNDLE_IMG) . + +.PHONY: bundle-push +bundle-push: ## Push the bundle image. + $(MAKE) docker-push IMG=$(BUNDLE_IMG) + +.PHONY: opm +OPM = ./bin/opm +opm: ## Download opm locally if necessary. +ifeq (,$(wildcard $(OPM))) +ifeq (,$(shell which opm 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p $(dir $(OPM)) ;\ + curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.15.1/$(OS)-$(ARCH)-opm ;\ + chmod +x $(OPM) ;\ + } +else +OPM = $(shell which opm) +endif +endif + +# A comma-separated list of bundle images (e.g. make catalog-build BUNDLE_IMGS=example.com/operator-bundle:v0.1.0,example.com/operator-bundle:v0.2.0). +# These images MUST exist in a registry and be pull-able. +BUNDLE_IMGS ?= $(BUNDLE_IMG) + +# The image tag given to the resulting catalog image (e.g. make catalog-build CATALOG_IMG=example.com/operator-catalog:v0.2.0). +CATALOG_IMG ?= $(IMAGE_TAG_BASE)-catalog:v$(VERSION) + +# Custom default catalog base image to append bundles to +CATALOG_BASE_IMG ?= $(IMAGE_TAG_BASE)-catalog:latest + +# Set CATALOG_BASE_IMG to an existing catalog image tag to add $BUNDLE_IMGS to that image. +ifneq ($(origin CATALOG_BASE_IMG), undefined) +FROM_INDEX_OPT := --from-index $(CATALOG_BASE_IMG) +endif + +# Build a catalog image by adding bundle images to an empty catalog using the operator package manager tool, 'opm'. +# This recipe invokes 'opm' in 'semver' bundle add mode. For more information on add modes, see: +# https://github.com/operator-framework/community-operators/blob/7f1438c/docs/packaging-operator.md#updating-your-existing-operator +.PHONY: catalog-build +catalog-build: opm ## Build a catalog image. + $(OPM) index add --container-tool docker --mode semver --tag $(CATALOG_IMG) --bundles $(BUNDLE_IMGS) $(FROM_INDEX_OPT) + +# Push the catalog image. +.PHONY: catalog-push +catalog-push: ## Push a catalog image. + $(MAKE) docker-push IMG=$(CATALOG_IMG) + +############################################# +#### Custom Targets with extra binaries ##### +############################################# + +# Download operator-sdk binary if necessary +OPERATOR_SDK_RELEASE = v1.15.0 +OPERATOR_SDK = $(shell pwd)/bin/operator-sdk-$(OPERATOR_SDK_RELEASE) +OPERATOR_SDK_DL_URL = https://github.com/operator-framework/operator-sdk/releases/download/$(OPERATOR_SDK_RELEASE)/operator-sdk_$(OS)_$(ARCH) +operator-sdk: +ifeq (,$(wildcard $(OPERATOR_SDK))) +ifeq (,$(shell which $(OPERATOR_SDK) 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p $(shell pwd)/bin ;\ + curl -sL -o $(OPERATOR_SDK) $(OPERATOR_SDK_DL_URL) ;\ + chmod +x $(OPERATOR_SDK) ;\ + } +else +OPERATOR_SDK = $(shell which $(OPERATOR_SDK)) +endif +endif + +# Download kind locally if necessary +KIND_RELEASE = v0.11.1 +KIND = $(shell pwd)/bin/kind-$(KIND_RELEASE) +KIND_DL_URL = https://github.com/kubernetes-sigs/kind/releases/download/$(KIND_RELEASE)/kind-$(OS)-$(ARCH) +kind: +ifeq (,$(wildcard $(KIND))) +ifeq (,$(shell which $(KIND) 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p $(shell pwd)/bin ;\ + curl -sL -o $(KIND) $(KIND_DL_URL) ;\ + chmod +x $(KIND) ;\ + } +else +KIND = $(shell which $(KIND)) +endif +endif + +# Download kuttl locally if necessary for e2e tests +KUTTL_RELEASE = 0.9.0 +KUTTL = $(shell pwd)/bin/kuttl-v$(KUTTL_RELEASE) +KUTTL_DL_URL = https://github.com/kudobuilder/kuttl/releases/download/v$(KUTTL_RELEASE)/kubectl-kuttl_$(KUTTL_RELEASE)_$(OS)_x86_64 +kuttl: +ifeq (,$(wildcard $(KUTTL))) +ifeq (,$(shell which $(KUTTL) 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p $(shell pwd)/bin ;\ + curl -sL -o $(KUTTL) $(KUTTL_DL_URL) ;\ + chmod +x $(KUTTL) ;\ + } +else +KUTTL = $(shell which $(KUTTL)) +endif +endif + +#################################################### +#### Custom Targets clones original helm chart ##### +#################################################### +##@ Download Helm Chart + +download-helm-chart: ## Download original helm chart into operator directory helm-charts/ + @hack/download-helm-chart.sh $(VERSION) + +#################################################### +#### Custom Targets to publish release catalog ##### +#################################################### +##@ Release Catalog + +prepare-alpha-release: bundle ## Prepare alpha release + +prepare-stable-release: bundle ## Prepare stable release + $(MAKE) bundle CHANNELS=alpha,stable DEFAULT_CHANNEL=alpha + +catalog-retag-latest: + docker tag $(CATALOG_IMG) $(CATALOG_BASE_IMG) + $(MAKE) docker-push IMG=$(CATALOG_BASE_IMG) + +bundle-publish: test-e2e bundle-build bundle-push catalog-build catalog-push catalog-retag-latest ## Publish new release in catalog + +get-new-release: + @hack/new-release.sh v$(VERSION) + +################################################### +#### Custom Targets to manually test with Kind #### +################################################### +##@ Testing + +kind-create: export KUBECONFIG = ${PWD}/kubeconfig +kind-create: kind ## Creates a k8s kind cluster +ifeq (1, $(shell $(KIND) get clusters | grep kind | wc -l)) + @echo "Kind cluster already exists, doing nothing" +else + @echo "Creating kind cluster" + $(KIND) create cluster --wait 5m +endif + +kind-delete: kind ## Deletes the k8s kind cluster + $(KIND) delete cluster + +kind-deploy: export KUBECONFIG = ${PWD}/kubeconfig +kind-deploy: docker-build kind ## Deploys the operator in the k8s kind cluster + $(KIND) load docker-image $(IMG) + cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} + $(KUSTOMIZE) build config/default | kubectl apply -f - + +kind-undeploy: export KUBECONFIG = ${PWD}/kubeconfig +kind-undeploy: kind ## Undeploys the operator in the k8s kind cluster + $(KUSTOMIZE) build config/default | kubectl delete -f - + + +test-e2e: export KUBECONFIG = ${PWD}/kubeconfig +test-e2e: kuttl kind-create kind-deploy ## Run kuttl e2e tests in the k8s kind cluster + $(KUTTL) test \ No newline at end of file diff --git a/OWNERS b/OWNERS new file mode 100644 index 0000000..5f67bef --- /dev/null +++ b/OWNERS @@ -0,0 +1,8 @@ +approvers: + - raelga + - roivaz + - slopezz +reviewers: + - raelga + - roivaz + - slopezz diff --git a/PROJECT b/PROJECT new file mode 100644 index 0000000..5c7c5c8 --- /dev/null +++ b/PROJECT @@ -0,0 +1,16 @@ +domain: external-secrets.io +layout: +- helm.sdk.operatorframework.io/v1 +plugins: + manifests.sdk.operatorframework.io/v2: {} + scorecard.sdk.operatorframework.io/v2: {} +projectName: external-secrets-operator +resources: +- api: + crdVersion: v1 + namespaced: true + domain: external-secrets.io + group: operator + kind: OperatorConfig + version: v1alpha1 +version: "3" diff --git a/README.md b/README.md index 932f71c..b812729 100644 --- a/README.md +++ b/README.md @@ -1 +1,85 @@ -# external-secrets-operator \ No newline at end of file +# External Secrets Operator + +[![test](https://github.com/3scale-ops/external-secrets-operator/actions/workflows/test.yaml/badge.svg)](https://github.com/3scale-ops/external-secrets-operator/actions/workflows/test.yaml) +[![build](https://github.com/3scale-ops/external-secrets-operator/actions/workflows/release.yaml/badge.svg)](https://github.com/3scale-ops/external-secrets-operator/actions/workflows/release.yaml) +[![release](https://badgen.net/github/release/3scale-ops/external-secrets-operator)](https://github.com/3scale-ops/external-secrets-operator/releases) +[![license](https://badgen.net/github/license/3scale-ops/external-secrets-operator)](https://github.com/3scale-ops/external-secrets-operator/blob/main/LICENSE) + +A Kubernetes Operator based on the Operator SDK (Helm version) to configure **[official external-secrets operator helm chart](https://github.com/external-secrets/external-secrets)**, so it can be installed via OLM without having to do any change on current Helm Charts. + +The usual Helm Chart file `values.yaml`, like: +```yaml +prometheus: + enabled: true + service: + port: 8080 +resources: + requests: + cpu: 10m + memory: 96Mi + limits: + cpu: 100m + memory: 256Mi +``` + +Need to be encapsulated into a new custom resource called `OperatorConfig`: +```yaml +apiVersion: operator.external-secrets.io/v1alpha1 +kind: OperatorConfig +metadata: + name: cluster +spec: + prometheus: + enabled: true + service: + port: 8080 + resources: + requests: + cpu: 10m + memory: 96Mi + limits: + cpu: 100m + memory: 256Mi +``` + +So the operator will create all helm chart resources, using the custom resource name as a preffix for all resources names, like for example a `Deployment` called `cluster-external-secrets`. + +## Initial bootstrap + +Initially, all operator files bootstraping have been created with `operator-sdk:v1.15.0` ([commit](https://github.com/3scale-ops/external-secrets-operator/commit/0694458c1d87db46331e6788b96ac82513de30d0)): +```bash +$ operator-sdk init --plugins helm --group operator --domain external-secrets.io --version v1alpha1 --kind OperatorConfig --helm-chart=external-secrets --helm-chart-repo=https://charts.external-secrets.io/ --helm-chart-version=0.3.8 +Writing kustomize manifests for you to edit... +Creating the API: +$ operator-sdk create api --group operator --version v1alpha1 --kind OperatorConfig --helm-chart external-secrets --helm-chart-repo https://charts.external-secrets.io/ --helm-chart-version 0.3.8 +Writing kustomize manifests for you to edit... +Created helm-charts/external-secrets +Generating RBAC rules +WARN[0006] Using default RBAC rules: failed to generate RBAC rules: failed to get server resources: Unauthorized +``` + +And then, the most important change done on predefined files was the operator `ClusterRole`, which needed extra permissions in order to be able to create all resources created by the Helm Chart ([commit](https://github.com/3scale-ops/external-secrets-operator/commit/ee344d8eddf683216af947b94b6c2a3ca6d7fe9a)). + +The rest of the changes are mostly cosmetic, a kind of k8s-operator-olm envelope for the real Helm Chart that will be downloaded dynamically using helm chart version on every operator image build at [helm-charts/external-secrets](helm-charts/external-secrets/). + +## Documentation + +* [Install](docs/install.md) +* [Development](docs/development.md) +* [Release](docs/release.md) + +## Contributing + +You can contribute by: + +* Raising any issues you find using External Secrets Operator +* Fixing issues by opening [Pull Requests](https://github.com/3scale-ops/external-secrets-operator/pulls) +* Submitting a patch or opening a PR +* Improving documentation +* Talking about External Secrets Operator + +All bugs, tasks or enhancements are tracked as [GitHub issues](https://github.com/3scale-ops/external-secrets-operator/issues). + +## License + +External Secrets Operator is under Apache 2.0 license. See the [LICENSE](LICENSE) file for details. \ No newline at end of file diff --git a/bundle.Dockerfile b/bundle.Dockerfile new file mode 100644 index 0000000..6cbdbf9 --- /dev/null +++ b/bundle.Dockerfile @@ -0,0 +1,21 @@ +FROM scratch + +# Core bundle labels. +LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1 +LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ +LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ +LABEL operators.operatorframework.io.bundle.package.v1=external-secrets-operator +LABEL operators.operatorframework.io.bundle.channels.v1=alpha,stable +LABEL operators.operatorframework.io.bundle.channel.default.v1=alpha +LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.14.0+git +LABEL operators.operatorframework.io.metrics.mediatype.v1=metrics+v1 +LABEL operators.operatorframework.io.metrics.project_layout=helm.sdk.operatorframework.io/v1 + +# Labels for testing. +LABEL operators.operatorframework.io.test.mediatype.v1=scorecard+v1 +LABEL operators.operatorframework.io.test.config.v1=tests/scorecard/ + +# Copy files to locations specified by labels. +COPY bundle/manifests /manifests/ +COPY bundle/metadata /metadata/ +COPY bundle/tests/scorecard /tests/scorecard/ diff --git a/bundle/manifests/external-secrets-operator-manager-config_v1_configmap.yaml b/bundle/manifests/external-secrets-operator-manager-config_v1_configmap.yaml new file mode 100644 index 0000000..c1876c2 --- /dev/null +++ b/bundle/manifests/external-secrets-operator-manager-config_v1_configmap.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +data: + controller_manager_config.yaml: | + apiVersion: controller-runtime.sigs.k8s.io/v1alpha1 + kind: ControllerManagerConfig + health: + healthProbeBindAddress: :8081 + metrics: + bindAddress: 127.0.0.1:8080 + + leaderElection: + leaderElect: true + resourceName: 811c9dc5.external-secrets.io +kind: ConfigMap +metadata: + name: external-secrets-operator-manager-config diff --git a/bundle/manifests/external-secrets-operator.clusterserviceversion.yaml b/bundle/manifests/external-secrets-operator.clusterserviceversion.yaml new file mode 100644 index 0000000..b727475 --- /dev/null +++ b/bundle/manifests/external-secrets-operator.clusterserviceversion.yaml @@ -0,0 +1,355 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + annotations: + alm-examples: |- + [ + { + "apiVersion": "operator.external-secrets.io/v1alpha1", + "kind": "OperatorConfig", + "metadata": { + "name": "sample" + }, + "spec": { + "affinity": {}, + "extraArgs": {}, + "extraEnv": [], + "fullnameOverride": "", + "image": { + "pullPolicy": "IfNotPresent", + "repository": "ghcr.io/external-secrets/external-secrets", + "tag": "" + }, + "imagePullSecrets": [], + "installCRDs": true, + "leaderElect": false, + "nameOverride": "", + "nodeSelector": {}, + "podAnnotations": {}, + "podLabels": {}, + "podSecurityContext": {}, + "priorityClassName": "", + "prometheus": { + "enabled": false, + "service": { + "port": 8080 + } + }, + "rbac": { + "create": true + }, + "replicaCount": 1, + "resources": {}, + "scopedNamespace": "", + "securityContext": {}, + "serviceAccount": { + "annotations": {}, + "create": true, + "name": "" + }, + "tolerations": [] + } + } + ] + capabilities: Basic Install + categories: Security + certified: "false" + containerImage: quay.io/3scale/external-secrets-operator + createdAt: "2021-11-22 00:00:00" + description: Operator to configure external-secrets helm-chart based operator + operators.operatorframework.io/builder: operator-sdk-v1.14.0+git + operators.operatorframework.io/project_layout: helm.sdk.operatorframework.io/v1 + repository: https://github.com/3scale-ops/external-secrets-operator + name: external-secrets-operator.v0.3.8 + namespace: placeholder +spec: + apiservicedefinitions: {} + customresourcedefinitions: + owned: + - description: Configures external-secrets helm-chart based operator + displayName: OperatorConfig + kind: OperatorConfig + name: operatorconfigs.operator.external-secrets.io + version: v1alpha1 + description: | + A Kubernetes Operator based on the Operator SDK (Helm version) to configure **[official external-secrets operator helm chart](https://github.com/external-secrets/external-secrets)**, so it can be installed via OLM without having to do any change on current Helm Charts. + + The usual Helm Chart file `values.yaml`, like: + ```yaml + prometheus: + enabled: true + service: + port: 8080 + resources: + requests: + cpu: 10m + memory: 96Mi + limits: + cpu: 100m + memory: 256Mi + ``` + + Need to be encapsulated into a new custom resource called `OperatorConfig`: + ```yaml + apiVersion: operator.external-secrets.io/v1alpha1 + kind: OperatorConfig + metadata: + name: cluster + spec: + prometheus: + enabled: true + service: + port: 8080 + resources: + requests: + cpu: 10m + memory: 96Mi + limits: + cpu: 100m + memory: 256Mi + ``` + + So the operator will create all helm chart resources, using the custom resource name as a preffix for all resources names, like for example a `Deployment` called `cluster-external-secrets`. + + ## Documentation + + * [Install](docs/install.md) + * [Development](docs/development.md) + * [Release](docs/release.md) + + ## Contributing + + You can contribute by: + + * Raising any issues you find using External Secrets Operator + * Fixing issues by opening [Pull Requests](https://github.com/3scale-ops/external-secrets-operator/pulls) + * Submitting a patch or opening a PR + * Improving documentation + * Talking about External Secrets Operator + + All bugs, tasks or enhancements are tracked as [GitHub issues](https://github.com/3scale-ops/external-secrets-operator/issues). + + ## License + + External Secrets Operator is under Apache 2.0 license. See the [LICENSE](LICENSE) file for details. + displayName: External Secrets Operator + icon: + - base64data: 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 + mediatype: image/png+xml + install: + spec: + clusterPermissions: + - rules: + - apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - apiGroups: + - "" + resources: + - secrets + verbs: + - '*' + - apiGroups: + - "" + resources: + - events + verbs: + - create + - apiGroups: + - operator.external-secrets.io + resources: + - operatorconfigs + - operatorconfigs/status + - operatorconfigs/finalizers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - "" + resources: + - pods + - services + - services/finalizers + - endpoints + - persistentvolumeclaims + - events + - configmaps + - secrets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - apps + resources: + - deployments + - daemonsets + - replicasets + - statefulsets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - '*' + - apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterroles + - clusterrolebindings + - roles + - rolebindings + verbs: + - '*' + - apiGroups: + - "" + resources: + - serviceaccounts + - services + verbs: + - '*' + - apiGroups: + - apps + resources: + - deployments + verbs: + - '*' + serviceAccountName: external-secrets-operator-controller-manager + deployments: + - name: external-secrets-operator-controller-manager + spec: + replicas: 1 + selector: + matchLabels: + control-plane: controller-manager + strategy: {} + template: + metadata: + labels: + control-plane: controller-manager + spec: + containers: + - args: + - --health-probe-bind-address=:8081 + - --metrics-bind-address=0.0.0.0:8080 + - --leader-elect + - --leader-election-id=external-secrets-operator + env: + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.annotations['olm.targetNamespaces'] + image: quay.io/3scale/external-secrets-operator:v0.3.8 + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + timeoutSeconds: 5 + name: manager + ports: + - containerPort: 8080 + name: metrics + protocol: TCP + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + resources: {} + securityContext: + allowPrivilegeEscalation: false + securityContext: + runAsNonRoot: true + serviceAccountName: external-secrets-operator-controller-manager + terminationGracePeriodSeconds: 10 + permissions: + - rules: + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + serviceAccountName: external-secrets-operator-controller-manager + strategy: deployment + installModes: + - supported: true + type: OwnNamespace + - supported: true + type: SingleNamespace + - supported: true + type: MultiNamespace + - supported: true + type: AllNamespaces + keywords: + - secrets + - secrets-manager + - vault + - aws + - azure + - google + - ibm + - akeyless + - yandex + - gitlab + - oracle + links: + - name: External Secrets Operator + url: https://external-secrets.io + maintainers: + - email: 3scale-operations@redhat.com + name: 3scale Ops + maturity: alpha + provider: + name: Red Hat + url: https://www.redhat.com + version: 0.3.8 diff --git a/bundle/manifests/operator.external-secrets.io_operatorconfigs.yaml b/bundle/manifests/operator.external-secrets.io_operatorconfigs.yaml new file mode 100644 index 0000000..4da1162 --- /dev/null +++ b/bundle/manifests/operator.external-secrets.io_operatorconfigs.yaml @@ -0,0 +1,50 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + creationTimestamp: null + name: operatorconfigs.operator.external-secrets.io +spec: + group: operator.external-secrets.io + names: + kind: OperatorConfig + listKind: OperatorConfigList + plural: operatorconfigs + singular: operatorconfig + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: OperatorConfig is the Schema for the operatorconfigs API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of OperatorConfig + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: Status defines the observed state of OperatorConfig + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null diff --git a/bundle/metadata/annotations.yaml b/bundle/metadata/annotations.yaml new file mode 100644 index 0000000..c21964f --- /dev/null +++ b/bundle/metadata/annotations.yaml @@ -0,0 +1,15 @@ +annotations: + # Core bundle annotations. + operators.operatorframework.io.bundle.mediatype.v1: registry+v1 + operators.operatorframework.io.bundle.manifests.v1: manifests/ + operators.operatorframework.io.bundle.metadata.v1: metadata/ + operators.operatorframework.io.bundle.package.v1: external-secrets-operator + operators.operatorframework.io.bundle.channels.v1: alpha,stable + operators.operatorframework.io.bundle.channel.default.v1: alpha + operators.operatorframework.io.metrics.builder: operator-sdk-v1.14.0+git + operators.operatorframework.io.metrics.mediatype.v1: metrics+v1 + operators.operatorframework.io.metrics.project_layout: helm.sdk.operatorframework.io/v1 + + # Annotations for testing. + operators.operatorframework.io.test.mediatype.v1: scorecard+v1 + operators.operatorframework.io.test.config.v1: tests/scorecard/ diff --git a/bundle/tests/scorecard/config.yaml b/bundle/tests/scorecard/config.yaml new file mode 100644 index 0000000..14c9f7c --- /dev/null +++ b/bundle/tests/scorecard/config.yaml @@ -0,0 +1,70 @@ +apiVersion: scorecard.operatorframework.io/v1alpha3 +kind: Configuration +metadata: + name: config +stages: +- parallel: true + tests: + - entrypoint: + - scorecard-test + - basic-check-spec + image: quay.io/operator-framework/scorecard-test:v1.15.0 + labels: + suite: basic + test: basic-check-spec-test + storage: + spec: + mountPath: {} + - entrypoint: + - scorecard-test + - olm-bundle-validation + image: quay.io/operator-framework/scorecard-test:v1.15.0 + labels: + suite: olm + test: olm-bundle-validation-test + storage: + spec: + mountPath: {} + - entrypoint: + - scorecard-test + - olm-crds-have-validation + image: quay.io/operator-framework/scorecard-test:v1.15.0 + labels: + suite: olm + test: olm-crds-have-validation-test + storage: + spec: + mountPath: {} + - entrypoint: + - scorecard-test + - olm-crds-have-resources + image: quay.io/operator-framework/scorecard-test:v1.15.0 + labels: + suite: olm + test: olm-crds-have-resources-test + storage: + spec: + mountPath: {} + - entrypoint: + - scorecard-test + - olm-spec-descriptors + image: quay.io/operator-framework/scorecard-test:v1.15.0 + labels: + suite: olm + test: olm-spec-descriptors-test + storage: + spec: + mountPath: {} + - entrypoint: + - scorecard-test + - olm-status-descriptors + image: quay.io/operator-framework/scorecard-test:v1.15.0 + labels: + suite: olm + test: olm-status-descriptors-test + storage: + spec: + mountPath: {} +storage: + spec: + mountPath: {} diff --git a/config/crd/bases/operator.external-secrets.io_operatorconfigs.yaml b/config/crd/bases/operator.external-secrets.io_operatorconfigs.yaml new file mode 100644 index 0000000..6678302 --- /dev/null +++ b/config/crd/bases/operator.external-secrets.io_operatorconfigs.yaml @@ -0,0 +1,44 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: operatorconfigs.operator.external-secrets.io +spec: + group: operator.external-secrets.io + names: + kind: OperatorConfig + listKind: OperatorConfigList + plural: operatorconfigs + singular: operatorconfig + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: OperatorConfig is the Schema for the operatorconfigs API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of OperatorConfig + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: Status defines the observed state of OperatorConfig + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml new file mode 100644 index 0000000..1cf2f74 --- /dev/null +++ b/config/crd/kustomization.yaml @@ -0,0 +1,6 @@ +# This kustomization.yaml is not intended to be run by itself, +# since it depends on service name and namespace that are out of this kustomize package. +# It should be run by config/default +resources: +- bases/operator.external-secrets.io_operatorconfigs.yaml +#+kubebuilder:scaffold:crdkustomizeresource diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml new file mode 100644 index 0000000..0af5fbf --- /dev/null +++ b/config/default/kustomization.yaml @@ -0,0 +1,32 @@ +# Adds namespace to all resources. +namespace: external-secrets-operator-system + +# Value of this field is prepended to the +# names of all resources, e.g. a deployment named +# "wordpress" becomes "alices-wordpress". +# Note that it should also match with the prefix (text before '-') of the namespace +# field above. +namePrefix: external-secrets-operator- + +# Labels to add to all resources and selectors. +#commonLabels: +# someName: someValue + +bases: +- ../crd +- ../rbac +- ../manager +# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. +#- ../prometheus + +patchesStrategicMerge: +# This patch makes operator metrics available at 0.0.0.0:8080 without the usage of a rbac-proxy. +- manager_metrics_patch.yaml +# Protect the /metrics endpoint by putting it behind auth. +# If you want your controller-manager to expose the /metrics +# endpoint w/o any authn/z, please comment the following line. +#- manager_auth_proxy_patch.yaml + +# Mount the controller config file for loading manager configurations +# through a ComponentConfig type +#- manager_config_patch.yaml diff --git a/config/default/manager_auth_proxy_patch.yaml b/config/default/manager_auth_proxy_patch.yaml new file mode 100644 index 0000000..2173afb --- /dev/null +++ b/config/default/manager_auth_proxy_patch.yaml @@ -0,0 +1,28 @@ +# This patch inject a sidecar container which is a HTTP proxy for the +# controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews. +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + - name: kube-rbac-proxy + image: gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0 + args: + - "--secure-listen-address=0.0.0.0:8443" + - "--upstream=http://127.0.0.1:8080/" + - "--logtostderr=true" + - "--v=10" + ports: + - containerPort: 8443 + protocol: TCP + name: https + - name: manager + args: + - "--health-probe-bind-address=:8081" + - "--metrics-bind-address=127.0.0.1:8080" + - "--leader-elect" + - "--leader-election-id=external-secrets-operator" diff --git a/config/default/manager_config_patch.yaml b/config/default/manager_config_patch.yaml new file mode 100644 index 0000000..6c40015 --- /dev/null +++ b/config/default/manager_config_patch.yaml @@ -0,0 +1,20 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + - name: manager + args: + - "--config=controller_manager_config.yaml" + volumeMounts: + - name: manager-config + mountPath: /controller_manager_config.yaml + subPath: controller_manager_config.yaml + volumes: + - name: manager-config + configMap: + name: manager-config diff --git a/config/default/manager_metrics_patch.yaml b/config/default/manager_metrics_patch.yaml new file mode 100644 index 0000000..20f45ec --- /dev/null +++ b/config/default/manager_metrics_patch.yaml @@ -0,0 +1,20 @@ +# This patch makes operator metrics available at 0.0.0.0:8080 without the usage of a rbac-proxy. +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + - name: manager + args: + - "--health-probe-bind-address=:8081" + - "--metrics-bind-address=0.0.0.0:8080" + - "--leader-elect" + - "--leader-election-id=external-secrets-operator" + ports: + - containerPort: 8080 + protocol: TCP + name: metrics \ No newline at end of file diff --git a/config/manager/controller_manager_config.yaml b/config/manager/controller_manager_config.yaml new file mode 100644 index 0000000..6cdafd1 --- /dev/null +++ b/config/manager/controller_manager_config.yaml @@ -0,0 +1,10 @@ +apiVersion: controller-runtime.sigs.k8s.io/v1alpha1 +kind: ControllerManagerConfig +health: + healthProbeBindAddress: :8081 +metrics: + bindAddress: 127.0.0.1:8080 + +leaderElection: + leaderElect: true + resourceName: 811c9dc5.external-secrets.io diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml new file mode 100644 index 0000000..4d87e17 --- /dev/null +++ b/config/manager/kustomization.yaml @@ -0,0 +1,16 @@ +resources: +- manager.yaml + +generatorOptions: + disableNameSuffixHash: true + +configMapGenerator: +- files: + - controller_manager_config.yaml + name: manager-config +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +images: +- name: controller + newName: quay.io/3scale/external-secrets-operator + newTag: v0.3.8 diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml new file mode 100644 index 0000000..1eaff61 --- /dev/null +++ b/config/manager/manager.yaml @@ -0,0 +1,55 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + control-plane: controller-manager + name: system +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system + labels: + control-plane: controller-manager +spec: + selector: + matchLabels: + control-plane: controller-manager + replicas: 1 + template: + metadata: + labels: + control-plane: controller-manager + spec: + securityContext: + runAsNonRoot: true + containers: + - args: + - --leader-elect + - --leader-election-id=external-secrets-operator + image: controller:latest + name: manager + env: + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.annotations['olm.targetNamespaces'] + securityContext: + allowPrivilegeEscalation: false + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + serviceAccountName: controller-manager + terminationGracePeriodSeconds: 10 diff --git a/config/manifests/bases/external-secrets-operator.clusterserviceversion.yaml b/config/manifests/bases/external-secrets-operator.clusterserviceversion.yaml new file mode 100644 index 0000000..57f51d9 --- /dev/null +++ b/config/manifests/bases/external-secrets-operator.clusterserviceversion.yaml @@ -0,0 +1,124 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + annotations: + alm-examples: '[]' + capabilities: Basic Install + categories: Security + certified: "false" + containerImage: quay.io/3scale/external-secrets-operator + createdAt: "2021-11-22 00:00:00" + description: Operator to configure external-secrets helm-chart based operator + repository: https://github.com/3scale-ops/external-secrets-operator + name: external-secrets-operator.v0.0.0 + namespace: placeholder +spec: + apiservicedefinitions: {} + customresourcedefinitions: + owned: + - description: Configures external-secrets helm-chart based operator + displayName: OperatorConfig + kind: OperatorConfig + name: operatorconfigs.operator.external-secrets.io + version: v1alpha1 + description: | + A Kubernetes Operator based on the Operator SDK (Helm version) to configure **[official external-secrets operator helm chart](https://github.com/external-secrets/external-secrets)**, so it can be installed via OLM without having to do any change on current Helm Charts. + + The usual Helm Chart file `values.yaml`, like: + ```yaml + prometheus: + enabled: true + service: + port: 8080 + resources: + requests: + cpu: 10m + memory: 96Mi + limits: + cpu: 100m + memory: 256Mi + ``` + + Need to be encapsulated into a new custom resource called `OperatorConfig`: + ```yaml + apiVersion: operator.external-secrets.io/v1alpha1 + kind: OperatorConfig + metadata: + name: cluster + spec: + prometheus: + enabled: true + service: + port: 8080 + resources: + requests: + cpu: 10m + memory: 96Mi + limits: + cpu: 100m + memory: 256Mi + ``` + + So the operator will create all helm chart resources, using the custom resource name as a preffix for all resources names, like for example a `Deployment` called `cluster-external-secrets`. + + ## Documentation + + * [Install](docs/install.md) + * [Development](docs/development.md) + * [Release](docs/release.md) + + ## Contributing + + You can contribute by: + + * Raising any issues you find using External Secrets Operator + * Fixing issues by opening [Pull Requests](https://github.com/3scale-ops/external-secrets-operator/pulls) + * Submitting a patch or opening a PR + * Improving documentation + * Talking about External Secrets Operator + + All bugs, tasks or enhancements are tracked as [GitHub issues](https://github.com/3scale-ops/external-secrets-operator/issues). + + ## License + + External Secrets Operator is under Apache 2.0 license. See the [LICENSE](LICENSE) file for details. + displayName: External Secrets Operator + icon: + - base64data: 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 + mediatype: image/png+xml + install: + spec: + deployments: null + strategy: "" + installModes: + - supported: true + type: OwnNamespace + - supported: true + type: SingleNamespace + - supported: true + type: MultiNamespace + - supported: true + type: AllNamespaces + keywords: + - secrets + - secrets-manager + - vault + - aws + - azure + - google + - ibm + - akeyless + - yandex + - gitlab + - oracle + links: + - name: External Secrets Operator + url: https://external-secrets.io + maintainers: + - email: 3scale-operations@redhat.com + name: 3scale Ops + maturity: alpha + provider: + name: Red Hat + url: https://www.redhat.com + version: 0.0.0 diff --git a/config/manifests/kustomization.yaml b/config/manifests/kustomization.yaml new file mode 100644 index 0000000..105fbd1 --- /dev/null +++ b/config/manifests/kustomization.yaml @@ -0,0 +1,7 @@ +# These resources constitute the fully configured set of manifests +# used to generate the 'manifests/' directory in a bundle. +resources: +- bases/external-secrets-operator.clusterserviceversion.yaml +- ../default +- ../samples +- ../scorecard diff --git a/config/prometheus/kustomization.yaml b/config/prometheus/kustomization.yaml new file mode 100644 index 0000000..ed13716 --- /dev/null +++ b/config/prometheus/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- monitor.yaml diff --git a/config/prometheus/monitor.yaml b/config/prometheus/monitor.yaml new file mode 100644 index 0000000..d19136a --- /dev/null +++ b/config/prometheus/monitor.yaml @@ -0,0 +1,20 @@ + +# Prometheus Monitor Service (Metrics) +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + labels: + control-plane: controller-manager + name: controller-manager-metrics-monitor + namespace: system +spec: + endpoints: + - path: /metrics + port: https + scheme: https + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + tlsConfig: + insecureSkipVerify: true + selector: + matchLabels: + control-plane: controller-manager diff --git a/config/rbac/auth_proxy_client_clusterrole.yaml b/config/rbac/auth_proxy_client_clusterrole.yaml new file mode 100644 index 0000000..51a75db --- /dev/null +++ b/config/rbac/auth_proxy_client_clusterrole.yaml @@ -0,0 +1,9 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: metrics-reader +rules: +- nonResourceURLs: + - "/metrics" + verbs: + - get diff --git a/config/rbac/auth_proxy_role.yaml b/config/rbac/auth_proxy_role.yaml new file mode 100644 index 0000000..80e1857 --- /dev/null +++ b/config/rbac/auth_proxy_role.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: proxy-role +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create diff --git a/config/rbac/auth_proxy_role_binding.yaml b/config/rbac/auth_proxy_role_binding.yaml new file mode 100644 index 0000000..ec7acc0 --- /dev/null +++ b/config/rbac/auth_proxy_role_binding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: proxy-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: proxy-role +subjects: +- kind: ServiceAccount + name: controller-manager + namespace: system diff --git a/config/rbac/auth_proxy_service.yaml b/config/rbac/auth_proxy_service.yaml new file mode 100644 index 0000000..71f1797 --- /dev/null +++ b/config/rbac/auth_proxy_service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + control-plane: controller-manager + name: controller-manager-metrics-service + namespace: system +spec: + ports: + - name: https + port: 8443 + protocol: TCP + targetPort: https + selector: + control-plane: controller-manager diff --git a/config/rbac/kustomization.yaml b/config/rbac/kustomization.yaml new file mode 100644 index 0000000..40bc8c2 --- /dev/null +++ b/config/rbac/kustomization.yaml @@ -0,0 +1,18 @@ +resources: +# All RBAC will be applied under this service account in +# the deployment namespace. You may comment out this resource +# if your manager will use a service account that exists at +# runtime. Be sure to update RoleBinding and ClusterRoleBinding +# subjects if changing service account names. +- service_account.yaml +- role.yaml +- role_binding.yaml +- leader_election_role.yaml +- leader_election_role_binding.yaml +# Comment the following 4 lines if you want to disable +# the auth proxy (https://github.com/brancz/kube-rbac-proxy) +# which protects your /metrics endpoint. +#- auth_proxy_service.yaml +#- auth_proxy_role.yaml +#- auth_proxy_role_binding.yaml +#- auth_proxy_client_clusterrole.yaml diff --git a/config/rbac/leader_election_role.yaml b/config/rbac/leader_election_role.yaml new file mode 100644 index 0000000..4190ec8 --- /dev/null +++ b/config/rbac/leader_election_role.yaml @@ -0,0 +1,37 @@ +# permissions to do leader election. +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: leader-election-role +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch diff --git a/config/rbac/leader_election_role_binding.yaml b/config/rbac/leader_election_role_binding.yaml new file mode 100644 index 0000000..1d1321e --- /dev/null +++ b/config/rbac/leader_election_role_binding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: leader-election-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: leader-election-role +subjects: +- kind: ServiceAccount + name: controller-manager + namespace: system diff --git a/config/rbac/operatorconfig_editor_role.yaml b/config/rbac/operatorconfig_editor_role.yaml new file mode 100644 index 0000000..eb0447b --- /dev/null +++ b/config/rbac/operatorconfig_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit operatorconfigs. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: operatorconfig-editor-role +rules: +- apiGroups: + - operator.external-secrets.io + resources: + - operatorconfigs + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - operator.external-secrets.io + resources: + - operatorconfigs/status + verbs: + - get diff --git a/config/rbac/operatorconfig_viewer_role.yaml b/config/rbac/operatorconfig_viewer_role.yaml new file mode 100644 index 0000000..69520a3 --- /dev/null +++ b/config/rbac/operatorconfig_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view operatorconfigs. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: operatorconfig-viewer-role +rules: +- apiGroups: + - operator.external-secrets.io + resources: + - operatorconfigs + verbs: + - get + - list + - watch +- apiGroups: + - operator.external-secrets.io + resources: + - operatorconfigs/status + verbs: + - get diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml new file mode 100644 index 0000000..c86f222 --- /dev/null +++ b/config/rbac/role.yaml @@ -0,0 +1,115 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: manager-role +rules: +## +## Base operator rules +## +# We need to get namespaces so the operator can read namespaces to ensure they exist +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get +# We need to manage Helm release secrets +- apiGroups: + - "" + resources: + - secrets + verbs: + - "*" +# We need to create events on CRs about things happening during reconciliation +- apiGroups: + - "" + resources: + - events + verbs: + - create + +## +## Rules for operator.external-secrets.io/v1alpha1, Kind: OperatorConfig +## +- apiGroups: + - operator.external-secrets.io + resources: + - operatorconfigs + - operatorconfigs/status + - operatorconfigs/finalizers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - pods + - services + - services/finalizers + - endpoints + - persistentvolumeclaims + - events + - configmaps + - secrets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - apps + resources: + - deployments + - daemonsets + - replicasets + - statefulsets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + +## +## Custom rules needed by real helm chart operator to manage all operator resources) +## +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - '*' +- apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterroles + - clusterrolebindings + - roles + - rolebindings + verbs: + - '*' +- apiGroups: + - "" + resources: + - serviceaccounts + - services + verbs: + - '*' +- apiGroups: + - apps + resources: + - deployments + verbs: + - '*' + +#+kubebuilder:scaffold:rules diff --git a/config/rbac/role_binding.yaml b/config/rbac/role_binding.yaml new file mode 100644 index 0000000..2070ede --- /dev/null +++ b/config/rbac/role_binding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: manager-role +subjects: +- kind: ServiceAccount + name: controller-manager + namespace: system diff --git a/config/rbac/service_account.yaml b/config/rbac/service_account.yaml new file mode 100644 index 0000000..7cd6025 --- /dev/null +++ b/config/rbac/service_account.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: controller-manager + namespace: system diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml new file mode 100644 index 0000000..1e277ab --- /dev/null +++ b/config/samples/kustomization.yaml @@ -0,0 +1,4 @@ +## Append samples you want in your CSV to this file as resources ## +resources: +- operator_v1alpha1_operatorconfig.yaml +#+kubebuilder:scaffold:manifestskustomizesamples diff --git a/config/samples/operator_v1alpha1_operatorconfig.yaml b/config/samples/operator_v1alpha1_operatorconfig.yaml new file mode 100644 index 0000000..fb2eda3 --- /dev/null +++ b/config/samples/operator_v1alpha1_operatorconfig.yaml @@ -0,0 +1,40 @@ +apiVersion: operator.external-secrets.io/v1alpha1 +kind: OperatorConfig +metadata: + name: sample +spec: + # Default values copied from /helm-charts/external-secrets/values.yaml + affinity: {} + extraArgs: {} + extraEnv: [] + fullnameOverride: "" + image: + pullPolicy: IfNotPresent + repository: ghcr.io/external-secrets/external-secrets + tag: "" + imagePullSecrets: [] + installCRDs: true + leaderElect: false + nameOverride: "" + nodeSelector: {} + podAnnotations: {} + podLabels: {} + podSecurityContext: {} + priorityClassName: "" + prometheus: + enabled: false + service: + port: 8080 + rbac: + create: true + replicaCount: 1 + resources: {} + scopedNamespace: "" + securityContext: {} + serviceAccount: + annotations: {} + create: true + name: "" + tolerations: [] + + diff --git a/config/scorecard/bases/config.yaml b/config/scorecard/bases/config.yaml new file mode 100644 index 0000000..c770478 --- /dev/null +++ b/config/scorecard/bases/config.yaml @@ -0,0 +1,7 @@ +apiVersion: scorecard.operatorframework.io/v1alpha3 +kind: Configuration +metadata: + name: config +stages: +- parallel: true + tests: [] diff --git a/config/scorecard/kustomization.yaml b/config/scorecard/kustomization.yaml new file mode 100644 index 0000000..50cd2d0 --- /dev/null +++ b/config/scorecard/kustomization.yaml @@ -0,0 +1,16 @@ +resources: +- bases/config.yaml +patchesJson6902: +- path: patches/basic.config.yaml + target: + group: scorecard.operatorframework.io + version: v1alpha3 + kind: Configuration + name: config +- path: patches/olm.config.yaml + target: + group: scorecard.operatorframework.io + version: v1alpha3 + kind: Configuration + name: config +#+kubebuilder:scaffold:patchesJson6902 diff --git a/config/scorecard/patches/basic.config.yaml b/config/scorecard/patches/basic.config.yaml new file mode 100644 index 0000000..c19af06 --- /dev/null +++ b/config/scorecard/patches/basic.config.yaml @@ -0,0 +1,10 @@ +- op: add + path: /stages/0/tests/- + value: + entrypoint: + - scorecard-test + - basic-check-spec + image: quay.io/operator-framework/scorecard-test:v1.15.0 + labels: + suite: basic + test: basic-check-spec-test diff --git a/config/scorecard/patches/olm.config.yaml b/config/scorecard/patches/olm.config.yaml new file mode 100644 index 0000000..0e4888c --- /dev/null +++ b/config/scorecard/patches/olm.config.yaml @@ -0,0 +1,50 @@ +- op: add + path: /stages/0/tests/- + value: + entrypoint: + - scorecard-test + - olm-bundle-validation + image: quay.io/operator-framework/scorecard-test:v1.15.0 + labels: + suite: olm + test: olm-bundle-validation-test +- op: add + path: /stages/0/tests/- + value: + entrypoint: + - scorecard-test + - olm-crds-have-validation + image: quay.io/operator-framework/scorecard-test:v1.15.0 + labels: + suite: olm + test: olm-crds-have-validation-test +- op: add + path: /stages/0/tests/- + value: + entrypoint: + - scorecard-test + - olm-crds-have-resources + image: quay.io/operator-framework/scorecard-test:v1.15.0 + labels: + suite: olm + test: olm-crds-have-resources-test +- op: add + path: /stages/0/tests/- + value: + entrypoint: + - scorecard-test + - olm-spec-descriptors + image: quay.io/operator-framework/scorecard-test:v1.15.0 + labels: + suite: olm + test: olm-spec-descriptors-test +- op: add + path: /stages/0/tests/- + value: + entrypoint: + - scorecard-test + - olm-status-descriptors + image: quay.io/operator-framework/scorecard-test:v1.15.0 + labels: + suite: olm + test: olm-status-descriptors-test diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 0000000..b1fad82 --- /dev/null +++ b/docs/development.md @@ -0,0 +1,11 @@ +# Development + +To run the operator locally without creating any new image: +* You can run the operator locally watching all namespaces (default behaviour): +```bash +make run +``` +* Or watching a specific namespace using envvar `WATCH_NAMESPACE`: +```bash +make run WATCH_NAMESPACE=example +``` \ No newline at end of file diff --git a/docs/install.md b/docs/install.md new file mode 100644 index 0000000..527ccc3 --- /dev/null +++ b/docs/install.md @@ -0,0 +1,68 @@ +# Install + +## Manual deploy +* To manually install the operator (on all its dependant resources) on default namespace `external-secrets-operator-system` without using OLM, you can use the following make target (which uses `kustomize`): +```bash +$ make deploy +``` +* Then create any `OperatorConfig` resource type (you can find an example [here](../config/samples/operator_v1alpha1_operatorconfig.yaml)). +* Once tested, delete created operator resources using the following make target: +```bash +$ make undeploy +``` + +## OLM manual deploy +* If you want to install a specific version of the operator via OLM on a **manual** way, you can use for example the following command: +```bash +operator-sdk run bundle quay.io/3scale/external-secrets-operator-bundle:0.3.8-alpha.3 --namespace external-secrets +``` +* Then create any `OperatorConfig` resource type (you can find an example [here](../config/samples/operator_v1alpha1_operatorconfig.yaml)). +* If you want to test an operator upgrade of a newer version, execute for example: +```bash +operator-sdk run bundle-upgrade quay.io/3scale/external-secrets-operator-bundle:0.3.8-alpha.4 --namespace external-secrets +``` + +## OLM automatic deploy +* If you want to install the operator via OLM on an **automatic** way subscribing to a catalog, you can need to follow the following steps. + +* First you need to deploy an specific `CatalogSource` in which operator releases will be published: +```yaml +apiVersion: operators.coreos.com/v1alpha1 +kind: CatalogSource +metadata: + name: external-secrets-operator-catalog + namespace: external-secrets +spec: + sourceType: grpc + image: quay.io/3scale/external-secrets-operator-catalog:latest + displayName: External Secrets Operator + updateStrategy: + registryPoll: + interval: 30m +``` +* Then you need to create an `OperatorGroup`, so you set the target namespaces in which the external-secrets-operator will watch for `OperatorConfig` custom resources (so it will be set operator ENVVAR `WATCH_NAMESPACE`): +```yaml +apiVersion: operators.coreos.com/v1alpha2 +kind: OperatorGroup +metadata: + name: external-secrets + namespace: external-secrets +spec: + targetNamespaces: + - external-secrets +``` +* Finally create an operator `Subscription` on a given channel (`alpha`/`stable`) with `Automatic`/`Manual` installation (with `Manual` it will ask you confirmation to install an operator upgrade): +```yaml +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: external-secrets-operator + namespace: external-secrets +spec: + channel: alpha + installPlanApproval: Automatic + name: external-secrets-operator + source: external-secrets-operator-catalog + sourceNamespace: external-secrets +``` +* Now you can create any `OperatorConfig` resource type (you can find an example [here](../config/samples/operator_v1alpha1_operatorconfig.yaml)). \ No newline at end of file diff --git a/docs/release.md b/docs/release.md new file mode 100644 index 0000000..0c508c6 --- /dev/null +++ b/docs/release.md @@ -0,0 +1,25 @@ +# Release +* Update Makefile variable `VERSION` to the appropiate release version. Allowed formats: + * alpha: `VERSION ?= 0.3.8-alpha.3` - Used for operator development before doing a final release + * stable: `VERSION ?= 0.3.8` - Used once alpha releases have been tested successfully +* **IMPORTANT**: `VERSION` (having the `-alpha` suffix or not, **must coincide with the original helm chart release**, because it is used to download the original helm chart from [Git Hub](https://github.com/external-secrets/external-secrets/releases) + + +## Alpha +* If it is an **alpha** release, execute the following target to create appropiate `alpha` bundle files: +```bash +make prepare-alpha-release +``` +* Then you can manually execute opetator, bundle and catalog build/push: +```bash +make docker-build +make docker-push +make bundle-publish +``` + +## Stable +* But if it is an **stable** release, execute the following target to create appropiate `alpha` and `stable` bundle files: +```bash +make prepare-stable-release +``` +* Then open a [Pull Request](https://github.com/3scale-ops/external-secrets-operator/pulls), and a GitHub Action will automatically detect if it is new release or not, in order to create it by building/pushing new operator, bundle and catalog images, as well as creating a GitHub release draft. \ No newline at end of file diff --git a/hack/download-helm-chart.sh b/hack/download-helm-chart.sh new file mode 100755 index 0000000..a2c087c --- /dev/null +++ b/hack/download-helm-chart.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +REPO="https://github.com/external-secrets/external-secrets" +HELM_CHART_PATH="helm-charts/external-secrets" +HELM_CHART_VERSION=`echo ${1} | awk '{split($0,a,"-alpha"); print a[1]}'` + +EXISTS=`grep -ir ${HELM_CHART_VERSION} ${HELM_CHART_PATH}/Chart.yaml | wc -l` + +if [ ${EXISTS} -ge 1 ]; then + echo "Helm chart version ${HELM_CHART_VERSION} already exists, doing nothing" +else + echo "Helm chart version ${HELM_CHART_VERSION} does not exists, downloading into ${HELM_CHART_PATH}/" + rm -rf ${HELM_CHART_PATH}/* + curl -sL ${REPO}/releases/download/helm-chart-${HELM_CHART_VERSION}/external-secrets-${HELM_CHART_VERSION}.tgz | tar xz -C helm-charts/ +fi \ No newline at end of file diff --git a/hack/new-release.sh b/hack/new-release.sh new file mode 100755 index 0000000..d3e9958 --- /dev/null +++ b/hack/new-release.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +REPO="3scale-ops/external-secrets-operator" + +# Skip if alpha release +[[ ${1} == *"-alpha"* ]] && echo "" && exit 0 + +# Skip if release already exists +curl -o /dev/null --fail --silent "https://api.github.com/repos/${REPO}/releases/tags/${1}" && echo "" && exit 0 + +echo ${1} \ No newline at end of file diff --git a/helm-charts/external-secrets/.empty b/helm-charts/external-secrets/.empty new file mode 100644 index 0000000..3e2ace3 --- /dev/null +++ b/helm-charts/external-secrets/.empty @@ -0,0 +1 @@ +The content of this directory will be created dynamically on every operator docker-build diff --git a/kuttl-test.yaml b/kuttl-test.yaml new file mode 100644 index 0000000..ef35043 --- /dev/null +++ b/kuttl-test.yaml @@ -0,0 +1,5 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestSuite +timeout: 120 +testDirs: +- ./test/e2e/ \ No newline at end of file diff --git a/test/e2e/operator/00-assert.yaml b/test/e2e/operator/00-assert.yaml new file mode 100644 index 0000000..4e8eac5 --- /dev/null +++ b/test/e2e/operator/00-assert.yaml @@ -0,0 +1,24 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: external-secrets-operator-manager-role +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: external-secrets-operator-manager-rolebinding +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: external-secrets-operator-controller-manager + namespace: external-secrets-operator-system +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: external-secrets-operator-controller-manager + namespace: external-secrets-operator-system +status: + readyReplicas: 1 \ No newline at end of file diff --git a/test/e2e/operatorconfig/01-assert.yaml b/test/e2e/operatorconfig/01-assert.yaml new file mode 100644 index 0000000..7f1ac88 --- /dev/null +++ b/test/e2e/operatorconfig/01-assert.yaml @@ -0,0 +1,39 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: secretstores.external-secrets.io +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: clustersecretstores.external-secrets.io +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: externalsecrets.external-secrets.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: instance-external-secrets-controller +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: instance-external-secrets-controller +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: instance-external-secrets + namespace: external-secrets-operator-system +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: instance-external-secrets + namespace: external-secrets-operator-system +status: + readyReplicas: 1 \ No newline at end of file diff --git a/test/e2e/operatorconfig/01-operatorconfig.yaml b/test/e2e/operatorconfig/01-operatorconfig.yaml new file mode 100644 index 0000000..6f696c1 --- /dev/null +++ b/test/e2e/operatorconfig/01-operatorconfig.yaml @@ -0,0 +1,6 @@ +apiVersion: operator.external-secrets.io/v1alpha1 +kind: OperatorConfig +metadata: + name: instance + namespace: external-secrets-operator-system +spec: {} \ No newline at end of file diff --git a/watches.yaml b/watches.yaml new file mode 100644 index 0000000..49987cc --- /dev/null +++ b/watches.yaml @@ -0,0 +1,6 @@ +# Use the 'create api' subcommand to add watches to this file. +- group: operator.external-secrets.io + version: v1alpha1 + kind: OperatorConfig + chart: helm-charts/external-secrets +#+kubebuilder:scaffold:watch