From 9fba152fd2c8dc837adecb907179b94af90ca9be Mon Sep 17 00:00:00 2001 From: Arthur Date: Tue, 13 Feb 2024 22:17:40 -0500 Subject: [PATCH] feat: External Secrets Operator Incept --- .../external-secrets-operator.yaml | 22 ++ .../argocd/applications/kustomization.yaml | 1 + .../external-secrets-operator/README.md | 9 + .../base/installplan-approver.yaml | 250 ++++++++++++++++++ .../base/kustomization.yaml | 9 + .../base/kyverno.yaml | 22 ++ .../base/namespace.yaml | 9 + .../base/operator-config.yaml | 80 ++++++ .../base/operator-group.yaml | 7 + .../base/subscription.yaml | 14 + .../overlays/okd/kustomization.yaml | 4 + 11 files changed, 427 insertions(+) create mode 100644 kubernetes/argocd/applications/external-secrets-operator.yaml create mode 100644 kubernetes/external-secrets-operator/README.md create mode 100644 kubernetes/external-secrets-operator/base/installplan-approver.yaml create mode 100644 kubernetes/external-secrets-operator/base/kustomization.yaml create mode 100644 kubernetes/external-secrets-operator/base/kyverno.yaml create mode 100644 kubernetes/external-secrets-operator/base/namespace.yaml create mode 100644 kubernetes/external-secrets-operator/base/operator-config.yaml create mode 100644 kubernetes/external-secrets-operator/base/operator-group.yaml create mode 100644 kubernetes/external-secrets-operator/base/subscription.yaml create mode 100644 kubernetes/external-secrets-operator/overlays/okd/kustomization.yaml diff --git a/kubernetes/argocd/applications/external-secrets-operator.yaml b/kubernetes/argocd/applications/external-secrets-operator.yaml new file mode 100644 index 000000000..873391eeb --- /dev/null +++ b/kubernetes/argocd/applications/external-secrets-operator.yaml @@ -0,0 +1,22 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: external-secrets-operator + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "1" + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + labels: + app.kubernetes.io/instance: argocd +spec: + destination: + namespace: external-secrets-operator + server: https://kubernetes.default.svc + project: default + source: + path: kubernetes/external-secrets-operator/okd + repoURL: https://git.arthurvardevanyan.com/ArthurVardevanyan/HomeLab + targetRevision: HEAD + syncPolicy: + syncOptions: + - CreateNamespace=true diff --git a/kubernetes/argocd/applications/kustomization.yaml b/kubernetes/argocd/applications/kustomization.yaml index 925b98733..c87b806c6 100644 --- a/kubernetes/argocd/applications/kustomization.yaml +++ b/kubernetes/argocd/applications/kustomization.yaml @@ -8,6 +8,7 @@ resources: - container-security-operator.yaml - dragonfly-operator.yaml - eclipse-che-operator.yaml + - external-secrets-operator.yaml - gitea.yaml - grafana.yaml - heimdall.yaml diff --git a/kubernetes/external-secrets-operator/README.md b/kubernetes/external-secrets-operator/README.md new file mode 100644 index 000000000..eefc00f07 --- /dev/null +++ b/kubernetes/external-secrets-operator/README.md @@ -0,0 +1,9 @@ +# External Secrets Operator + +```bash +kubectl kustomize kubernetes/external-secrets-operator/overlays/okd | kubectl apply -f - +``` + +## REF + +- diff --git a/kubernetes/external-secrets-operator/base/installplan-approver.yaml b/kubernetes/external-secrets-operator/base/installplan-approver.yaml new file mode 100644 index 000000000..8e70656dc --- /dev/null +++ b/kubernetes/external-secrets-operator/base/installplan-approver.yaml @@ -0,0 +1,250 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: installplan-approvers + namespace: external-secrets-operator + labels: + app.kubernetes.io/instance: external-secrets-operator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: installplan-approver +subjects: + - kind: ServiceAccount + name: installplan-approver-job +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: installplan-approver-job + namespace: external-secrets-operator + labels: + app.kubernetes.io/instance: external-secrets-operator +--- +kind: Job +apiVersion: batch/v1 +metadata: + name: installplan-approver-external-secrets-operator + namespace: external-secrets-operator + annotations: + argocd.argoproj.io/hook: Sync + argocd.argoproj.io/hook-delete-policy: HookSucceeded + argocd.argoproj.io/sync-wave: "1" + checkov.io/skip1: CKV_K8S_38=Need to Approve Install Plans + checkov.io/skip2: CKV_K8S_40=OpenShift Injects Random UID + checkov.io/skip3: CKV_K8S_43=Don't Mind Tag for This + labels: + app.kubernetes.io/instance: external-secrets-operator +spec: + parallelism: 1 + backoffLimit: 0 + ttlSecondsAfterFinished: 500 + completionMode: NonIndexed + suspend: false + template: + metadata: + labels: + app: installplan-approver + spec: + restartPolicy: OnFailure + activeDeadlineSeconds: 300 + serviceAccountName: installplan-approver-job + automountServiceAccountToken: true + enableServiceLinks: true + terminationGracePeriodSeconds: 30 + securityContext: + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + dnsPolicy: ClusterFirst + containers: + - name: installplan-approver + imagePullPolicy: IfNotPresent + image: registry./homelab/toolbox:not_latest + env: + - name: SUBSCRIPTION + value: external-secrets-operator + - name: SLEEP + value: "15" + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + securityContext: + runAsNonRoot: true + privileged: false + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + seccompProfile: + type: RuntimeDefault + capabilities: + drop: + - ALL + resources: + requests: + cpu: 10m + memory: 32Mi + limits: + cpu: 100m + memory: 64Mi + command: + - /bin/bash + - -c + - | + set -o errexit # exit on any failure + set -o nounset # exit on undeclared variables + set -o pipefail # return value of all commands in a pipe + + echo "Approving Operator Install. Waiting a few seconds to make sure the InstallPlan gets Created First." + sleep "${SLEEP}" + + echo "Processing subscription '${SUBSCRIPTION}'" + export INSTALL_PLAN + export STARTING_CSV + export INSTALL_PLAN_VERSION + export INSTALL_CSV + + INSTALLED_CSV=$(kubectl -n "${NAMESPACE}" get subscriptions.operators.coreos.com --field-selector metadata.name="${SUBSCRIPTION}" -o jsonpath='{.items[0].status.installedCSV}') + STARTING_CSV=$(kubectl -n "${NAMESPACE}" get subscriptions.operators.coreos.com --field-selector metadata.name="${SUBSCRIPTION}" -o jsonpath='{.items[0].spec.startingCSV}') + echo Installed CSV: "${INSTALLED_CSV}" + echo Starting CSV: "${STARTING_CSV}" + + # If Installed (Current) Version equals Starting (Target) Version then Exit + if [[ "${INSTALLED_CSV}" == "${STARTING_CSV}" ]]; then + echo "Installed CSV and Starting CSV Identical, Exiting" + exit 0 + fi + + INSTALL_PLAN=$(kubectl -n "${NAMESPACE}" get subscriptions.operators.coreos.com --field-selector metadata.name="${SUBSCRIPTION}" -o jsonpath='{.items[0].status.installPlanRef.name}') + INSTALL_PLAN_VERSION=$(kubectl -n "${NAMESPACE}" get installplan "${INSTALL_PLAN}" -o jsonpath="{.spec.clusterServiceVersionNames}") + echo Install Plan CSV: "${INSTALL_PLAN_VERSION}" + echo Starting CSV: "${STARTING_CSV}" + + # Check if Install Plan Version Matches Target Version, if not Exit. + # Common Cause is due to attempting to skip multiple versions + if [[ "${INSTALL_PLAN_VERSION}" != *"${STARTING_CSV}"* ]]; then + echo "Install Plan Does Not Match Desired Version, Manual Intervention Might be Required" + exit 1 + fi + + # Approve Install Plan if Not Approved + if [[ "$(kubectl -n "${NAMESPACE}" get installplan "${INSTALL_PLAN}" -o jsonpath="{.spec.approved}")" == "false" ]]; then + echo "Approving Subscription ${SUBSCRIPTION} with install plan $INSTALL_PLAN" + kubectl -n "${NAMESPACE}" patch installplan "${INSTALL_PLAN}" --type=json -p='[{"op":"replace","path": "/spec/approved", "value": true}]' + else + echo "Install Plan '$INSTALL_PLAN' already approved" + fi +--- +kind: Job +apiVersion: batch/v1 +metadata: + name: installplan-approver-devworkspace-operator + namespace: external-secrets-operator + annotations: + argocd.argoproj.io/hook: Sync + argocd.argoproj.io/hook-delete-policy: HookSucceeded + argocd.argoproj.io/sync-wave: "1" + checkov.io/skip1: CKV_K8S_38=Need to Approve Install Plans + checkov.io/skip2: CKV_K8S_40=OpenShift Injects Random UID + checkov.io/skip3: CKV_K8S_43=Don't Mind Tag for This + labels: + app.kubernetes.io/instance: external-secrets-operator +spec: + parallelism: 1 + backoffLimit: 0 + ttlSecondsAfterFinished: 500 + completionMode: NonIndexed + suspend: false + template: + metadata: + labels: + app: installplan-approver + spec: + restartPolicy: OnFailure + activeDeadlineSeconds: 300 + serviceAccountName: installplan-approver-job + automountServiceAccountToken: true + enableServiceLinks: true + terminationGracePeriodSeconds: 30 + securityContext: + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + dnsPolicy: ClusterFirst + containers: + - name: installplan-approver + imagePullPolicy: IfNotPresent + image: registry./homelab/toolbox:not_latest + env: + - name: SUBSCRIPTION + value: devworkspace-operator + - name: SLEEP + value: "15" + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + securityContext: + runAsNonRoot: true + privileged: false + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + seccompProfile: + type: RuntimeDefault + capabilities: + drop: + - ALL + resources: + requests: + cpu: 10m + memory: 32Mi + limits: + cpu: 100m + memory: 64Mi + command: + - /bin/bash + - -c + - | + set -o errexit # exit on any failure + set -o nounset # exit on undeclared variables + set -o pipefail # return value of all commands in a pipe + + echo "Approving Operator Install. Waiting a few seconds to make sure the InstallPlan gets Created First." + sleep "${SLEEP}" + + echo "Processing subscription '${SUBSCRIPTION}'" + export INSTALL_PLAN + export STARTING_CSV + export INSTALL_PLAN_VERSION + export INSTALL_CSV + + INSTALLED_CSV=$(kubectl -n "${NAMESPACE}" get subscriptions.operators.coreos.com --field-selector metadata.name="${SUBSCRIPTION}" -o jsonpath='{.items[0].status.installedCSV}') + STARTING_CSV=$(kubectl -n "${NAMESPACE}" get subscriptions.operators.coreos.com --field-selector metadata.name="${SUBSCRIPTION}" -o jsonpath='{.items[0].spec.startingCSV}') + echo Installed CSV: "${INSTALLED_CSV}" + echo Starting CSV: "${STARTING_CSV}" + + # If Installed (Current) Version equals Starting (Target) Version then Exit + if [[ "${INSTALLED_CSV}" == "${STARTING_CSV}" ]]; then + echo "Installed CSV and Starting CSV Identical, Exiting" + exit 0 + fi + + INSTALL_PLAN=$(kubectl -n "${NAMESPACE}" get subscriptions.operators.coreos.com --field-selector metadata.name="${SUBSCRIPTION}" -o jsonpath='{.items[0].status.installPlanRef.name}') + INSTALL_PLAN_VERSION=$(kubectl -n "${NAMESPACE}" get installplan "${INSTALL_PLAN}" -o jsonpath="{.spec.clusterServiceVersionNames}") + echo Install Plan CSV: "${INSTALL_PLAN_VERSION}" + echo Starting CSV: "${STARTING_CSV}" + + # Check if Install Plan Version Matches Target Version, if not Exit. + # Common Cause is due to attempting to skip multiple versions + if [[ "${INSTALL_PLAN_VERSION}" != *"${STARTING_CSV}"* ]]; then + echo "Install Plan Does Not Match Desired Version, Manual Intervention Might be Required" + exit 1 + fi + + # Approve Install Plan if Not Approved + if [[ "$(kubectl -n "${NAMESPACE}" get installplan "${INSTALL_PLAN}" -o jsonpath="{.spec.approved}")" == "false" ]]; then + echo "Approving Subscription ${SUBSCRIPTION} with install plan $INSTALL_PLAN" + kubectl -n "${NAMESPACE}" patch installplan "${INSTALL_PLAN}" --type=json -p='[{"op":"replace","path": "/spec/approved", "value": true}]' + else + echo "Install Plan '$INSTALL_PLAN' already approved" + fi diff --git a/kubernetes/external-secrets-operator/base/kustomization.yaml b/kubernetes/external-secrets-operator/base/kustomization.yaml new file mode 100644 index 000000000..08badb3b4 --- /dev/null +++ b/kubernetes/external-secrets-operator/base/kustomization.yaml @@ -0,0 +1,9 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ./installplan-approver.yaml + - ./kyverno.yaml + - ./namespace.yaml + - ./operator-config.yaml + - ./operator-group.yaml + - ./subscription.yaml diff --git a/kubernetes/external-secrets-operator/base/kyverno.yaml b/kubernetes/external-secrets-operator/base/kyverno.yaml new file mode 100644 index 000000000..df55dc543 --- /dev/null +++ b/kubernetes/external-secrets-operator/base/kyverno.yaml @@ -0,0 +1,22 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: replace-external-secrets-operator + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + argocd.argoproj.io/sync-wave: "1" +spec: + background: false + rules: + - name: replace-external-secrets-operator + match: + any: + - resources: + kinds: + - Pod + mutate: + patchStrategicMerge: + spec: + containers: + - (image): "ghcr.io/external-secrets/external-secrets-helm-operator@sha256:8792003c97d3982ad246cf6a43103d8968cd04fd126a719bc5ee49ea6248ecb3" + image: "ghcr.io/external-secrets/external-secrets-helm-operator@sha256:fb433d368f2f91efc1f637de80d670445a76a3577a7c9835f8fc9ad8bc630376" diff --git a/kubernetes/external-secrets-operator/base/namespace.yaml b/kubernetes/external-secrets-operator/base/namespace.yaml new file mode 100644 index 000000000..5529a9421 --- /dev/null +++ b/kubernetes/external-secrets-operator/base/namespace.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Namespace +metadata: + annotations: + argocd.argoproj.io/sync-wave: "0" + labels: + app.kubernetes.io/instance: external-secrets-operator + kubernetes.io/metadata.name: external-secrets-operator + name: external-secrets-operator diff --git a/kubernetes/external-secrets-operator/base/operator-config.yaml b/kubernetes/external-secrets-operator/base/operator-config.yaml new file mode 100644 index 000000000..2f738a624 --- /dev/null +++ b/kubernetes/external-secrets-operator/base/operator-config.yaml @@ -0,0 +1,80 @@ +apiVersion: operator.external-secrets.io/v1alpha1 +kind: OperatorConfig +metadata: + annotations: + operator-sdk/primary-resource: /externalsecret-validate + operator-sdk/primary-resource-type: ValidatingWebhookConfiguration.admissionregistration.k8s.io + argocd.argoproj.io/sync-wave: "2" + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + name: external + namespace: external-secrets-operator +spec: + certController: + create: true + fullnameOverride: "" + image: + pullPolicy: IfNotPresent + repository: ghcr.io/external-secrets/external-secrets + tag: v0.9.11@sha256:5660a29f1bfbf3666ebd99f692cea46fb12fa209db4fa460a97fd8c00f991671 + nameOverride: "" + priorityClassName: "" + prometheus: + enabled: false + service: + port: 8080 + rbac: + create: true + requeueInterval: 5m + serviceAccount: + create: true + name: "" + concurrent: 1 + controllerClass: "" + crds: + createClusterExternalSecret: true + createClusterSecretStore: true + createOperator: true + fullnameOverride: "" + image: + pullPolicy: IfNotPresent + repository: ghcr.io/external-secrets/external-secrets + tag: v0.9.11@sha256:5660a29f1bfbf3666ebd99f692cea46fb12fa209db4fa460a97fd8c00f991671 + installCRDs: false + leaderElect: false + nameOverride: "" + priorityClassName: "" + processClusterExternalSecret: true + processClusterStore: true + prometheus: + enabled: false + service: + port: 8080 + rbac: + create: true + replicaCount: 2 + scopedNamespace: "" + scopedRBAC: false + serviceAccount: + create: true + name: "" + webhook: + certCheckInterval: 5m + certDir: /tmp/certs + create: true + fullnameOverride: "" + image: + pullPolicy: IfNotPresent + repository: ghcr.io/external-secrets/external-secrets + tag: v0.9.11@sha256:5660a29f1bfbf3666ebd99f692cea46fb12fa209db4fa460a97fd8c00f991671 + nameOverride: "" + priorityClassName: "" + prometheus: + enabled: false + service: + port: 8080 + rbac: + create: true + replicaCount: 2 + serviceAccount: + create: true + name: "" diff --git a/kubernetes/external-secrets-operator/base/operator-group.yaml b/kubernetes/external-secrets-operator/base/operator-group.yaml new file mode 100644 index 000000000..450befe18 --- /dev/null +++ b/kubernetes/external-secrets-operator/base/operator-group.yaml @@ -0,0 +1,7 @@ +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: external-secrets-operator + namespace: external-secrets-operator +spec: + upgradeStrategy: Default diff --git a/kubernetes/external-secrets-operator/base/subscription.yaml b/kubernetes/external-secrets-operator/base/subscription.yaml new file mode 100644 index 000000000..071fd74b8 --- /dev/null +++ b/kubernetes/external-secrets-operator/base/subscription.yaml @@ -0,0 +1,14 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: external-secrets-operator + namespace: external-secrets-operator + annotations: + argocd.argoproj.io/sync-wave: "1" +spec: + channel: alpha + installPlanApproval: Manual + name: external-secrets-operator + source: community-operators + sourceNamespace: openshift-marketplace + startingCSV: external-secrets-operator.v0.9.11 diff --git a/kubernetes/external-secrets-operator/overlays/okd/kustomization.yaml b/kubernetes/external-secrets-operator/overlays/okd/kustomization.yaml new file mode 100644 index 000000000..2333422e2 --- /dev/null +++ b/kubernetes/external-secrets-operator/overlays/okd/kustomization.yaml @@ -0,0 +1,4 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ../../base