From 4769301f4bbe4d5d763efe4b387c4b16b4871221 Mon Sep 17 00:00:00 2001 From: ruromero Date: Mon, 3 Oct 2022 10:19:56 +0200 Subject: [PATCH 1/4] delete common before adding it again Signed-off-by: ruromero --- common/.ansible-lint | 3 - common/.github/linters/.markdown-lint.yml | 6 - common/.github/workflows/ansible-lint.yml | 18 - common/.github/workflows/linter.yml | 64 - common/.github/workflows/superlinter.yml | 38 - common/.gitignore | 9 - common/LICENSE | 202 - common/Makefile | 101 - common/README.md | 18 - common/acm/.helmignore | 1 - common/acm/Chart.yaml | 6 - common/acm/templates/multiclusterhub.yaml | 8 - .../policies/application-policies.yaml | 124 - .../templates/policies/ocp-gitops-policy.yaml | 76 - .../templates/provision/_install-config.tpl | 59 - .../acm/templates/provision/clusterpool.yaml | 83 - .../acm/templates/provision/secrets-aws.yaml | 84 - .../templates/provision/secrets-azure.yaml | 83 - .../templates/provision/secrets-common.yaml | 60 - common/acm/test.yaml | 35 - common/acm/values.yaml | 26 - common/ansible/ansible.cfg | 4 - .../ansible/playbooks/vault/push_secrets.yaml | 10 - common/ansible/playbooks/vault/vault.yaml | 7 - common/ansible/roles/vault_utils/README.md | 79 - .../roles/vault_utils/defaults/main.yml | 26 - .../roles/vault_utils/handlers/main.yml | 2 - .../ansible/roles/vault_utils/meta/main.yml | 31 - .../ansible/roles/vault_utils/tasks/main.yml | 20 - .../roles/vault_utils/tasks/pre_check.yaml | 26 - .../roles/vault_utils/tasks/push_secrets.yaml | 208 - .../roles/vault_utils/tasks/vault_delete.yaml | 23 - .../roles/vault_utils/tasks/vault_init.yaml | 85 - .../vault_utils/tasks/vault_pki_init.yaml | 50 - .../vault_utils/tasks/vault_secrets_init.yaml | 80 - .../roles/vault_utils/tasks/vault_status.yaml | 61 - .../roles/vault_utils/tasks/vault_unseal.yaml | 116 - .../ansible/roles/vault_utils/tests/inventory | 2 - .../ansible/roles/vault_utils/tests/test.yml | 5 - .../ansible/roles/vault_utils/vars/main.yml | 2 - common/clustergroup/.helmignore | 1 - common/clustergroup/Chart.yaml | 6 - .../clustergroup/templates/applications.yaml | 207 - .../templates/argocd-super-role.yaml | 41 - common/clustergroup/templates/argocd.yaml | 123 - .../templates/catalog-sources.yaml | 10 - .../templates/cluster-external-secrets.yaml | 51 - .../templates/gitops-namespace.yaml | 11 - .../templates/imperative/_helpers.tpl | 38 - .../templates/imperative/clusterrole.yaml | 22 - .../templates/imperative/configmap.yaml | 13 - .../templates/imperative/job.yaml | 67 - .../templates/imperative/namespace.yaml | 11 - .../templates/imperative/rbac.yaml | 31 - .../templates/imperative/role.yaml | 21 - .../templates/imperative/serviceaccount.yaml | 11 - .../templates/imperative/unsealjob.yaml | 59 - common/clustergroup/templates/namespaces.yaml | 11 - .../clustergroup/templates/operatorgroup.yaml | 25 - common/clustergroup/templates/projects.yaml | 22 - .../clustergroup/templates/subscriptions.yaml | 67 - common/clustergroup/test.yaml | 104 - common/clustergroup/values.yaml | 86 - common/common | 1 - common/examples/blank/Chart.yaml | 6 - common/examples/blank/templates/manifest.yaml | 4 - common/examples/blank/values.yaml | 2 - common/examples/kustomize-renderer/Chart.yaml | 6 - .../kustomize-renderer/environment.yaml | 34 - .../kustomize-renderer/kustomization.yaml | 5 - common/examples/kustomize-renderer/kustomize | 15 - .../templates/environment.yaml | 34 - .../examples/kustomize-renderer/values.yaml | 12 - common/examples/values-example.yaml | 78 - common/examples/values-secret.yaml | 32 - common/golang-external-secrets/Chart.yaml | 11 - .../charts/external-secrets-0.5.9.tgz | Bin 40987 -> 0 bytes ...ternal-secrets-hub-clusterrolebinding.yaml | 23 - ...lang-external-secrets-hub-secretstore.yaml | 25 - common/golang-external-secrets/values.yaml | 6 - common/hashicorp-vault/Chart.yaml | 10 - common/hashicorp-vault/README.md | 12 - .../hashicorp-vault/charts/vault-0.22.0.tgz | Bin 51863 -> 0 bytes .../hashicorp-vault/patch-server-route.diff | 28 - .../hashicorp-vault/templates/vault-app.yaml | 12 - .../hashicorp-vault/update-helm-dependency.sh | 26 - common/hashicorp-vault/values.yaml | 20 - common/install/.helmignore | 1 - common/install/Chart.yaml | 6 - .../crds/applications.argoproj.io.yaml | 2312 ------- .../install/templates/argocd/application.yaml | 37 - .../install/templates/argocd/namespace.yaml | 6 - .../templates/argocd/subscription.yaml | 20 - common/install/values.yaml | 25 - common/operator-install/Chart.yaml | 6 - ...ops.hybrid-cloud-patterns.io_patterns.yaml | 157 - .../operator-install/templates/pattern.yaml | 12 - .../templates/subscription.yaml | 13 - common/operator-install/values.yaml | 9 - common/reference-output.yaml | 119 - common/scripts/make_common_subtree.sh | 76 - common/scripts/pattern-util.sh | 20 - common/scripts/test.sh | 50 - common/scripts/vault-utils.sh | 30 - common/tests/acm-naked.expected.yaml | 93 - common/tests/acm-normal.expected.yaml | 204 - common/tests/clustergroup-naked.expected.yaml | 182 - .../tests/clustergroup-normal.expected.yaml | 802 --- .../tests/examples-blank-naked.expected.yaml | 6 - .../tests/examples-blank-normal.expected.yaml | 6 - ...les-kustomize-renderer-naked.expected.yaml | 36 - ...es-kustomize-renderer-normal.expected.yaml | 36 - ...olang-external-secrets-naked.expected.yaml | 5911 ----------------- ...lang-external-secrets-normal.expected.yaml | 5911 ----------------- .../tests/hashicorp-vault-naked.expected.yaml | 409 -- .../hashicorp-vault-normal.expected.yaml | 409 -- common/tests/install-naked.expected.yaml | 64 - common/tests/install-normal.expected.yaml | 64 - .../operator-install-naked.expected.yaml | 29 - .../operator-install-normal.expected.yaml | 29 - common/values-global.yaml | 16 - 121 files changed, 20487 deletions(-) delete mode 100644 common/.ansible-lint delete mode 100644 common/.github/linters/.markdown-lint.yml delete mode 100644 common/.github/workflows/ansible-lint.yml delete mode 100644 common/.github/workflows/linter.yml delete mode 100644 common/.github/workflows/superlinter.yml delete mode 100644 common/.gitignore delete mode 100644 common/LICENSE delete mode 100644 common/Makefile delete mode 100644 common/README.md delete mode 100644 common/acm/.helmignore delete mode 100644 common/acm/Chart.yaml delete mode 100644 common/acm/templates/multiclusterhub.yaml delete mode 100644 common/acm/templates/policies/application-policies.yaml delete mode 100644 common/acm/templates/policies/ocp-gitops-policy.yaml delete mode 100644 common/acm/templates/provision/_install-config.tpl delete mode 100644 common/acm/templates/provision/clusterpool.yaml delete mode 100644 common/acm/templates/provision/secrets-aws.yaml delete mode 100644 common/acm/templates/provision/secrets-azure.yaml delete mode 100644 common/acm/templates/provision/secrets-common.yaml delete mode 100644 common/acm/test.yaml delete mode 100644 common/acm/values.yaml delete mode 100644 common/ansible/ansible.cfg delete mode 100644 common/ansible/playbooks/vault/push_secrets.yaml delete mode 100644 common/ansible/playbooks/vault/vault.yaml delete mode 100644 common/ansible/roles/vault_utils/README.md delete mode 100644 common/ansible/roles/vault_utils/defaults/main.yml delete mode 100644 common/ansible/roles/vault_utils/handlers/main.yml delete mode 100644 common/ansible/roles/vault_utils/meta/main.yml delete mode 100644 common/ansible/roles/vault_utils/tasks/main.yml delete mode 100644 common/ansible/roles/vault_utils/tasks/pre_check.yaml delete mode 100644 common/ansible/roles/vault_utils/tasks/push_secrets.yaml delete mode 100644 common/ansible/roles/vault_utils/tasks/vault_delete.yaml delete mode 100644 common/ansible/roles/vault_utils/tasks/vault_init.yaml delete mode 100644 common/ansible/roles/vault_utils/tasks/vault_pki_init.yaml delete mode 100644 common/ansible/roles/vault_utils/tasks/vault_secrets_init.yaml delete mode 100644 common/ansible/roles/vault_utils/tasks/vault_status.yaml delete mode 100644 common/ansible/roles/vault_utils/tasks/vault_unseal.yaml delete mode 100644 common/ansible/roles/vault_utils/tests/inventory delete mode 100644 common/ansible/roles/vault_utils/tests/test.yml delete mode 100644 common/ansible/roles/vault_utils/vars/main.yml delete mode 100644 common/clustergroup/.helmignore delete mode 100644 common/clustergroup/Chart.yaml delete mode 100644 common/clustergroup/templates/applications.yaml delete mode 100644 common/clustergroup/templates/argocd-super-role.yaml delete mode 100644 common/clustergroup/templates/argocd.yaml delete mode 100644 common/clustergroup/templates/catalog-sources.yaml delete mode 100644 common/clustergroup/templates/cluster-external-secrets.yaml delete mode 100644 common/clustergroup/templates/gitops-namespace.yaml delete mode 100644 common/clustergroup/templates/imperative/_helpers.tpl delete mode 100644 common/clustergroup/templates/imperative/clusterrole.yaml delete mode 100644 common/clustergroup/templates/imperative/configmap.yaml delete mode 100644 common/clustergroup/templates/imperative/job.yaml delete mode 100644 common/clustergroup/templates/imperative/namespace.yaml delete mode 100644 common/clustergroup/templates/imperative/rbac.yaml delete mode 100644 common/clustergroup/templates/imperative/role.yaml delete mode 100644 common/clustergroup/templates/imperative/serviceaccount.yaml delete mode 100644 common/clustergroup/templates/imperative/unsealjob.yaml delete mode 100644 common/clustergroup/templates/namespaces.yaml delete mode 100644 common/clustergroup/templates/operatorgroup.yaml delete mode 100644 common/clustergroup/templates/projects.yaml delete mode 100644 common/clustergroup/templates/subscriptions.yaml delete mode 100644 common/clustergroup/test.yaml delete mode 100644 common/clustergroup/values.yaml delete mode 120000 common/common delete mode 100644 common/examples/blank/Chart.yaml delete mode 100644 common/examples/blank/templates/manifest.yaml delete mode 100644 common/examples/blank/values.yaml delete mode 100644 common/examples/kustomize-renderer/Chart.yaml delete mode 100644 common/examples/kustomize-renderer/environment.yaml delete mode 100644 common/examples/kustomize-renderer/kustomization.yaml delete mode 100755 common/examples/kustomize-renderer/kustomize delete mode 100644 common/examples/kustomize-renderer/templates/environment.yaml delete mode 100644 common/examples/kustomize-renderer/values.yaml delete mode 100644 common/examples/values-example.yaml delete mode 100644 common/examples/values-secret.yaml delete mode 100644 common/golang-external-secrets/Chart.yaml delete mode 100644 common/golang-external-secrets/charts/external-secrets-0.5.9.tgz delete mode 100644 common/golang-external-secrets/templates/golang-external-secrets-hub-clusterrolebinding.yaml delete mode 100644 common/golang-external-secrets/templates/golang-external-secrets-hub-secretstore.yaml delete mode 100644 common/golang-external-secrets/values.yaml delete mode 100644 common/hashicorp-vault/Chart.yaml delete mode 100644 common/hashicorp-vault/README.md delete mode 100644 common/hashicorp-vault/charts/vault-0.22.0.tgz delete mode 100644 common/hashicorp-vault/patch-server-route.diff delete mode 100644 common/hashicorp-vault/templates/vault-app.yaml delete mode 100755 common/hashicorp-vault/update-helm-dependency.sh delete mode 100644 common/hashicorp-vault/values.yaml delete mode 100644 common/install/.helmignore delete mode 100644 common/install/Chart.yaml delete mode 100644 common/install/crds/applications.argoproj.io.yaml delete mode 100644 common/install/templates/argocd/application.yaml delete mode 100644 common/install/templates/argocd/namespace.yaml delete mode 100644 common/install/templates/argocd/subscription.yaml delete mode 100644 common/install/values.yaml delete mode 100644 common/operator-install/Chart.yaml delete mode 100644 common/operator-install/crds/gitops.hybrid-cloud-patterns.io_patterns.yaml delete mode 100644 common/operator-install/templates/pattern.yaml delete mode 100644 common/operator-install/templates/subscription.yaml delete mode 100644 common/operator-install/values.yaml delete mode 100644 common/reference-output.yaml delete mode 100755 common/scripts/make_common_subtree.sh delete mode 100755 common/scripts/pattern-util.sh delete mode 100755 common/scripts/test.sh delete mode 100755 common/scripts/vault-utils.sh delete mode 100644 common/tests/acm-naked.expected.yaml delete mode 100644 common/tests/acm-normal.expected.yaml delete mode 100644 common/tests/clustergroup-naked.expected.yaml delete mode 100644 common/tests/clustergroup-normal.expected.yaml delete mode 100644 common/tests/examples-blank-naked.expected.yaml delete mode 100644 common/tests/examples-blank-normal.expected.yaml delete mode 100644 common/tests/examples-kustomize-renderer-naked.expected.yaml delete mode 100644 common/tests/examples-kustomize-renderer-normal.expected.yaml delete mode 100644 common/tests/golang-external-secrets-naked.expected.yaml delete mode 100644 common/tests/golang-external-secrets-normal.expected.yaml delete mode 100644 common/tests/hashicorp-vault-naked.expected.yaml delete mode 100644 common/tests/hashicorp-vault-normal.expected.yaml delete mode 100644 common/tests/install-naked.expected.yaml delete mode 100644 common/tests/install-normal.expected.yaml delete mode 100644 common/tests/operator-install-naked.expected.yaml delete mode 100644 common/tests/operator-install-normal.expected.yaml delete mode 100644 common/values-global.yaml diff --git a/common/.ansible-lint b/common/.ansible-lint deleted file mode 100644 index 138ae765..00000000 --- a/common/.ansible-lint +++ /dev/null @@ -1,3 +0,0 @@ -# Vim filetype=yaml ---- -offline: false diff --git a/common/.github/linters/.markdown-lint.yml b/common/.github/linters/.markdown-lint.yml deleted file mode 100644 index a0bc47d1..00000000 --- a/common/.github/linters/.markdown-lint.yml +++ /dev/null @@ -1,6 +0,0 @@ -{ - "default": true, - "MD003": false, - "MD013": false, - "MD033": false -} \ No newline at end of file diff --git a/common/.github/workflows/ansible-lint.yml b/common/.github/workflows/ansible-lint.yml deleted file mode 100644 index f0943b53..00000000 --- a/common/.github/workflows/ansible-lint.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Ansible Lint # feel free to pick your own name - -on: [push, pull_request] - -jobs: - build: - runs-on: ubuntu-latest - - steps: - # Important: This sets up your GITHUB_WORKSPACE environment variable - - uses: actions/checkout@v2 - - - name: Lint Ansible Playbook - # Using the latest as of today (2022-06-23) v6.2.1 - uses: ansible/ansible-lint-action@v6.2.1 - # Let's point it to the path - with: - path: "ansible/" diff --git a/common/.github/workflows/linter.yml b/common/.github/workflows/linter.yml deleted file mode 100644 index 81eee65b..00000000 --- a/common/.github/workflows/linter.yml +++ /dev/null @@ -1,64 +0,0 @@ ---- -name: Unit test common - -# -# Documentation: -# https://help.github.com/en/articles/workflow-syntax-for-github-actions -# - -############################# -# Start the job on all push # -############################# -on: [push, pull_request] - -############### -# Set the Job # -############### -jobs: - build: - # Name the Job - name: Unit common/ Code Base - # Set the agent to run on - runs-on: ubuntu-latest - - ################## - # Load all steps # - ################## - steps: - ########################## - # Checkout the code base # - ########################## - - name: Checkout Code - uses: actions/checkout@v2 - with: - # Full git history is needed to get a proper list of changed files within `super-linter` - fetch-depth: 0 - - name: Setup helm - uses: azure/setup-helm@v1 - # with: - # version: '' # default is latest stable - id: install - - ################################ - # Run Linter against code base # - ################################ - # - name: Lint Code Base - # uses: github/super-linter@v4 - # env: - # VALIDATE_ALL_CODEBASE: false - # DEFAULT_BRANCH: main - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Run make test - run: | - make test - - - name: Run make helmlint - run: | - make helmlint - - - name: Run make helm kubeconform - run: | - curl -L -O https://github.com/yannh/kubeconform/releases/download/v0.4.13/kubeconform-linux-amd64.tar.gz - tar xf kubeconform-linux-amd64.tar.gz - sudo mv -v kubeconform /usr/local/bin - make kubeconform diff --git a/common/.github/workflows/superlinter.yml b/common/.github/workflows/superlinter.yml deleted file mode 100644 index 0141598c..00000000 --- a/common/.github/workflows/superlinter.yml +++ /dev/null @@ -1,38 +0,0 @@ ---- -name: Super linter - -on: [push, pull_request] - -jobs: - build: - # Name the Job - name: Super linter - # Set the agent to run on - runs-on: ubuntu-latest - - steps: - - name: Checkout Code - uses: actions/checkout@v2 - with: - # Full git history is needed to get a proper list of changed files within `super-linter` - fetch-depth: 0 - - ################################ - # Run Linter against code base # - ################################ - - name: Lint Code Base - uses: github/super-linter/slim@v4 - env: - VALIDATE_ALL_CODEBASE: true - DEFAULT_BRANCH: main - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # These are the validation we disable atm - VALIDATE_BASH: false - VALIDATE_JSCPD: false - VALIDATE_KUBERNETES_KUBEVAL: false - VALIDATE_YAML: false - # VALIDATE_ANSIBLE: false - # VALIDATE_DOCKERFILE_HADOLINT: false - # VALIDATE_MARKDOWN: false - # VALIDATE_NATURAL_LANGUAGE: false - # VALIDATE_TEKTON: false diff --git a/common/.gitignore b/common/.gitignore deleted file mode 100644 index fd2282bc..00000000 --- a/common/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -*~ -*.swp -*.swo -values-secret.yaml -.*.expected.yaml -pattern-vault.init -pattern-vault.init.bak -super-linter.log -golang-external-secrets/Chart.lock diff --git a/common/LICENSE b/common/LICENSE deleted file mode 100644 index d6456956..00000000 --- a/common/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/common/Makefile b/common/Makefile deleted file mode 100644 index 3f371774..00000000 --- a/common/Makefile +++ /dev/null @@ -1,101 +0,0 @@ -NAME=$(shell basename `pwd`) -# This is to ensure that whether we start with a git@ or https:// URL, we end up with an https:// URL -# This is because we expect to use tokens for repo authentication as opposed to SSH keys -TARGET_ORIGIN ?= origin -TARGET_REPO=$(shell git remote show $(TARGET_ORIGIN) | grep Push | sed -e 's/.*URL:[[:space:]]*//' -e 's%^git@%%' -e 's%^https://%%' -e 's%:%/%' -e 's%^%https://%') -# git branch --show-current is also available as of git 2.22, but we will use this for compatibility -TARGET_BRANCH=$(shell git rev-parse --abbrev-ref HEAD) -HUBCLUSTER_APPS_DOMAIN=$(shell oc get ingresses.config/cluster -o jsonpath={.spec.domain}) - -# --set values always take precedence over the contents of -f -HELM_OPTS=-f values-global.yaml --set main.git.repoURL="$(TARGET_REPO)" --set main.git.revision=$(TARGET_BRANCH) \ - --set global.hubClusterDomain=$(HUBCLUSTER_APPS_DOMAIN) -TEST_OPTS= -f common/examples/values-secret.yaml -f values-global.yaml --set global.repoURL="https://github.com/pattern-clone/mypattern" \ - --set main.git.repoURL="https://github.com/pattern-clone/mypattern" --set main.git.revision=main --set global.pattern="mypattern" \ - --set global.namespace="pattern-namespace" --set global.hubClusterDomain=hub.example.com --set global.localClusterDomain=region.example.com \ - --set "clusterGroup.imperative.jobs[0].name"="test" --set "clusterGroup.imperative.jobs[0].playbook"="ansible/test.yml" \ - --set clusterGroup.insecureUnsealVaultInsideCluster=true -PATTERN_OPTS=-f common/examples/values-example.yaml -EXECUTABLES=git helm oc ansible - -.PHONY: help -help: ## This help message - @printf "$$(grep -hE '^\S+:.*##' $(MAKEFILE_LIST) | sed -e 's/:.*##\s*/:/' -e 's/^\(.\+\):\(.*\)/\\x1b[36m\1\\x1b[m:\2/' | column -c2 -t -s :)\n" - -# Makefiles in the individual patterns should call these targets explicitly -# e.g. from industrial-edge: make -f common/Makefile show -show: ## show the starting template without installing it - helm template common/install/ --name-template $(NAME) $(HELM_OPTS) - -CHARTS=$(shell find . -type f -iname 'Chart.yaml' -exec dirname "{}" \; | sed -e 's/.\///') -test: ## run helm tests -# Test that all values used by the chart are in values.yaml with the same defaults as the pattern - @for t in $(CHARTS); do common/scripts/test.sh $$t naked ""; if [ $$? != 0 ]; then exit 1; fi; done -# Test the charts as the pattern would drive them - @for t in $(CHARTS); do common/scripts/test.sh $$t normal "$(TEST_OPTS) $(PATTERN_OPTS)"; if [ $$? != 0 ]; then exit 1; fi; done - -helmlint: ## run helm lint - @for t in $(CHARTS); do helm lint $(TEST_OPTS) $(PATTERN_OPTS) $$t; if [ $$? != 0 ]; then exit 1; fi; done - -API_URL ?= https://raw.githubusercontent.com/hybrid-cloud-patterns/ocp-schemas/main/openshift/4.10/ -KUBECONFORM_SKIP ?= -skip 'CustomResourceDefinition' -# We need to skip 'CustomResourceDefinition' as openapi2jsonschema seems to be unable to generate them ATM -kubeconform: ## run helm kubeconform - @for t in $(CHARTS); do helm template $(TEST_OPTS) $(PATTERN_OPTS) $$t | kubeconform -strict $(KUBECONFORM_SKIP) -verbose -schema-location $(API_URL); if [ $$? != 0 ]; then exit 1; fi; done - -validate-prereq: ## verify pre-requisites - @for t in $(EXECUTABLES); do if ! which $$t > /dev/null 2>&1; then echo "No $$t in PATH"; exit 1; fi; done - @echo "Prerequisites checked '$(EXECUTABLES)': OK" - @ansible -m ansible.builtin.command -a "{{ ansible_python_interpreter }} -c 'import kubernetes'" localhost > /dev/null 2>&1 - @echo "Python kubernetes module: OK" - @echo -n "Check for kubernetes.core collection: " - @if ! ansible-galaxy collection list | grep kubernetes.core > /dev/null 2>&1; then echo "Not found"; exit 1; fi - @echo "OK" - -validate-origin: ## verify the git origin is available - @echo Checking repo $(TARGET_REPO) - branch $(TARGET_BRANCH) - @git ls-remote --exit-code --heads $(TARGET_REPO) $(TARGET_BRANCH) >/dev/null && \ - echo "$(TARGET_REPO) - $(TARGET_BRANCH) exists" || \ - (echo "$(TARGET_BRANCH) not found in $(TARGET_REPO)"; exit 1) - -# Default targets are "deploy" and "upgrade"; they can "move" to whichever install mechanism should be default. -# legacy-deploy and legacy-upgrade should be present so that patterns don't need to depend on "deploy" and "upgrade" -# pointing to one place or another, and don't need to change when they do (provide they use either legacy- or operator- -# targets) -deploy upgrade legacy-deploy legacy-upgrade: validate-prereq validate-origin ## deploys the pattern - helm upgrade --install $(NAME) common/install/ $(HELM_OPTS) - -operator-deploy operator-upgrade: validate-origin ## runs helm install - helm upgrade --install $(NAME) common/operator-install/ $(HELM_OPTS) - -uninstall: ## runs helm uninstall - $(eval CSV := $(shell oc get subscriptions -n openshift-operators openshift-gitops-operator -ojsonpath={.status.currentCSV})) - helm uninstall $(NAME) - @oc delete csv -n openshift-operators $(CSV) - -vault-init: ## inits, unseals and configured the vault - common/scripts/vault-utils.sh vault_init common/pattern-vault.init - common/scripts/vault-utils.sh vault_unseal common/pattern-vault.init - common/scripts/vault-utils.sh vault_secrets_init common/pattern-vault.init - -vault-unseal: ## unseals the vault - common/scripts/vault-utils.sh vault_unseal common/pattern-vault.init - -load-secrets: ## loads the secrets into the vault - common/scripts/vault-utils.sh push_secrets common/pattern-vault.init - -super-linter: ## Runs super linter locally - podman run -e RUN_LOCAL=true -e USE_FIND_ALGORITHM=true \ - -e VALIDATE_BASH=false \ - -e VALIDATE_JSCPD=false \ - -e VALIDATE_KUBERNETES_KUBEVAL=false \ - -e VALIDATE_YAML=false \ - -e VALIDATE_ANSIBLE=false \ - $(DISABLE_LINTERS) \ - -v $(PWD):/tmp/lint:rw,z docker.io/github/super-linter:slim-v4 - -ansible-lint: ## run ansible lint on ansible/ folder - podman run -it -v $(PWD):/workspace:rw,z --workdir /workspace --entrypoint "/usr/local/bin/ansible-lint" quay.io/ansible/creator-ee:latest "-vvv" "ansible/" - -.phony: install test - diff --git a/common/README.md b/common/README.md deleted file mode 100644 index 9c6fa0cb..00000000 --- a/common/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Validated Patterns common/ repository - -[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) - -## Start Here - -This repository is never used as standalone. It is usually imported in each pattern as a subtree. -In order to import the common/ the very first time you can use -`https://github.com/hybrid-cloud-patterns/multicloud-gitops/blob/main/common/scripts/make_common_subtree.sh` - -In order to update your common subtree inside your pattern repository you can either use -`https://github.com/hybrid-cloud-patterns/utilities/blob/main/scripts/update-common-everywhere.sh` or -do it manually by doing the following: - -```sh -git remote add -f upstream-common https://github.com/hybrid-cloud-patterns/common.git -git merge -s subtree -Xtheirs -Xsubtree=common upstream-common/ha-vault -``` diff --git a/common/acm/.helmignore b/common/acm/.helmignore deleted file mode 100644 index b25c15b8..00000000 --- a/common/acm/.helmignore +++ /dev/null @@ -1 +0,0 @@ -*~ diff --git a/common/acm/Chart.yaml b/common/acm/Chart.yaml deleted file mode 100644 index 1c3db911..00000000 --- a/common/acm/Chart.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v2 -description: A Helm chart to configure Advanced Cluster Manager for OpenShift -keywords: -- pattern -name: acm -version: 0.0.1 diff --git a/common/acm/templates/multiclusterhub.yaml b/common/acm/templates/multiclusterhub.yaml deleted file mode 100644 index f925d5a6..00000000 --- a/common/acm/templates/multiclusterhub.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: operator.open-cluster-management.io/v1 -kind: MultiClusterHub -metadata: - name: multiclusterhub - namespace: open-cluster-management - annotations: - argocd.argoproj.io/sync-wave: "-1" -spec: {} diff --git a/common/acm/templates/policies/application-policies.yaml b/common/acm/templates/policies/application-policies.yaml deleted file mode 100644 index dd9a4658..00000000 --- a/common/acm/templates/policies/application-policies.yaml +++ /dev/null @@ -1,124 +0,0 @@ -# TODO: Also create a GitOpsCluster.apps.open-cluster-management.io -{{- range .Values.clusterGroup.managedClusterGroups }} -{{- $group := . }} -apiVersion: policy.open-cluster-management.io/v1 -kind: Policy -metadata: - name: {{ .name }}-clustergroup-policy - annotations: - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true - argocd.argoproj.io/compare-options: IgnoreExtraneous -spec: - remediationAction: enforce - disabled: false - policy-templates: - - objectDefinition: - apiVersion: policy.open-cluster-management.io/v1 - kind: ConfigurationPolicy - metadata: - name: {{ .name }}-clustergroup-config - spec: - remediationAction: enforce - severity: medium - namespaceSelector: - include: - - default - object-templates: - - complianceType: mustonlyhave - objectDefinition: - apiVersion: argoproj.io/v1alpha1 - kind: Application - metadata: - name: {{ $.Values.global.pattern }}-{{ .name }} - namespace: openshift-gitops - finalizers: - - resources-finalizer.argocd.argoproj.io/foreground - spec: - project: default - source: - repoURL: {{ coalesce .repoURL $.Values.global.repoURL }} - targetRevision: {{ coalesce .targetRevision $.Values.global.targetRevision }} - path: {{ default "common/clustergroup" .path }} - helm: - ignoreMissingValueFiles: true - valueFiles: - - "/values-global.yaml" - - "/values-{{ .name }}.yaml" - {{- range $valueFile := .extraValueFiles }} - - {{ $valueFile | quote }} - {{- end }} - parameters: - - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL - - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION - - name: global.namespace - value: $ARGOCD_APP_NAMESPACE - - name: global.pattern - value: {{ $.Values.global.pattern }} - - name: global.hubClusterDomain - value: {{ $.Values.global.hubClusterDomain }} - - name: global.localClusterDomain - value: '{{ `{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain }}` }}' - {{- range .helmOverrides }} - - name: {{ .name }} - value: {{ .value | quote }} - {{- end }} - {{- if .fileParameters }} - fileParameters: - {{- range .fileParameters }} - - name: {{ .name }} - path: {{ .path }} - {{- end }} - {{- end }} - destination: - server: https://kubernetes.default.svc - namespace: {{ $.Values.global.pattern }}-{{ .name }} - syncPolicy: - automated: - prune: false - selfHeal: true - ignoreDifferences: - - group: apps - kind: Deployment - jsonPointers: - - /spec/replicas - - group: route.openshift.io - kind: Route - jsonPointers: - - /status ---- -apiVersion: policy.open-cluster-management.io/v1 -kind: PlacementBinding -metadata: - name: {{ .name }}-placement-binding - annotations: - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true -placementRef: - name: {{ .name }}-placement - kind: PlacementRule - apiGroup: apps.open-cluster-management.io -subjects: - - name: {{ .name }}-clustergroup-policy - kind: Policy - apiGroup: policy.open-cluster-management.io ---- -apiVersion: apps.open-cluster-management.io/v1 -kind: PlacementRule -metadata: - name: {{ .name }}-placement -spec: - clusterConditions: - - status: 'True' - type: ManagedClusterConditionAvailable - {{- if .clusterSelector }} - clusterSelector: {{ .clusterSelector | toPrettyJson }} - {{- else }} - clusterSelector: - matchLabels: - {{- range .labels }} - {{ .name }}: {{ .value }} - {{- end }} - {{- end }} ---- -{{- end }} diff --git a/common/acm/templates/policies/ocp-gitops-policy.yaml b/common/acm/templates/policies/ocp-gitops-policy.yaml deleted file mode 100644 index 7ca61b0f..00000000 --- a/common/acm/templates/policies/ocp-gitops-policy.yaml +++ /dev/null @@ -1,76 +0,0 @@ -apiVersion: policy.open-cluster-management.io/v1 -kind: Policy -metadata: - name: openshift-gitops-policy - annotations: - policy.open-cluster-management.io/standards: NIST-CSF - policy.open-cluster-management.io/categories: PR.DS Data Security - policy.open-cluster-management.io/controls: PR.DS-1 Data-at-rest - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true - argocd.argoproj.io/compare-options: IgnoreExtraneous -spec: - remediationAction: enforce - disabled: false - policy-templates: - - objectDefinition: - apiVersion: policy.open-cluster-management.io/v1 - kind: ConfigurationPolicy - metadata: - name: openshift-gitops-config - spec: - remediationAction: enforce - severity: medium - namespaceSelector: - include: - - default - object-templates: - - complianceType: mustonlyhave - objectDefinition: - # This is an auto-generated file. DO NOT EDIT - apiVersion: operators.coreos.com/v1alpha1 - kind: Subscription - metadata: - name: openshift-gitops-operator - namespace: openshift-operators - labels: - operators.coreos.com/openshift-gitops-operator.openshift-operators: '' - spec: - channel: stable - installPlanApproval: Automatic - name: openshift-gitops-operator - source: redhat-operators - sourceNamespace: openshift-marketplace - config: - env: - - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES - value: "*" ---- -apiVersion: policy.open-cluster-management.io/v1 -kind: PlacementBinding -metadata: - name: openshift-gitops-placement-binding - annotations: - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true -placementRef: - name: openshift-gitops-placement - kind: PlacementRule - apiGroup: apps.open-cluster-management.io -subjects: - - name: openshift-gitops-policy - kind: Policy - apiGroup: policy.open-cluster-management.io ---- -apiVersion: apps.open-cluster-management.io/v1 -kind: PlacementRule -metadata: - name: openshift-gitops-placement -spec: - clusterConditions: - - status: 'True' - type: ManagedClusterConditionAvailable - clusterSelector: - matchExpressions: - - key: vendor - operator: In - values: - - OpenShift diff --git a/common/acm/templates/provision/_install-config.tpl b/common/acm/templates/provision/_install-config.tpl deleted file mode 100644 index 39aa03eb..00000000 --- a/common/acm/templates/provision/_install-config.tpl +++ /dev/null @@ -1,59 +0,0 @@ -{{- define "cluster.install-config" -}} - -{{- $type := "None" }} -{{- $cloud := "None" }} -{{- $region := "None" }} - -{{- if .platform.aws }} -{{- $cloud = "aws" }} -{{- $region = .platform.aws.region }} -{{- $type = "m5.xlarge" }} -{{- else if .platform.azure }} -{{- $cloud = "azure" }} -{{- $region = .platform.azure.region }} -{{- $type = "Standard_D8s_v3" }} -{{- end }} - -apiVersion: v1 -metadata: - name: '{{ .name }}' -baseDomain: {{ .baseDomain }} -controlPlane: - architecture: amd64 - hyperthreading: Enabled - name: controlPlane - {{- if .controlPlane }} - replicas: {{ default 3 .controlPlane.count }} - platform: {{- .controlPlane.platform | toPrettyJson }} - {{- else }} - replicas: 3 - platform: - {{ $cloud }}: - type: {{ $type }} - {{- end }} -compute: -- hyperthreading: Enabled - architecture: amd64 - name: 'worker' - {{- if .workers }} - replicas: {{ default 3 .workers.count }} - platform: {{- .workers.platform | toPrettyJson }} - {{- else }} - replicas: 3 - platform: - {{ $cloud }}: - type: {{ $type }} - {{- end }} -networking: - clusterNetwork: - - cidr: 10.128.0.0/14 - hostPrefix: 23 - machineNetwork: - - cidr: 10.0.0.0/16 - networkType: OpenShiftSDN - serviceNetwork: - - 172.30.0.0/16 -platform: {{ .platform | toPrettyJson }} -pullSecret: "" # skip, hive will inject based on it's secrets -sshKey: "" # skip, hive will inject based on it's secrets -{{- end -}} \ No newline at end of file diff --git a/common/acm/templates/provision/clusterpool.yaml b/common/acm/templates/provision/clusterpool.yaml deleted file mode 100644 index b8cf1ade..00000000 --- a/common/acm/templates/provision/clusterpool.yaml +++ /dev/null @@ -1,83 +0,0 @@ -{{- range .Values.clusterGroup.managedClusterGroups }} -{{- $group := . }} -{{- if .clusterPools }}{{- /* We only create ManagedClusterSets if there are clusterPools defined */}} -apiVersion: cluster.open-cluster-management.io/v1beta1 -kind: ManagedClusterSet -metadata: - annotations: - cluster.open-cluster-management.io/submariner-broker-ns: {{ .name }}-broker - name: {{ .name }} -spec: - clusterSelector: - selectorType: LegacyClusterSetLabel ---- -{{- range .clusterPools }} - -{{- $pool := . }} -{{- $poolName := cat .name $group.name | replace " " "-" }} - -{{- $cloud := "None" }} -{{- $region := "None" }} - -{{- if .platform.aws }} -{{- $cloud = "aws" }} -{{- $region = .platform.aws.region }} -{{- else if .platform.azure }} -{{- $cloud = "azure" }} -{{- $region = .platform.azure.region }} -{{- end }} - -apiVersion: hive.openshift.io/v1 -kind: ClusterPool -metadata: - name: "{{ $poolName }}" - annotations: - argocd.argoproj.io/sync-wave: "10" - labels: - cloud: {{ $cloud }} - region: '{{ $region }}' - vendor: OpenShift - cluster.open-cluster-management.io/clusterset: {{ .name }} -spec: - {{- if .size }} - size: {{ .size }} - {{- else }} - size: {{ len .clusters }} - {{- end }} - runningCount: {{ len .clusters }} - baseDomain: {{ .baseDomain }} - installConfigSecretTemplateRef: - name: {{ $poolName }}-install-config - imageSetRef: - name: img{{ .openshiftVersion }}-x86-64-appsub - pullSecretRef: - name: {{ $poolName }}-pull-secret - sshPrivateKeySecretRef: - name: {{ $poolName }}-ssh-private-key - skipMachinePools: true # Disable MachinePool as using custom install-config - platform: - {{ $cloud }}: - credentialsSecretRef: - name: {{ $poolName }}-creds - region: {{ $region }} ---- -{{- range .clusters }} -apiVersion: hive.openshift.io/v1 -kind: ClusterClaim -metadata: - name: '{{ . }}-{{ $group.name }}' - annotations: - argocd.argoproj.io/sync-wave: "20" - cluster.open-cluster-management.io/createmanagedcluster: "true" - labels: - clusterClaimName: {{ . }}-{{ $group.name }} - {{- range $group.labels }} - {{ .name }}: {{ .value }} - {{- end }} -spec: - clusterPoolName: {{ $pool.name }} ---- -{{- end }}{{- /* range .range clusters */}} -{{- end }}{{- /* range .clusterPools */}} -{{- end }}{{- /* if .clusterPools) */}} -{{- end }}{{- /* range .Values.clusterGroup.managedClusterGroups */}} diff --git a/common/acm/templates/provision/secrets-aws.yaml b/common/acm/templates/provision/secrets-aws.yaml deleted file mode 100644 index 99022df6..00000000 --- a/common/acm/templates/provision/secrets-aws.yaml +++ /dev/null @@ -1,84 +0,0 @@ -{{- range .Values.clusterGroup.managedClusterGroups }} -{{- $group := . }} -{{- range .clusterPools }} -{{- $poolName := cat .name $group.name | replace " " "-" }} -{{- if .platform.aws }} -apiVersion: external-secrets.io/v1beta1 -kind: ExternalSecret -metadata: - name: {{ $poolName }}-creds -spec: - dataFrom: - - extract: - # Expects entries called: aws_access_key_id and aws_secret_access_key - key: {{ default "secret/data/hub/aws" .awsKeyPath }} - refreshInterval: 24h0m0s - secretStoreRef: - name: {{ $.Values.secretStore.name }} - kind: {{ $.Values.secretStore.kind }} - target: - name: {{ $poolName }}-creds - creationPolicy: Owner - template: - type: Opaque ---- -# For use when manually creating clusters with ACM -apiVersion: external-secrets.io/v1beta1 -kind: ExternalSecret -metadata: - name: {{ $poolName }}-infra-creds -spec: - data: - - secretKey: openshiftPullSecret - remoteRef: - key: {{ default "secret/data/hub/openshiftPullSecret" .pullSecretKeyPath }} - property: content - - secretKey: awsKeyId - remoteRef: - key: {{ default "secret/data/hub/aws" .awsKeyPath }} - property: aws_access_key_id - - secretKey: awsAccessKey - remoteRef: - key: {{ default "secret/data/hub/aws" .awsKeyPath }} - property: aws_secret_access_key - - secretKey: sshPublicKey - remoteRef: - key: {{ default "secret/data/hub/publickey" .sshPublicKeyPath }} - property: content - - secretKey: sshPrivateKey - remoteRef: - key: {{ default "secret/data/hub/privatekey" .sshPrivateKeyPath }} - property: content - refreshInterval: 24h0m0s - secretStoreRef: - name: {{ $.Values.secretStore.name }} - kind: {{ $.Values.secretStore.kind }} - target: - name: {{ $poolName }}-infra-creds - creationPolicy: Owner - template: - type: Opaque - metadata: - labels: - cluster.open-cluster-management.io/credentials: "" - cluster.open-cluster-management.io/type: aws - data: - baseDomain: "{{ .baseDomain }}" - pullSecret: |- - {{ "{{ .openshiftPullSecret | toString }}" }} - aws_access_key_id: |- - {{ "{{ .awsKeyId | toString }}" }} - aws_secret_access_key: |- - {{ "{{ .awsAccessKey | toString }}" }} - ssh-privatekey: |- - {{ "{{ .sshPrivateKey | toString }}" }} - ssh-publickey: |- - {{ "{{ .sshPublicKey | toString }}" }} - httpProxy: "" - httpsProxy: "" - noProxy: "" - additionalTrustBundle: "" ---- -{{- end }} -{{- end }} -{{- end }} \ No newline at end of file diff --git a/common/acm/templates/provision/secrets-azure.yaml b/common/acm/templates/provision/secrets-azure.yaml deleted file mode 100644 index 66b470c1..00000000 --- a/common/acm/templates/provision/secrets-azure.yaml +++ /dev/null @@ -1,83 +0,0 @@ -{{- range .Values.clusterGroup.managedClusterGroups }} -{{- $group := . }} -{{- range .clusterPools }} -{{- $poolName := cat .name $group.name | replace " " "-" }} -{{- if .platform.azure }} -apiVersion: external-secrets.io/v1beta1 -kind: ExternalSecret -metadata: - name: {{ $poolName }}-creds -spec: - data: - - secretKey: azureOsServicePrincipal - remoteRef: - key: {{ default "secret/data/hub/azureOsServicePrincipal" .azureKeyPath }} - property: content - refreshInterval: 24h0m0s - secretStoreRef: - name: {{ $.Values.secretStore.name }} - kind: {{ $.Values.secretStore.kind }} - target: - name: {{ $poolName }}-creds - creationPolicy: Owner - template: - type: Opaque - data: - osServicePrincipal.json: |- - {{ "{{ .azureOsServicePrincipal | toString }}" }} ---- -# For use when manually creating clusters with ACM -apiVersion: external-secrets.io/v1beta1 -kind: ExternalSecret -metadata: - name: {{ $poolName }}-infra-creds -spec: - data: - - secretKey: openshiftPullSecret - remoteRef: - key: {{ default "secret/data/hub/openshiftPullSecret" .pullSecretKeyPath }} - property: content - - secretKey: sshPublicKey - remoteRef: - key: {{ default "secret/data/hub/publickey" .sshPublicKeyPath }} - property: content - - secretKey: sshPrivateKey - remoteRef: - key: {{ default "secret/data/hub/privatekey" .sshPrivateKeyPath }} - property: content - - secretKey: azureOsServicePrincipal - remoteRef: - key: {{ default "secret/data/hub/azureOsServicePrincipal" .azureKeyPath }} - property: content - refreshInterval: 24h0m0s - secretStoreRef: - name: {{ $.Values.secretStore.name }} - kind: {{ $.Values.secretStore.kind }} - target: - name: {{ $poolName }}-infra-creds - creationPolicy: Owner - template: - type: Opaque - metadata: - labels: - cluster.open-cluster-management.io/credentials: "" - cluster.open-cluster-management.io/type: aws - data: - cloudName: AzurePublicCloud - osServicePrincipal.json: |- - {{ "{{ .azureOsServicePrincipal | toString }}" }} - baseDomain: "{{ .baseDomain }}" - baseDomainResourceGroupName: "{{ .platform.azure.baseDomainResourceGroupName | toString }}" - pullSecret: |- - {{ "{{ .openshiftPullSecret | toString }}" }} - ssh-privatekey: |- - {{ "{{ .sshPrivateKey | toString }}" }} - ssh-publickey: |- - {{ "{{ .sshPublicKey | toString }}" }} - httpProxy: "" - httpsProxy: "" - noProxy: "" - additionalTrustBundle: "" -{{- end }} -{{- end }} -{{- end }} \ No newline at end of file diff --git a/common/acm/templates/provision/secrets-common.yaml b/common/acm/templates/provision/secrets-common.yaml deleted file mode 100644 index 62641dde..00000000 --- a/common/acm/templates/provision/secrets-common.yaml +++ /dev/null @@ -1,60 +0,0 @@ -{{- range .Values.clusterGroup.managedClusterGroups }} -{{- $group := . }} -{{- range .clusterPools }} -{{- $poolName := cat .name $group.name | replace " " "-" }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ $poolName }}-install-config -data: - # Base64 encoding of install-config yaml - install-config.yaml: {{ include "cluster.install-config" . | b64enc }} -type: Opaque ---- -apiVersion: external-secrets.io/v1beta1 -kind: ExternalSecret -metadata: - name: {{ $poolName }}-pull-secret -spec: - data: - - secretKey: openshiftPullSecret - remoteRef: - key: {{ default "secret/data/hub/openshiftPullSecret" .pullSecretKeyPath }} - property: content - refreshInterval: 24h0m0s - secretStoreRef: - name: {{ $.Values.secretStore.name }} - kind: {{ $.Values.secretStore.kind }} - target: - name: {{ $poolName }}-pull-secret - creationPolicy: Owner - template: - type: kubernetes.io/dockerconfigjson - data: - .dockerconfigjson: |- - {{ "{{ .openshiftPullSecret | toString }}" }} ---- -apiVersion: external-secrets.io/v1beta1 -kind: ExternalSecret -metadata: - name: {{ $poolName }}-ssh-private-key -spec: - data: - - secretKey: sshPrivateKey - remoteRef: - key: {{ default "secret/data/hub/privatekey" .sshPrivateKeyPath }} - property: content - refreshInterval: 24h0m0s - secretStoreRef: - name: {{ $.Values.secretStore.name }} - kind: {{ $.Values.secretStore.kind }} - target: - name: {{ $poolName }}-ssh-private-key - creationPolicy: Owner - template: - type: Opaque - data: - ssh-privatekey: |- - {{ "{{ .sshPrivateKey | toString }}" }} -{{- end }} -{{- end }} \ No newline at end of file diff --git a/common/acm/test.yaml b/common/acm/test.yaml deleted file mode 100644 index 225f4bf8..00000000 --- a/common/acm/test.yaml +++ /dev/null @@ -1,35 +0,0 @@ -clusterGroup: - managedClusterGroups: - exampleRegion: - name: region-one - - # Before enabling cluster provisioning, ensure AWS/Azure credentials and OCP - # pull secrets are defined in Vault. See values-secret.yaml.template - # - clusterPools: - exampleAWSPool: - name: aws-ap - openshiftVersion: 4.10.18 - baseDomain: blueprints.rhecoeng.com - platform: - aws: - region: ap-southeast-2 - clusters: - - One - exampleAzurePool: - name: azure-us - openshiftVersion: 4.10.18 - baseDomain: blueprints.rhecoeng.com - platform: - azure: - baseDomainResourceGroupName: dojo-dns-zones - region: eastus - clusters: - - Two - - Three - labels: - - name: clusterGroup - value: region-one - helmOverrides: - - name: clusterGroup.isHubCluster - value: false diff --git a/common/acm/values.yaml b/common/acm/values.yaml deleted file mode 100644 index e423d531..00000000 --- a/common/acm/values.yaml +++ /dev/null @@ -1,26 +0,0 @@ -global: - pattern: none - repoURL: none - targetRevision: main - - -clusterGroup: - managedClusterGroups: -# testRegion: -# name: region-one -# clusterPools: -# testPool: -# name: spoke -# openshiftVersion: 4.10.18 -# provider: -# region: ap-southeast-2 -# baseDomain: blueprints.rhecoeng.com -# clusters: -# - spoke1 -# labels: -# - name: clusterGroup -# value: region-one - -secretStore: - name: vault-backend - kind: ClusterSecretStore \ No newline at end of file diff --git a/common/ansible/ansible.cfg b/common/ansible/ansible.cfg deleted file mode 100644 index c8bec627..00000000 --- a/common/ansible/ansible.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[defaults] -display_skipped_hosts=False -localhost_warning=False -roles_path=./roles:~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles diff --git a/common/ansible/playbooks/vault/push_secrets.yaml b/common/ansible/playbooks/vault/push_secrets.yaml deleted file mode 100644 index ed3cad61..00000000 --- a/common/ansible/playbooks/vault/push_secrets.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -- name: Secret injection of validated-patterns - hosts: localhost - connection: local - gather_facts: false - tasks: - - name: Run push secrets task - include_role: - name: vault_utils - tasks_from: push_secrets diff --git a/common/ansible/playbooks/vault/vault.yaml b/common/ansible/playbooks/vault/vault.yaml deleted file mode 100644 index 64711e47..00000000 --- a/common/ansible/playbooks/vault/vault.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -- name: Vault initialization - hosts: localhost - connection: local - gather_facts: false - roles: - - vault_utils diff --git a/common/ansible/roles/vault_utils/README.md b/common/ansible/roles/vault_utils/README.md deleted file mode 100644 index e83471b9..00000000 --- a/common/ansible/roles/vault_utils/README.md +++ /dev/null @@ -1,79 +0,0 @@ -Role Name -========= - -Bunch of utilities to manage the vault inside k8s imperatively - -Requirements ------------- - -ansible-galaxy collection install kubernetes.core (formerly known as community.kubernetes) - -Role Variables --------------- - -Defaults as to where the values-secret.yaml file is and the two ways to connect to a kubernetes cluster -(KUBERCONFIG and ~/.kube/config respectively): - -```yaml -values_secret: "{{ lookup('env', 'HOME') }}/values-secret.yaml" -kubeconfig: "{{ lookup('env', 'KUBECONFIG') }}" -kubeconfig_backup: "{{ lookup('env', 'HOME') }}/.kube/config" -``` - -Default values for vault configuration: - -```yaml -vault_ns: "vault" -vault_pod: "vault-0" -vault_hub: "hub" -vault_hub_kubernetes_host: https://$KUBERNETES_PORT_443_TCP_ADDR:443 -# Needs extra escaping due to how it gets injected via shell in the vault -vault_hub_capabilities: '[\\\"read\\\"]' -vault_base_path: "secret" -vault_path: "{{ vault_base_path }}/{{ vault_hub }}" -vault_hub_ttl: "15m" -vault_pki_max_lease_ttl: "8760h" -external_secrets_ns: golang-external-secrets -external_secrets_sa: golang-external-secrets -``` - -Use the local file system (output_file variable) to store the vault's unseal keys. -If set to false they will be stored inside a secret defined by `unseal_secret` -in the `unseal_namespace` namespace: - -```yaml -file_unseal: true -# token inside a secret in the cluster. -# *Note* that this is fundamentally unsafe -output_file: "common/pattern-vault.init" -unseal_secret: "vaultkeys" -unseal_namespace: "imperative" -``` - -Dependencies ------------- - -This relies on [kubernetes.core](https://docs.ansible.com/ansible/latest/collections/kubernetes/core/k8s_module.html) - -Internals ---------- - -Here is the rough high-level algorithm used to unseal the vault: - -1. Check vault status. If vault is not initialized go to 2. If initialized go to 3. -2. Initialize vault and store unseal keys + login token either on a local file - or inside a secret in k8s (file_unseal var controls this) -3. Check vault status. If vault is unsealed go to 5. else to to 4. -4. Unseal the vault using the secrets read from the file or the secret - (file_unseal controls this) -5. Configure the vault (should be idempotent) - -License -------- - -Apache - -Author Information ------------------- - -Michele Baldessari diff --git a/common/ansible/roles/vault_utils/defaults/main.yml b/common/ansible/roles/vault_utils/defaults/main.yml deleted file mode 100644 index 04fccf7b..00000000 --- a/common/ansible/roles/vault_utils/defaults/main.yml +++ /dev/null @@ -1,26 +0,0 @@ ---- -# defaults file for vault_utils -values_secret: "{{ lookup('env', 'HOME') }}/values-secret.yaml" -kubeconfig: "{{ lookup('env', 'KUBECONFIG') }}" -kubeconfig_backup: "{{ lookup('env', 'HOME') }}/.kube/config" -vault_ns: "vault" -vault_pod: "vault-0" -vault_hub: "hub" -vault_pvc: "data-vault-0" -vault_hub_kubernetes_host: https://$KUBERNETES_PORT_443_TCP_ADDR:443 -# Needs extra escaping due to how it gets injected via shell in the vault -vault_hub_capabilities: '[\\\"read\\\"]' -vault_base_path: "secret" -vault_path: "{{ vault_base_path }}/{{ vault_hub }}" -vault_hub_ttl: "15m" -vault_pki_max_lease_ttl: "8760h" -output_file: "common/pattern-vault.init" -external_secrets_ns: golang-external-secrets -external_secrets_sa: golang-external-secrets -external_secrets_secret: golang-external-secrets -# Setting this to false makes the role store the vault unseal keys and root login -# token inside a secret in the cluster. -# *Note* that this is fundamentally unsafe -file_unseal: true -unseal_secret: "vaultkeys" -unseal_namespace: "imperative" diff --git a/common/ansible/roles/vault_utils/handlers/main.yml b/common/ansible/roles/vault_utils/handlers/main.yml deleted file mode 100644 index a983544d..00000000 --- a/common/ansible/roles/vault_utils/handlers/main.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -# handlers file for vault_utils diff --git a/common/ansible/roles/vault_utils/meta/main.yml b/common/ansible/roles/vault_utils/meta/main.yml deleted file mode 100644 index c99eb3a9..00000000 --- a/common/ansible/roles/vault_utils/meta/main.yml +++ /dev/null @@ -1,31 +0,0 @@ -galaxy_info: - author: Validated Patterns Team https://github.com/hybrid-cloud-patterns/ - description: Utilities to manage vault in kubernetes (init, unseal, etc) - - issue_tracker_url: https://github.com/hybrid-cloud-patterns/common/issues - license: Apache-2.0 - min_ansible_version: "2.1" - - # If this a Container Enabled role, provide the minimum Ansible Container version. - # min_ansible_container_version: - - platforms: - - name: Fedora - versions: - - all - - name: Ubuntu - versions: - - all - - name: Debian - versions: - - all - - name: EL - versions: - - "8" - - "9" - - galaxy_tags: [] - -dependencies: [] - # List your role dependencies here, one per line. Be sure to remove the '[]' above, - # if you add dependencies to this list. diff --git a/common/ansible/roles/vault_utils/tasks/main.yml b/common/ansible/roles/vault_utils/tasks/main.yml deleted file mode 100644 index 1da3e440..00000000 --- a/common/ansible/roles/vault_utils/tasks/main.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- -- name: Delete vault - import_tasks: vault_delete.yaml - tags: vault_delete - -- name: Run vault init tasks - import_tasks: vault_init.yaml - tags: vault_init - -- name: Unseal vault - import_tasks: vault_unseal.yaml - tags: vault_unseal - -- name: Vault secrets init - import_tasks: vault_secrets_init.yaml - tags: vault_secrets_init - -- name: Load secrets - import_tasks: push_secrets.yaml - tags: push_secrets diff --git a/common/ansible/roles/vault_utils/tasks/pre_check.yaml b/common/ansible/roles/vault_utils/tasks/pre_check.yaml deleted file mode 100644 index 1dc5f445..00000000 --- a/common/ansible/roles/vault_utils/tasks/pre_check.yaml +++ /dev/null @@ -1,26 +0,0 @@ ---- -- name: Check if the kubernetes python module is usable from ansible - ansible.builtin.command: "{{ ansible_python_interpreter }} -c 'import kubernetes'" - changed_when: false - -- name: Check if KUBECONFIG is correctly set - ansible.builtin.debug: - msg: "KUBECONFIG is not set, falling back to ~/.kube/config" - when: kubeconfig is not defined or kubeconfig | length == 0 - -- name: Check if ~/.kube/config exists - ansible.builtin.stat: - path: "{{ kubeconfig_backup }}" - register: kubeconfig_result - -- name: Check if we're running inside an OCP cluster directly - ansible.builtin.set_fact: - running_in_ocp: "{{ lookup('env', 'KUBERNETES_SERVICE_HOST') | length > 0 | bool }}" - -- name: Fail if both KUBECONFIG and ~/.kube/config do not exist but only when not running in a cluster - ansible.builtin.fail: - msg: "{{ kubeconfig_backup }} not found and KUBECONFIG unset. Bailing out." - failed_when: - - not running_in_ocp - - not kubeconfig_result.stat.exists - - kubeconfig is not defined or kubeconfig | length == 0 diff --git a/common/ansible/roles/vault_utils/tasks/push_secrets.yaml b/common/ansible/roles/vault_utils/tasks/push_secrets.yaml deleted file mode 100644 index 3569d24a..00000000 --- a/common/ansible/roles/vault_utils/tasks/push_secrets.yaml +++ /dev/null @@ -1,208 +0,0 @@ ---- -- include_tasks: pre_check.yaml -- include_tasks: vault_status.yaml - -# Unfortunately we cannot loop vault_status and just check if the vault is unsealed -# https://github.com/ansible/proposals/issues/136 -# So here we keep running the 'vault status' command until sealed is set to false -- name: If the vault is still sealed we need to retry - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ vault_pod }}" - command: vault status -format=json - register: vault_status_json - until: "'stdout' in vault_status_json and (not (vault_status_json.stdout | from_json)['sealed'] | bool)" - retries: 20 - delay: 45 - failed_when: "'stdout_lines' not in vault_status_json" - -- name: Check for existence of "{{ values_secret }}" - ansible.builtin.stat: - path: "{{ values_secret }}" - register: result - failed_when: not result.stat.exists - -- name: Parse "{{ values_secret }}" - ansible.builtin.set_fact: - all_values: "{{ lookup('file', values_secret) | from_yaml | default({}, true) }}" - -- name: Check for secrets keys - ansible.builtin.assert: - that: - - "('secrets' in all_values.keys()) or ('files' in all_values.keys())" - fail_msg: "Was not able to parse any secrets from file {{ values_secret }}. Either 'secrets:' or 'files:' top-level keys (or both) must exist" - -- name: Set secrets and file_secrets facts - ansible.builtin.set_fact: - secrets: "{{ all_values['secrets'] | default({}) }}" - file_secrets: "{{ all_values['files'] | default({}) }}" - -- name: Verify we have any secrets at all - ansible.builtin.fail: - msg: "Was not able to parse any secrets from file {{ values_secret }}: {{ all_values }}" - failed_when: - secrets | combine(file_secrets) | length == 0 - -- name: Check the value-secret.yaml file for errors in the secrets section - ansible.builtin.fail: - msg: > - "{{ item }}" is not properly formatted. Each key under 'secrets:' - needs to point to a dictionary of key, value pairs. See values-secret.yaml.template. - when: > - item.key | length == 0 or - item.value is not mapping - loop: - "{{ secrets | dict2items }}" - loop_control: - label: "{{ item.key }}" - -- name: Validate file references in the files section of value-secret.yaml - ansible.builtin.stat: - path: '{{ file_stat.value }}' - register: file_values - loop_control: - loop_var: file_stat - loop: - "{{ file_secrets | dict2items }}" - -- name: debug file_stat - ansible.builtin.debug: - var: file_stat - when: debug | default(False) | bool - -- name: debug file_values - ansible.builtin.debug: - var: file_values - when: debug | default(False) | bool - -- name: Fail if referenced file does not exist - ansible.builtin.fail: - msg: > - "file {{ item.file_stat.key }} {{ item.file_stat.value }}" must exist and be a file - when: > - not item.stat.exists - loop: - "{{ file_values.results }}" - -# Detect here if we have only the following two keys under a password -# s3.accessKey: -# s3.secretKey: -# If we do, then detect it and calculate the b64 s3Secret token -# Note: the vars: line is due to https://github.com/ansible/ansible/issues/40239 -- name: Check if any of the passwords has only s3.[accessKey,secretKey] and generate the combined s3Secret in that case - ansible.builtin.set_fact: - s3keys: "{{ s3keys | default({}) | combine({ item.key: {'s3Secret': s3secret | b64encode } }) }}" - vars: - s3secret: "{{ 's3.accessKey: ' + item.value['s3.accessKey'] + '\ns3.secretKey: ' + item.value['s3.secretKey'] }}" - when: - - '"s3.accessKey" in item.value.keys()' - - '"s3.secretKey" in item.value.keys()' - - '"s3Secret" not in item.value.keys()' - loop: - "{{ secrets | dict2items }}" - loop_control: - label: "{{ item.key }}" - -- name: Merge any s3Secret into the secrets dictionary if we have any - ansible.builtin.set_fact: - secrets: "{{ secrets | combine(s3keys) }}" - when: - s3keys is defined and s3keys | length > 0 - -# The values-secret.yaml file is in the fairly loose form of: -# secrets: -# group1: -# key1: value1 -# key2: value2 -# group2: -# key1: valueA -# key4: valueC -# The above will generate: -# vault kv put 'secret/hub/group1' key1='value1' key2='value2' -# vault kv put 'secret/hub/group2' key1='valueA' key4='valueC' -# Below we loop on the top level keys (group1, group2) and for each -# sub-top-level key (key1, key2) we create a single 'key1=value1 key2=value2' string -# -# Special note is to be given to the regex_replace which is run against each value aka password: -# A. The need for it is to quote the passwords -# B. Since it needs to cater to multiline strings (certs) and ansible offers no way -# to specify re.DOTALL and re.MULTILINE we need to use (?ms) at the beginning -# See https://docs.python.org/3/library/re.html and (?aiLmsux) section -# and https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/filter/core.py#L124 -# C. The \\A and \\Z match the beginning and end of a string (in case of multiline strings -# do not want to match every line) - -- name: Set defaults for vault_cmds and secret_files_vault_cmds to prevent undefined variable errors - ansible.builtin.set_fact: - vault_cmds: "{{ vault_cmds | default({}) }}" - secret_files_vault_cmds: "{{ secret_files_vault_cmds | default({}) }}" - -- name: Set secrets vault commands fact - ansible.builtin.set_fact: - vault_cmds: "{{ vault_cmds | combine({ item.key: vault_cmd}) }}" - vars: - vault_cmd: "vault kv put '{{ vault_path }}/{{ item.key }}' - {{ item.value.keys() | zip(item.value.values() | map('regex_replace', '(?ms)\\A(.*)\\Z', \"'\\1'\")) | map('join', '=') | list | join(' ') }}" - loop: - "{{ secrets | dict2items }}" - loop_control: - label: "{{ item.key }}" - -- name: Set files vault commands fact - ansible.builtin.set_fact: - secret_files_vault_cmds: "{{ secret_files_vault_cmds | combine({ item.key: vault_cmd}) }}" - vars: - vault_cmd: "cat '{{ item.value | expanduser }}' | oc exec -n {{ vault_ns }} {{ vault_pod }} -it -- sh -c 'cat - > /tmp/vault_content'; oc exec -n {{ vault_ns }} {{ vault_pod }} -it -- sh -c 'base64 --wrap=0 /tmp/vault_content | vault kv put {{ vault_path }}/{{ item.key }} b64content=- content=@/tmp/vault_content; rm /tmp/vault_content'" # noqa yaml - loop: - "{{ file_secrets | dict2items }}" - loop_control: - label: "{{ item.key }}" - -- name: Debug vault commands - ansible.builtin.debug: - msg: "{{ vault_cmds }}" - when: debug | default(False) | bool - -- name: Debug files vault commands - ansible.builtin.debug: - msg: "{{ secret_files_vault_cmds }}" - when: debug | default(False) | bool - -# This step is not really needed when running make vault-init + load-secrets as -# everything is sequential -# It is needed when the vault is unsealed/configured inside the cluster and load-secrets -# gets run *while* the cronjob configures the vault. I.e. it might be half configured and return -# errors -- name: Make sure that the vault auth policy exists - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ vault_pod }}" - command: - sh -c "vault list auth/{{ vault_hub }}/role | grep '{{ vault_hub }}-role'" - register: vault_role_cmd - until: vault_role_cmd.rc == 0 - retries: 20 - delay: 45 - changed_when: false - -- name: Add the actual secrets to the vault - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ vault_pod }}" - command: | - sh -c "{{ item.value }}" - loop: - "{{ vault_cmds | dict2items }}" - loop_control: - label: "{{ item.key }}" - when: not debug | default(False) | bool - - # This has to be shell because of the use of stdin and pipes -- name: Add the file secrets to the vault - ansible.builtin.shell: # noqa: command-instead-of-shell - "{{ item.value }}" - loop: - "{{ secret_files_vault_cmds | dict2items }}" - loop_control: - label: "{{ item.key }}" - when: not debug | default(False) | bool diff --git a/common/ansible/roles/vault_utils/tasks/vault_delete.yaml b/common/ansible/roles/vault_utils/tasks/vault_delete.yaml deleted file mode 100644 index f0e289e7..00000000 --- a/common/ansible/roles/vault_utils/tasks/vault_delete.yaml +++ /dev/null @@ -1,23 +0,0 @@ ---- -- include_tasks: pre_check.yaml -- include_tasks: vault_status.yaml - -# Note: We do not wait on purpose here as the pod will be recreated -# anyways and that would race. We are fine with having it gone once -- name: Delete vault pod - kubernetes.core.k8s: - state: absent - api_version: v1 - kind: Pod - namespace: "{{ vault_ns }}" - name: "{{ item }}" - loop: "{{ vault_pods }}" - -- name: Delete vault pvc - kubernetes.core.k8s: - state: absent - api_version: v1 - kind: PersistentVolumeClaim - namespace: "{{ vault_ns }}" - name: "data-{{ item }}" - loop: "{{ vault_pods }}" diff --git a/common/ansible/roles/vault_utils/tasks/vault_init.yaml b/common/ansible/roles/vault_utils/tasks/vault_init.yaml deleted file mode 100644 index e3ba9cb6..00000000 --- a/common/ansible/roles/vault_utils/tasks/vault_init.yaml +++ /dev/null @@ -1,85 +0,0 @@ ---- -- include_tasks: pre_check.yaml -- include_tasks: vault_status.yaml - -# If the vault is already initialized we skip all the tasks below -- name: Is the vault initialized? - ansible.builtin.set_fact: - vault_initialized: "{{ vault_status['initialized'] | bool }}" - -# Note that the 'realpath' filter explicitely only resolves on the ansible/local box -# which is fine in our case -- name: Set absolute path for output_file - ansible.builtin.set_fact: - output_file_abs: "{{ output_file | realpath }}" - when: - - not vault_initialized - - file_unseal - -- name: Check for existence of "{{ output_file_abs }}" - ansible.builtin.stat: - path: "{{ output_file_abs }}" - register: result - when: - - not vault_initialized - - file_unseal - -- name: Rename "{{ output_file_abs }} if it exists" - ansible.builtin.copy: - src: "{{ output_file_abs }}" - dest: "{{ output_file_abs }}.bak" - mode: '0600' - when: - - not vault_initialized - - file_unseal - - result.stat.exists - -# We need to retry here because the vault service might be starting -# and can return a 500 internal server until its state is fully ready -- name: Init vault operator - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ vault_pod }}" - command: vault operator init -format=json - register: vault_init_json_out - until: vault_init_json_out is not failed - retries: 10 - delay: 15 - when: not vault_initialized - -- name: Set vault init output json fact - ansible.builtin.set_fact: - vault_init_json: "{{ vault_init_json_out.stdout | from_json }}" - when: not vault_initialized - -# We store the the operator unseal keys and root token to a file when -# the vault was not already initialized *and* when unseal_from_cluster -# is set to false -- name: Save vault operator output (local file) - ansible.builtin.copy: - follow: true - dest: "{{ output_file_abs }}" - content: "{{ vault_init_json | to_nice_json }}" - mode: '0600' - when: - - not vault_initialized - - file_unseal - -# We store the the operator unseal keys and root token to a secret inside -# the cluster when the vault was not already initialized *and* when -# unseal_from_cluster is set to true -- name: Save vault operator output (into a secret inside the cluster) - kubernetes.core.k8s: - state: present - definition: - apiVersion: v1 - kind: Secret - type: Opaque - metadata: - name: "{{ unseal_secret }}" - namespace: "{{ unseal_namespace }}" - data: - vault_data_json: "{{ vault_init_json | to_nice_json | b64encode }}" - when: - - not vault_initialized - - not file_unseal diff --git a/common/ansible/roles/vault_utils/tasks/vault_pki_init.yaml b/common/ansible/roles/vault_utils/tasks/vault_pki_init.yaml deleted file mode 100644 index ca5fe697..00000000 --- a/common/ansible/roles/vault_utils/tasks/vault_pki_init.yaml +++ /dev/null @@ -1,50 +0,0 @@ -# NOTE: This task is currently not used ---- -- include_tasks: pre_check.yaml - -- name: Fetch Ingress object - kubernetes.core.k8s_info: - kind: Ingress - api_version: config.openshift.io/v1 - register: ingress_domain_raw - -# We split the domain and skip the first two parts -# apps.bandini-dc.blueprints.rhecoeng.com -> blueprints.rhecoeng.com -- name: Set ingress domain - ansible.builtin.set_fact: - ingress_domain_out: "{{ ingress_raw.resources[0].spec.domain.split('.')[2:] | join('.') }}" - -- name: Set ingress domain cleaned up - ansible.builtin.set_fact: - ingress_domain: "{{ ingress_domain_out.stdout }}" - cert_role: "{{ ingress_domain_out.stdout | replace('.', '_') }}" - -- name: Enable vault pki backend - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ vault_pod }}" - command: vault secrets enable pki - -- name: Set vault pki max-lease-ttl - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ vault_pod }}" - command: vault secrets tune --max-lease-ttl="{{ vault_pki_max_lease_ttl }}" pki - -- name: Set vault pki generate/internal CN - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ vault_pod }}" - command: vault write pki/root/generate/internal common_name="{{ ingress_domain }}" ttl="{{ vault_pki_max_lease_ttl }}" - -- name: Set vault pki CRL - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ vault_pod }}" - command: vault write pki/config/urls issuing_certificates="http://127.0.0.1:8200/v1/pki/ca" crl_distribution_points="http://127.0.0.1:8200/v1/pki/crl" - -- name: Set vault pki roles - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ vault_pod }}" - command: vault write pki/roles/"{{ cert_role }}" allowed_domains="{{ ingress_domain }}" allow_subdomains=true max_ttl="{{ vault_pki_max_lease_ttl }}" diff --git a/common/ansible/roles/vault_utils/tasks/vault_secrets_init.yaml b/common/ansible/roles/vault_utils/tasks/vault_secrets_init.yaml deleted file mode 100644 index 9fdb9024..00000000 --- a/common/ansible/roles/vault_utils/tasks/vault_secrets_init.yaml +++ /dev/null @@ -1,80 +0,0 @@ ---- -- include_tasks: pre_check.yaml - -- name: Is secrets backend already enabled - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ vault_pod }}" - command: > - bash -e -c "vault secrets list | grep -e '^{{ vault_base_path }}'" - register: secrets_enabled - failed_when: false - -- name: Create secrets backend kv-v2 - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ vault_pod }}" - command: vault secrets enable -path="{{ vault_base_path }}" kv-v2 - when: secrets_enabled.rc != 0 - -- name: Is kubernetes backend already enabled - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ vault_pod }}" - command: > - bash -e -c "vault auth list | grep -e '^{{ vault_hub }}'" - register: kubernetes_enabled - failed_when: false - -- name: Enable kubernetes backend on hub - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ vault_pod }}" - command: "vault auth enable -path={{ vault_hub }} kubernetes" - when: kubernetes_enabled.rc != 0 - -- name: Get token from service account secret {{ external_secrets_ns }}/{{ external_secrets_secret }} - kubernetes.core.k8s_info: - kind: Secret - namespace: "{{ external_secrets_ns }}" - name: "{{ external_secrets_secret }}" - api_version: v1 - register: token_data - failed_when: token_data.resources | length == 0 - -- name: Set sa_token fact - ansible.builtin.set_fact: - sa_token: "{{ token_data.resources[0].data.token | b64decode }}" - -- name: Configure hub kubernetes backend - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ vault_pod }}" - command: bash -e -c "vault write auth/{{ vault_hub }}/config token_reviewer_jwt={{ sa_token }} - kubernetes_host={{ vault_hub_kubernetes_host }} - kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt - issuer=https://kubernetes.default.svc" - -- name: Configure policy template for hub - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ vault_pod }}" - command: > - bash -e -c "echo \"path \\\"secret/data/{{ vault_hub }}/*\\\" { - capabilities = {{ vault_hub_capabilities }} }\" > /tmp/policy-{{ vault_hub }}.hcl" - -- name: Configure policy for hub - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ vault_pod }}" - command: "vault policy write {{ vault_hub }}-secret /tmp/policy-{{ vault_hub }}.hcl" - -- name: Configure kubernetes role for hub - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ vault_pod }}" - command: > - vault write auth/"{{ vault_hub }}"/role/"{{ vault_hub }}"-role - bound_service_account_names="{{ external_secrets_sa }}" - bound_service_account_namespaces="{{ external_secrets_ns }}" - policies="default,{{ vault_hub }}-secret" ttl="{{ vault_hub_ttl }}" diff --git a/common/ansible/roles/vault_utils/tasks/vault_status.yaml b/common/ansible/roles/vault_utils/tasks/vault_status.yaml deleted file mode 100644 index 9dc3e426..00000000 --- a/common/ansible/roles/vault_utils/tasks/vault_status.yaml +++ /dev/null @@ -1,61 +0,0 @@ ---- -# Registers a variable valled vault_status containing the vault's status json dict -- name: Check for vault namespace - kubernetes.core.k8s_info: - kind: Namespace - name: "{{ vault_ns }}" - register: vault_ns_rc - until: vault_ns_rc.resources | length > 0 - retries: 20 - delay: 45 - -- name: Check if the vault pod is present - kubernetes.core.k8s_info: - kind: Pod - namespace: "{{ vault_ns }}" - name: "{{ vault_pod }}" - register: vault_pod_rc - until: vault_pod_rc.resources | length > 0 - retries: 20 - delay: 45 - -# This needs retrying because during startup we can just get -# Failed to execute on pod vault-0 due to : (0)\nReason: Handshake status 500 Internal Server Error -# In the above case there is no 'rc' in vault_status. So first we wait for 'rc' to show up and ignore -# any errors, and then we bail out if rc is 2 as it means the vault is already initialized -- name: Check for the vault status - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ vault_pod }}" - command: vault status -format=json - register: vault_status_json - until: "'rc' in vault_status_json" - retries: 20 - delay: 45 - failed_when: "'stdout_lines' not in vault_status_json" - -- name: Set vault status output json fact - ansible.builtin.set_fact: - vault_status: "{{ vault_status_json.stdout | from_json }}" - when: vault_status_json.stdout_lines | length > 0 - -- name: List Vault pods - kubernetes.core.k8s_info: - namespace: "{{ vault_ns }}" - kind: Pod - label_selectors: - - "component = server" - register: vault_pods_list - -- name: "Get pods" - ansible.builtin.set_fact: - vault_pods: "{{ vault_pods + [item.metadata.name] }}" - loop: "{{ vault_pods_list.resources }}" - loop_control: - label: "{{ item.metadata.name }}" - vars: - vault_pods: [] - -- name: "Followers" - ansible.builtin.set_fact: - followers: "{{ vault_pods | difference(vault_pod) }}" diff --git a/common/ansible/roles/vault_utils/tasks/vault_unseal.yaml b/common/ansible/roles/vault_utils/tasks/vault_unseal.yaml deleted file mode 100644 index 10e63629..00000000 --- a/common/ansible/roles/vault_utils/tasks/vault_unseal.yaml +++ /dev/null @@ -1,116 +0,0 @@ ---- -- include_tasks: pre_check.yaml -- include_tasks: vault_status.yaml - -# If the vault is already unsealed we skip all the tasks below -- name: Is the vault sealed? - ansible.builtin.set_fact: - vault_sealed: "{{ vault_status['sealed'] | bool }}" - -# Note that the 'realpath' filter explicitely only resolves on the ansible/local box -# which is fine in our case -- name: Set absolute path for output_file - ansible.builtin.set_fact: - output_file_abs: "{{ output_file | realpath }}" - when: - - vault_sealed - - file_unseal - -- name: Check for existence of "{{ output_file_abs }}" - ansible.builtin.stat: - path: "{{ output_file_abs }}" - register: result - when: - - vault_sealed - - file_unseal - -- name: Fail if "{{ output_file_abs }}" does not exists - ansible.builtin.fail: - msg: "{{ output_file_abs }} does not exist. Stopping here" - failed_when: not result.stat.exists - when: - - vault_sealed - - file_unseal - -# We reparse the json vault init file in case unseal was called without operator init before -# and if file_unseal is true -- name: Parse "{{ output_file_abs }}" - ansible.builtin.set_fact: - vault_init_json: "{{ lookup('file', output_file_abs) | from_json }}" - when: - - vault_sealed - - file_unseal - -# We reparse the json vault init secret in case unseal was called without operator init before -# and if file_unseal is false -- name: Parse "{{ output_file_abs }}" - kubernetes.core.k8s_info: - kind: Secret - namespace: "{{ unseal_namespace }}" - name: "{{ unseal_secret }}" - api_version: v1 - register: vault_init_data - when: - - vault_sealed - - not file_unseal - -- name: Set vault init json - ansible.builtin.set_fact: - vault_init_json: "{{ vault_init_data.resources[0].data.vault_data_json | b64decode | from_json }}" - when: - - vault_sealed - - not file_unseal - -- name: Set root token and unseal_keys - ansible.builtin.set_fact: - root_token: "{{ vault_init_json['root_token'] }}" - unseal_keys: "{{ vault_init_json['unseal_keys_hex'] }}" - when: vault_sealed - -- name: Unseal leader - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ vault_pod }}" - command: vault operator unseal "{{ item }}" - loop: "{{ unseal_keys }}" - loop_control: - extended: true - label: "Unsealing with key {{ ansible_loop.index }}" - when: vault_sealed - -- name: Join Raft cluster - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ item }}" - command: vault operator raft join http://{{ vault_pod }}.{{ vault_ns }}-internal:8200 - register: join_raft_cluster_out - until: join_raft_cluster_out is not failed - retries: 10 - delay: 15 - loop: "{{ followers }}" - loop_control: - extended: true - label: "Joining Raft Cluster on http://{{ vault_pod }}.{{ vault_ns }}-internal:8200" - when: - - vault_sealed - - followers | length > 0 - -- name: Unseal followers - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ item.0 }}" - command: vault operator unseal "{{ item.1 }}" - loop: "{{ followers | product(unseal_keys) | list }}" - loop_control: - extended: true - label: "Unsealing {{ item.0 }} with key {{ ansible_loop.index }}" - when: - - vault_sealed - - followers | length > 0 - -- name: Login into vault - kubernetes.core.k8s_exec: - namespace: "{{ vault_ns }}" - pod: "{{ vault_pod }}" - command: vault login "{{ root_token }}" - when: vault_sealed diff --git a/common/ansible/roles/vault_utils/tests/inventory b/common/ansible/roles/vault_utils/tests/inventory deleted file mode 100644 index 878877b0..00000000 --- a/common/ansible/roles/vault_utils/tests/inventory +++ /dev/null @@ -1,2 +0,0 @@ -localhost - diff --git a/common/ansible/roles/vault_utils/tests/test.yml b/common/ansible/roles/vault_utils/tests/test.yml deleted file mode 100644 index 0998beb6..00000000 --- a/common/ansible/roles/vault_utils/tests/test.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -- hosts: localhost - remote_user: root - roles: - - vault_utils diff --git a/common/ansible/roles/vault_utils/vars/main.yml b/common/ansible/roles/vault_utils/vars/main.yml deleted file mode 100644 index f6e02b93..00000000 --- a/common/ansible/roles/vault_utils/vars/main.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -# vars file for vault_utils diff --git a/common/clustergroup/.helmignore b/common/clustergroup/.helmignore deleted file mode 100644 index b25c15b8..00000000 --- a/common/clustergroup/.helmignore +++ /dev/null @@ -1 +0,0 @@ -*~ diff --git a/common/clustergroup/Chart.yaml b/common/clustergroup/Chart.yaml deleted file mode 100644 index 249163ae..00000000 --- a/common/clustergroup/Chart.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v2 -description: A Helm chart to create per-clustergroup ArgoCD applications and any required namespaces or subscriptions -keywords: -- pattern -name: pattern-clustergroup -version: 0.0.1 diff --git a/common/clustergroup/templates/applications.yaml b/common/clustergroup/templates/applications.yaml deleted file mode 100644 index 3ffd6a0f..00000000 --- a/common/clustergroup/templates/applications.yaml +++ /dev/null @@ -1,207 +0,0 @@ -{{- $namespace := cat $.Values.global.pattern $.Values.clusterGroup.name | replace " " "-" }} -{{- range .Values.clusterGroup.applications }} -{{- if or (.generators) (.generatorFile) (.useGeneratorValues) (.destinationServer) (.destinationNamespace) }} -apiVersion: argoproj.io/v1alpha1 -kind: ApplicationSet -metadata: - name: {{ .name }} - namespace: {{ $namespace }} - labels: - app: {{ .name }} -spec: - {{- if .generators }} - generators: {{ .generators | toPrettyJson }} - {{- else }} - generators: - - git: - repoURL: {{ $.Values.global.repoURL }} - revision: {{ $.Values.global.targetRevision }} - {{- if .generatorFile }} - files: - - path: {{ .generatorFile | quote }} - {{- end }} - {{- end }} - template: - metadata: - name: {{ coalesce .namespace $namespace }} - spec: - project: {{ .project }} - {{- if .syncPolicy }} - syncPolicy: {{ .syncPolicy | toPrettyJson }} - {{- else }} - syncPolicy: - automated: {} - {{- end }} - {{- if .ignoreDifferences }} - ignoreDifferences: {{ .ignoreDifferences | toPrettyJson }} - {{- end }} - source: - repoURL: {{ coalesce .repoURL $.Values.global.repoURL }} - targetRevision: {{ coalesce .targetRevision $.Values.global.targetRevision }} - {{- if .chart }} - chart: {{ .chart }} - {{- end }} - {{- if .path }} - path: {{ .path }} - {{- end }} - {{- if .plugin }} - plugin: {{ .plugin }} - {{- end }} - {{- if not .kustomize }} - helm: - ignoreMissingValueFiles: true - valueFiles: - - "values.yaml" - {{- range .extraValueFiles }} - - {{ . | quote }} - {{- end }} - {{- if .useGeneratorValues }} - values: |- - {{ `{{ values }}` }} - {{- end }} - parameters: - - name: global.hubClusterDomain - value: {{ $.Values.global.hubClusterDomain }} - - name: global.localClusterDomain - value: {{ coalesce $.Values.global.localClusterDomain $.Values.global.hubClusterDomain }} - - name: global.repoURL - value: {{ $.Values.global.repoURL }} - - name: global.targetRevision - value: {{ $.Values.global.targetRevision }} - - name: global.namespace - value: {{ $.Values.global.namespace }} - - name: global.pattern - value: {{ $.Values.global.pattern }} - {{- range .extraHubClusterDomainFields }} - - name: {{ . }} - value: {{ $.Values.global.hubClusterDomain }} - {{- end }} - {{- range .extraLocalClusterDomainFields }} - - name: {{ . }} - value: {{ $.Values.global.localClusterDomain }} - {{- end }} - {{- range .extraRepoURLFields }} - - name: {{ . }} - value: {{ $.Values.global.repoURL }} - {{- end }} - {{- range .extraTargetRevisionFields }} - - name: {{ . }} - value: {{ $.Values.global.targetRevision }} - {{- end }} - {{- range .extraNamespaceFields }} - - name: {{ . }} - value: {{ $.Values.global.namespace }} - {{- end }} - {{- range .extraPatternNameFields }} - - name: {{ . }} - value: {{ $.Values.global.pattern }} - {{- end }} - {{- range .overrides }} - - name: {{ .name }} - value: {{ .value | quote }} - {{- if .forceString }} - forceString: true - {{- end }} - {{- end }} - {{- end }} - destination: - server: {{ coalesce .destinationServer "https://kubernetes.default.svc" }} - namespace: {{ coalesce .destinationNamespace .namespace $namespace }} -{{- else }} -apiVersion: argoproj.io/v1alpha1 -kind: Application -metadata: - name: {{ .name }} - namespace: {{ $namespace }} - finalizers: - - resources-finalizer.argocd.argoproj.io/foreground -spec: - destination: - name: {{ coalesce .clusterName "in-cluster" }} - namespace: {{ default $namespace .namespace }} - project: {{ .project }} - source: - repoURL: {{ coalesce .repoURL $.Values.global.repoURL }} - targetRevision: {{ coalesce .targetRevision $.Values.global.targetRevision }} - {{- if .chart }} - chart: {{ .chart }} - {{- else }} - path: {{ .path }} - {{- end }} - {{- if .plugin }} - plugin: {{ .plugin | toPrettyJson }} - {{- else if not .kustomize }} - helm: - ignoreMissingValueFiles: true - valueFiles: - - "/values-global.yaml" - - "/values-{{ $.Values.clusterGroup.name }}.yaml" - {{- range $valueFile := .extraValueFiles }} - - {{ $valueFile | quote }} - {{- end }} - # Watch the progress of https://issues.redhat.com/browse/GITOPS-891 and update accordingly - parameters: - - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL - - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION - - name: global.namespace - value: $ARGOCD_APP_NAMESPACE - - name: global.pattern - value: {{ $.Values.global.pattern }} - - name: global.hubClusterDomain - value: {{ $.Values.global.hubClusterDomain }} - - name: global.localClusterDomain - value: {{ coalesce $.Values.global.localClusterDomain $.Values.global.hubClusterDomain }} - {{- range .extraHubClusterDomainFields }} - - name: {{ . }} - value: {{ $.Values.global.hubClusterDomain }} - {{- end }} - {{- range .extraLocalClusterDomainFields }} - - name: {{ . }} - value: {{ $.Values.global.localClusterDomain }} - {{- end }} - {{- range .extraRepoURLFields }} - - name: {{ . }} - value: $ARGOCD_APP_SOURCE_REPO_URL - {{- end }} - {{- range .extraTargetRevisionFields }} - - name: {{ . }} - value: $ARGOCD_APP_SOURCE_TARGET_REVISION - {{- end }} - {{- range .extraNamespaceFields }} - - name: {{ . }} - value: $ARGOCD_APP_NAMESPACE - {{- end }} - {{- range .extraPatternNameFields }} - - name: {{ . }} - value: {{ $.Values.global.pattern }} - {{- end }} - {{- range .overrides }} - - name: {{ .name }} - value: {{ .value | quote }} - {{- if .forceString }} - forceString: true - {{- end }} - {{- end }} - {{- if .fileParameters }} - fileParameters: - {{- range .fileParameters }} - - name: {{ .name }} - path: {{ .path }} - {{- end }} - {{- end }} - {{- end }} - {{- if .ignoreDifferences }} - ignoreDifferences: {{ .ignoreDifferences | toPrettyJson }} - {{- end }} - {{- if .syncPolicy }} - syncPolicy: {{ .syncPolicy | toPrettyJson }} - {{- else }} - syncPolicy: - automated: {} - # selfHeal: true - {{- end }} ---- -{{- end }} -{{- end }} diff --git a/common/clustergroup/templates/argocd-super-role.yaml b/common/clustergroup/templates/argocd-super-role.yaml deleted file mode 100644 index 78af462d..00000000 --- a/common/clustergroup/templates/argocd-super-role.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# WARNING: ONLY USE THIS FOR MANAGING CLUSTERS NOT FOR REGULAR USERS -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: openshift-gitops-cluster-admin-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin -subjects: - - kind: ServiceAccount - name: openshift-gitops-argocd-application-controller - namespace: openshift-gitops - # NOTE: THIS MUST BE FIXED FOR MULTITENANT SETUP - - kind: ServiceAccount - name: openshift-gitops-argocd-server - namespace: openshift-gitops ---- -# WARNING: ONLY USE THIS FOR MANAGING CLUSTERS NOT FOR REGULAR USERS -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ $.Values.global.pattern }}-{{ .Values.clusterGroup.name }}-cluster-admin-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin -subjects: - - kind: ServiceAccount - # This is the {ArgoCD.name}-argocd-application-controller - name: {{ .Values.clusterGroup.name }}-gitops-argocd-application-controller - namespace: {{ $.Values.global.pattern }}-{{ .Values.clusterGroup.name }} - # NOTE: THIS MUST BE FIXED FOR MULTITENANT SETUP - - kind: ServiceAccount - # This is the {ArgoCD.name}-argocd-server - name: {{ .Values.clusterGroup.name }}-gitops-argocd-server - namespace: {{ $.Values.global.pattern }}-{{ .Values.clusterGroup.name }} - # NOTE: This is needed starting with gitops-1.5.0 (see issue common#76) - - kind: ServiceAccount - name: {{ .Values.clusterGroup.name }}-gitops-argocd-dex-server - namespace: {{ $.Values.global.pattern }}-{{ .Values.clusterGroup.name }} diff --git a/common/clustergroup/templates/argocd.yaml b/common/clustergroup/templates/argocd.yaml deleted file mode 100644 index 0126c0a5..00000000 --- a/common/clustergroup/templates/argocd.yaml +++ /dev/null @@ -1,123 +0,0 @@ -{{- $namespace := cat $.Values.global.pattern $.Values.clusterGroup.name | replace " " "-" }} -apiVersion: argoproj.io/v1alpha1 -kind: ArgoCD -metadata: - finalizers: - - argoproj.io/finalizer - # Changing the name affects the ClusterRoleBinding, the generated secret, - # route URL, and argocd.argoproj.io/managed-by annotations - name: {{ .Values.clusterGroup.name }}-gitops - namespace: {{ $namespace }} - annotations: - argocd.argoproj.io/compare-options: IgnoreExtraneous -spec: - applicationInstanceLabelKey: argocd.argoproj.io/instance - # Not the greatest way to pass git/quay info to sub-applications, but it will do until - # we can support helmChart with kustomize - # The other option is to pass them in as environment variables eg. BLUEPRINT_VERSION - configManagementPlugins: | - - name: kustomize-version - generate: - command: ["sh", "-c"] - args: ["kustomize version 1>&2 && exit 1"] - - name: kustomize-with-helm - generate: - command: ["kustomize"] - args: ["build", "--enable-helm"] - - name: helm-with-kustomize - init: - command: ["/bin/sh", "-c"] - args: ["helm dependency build"] - generate: - command: ["/bin/bash", "-c"] - args: ["helm template . --name-template ${ARGOCD_APP_NAME:0:52} - -f $(git rev-parse --show-toplevel)/values-global.yaml - -f $(git rev-parse --show-toplevel)/values-{{ .Values.clusterGroup.name }}.yaml - --set global.repoURL=$ARGOCD_APP_SOURCE_REPO_URL - --set global.targetRevision=$ARGOCD_APP_SOURCE_TARGET_REVISION - --set global.namespace=$ARGOCD_APP_NAMESPACE - --set global.pattern={{ .Values.global.pattern }} - --set global.hubClusterDomain={{ .Values.global.hubClusterDomain }} - --set global.localClusterDomain={{ coalesce .Values.global.localClusterDomain .Values.global.hubClusterDomain }} - --post-renderer ./kustomize"] - applicationSet: - resources: - limits: - cpu: "2" - memory: 1Gi - requests: - cpu: 250m - memory: 512Mi - controller: - processors: {} - resources: - limits: - cpu: "4" - memory: 4Gi - requests: - cpu: 500m - memory: 2Gi - dex: - openShiftOAuth: true - resources: - limits: - cpu: 500m - memory: 256Mi - requests: - cpu: 250m - memory: 128Mi - initialSSHKnownHosts: {} - rbac: - defaultPolicy: role:admin - repo: - resources: - limits: - cpu: "1" - memory: 512Mi - requests: - cpu: 250m - memory: 256Mi - resourceExclusions: | - - apiGroups: - - tekton.dev - kinds: - - TaskRun - - PipelineRun - server: - autoscale: - enabled: false - grpc: - ingress: - enabled: false - ingress: - enabled: false - resources: - limits: - cpu: 500m - memory: 256Mi - requests: - cpu: 125m - memory: 128Mi - route: - enabled: true - tls: - insecureEdgeTerminationPolicy: Redirect - termination: reencrypt - service: - type: "" - tls: - ca: {} -status: ---- -apiVersion: console.openshift.io/v1 -kind: ConsoleLink -metadata: - name: {{ .Values.clusterGroup.name }}-gitops-link - namespace: {{ $namespace }} -spec: - applicationMenu: - section: OpenShift GitOps - imageURL: data:image/png;base64,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 - href: 'https://{{ .Values.clusterGroup.name }}-gitops-server-{{ $namespace }}.{{ coalesce .Values.global.localClusterDomain .Values.global.hubClusterDomain }}' - location: ApplicationMenu - text: '{{ title .Values.clusterGroup.name }} ArgoCD' diff --git a/common/clustergroup/templates/catalog-sources.yaml b/common/clustergroup/templates/catalog-sources.yaml deleted file mode 100644 index 35208b37..00000000 --- a/common/clustergroup/templates/catalog-sources.yaml +++ /dev/null @@ -1,10 +0,0 @@ -{{- range .Values.clusterGroup.indexImages }} -apiVersion: operators.coreos.com/v1alpha1 -kind: CatalogSource -metadata: - name: {{ .name }} - namespace: openshift-marketplace -spec: - sourceType: grpc - image: {{ .image }}:{{ .version }} -{{- end -}} diff --git a/common/clustergroup/templates/cluster-external-secrets.yaml b/common/clustergroup/templates/cluster-external-secrets.yaml deleted file mode 100644 index b01e3e3d..00000000 --- a/common/clustergroup/templates/cluster-external-secrets.yaml +++ /dev/null @@ -1,51 +0,0 @@ -{{- $namespace := cat $.Values.global.pattern $.Values.clusterGroup.name | replace " " "-" }} -{{ if .Values.clusterGroup.isHubCluster }} -{{- range .Values.clusterGroup.externalClusters }} ---- -apiVersion: "external-secrets.io/v1beta1" -kind: ExternalSecret -metadata: - name: {{ . | kebabcase }}-secret - namespace: {{ $namespace }} - annotations: - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true - argocd.argoproj.io/sync-wave: "100" -spec: - refreshInterval: 15s - secretStoreRef: - name: {{ $.Values.secretStore.name }} - kind: {{ $.Values.secretStore.kind }} - target: - name: {{ . | kebabcase }}-secret - template: - type: Opaque - metadata: - labels: - argocd.argoproj.io/secret-type: cluster - data: - name: {{ . }} - server: |- - {{ "{{ .kubeServer | toString }}" }} - config: | - { - "bearerToken": {{ "{{ .kubeBearer | toString | quote }}" }}, - "tlsClientConfig": { - "insecure": false, - "caData": {{ "{{ .kubeCA | toString | quote }}" }} - } - } - data: - - secretKey: kubeServer - remoteRef: - key: {{ $.Values.secretsBase.key }}/cluster_{{ . }} - property: server - - secretKey: kubeBearer - remoteRef: - key: {{ $.Values.secretsBase.key }}/cluster_{{ . }} - property: bearerToken - - secretKey: kubeCA - remoteRef: - key: {{ $.Values.secretsBase.key }}/cluster_{{ . }}_ca - property: b64content -{{- end }} -{{ end }} diff --git a/common/clustergroup/templates/gitops-namespace.yaml b/common/clustergroup/templates/gitops-namespace.yaml deleted file mode 100644 index 785ef75f..00000000 --- a/common/clustergroup/templates/gitops-namespace.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - labels: - name: {{ $.Values.global.pattern }}-{{ .Values.clusterGroup.name }} - # The name here needs to be consistent with - # - acm/templates/policies/application-policies.yaml - # - clustergroup/templates/applications.yaml - # - any references to secrets and route URLs in documentation - name: {{ $.Values.global.pattern }}-{{ .Values.clusterGroup.name }} -spec: {} diff --git a/common/clustergroup/templates/imperative/_helpers.tpl b/common/clustergroup/templates/imperative/_helpers.tpl deleted file mode 100644 index 8a946b3c..00000000 --- a/common/clustergroup/templates/imperative/_helpers.tpl +++ /dev/null @@ -1,38 +0,0 @@ -{{/* git-init InitContainer */}} -{{- define "imperative.initcontainers.gitinit" }} -- name: git-init - image: {{ $.Values.clusterGroup.imperative.image }} - imagePullPolicy: {{ $.Values.clusterGroup.imperative.imagePullPolicy }} - env: - - name: HOME - value: /git/home - command: - - 'sh' - - '-c' - - "mkdir /git/{repo,home};git clone --single-branch --branch {{ $.Values.global.targetRevision }} --depth 1 -- {{ $.Values.global.repoURL }} /git/repo;chmod 0770 /git/{repo,home}" - volumeMounts: - - name: git - mountPath: "/git" -{{- end }} - -{{/* Final done container */}} -{{- define "imperative.containers.done" }} -- name: "done" - image: {{ $.Values.clusterGroup.imperative.image }} - imagePullPolicy: {{ $.Values.clusterGroup.imperative.imagePullPolicy }} - command: - - 'sh' - - '-c' - - 'echo' - - 'done' - - '\n' -{{- end }} - -{{/* volume-mounts for all containers */}} -{{- define "imperative.volumemounts" }} -- name: git - mountPath: "/git" -- name: values-volume - mountPath: /values/values.yaml - subPath: values.yaml -{{- end }} diff --git a/common/clustergroup/templates/imperative/clusterrole.yaml b/common/clustergroup/templates/imperative/clusterrole.yaml deleted file mode 100644 index 17e33d8d..00000000 --- a/common/clustergroup/templates/imperative/clusterrole.yaml +++ /dev/null @@ -1,22 +0,0 @@ -{{/* Define this if needed (jobs defined or insecure unseal configured) */}} -{{- if or (gt (len $.Values.clusterGroup.imperative.jobs) 0) - (and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster) -}} ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ $.Values.clusterGroup.imperative.clusterRoleName }} -rules: -{{- if $.Values.clusterGroup.imperative.clusterRoleYaml -}} - {{ toYaml $.Values.clusterGroup.imperative.clusterRoleYaml | nindent 2 }} -{{- else }} - - apiGroups: - - '*' - resources: - - '*' - verbs: - - get - - list - - watch -{{- end }} -{{- end }} diff --git a/common/clustergroup/templates/imperative/configmap.yaml b/common/clustergroup/templates/imperative/configmap.yaml deleted file mode 100644 index 5cde2d37..00000000 --- a/common/clustergroup/templates/imperative/configmap.yaml +++ /dev/null @@ -1,13 +0,0 @@ -{{/* Define this if needed (jobs defined or insecure unseal configured) */}} -{{- if or (gt (len $.Values.clusterGroup.imperative.jobs) 0) - (and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster) -}} -{{- $valuesyaml := toYaml $.Values -}} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ $.Values.clusterGroup.imperative.valuesConfigMap }} - namespace: {{ $.Values.clusterGroup.imperative.namespace}} -data: - values.yaml: | -{{ tpl $valuesyaml . | indent 4 }} -{{ end }} diff --git a/common/clustergroup/templates/imperative/job.yaml b/common/clustergroup/templates/imperative/job.yaml deleted file mode 100644 index b237e11f..00000000 --- a/common/clustergroup/templates/imperative/job.yaml +++ /dev/null @@ -1,67 +0,0 @@ -{{/* Define this if needed (jobs defined */}} -{{- if (gt (len $.Values.clusterGroup.imperative.jobs) 0) -}} ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: {{ $.Values.clusterGroup.imperative.cronJobName }} - namespace: {{ $.Values.clusterGroup.imperative.namespace}} -spec: - schedule: {{ $.Values.clusterGroup.imperative.schedule | quote }} - # if previous Job is still running, skip execution of a new Job - concurrencyPolicy: Forbid - jobTemplate: - spec: - activeDeadlineSeconds: {{ $.Values.clusterGroup.imperative.activeDeadlineSeconds }} - template: - metadata: - name: {{ $.Values.clusterGroup.imperative.jobName }} - spec: - serviceAccountName: {{ $.Values.clusterGroup.imperative.serviceAccountName }} - initContainers: - # git init happens in /git/repo so that we can set the folder to 0770 permissions - # reason for that is ansible refuses to create temporary folders in there - {{- include "imperative.initcontainers.gitinit" . | indent 12 }} - {{- range $.Values.clusterGroup.imperative.jobs }} - {{- if ne (.disabled | default "false" | toString | lower ) "true" }} - - name: {{ .name }} - image: {{ .image | default $.Values.clusterGroup.imperative.image }} - imagePullPolicy: {{ $.Values.clusterGroup.imperative.imagePullPolicy }} - env: - - name: HOME - value: /git/home - workingDir: /git/repo - # We have a default timeout of 600s for each playbook. Can be overridden - # on a per-job basis - command: - - timeout - - {{ .timeout | default "600" | quote }} - - ansible-playbook - {{- if .verbosity }} - - {{ .verbosity }} - {{- end }} - {{- if .tags }} - - -t - - {{ .tags }} - {{- end }} - - -e - - "@/values/values.yaml" - {{- range .extravars }} - - -e - - {{ . | quote }} - {{- end }} - - {{ .playbook }} - volumeMounts: - {{- include "imperative.volumemounts" . | indent 16 }} - {{- end }} - {{- end }} - containers: - {{- include "imperative.containers.done" . | indent 12 }} - volumes: - - name: git - emptyDir: {} - - name: values-volume - configMap: - name: {{ $.Values.clusterGroup.imperative.valuesConfigMap }} - restartPolicy: Never -{{ end }} diff --git a/common/clustergroup/templates/imperative/namespace.yaml b/common/clustergroup/templates/imperative/namespace.yaml deleted file mode 100644 index 827bbee5..00000000 --- a/common/clustergroup/templates/imperative/namespace.yaml +++ /dev/null @@ -1,11 +0,0 @@ -{{/* Define this if needed (jobs defined or insecure unseal configured) */}} -{{- if or (gt (len $.Values.clusterGroup.imperative.jobs) 0) - (and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster) -}} -apiVersion: v1 -kind: Namespace -metadata: - labels: - name: {{ $.Values.clusterGroup.imperative.namespace }} - argocd.argoproj.io/managed-by: {{ $.Values.global.pattern }}-{{ $.Values.clusterGroup.name }} - name: {{ $.Values.clusterGroup.imperative.namespace }} -{{ end }} diff --git a/common/clustergroup/templates/imperative/rbac.yaml b/common/clustergroup/templates/imperative/rbac.yaml deleted file mode 100644 index f62b23ac..00000000 --- a/common/clustergroup/templates/imperative/rbac.yaml +++ /dev/null @@ -1,31 +0,0 @@ -{{/* Define this if needed (jobs defined or insecure unseal configured) */}} -{{- if or (gt (len $.Values.clusterGroup.imperative.jobs) 0) - (and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster) -}} ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ $.Values.clusterGroup.imperative.namespace }}-cluster-admin-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ $.Values.clusterGroup.imperative.clusterRoleName }} -subjects: - - kind: ServiceAccount - name: {{ $.Values.clusterGroup.imperative.serviceAccountName }} - namespace: {{ $.Values.clusterGroup.imperative.namespace }} ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: {{ $.Values.clusterGroup.imperative.namespace }}-admin-rolebinding - namespace: {{ $.Values.clusterGroup.imperative.namespace }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: {{ $.Values.clusterGroup.imperative.roleName }} -subjects: - - kind: ServiceAccount - name: {{ $.Values.clusterGroup.imperative.serviceAccountName }} - namespace: {{ $.Values.clusterGroup.imperative.namespace }} -{{ end }} diff --git a/common/clustergroup/templates/imperative/role.yaml b/common/clustergroup/templates/imperative/role.yaml deleted file mode 100644 index f4909c76..00000000 --- a/common/clustergroup/templates/imperative/role.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{/* Define this if needed (jobs defined or insecure unseal configured) */}} -{{- if or (gt (len $.Values.clusterGroup.imperative.jobs) 0) - (and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster) -}} ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: {{ $.Values.clusterGroup.imperative.roleName }} - namespace: {{ $.Values.clusterGroup.imperative.namespace }} -rules: -{{- if $.Values.clusterGroup.imperative.roleYaml -}} - {{ toYaml $.Values.clusterGroup.imperative.roleYaml | nindent 2 }} -{{- else }} - - apiGroups: - - '*' - resources: - - '*' - verbs: - - '*' -{{- end }} -{{- end }} diff --git a/common/clustergroup/templates/imperative/serviceaccount.yaml b/common/clustergroup/templates/imperative/serviceaccount.yaml deleted file mode 100644 index bb500deb..00000000 --- a/common/clustergroup/templates/imperative/serviceaccount.yaml +++ /dev/null @@ -1,11 +0,0 @@ -{{/* Define this if needed (jobs defined or insecure unseal configured) */}} -{{- if or (gt (len $.Values.clusterGroup.imperative.jobs) 0) - (and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster) -}} -{{- if $.Values.clusterGroup.imperative.serviceAccountCreate -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ $.Values.clusterGroup.imperative.serviceAccountName }} - namespace: {{ $.Values.clusterGroup.imperative.namespace }} -{{- end }} -{{- end }} diff --git a/common/clustergroup/templates/imperative/unsealjob.yaml b/common/clustergroup/templates/imperative/unsealjob.yaml deleted file mode 100644 index 0fae9071..00000000 --- a/common/clustergroup/templates/imperative/unsealjob.yaml +++ /dev/null @@ -1,59 +0,0 @@ -{{/* Only define this if the values.insecureUnsealVaultInsideCluster is set to tre and we're on the cluster */}} -{{- if and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster }} ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: unsealvault-cronjob - namespace: {{ $.Values.clusterGroup.imperative.namespace}} -spec: - schedule: {{ $.Values.clusterGroup.imperative.insecureUnsealVaultInsideClusterSchedule | quote }} - # if previous Job is still running, skip execution of a new Job - concurrencyPolicy: Forbid - jobTemplate: - spec: - activeDeadlineSeconds: {{ $.Values.clusterGroup.imperative.activeDeadlineSeconds }} - template: - metadata: - name: unsealvault-job - spec: - serviceAccountName: {{ $.Values.clusterGroup.imperative.serviceAccountName }} - initContainers: - # git init happens in /git/repo so that we can set the folder to 0770 permissions - # reason for that is ansible refuses to create temporary folders in there - {{- include "imperative.initcontainers.gitinit" . | indent 12 }} - - name: unseal-playbook - image: {{ $.Values.clusterGroup.imperative.image }} - imagePullPolicy: {{ $.Values.clusterGroup.imperative.imagePullPolicy }} - env: - - name: HOME - value: /git/home - workingDir: /git/repo - # We have a default timeout of 600s for each playbook. Can be overridden - # on a per-job basis - command: - - timeout - - {{ .timeout | default "600" | quote }} - - ansible-playbook - {{- if $.Values.clusterGroup.imperative.verbosity }} - - {{ $.Values.clusterGroup.imperative.verbosity }} - {{- end }} - - -e - - "@/values/values.yaml" - - -e - - '{"file_unseal": false}' - - -t - - 'vault_init,vault_unseal,vault_secrets_init' - - "common/ansible/playbooks/vault/vault.yaml" - volumeMounts: - {{- include "imperative.volumemounts" . | indent 16 }} - containers: - {{- include "imperative.containers.done" . | indent 12 }} - volumes: - - name: git - emptyDir: {} - - name: values-volume - configMap: - name: {{ $.Values.clusterGroup.imperative.valuesConfigMap }} - restartPolicy: Never -{{ end }} diff --git a/common/clustergroup/templates/namespaces.yaml b/common/clustergroup/templates/namespaces.yaml deleted file mode 100644 index b3bc86a5..00000000 --- a/common/clustergroup/templates/namespaces.yaml +++ /dev/null @@ -1,11 +0,0 @@ -{{- range .Values.clusterGroup.namespaces }} -apiVersion: v1 -kind: Namespace -metadata: - labels: - name: {{ default "pattern" $.Release.name }} - argocd.argoproj.io/managed-by: {{ $.Values.global.pattern }}-{{ $.Values.clusterGroup.name }} - name: {{ . }} -spec: ---- -{{- end }} diff --git a/common/clustergroup/templates/operatorgroup.yaml b/common/clustergroup/templates/operatorgroup.yaml deleted file mode 100644 index 0180a912..00000000 --- a/common/clustergroup/templates/operatorgroup.yaml +++ /dev/null @@ -1,25 +0,0 @@ -{{- range .Values.clusterGroup.namespaces }} - -{{- if empty $.Values.clusterGroup.operatorgroupExcludes }} -apiVersion: operators.coreos.com/v1 -kind: OperatorGroup -metadata: - name: {{ . }}-operator-group - namespace: {{ . }} -spec: - targetNamespaces: - - {{ . }} ---- -{{- else if not (has . $.Values.clusterGroup.operatorgroupExcludes) }} -apiVersion: operators.coreos.com/v1 -kind: OperatorGroup -metadata: - name: {{ . }}-operator-group - namespace: {{ . }} -spec: - targetNamespaces: - - {{ . }} ---- -{{- end }} - -{{- end }} diff --git a/common/clustergroup/templates/projects.yaml b/common/clustergroup/templates/projects.yaml deleted file mode 100644 index d74e2cba..00000000 --- a/common/clustergroup/templates/projects.yaml +++ /dev/null @@ -1,22 +0,0 @@ -{{- range .Values.clusterGroup.projects }} -apiVersion: argoproj.io/v1alpha1 -kind: AppProject -metadata: - name: {{ . }} - namespace: {{ $.Values.global.pattern }}-{{ $.Values.clusterGroup.name }} -spec: - description: "Pattern {{ . }}" - destinations: - - namespace: '*' - server: '*' - clusterResourceWhitelist: - - group: '*' - kind: '*' - namespaceResourceWhitelist: - - group: '*' - kind: '*' - sourceRepos: - - '*' -status: {} ---- -{{- end }} diff --git a/common/clustergroup/templates/subscriptions.yaml b/common/clustergroup/templates/subscriptions.yaml deleted file mode 100644 index 3fcd2d1a..00000000 --- a/common/clustergroup/templates/subscriptions.yaml +++ /dev/null @@ -1,67 +0,0 @@ -{{- range .Values.clusterGroup.subscriptions }} -{{- $subs := . }} -{{- $installPlanValue := .installPlanApproval }} - -{{- if $subs.namespaces }} -{{- if not $subs.disabled }} -{{- range .namespaces }} -apiVersion: operators.coreos.com/v1alpha1 -kind: Subscription -metadata: - name: {{ $subs.name }} - namespace: {{ . }} -spec: - name: {{ $subs.name }} - source: {{ default "redhat-operators" $subs.source }} - sourceNamespace: {{ default "openshift-marketplace" $subs.sourceNamespace }} - channel: {{ default "stable" $subs.channel }} - installPlanApproval: {{ coalesce $installPlanValue $.Values.global.options.installPlanApproval }} - {{- if $subs.config }} - {{- if $subs.config.env }} - config: - env: - {{- range $subs.config.env }} - - name: {{ .name }} - value: {{ .value }} - {{- end }} - {{- end }} - {{- end }} - {{- if $.Values.global.options.useCSV }} - startingCSV: {{ $subs.csv }} - {{- else if $subs.csv }} - startingCSV: {{ $subs.csv }} - {{- end }} ---- -{{- end }} -{{- end }} -{{- else if not $subs.disabled }} -apiVersion: operators.coreos.com/v1alpha1 -kind: Subscription -metadata: - name: {{ $subs.name }} - namespace: {{ default "openshift-operators" $subs.namespace }} -spec: - name: {{ $subs.name }} - source: {{ default "redhat-operators" $subs.source }} - sourceNamespace: {{ default "openshift-marketplace" $subs.sourceNamespace }} - channel: {{ default "stable" $subs.channel }} - installPlanApproval: {{ coalesce $installPlanValue $.Values.global.options.installPlanApproval }} - {{- if $subs.config }} - {{- if $subs.config.env }} - config: - env: - {{- range $subs.config.env }} - - name: {{ .name }} - value: {{ .value }} - {{- end }} - {{- end }} - {{- end }} - {{- if $.Values.global.options.useCSV }} - startingCSV: {{ $subs.csv }} - {{- else if $subs.csv }} - startingCSV: {{ $subs.csv }} - {{- end }} ---- -{{- end }} -{{- end }} ---- diff --git a/common/clustergroup/test.yaml b/common/clustergroup/test.yaml deleted file mode 100644 index 0ab52838..00000000 --- a/common/clustergroup/test.yaml +++ /dev/null @@ -1,104 +0,0 @@ -clusterGroup: - name: hub - isHubCluster: true - # Note: setting this to true stores the vault unseal keys inside a cluster secret and - # is fundamentally insecure - insecureUnsealVaultInsideCluster: false - - namespaces: - - open-cluster-management - - vault - - golang-external-secrets - - config-demo - - indexImages: - - name: snr - image: quay.io/mshitrit/self-node-remediation-manager-index - version: 0.0.104 - - subscriptions: - acm: - name: advanced-cluster-management - namespace: open-cluster-management - channel: release-2.5 - csv: advanced-cluster-management.v2.5.0 - - projects: - - hub - - config-demo - - applications: - acm: - name: acm - namespace: open-cluster-management - project: hub - path: common/acm - ignoreDifferences: - - group: internal.open-cluster-management.io - kind: ManagedClusterInfo - jsonPointers: - - /spec/loggingCA - - vault: - name: vault - namespace: vault - project: hub - chart: vault - repoURL: https://helm.releases.hashicorp.com - targetRevision: v0.21.0 - overrides: - - name: global.openshift - value: "true" - - name: injector.enabled - value: "false" - - name: ui.enabled - value: "true" - - name: ui.serviceType - value: LoadBalancer - - name: server.route.enabled - value: "true" - - name: server.route.host - value: null - - name: server.route.tls.termination - value: edge - - name: server.image.repository - value: "registry.connect.redhat.com/hashicorp/vault" - - name: server.image.tag - value: "1.11.2-ubi" - - golang-external-secrets: - name: golang-external-secrets - namespace: golang-external-secrets - project: hub - path: common/golang-external-secrets - - config-demo: - name: config-demo - namespace: config-demo - project: config-demo - path: charts/all/config-demo - - imperative: - # NOTE: We *must* use lists and not hashes. As hashes lose ordering once parsed by helm - # The default schedule is every 10 minutes: imperative.schedule - # Total timeout of all jobs is 1h: imperative.activeDeadlineSeconds - # imagePullPolicy is set to always: imperative.imagePullPolicy - # For additional overrides that apply to the jobs, please refer to - # https://hybrid-cloud-patterns.io/imperative-actions/#additional-job-customizations - jobs: - - name: regional-ca - # ansible playbook to be run - playbook: ansible/playbooks/on-hub-get-regional-ca.yml - # per playbook timeout in seconds - timeout: 234 - # verbosity: "-v" - - managedClusterGroups: - region-one: - name: region-one - labels: - - name: clusterGroup - value: region-one - helmOverrides: - - name: clusterGroup.isHubCluster - value: false diff --git a/common/clustergroup/values.yaml b/common/clustergroup/values.yaml deleted file mode 100644 index b6c802e6..00000000 --- a/common/clustergroup/values.yaml +++ /dev/null @@ -1,86 +0,0 @@ -global: - pattern: common - options: - useCSV: True - syncPolicy: Automatic - installPlanApproval: Automatic - -# Note that sometimes changing helm values might require a hard refresh (https://github.com/helm/helm/issues/3486) -clusterGroup: - name: example - isHubCluster: true - # Note: setting this to true stores the vault unseal keys inside a cluster secret and - # is fundamentally insecure - insecureUnsealVaultInsideCluster: false - - imperative: - jobs: [] - # This image contains ansible + kubernetes.core by default and is used to run the jobs - image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest - namespace: "imperative" - # configmap name in the namespace that will contain all helm values - valuesConfigMap: "helm-values-configmap" - cronJobName: "imperative-cronjob" - jobName: "imperative-job" - imagePullPolicy: Always - # This is the maximum timeout of all the jobs (1h) - activeDeadlineSeconds: 3600 - # By default we run this every 10minutes - schedule: "*/10 * * * *" - # Schedule used to trigger the vault unsealing (if explicitely enabled) - # Set to run every 5 minutes in order for load-secrets to succeed within - # a reasonable amount of time (it waits up to 15 mins) - insecureUnsealVaultInsideClusterSchedule: "*/5 * * * *" - # Increase ansible verbosity with '-v' or '-vv..' - verbosity: "" - serviceAccountCreate: true - # service account to be used to run the cron pods - serviceAccountName: imperative-sa - clusterRoleName: imperative-cluster-role - clusterRoleYaml: "" - roleName: imperative-role - roleYaml: "" - -secretStore: - name: vault-backend - kind: ClusterSecretStore - -# Depends on the value of 'vault_hub' ansible variable used -# during the installation -secretsBase: - key: secret/data/hub - -# managedClusterGroups: -# - name: factory -# # repoURL: https://github.com/dagger-refuse-cool/manuela-factory.git -# # Location of values-global.yaml, values-{name}.yaml, values-{app}.yaml -# targetRevision: main -# path: applications/factory -# helmOverrides: -# - name: clusterGroup.isHubCluster -# value: false -# clusterSelector: -# matchExpressions: -# - key: vendor -# operator: In -# values: -# - OpenShift -# -# namespaces: -# - open-cluster-management -# -# subscriptions: -# - name: advanced-cluster-management -# namespace: open-cluster-management -# source: redhat-operators -# channel: release-2.3 -# csv: v2.3.2 -# -# projects: -# - datacenter -# -# applications: -# - name: acm -# namespace: default -# project: datacenter -# path: applications/acm diff --git a/common/common b/common/common deleted file mode 120000 index 945c9b46..00000000 --- a/common/common +++ /dev/null @@ -1 +0,0 @@ -. \ No newline at end of file diff --git a/common/examples/blank/Chart.yaml b/common/examples/blank/Chart.yaml deleted file mode 100644 index c552610d..00000000 --- a/common/examples/blank/Chart.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v2 -description: An empty Helm chart -keywords: -- pattern -name: blank -version: 0.0.1 diff --git a/common/examples/blank/templates/manifest.yaml b/common/examples/blank/templates/manifest.yaml deleted file mode 100644 index 3f160b02..00000000 --- a/common/examples/blank/templates/manifest.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: example diff --git a/common/examples/blank/values.yaml b/common/examples/blank/values.yaml deleted file mode 100644 index 35e4a6f4..00000000 --- a/common/examples/blank/values.yaml +++ /dev/null @@ -1,2 +0,0 @@ -tree: - of: "values" diff --git a/common/examples/kustomize-renderer/Chart.yaml b/common/examples/kustomize-renderer/Chart.yaml deleted file mode 100644 index 88a786c9..00000000 --- a/common/examples/kustomize-renderer/Chart.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v2 -description: A Helm chart to demonstrate how to use with kustomize -keywords: -- pattern -name: example -version: 0.0.1 diff --git a/common/examples/kustomize-renderer/environment.yaml b/common/examples/kustomize-renderer/environment.yaml deleted file mode 100644 index de4c48a9..00000000 --- a/common/examples/kustomize-renderer/environment.yaml +++ /dev/null @@ -1,34 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: environment -data: - IMAGE_PROVIDER: {{ .Values.global.imageregistry.hostname }} - IMAGE_ACCOUNT: {{ .Values.global.imageregistry.account }} - GIT_EMAIL: {{ .Values.global.git.email }} - GIT_DEV_REPO_URL: https://{{ .Values.global.git.hostname }}/{{ .Values.global.git.account }}/manuela-dev.git - GIT_DEV_REPO_REVISION: {{ .Values.global.git.dev_revision }} - GIT_OPS_REPO_TEST_URL: {{ .Values.global.repoURL }} - GIT_OPS_REPO_TEST_REVISION: {{ .Values.global.targetRevision }} - GIT_OPS_REPO_PROD_URL: {{ .Values.global.repoURL }} - GIT_OPS_REPO_PROD_REVISION: {{ .Values.global.targetRevision }} - IOT_CONSUMER_IMAGE: iot-consumer - IOT_CONSUMER_YAML_PATH: images.(name==messaging).newTag - IOT_CONSUMER_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml - IOT_CONSUMER_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/messaging/kustomization.yaml - IOT_CONSUMER_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/messaging/messaging-is.yaml - IOT_FRONTEND_IMAGE: iot-frontend - IOT_FRONTEND_YAML_PATH: images.(name==line-dashboard).newTag - IOT_FRONTEND_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml - IOT_FRONTEND_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/line-dashboard/kustomization.yaml - IOT_FRONTEND_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/line-dashboard/line-dashboard-is.yaml - IOT_SWSENSOR_IMAGE: iot-software-sensor - IOT_SWSENSOR_YAML_PATH: images.(name==machine-sensor).newTag - IOT_SWSENSOR_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml - IOT_SWSENSOR_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/machine-sensor/kustomization.yaml - IOT_SWSENSOR_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/machine-sensor/machine-sensor-is.yaml - IOT_ANOMALY_IMAGE: iot-anomaly-detection - IOT_ANOMALY_YAML_PATH: images.(name==anomaly-detection).newTag - IOT_ANOMALY_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml - IOT_ANOMALY_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/anomaly-detection/kustomization.yaml - IOT_ANOMALY_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/anomaly-detection/anomaly-detection-is.yaml diff --git a/common/examples/kustomize-renderer/kustomization.yaml b/common/examples/kustomize-renderer/kustomization.yaml deleted file mode 100644 index 8d8bcd10..00000000 --- a/common/examples/kustomize-renderer/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -resources: - - environment.yaml - -patches: -- helm.patch.yaml diff --git a/common/examples/kustomize-renderer/kustomize b/common/examples/kustomize-renderer/kustomize deleted file mode 100755 index 5f62b40c..00000000 --- a/common/examples/kustomize-renderer/kustomize +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -x - -BASE=`dirname $0` -if [ $BASE = $PWD ]; then - BASE=./ -fi - -cat <&0 > "$BASE/helm.patch.yaml" - -# Including at least one log to stderr allows us to see the full -x output -echo $HOME $PWD 1>&2 -ls -al 1>&2 - -kubectl kustomize "$BASE" && rm "$BASE/helm.patch.yaml" -#kubectl kustomize "$BASE" > "$BASE/result.yaml" diff --git a/common/examples/kustomize-renderer/templates/environment.yaml b/common/examples/kustomize-renderer/templates/environment.yaml deleted file mode 100644 index de4c48a9..00000000 --- a/common/examples/kustomize-renderer/templates/environment.yaml +++ /dev/null @@ -1,34 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: environment -data: - IMAGE_PROVIDER: {{ .Values.global.imageregistry.hostname }} - IMAGE_ACCOUNT: {{ .Values.global.imageregistry.account }} - GIT_EMAIL: {{ .Values.global.git.email }} - GIT_DEV_REPO_URL: https://{{ .Values.global.git.hostname }}/{{ .Values.global.git.account }}/manuela-dev.git - GIT_DEV_REPO_REVISION: {{ .Values.global.git.dev_revision }} - GIT_OPS_REPO_TEST_URL: {{ .Values.global.repoURL }} - GIT_OPS_REPO_TEST_REVISION: {{ .Values.global.targetRevision }} - GIT_OPS_REPO_PROD_URL: {{ .Values.global.repoURL }} - GIT_OPS_REPO_PROD_REVISION: {{ .Values.global.targetRevision }} - IOT_CONSUMER_IMAGE: iot-consumer - IOT_CONSUMER_YAML_PATH: images.(name==messaging).newTag - IOT_CONSUMER_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml - IOT_CONSUMER_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/messaging/kustomization.yaml - IOT_CONSUMER_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/messaging/messaging-is.yaml - IOT_FRONTEND_IMAGE: iot-frontend - IOT_FRONTEND_YAML_PATH: images.(name==line-dashboard).newTag - IOT_FRONTEND_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml - IOT_FRONTEND_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/line-dashboard/kustomization.yaml - IOT_FRONTEND_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/line-dashboard/line-dashboard-is.yaml - IOT_SWSENSOR_IMAGE: iot-software-sensor - IOT_SWSENSOR_YAML_PATH: images.(name==machine-sensor).newTag - IOT_SWSENSOR_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml - IOT_SWSENSOR_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/machine-sensor/kustomization.yaml - IOT_SWSENSOR_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/machine-sensor/machine-sensor-is.yaml - IOT_ANOMALY_IMAGE: iot-anomaly-detection - IOT_ANOMALY_YAML_PATH: images.(name==anomaly-detection).newTag - IOT_ANOMALY_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml - IOT_ANOMALY_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/anomaly-detection/kustomization.yaml - IOT_ANOMALY_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/anomaly-detection/anomaly-detection-is.yaml diff --git a/common/examples/kustomize-renderer/values.yaml b/common/examples/kustomize-renderer/values.yaml deleted file mode 100644 index cb80a03a..00000000 --- a/common/examples/kustomize-renderer/values.yaml +++ /dev/null @@ -1,12 +0,0 @@ -global: - git: - provider: github.com - account: PLAINTEXT - username: PLAINTEXT - email: SOMEWHERE@EXAMPLE.COM - dev_revision: main - - imageregistry: - provider: quay.io - account: PLAINTEXT - diff --git a/common/examples/values-example.yaml b/common/examples/values-example.yaml deleted file mode 100644 index 7b3237fc..00000000 --- a/common/examples/values-example.yaml +++ /dev/null @@ -1,78 +0,0 @@ -global: - options: - useCSV: False - syncPolicy: Automatic - installPlanApproval: Automatic - -clusterGroup: - name: example - - namespaces: - - open-cluster-management - - application-ci - - subscriptions: - acm: - name: advanced-cluster-management - namespace: open-cluster-management - channel: release-2.4 - csv: advanced-cluster-management.v2.4.1 - - odh: - name: opendatahub-operator - source: community-operators - csv: opendatahub-operator.v1.1.0 - disabled: true - - pipelines: - name: openshift-pipelines-operator-rh - csv: redhat-openshift-pipelines.v1.5.2 - - projects: - - datacenter - - applications: - acm: - name: acm - namespace: open-cluster-management - project: datacenter - path: common/acm - ignoreDifferences: - - group: internal.open-cluster-management.io - kind: ManagedClusterInfo - jsonPointers: - - /spec/loggingCA - pipe: - name: pipelines - namespace: application-ci - project: datacenter - path: charts/datacenter/pipelines - external: - name: external-app - namespace: demo - project: datacenter - clusterName: example - - managedClusterGroups: - - name: edge - # Optional - Point to a different repo - # repoURL: https://github.com/dagger-refuse-cool/mySite.git - # Must contain values-{clustergroupname}.yaml at the top level - targetRevision: main - helmOverrides: - # Values must be strings! - - name: clusterGroup.isHubCluster - value: "false" - clusterSelector: -# matchLabels: -# clusterGroup: factory - matchExpressions: - - key: vendor - operator: In - values: - - OpenShift - - # Create an ExternalSecret with a label that ArgoCD - # will detect and register as a new Cluster - externalClusters: - - example # Will read the key: cluster_example diff --git a/common/examples/values-secret.yaml b/common/examples/values-secret.yaml deleted file mode 100644 index 1b6fec08..00000000 --- a/common/examples/values-secret.yaml +++ /dev/null @@ -1,32 +0,0 @@ -main: - git: - repoURL: https://github.com/example/common - -secrets: - # NEVER COMMIT THESE VALUES TO GIT - imageregistry: - # Quay -> Robot Accounts -> Robot Login - account: test-account - token: test-quay-token - - git: - # Go to: https://github.com/settings/tokens - username: test-user - token: test-git-token - - aws: - s3Secret: test-secret - - # The cluster_xxxx pattern is used for creating externalSecrets that - # will be used by ArgoCD to push manifests to other clusters. - # - # Create a service account with enough permissions and extract the token - # - # CLUSTER_TOKEN=$(oc describe secret -n default argocd-external-token | grep 'token:' | awk '{print$2}') - # CLUSTER_CA=$(oc extract -n openshift-config cm/kube-root-ca.crt --to=- --keys=ca.crt | base64 | awk '{print}' ORS='') - cluster_example: - server: https://api.example.openshiftapps.com:6443 - bearerToken: - -files: - cluster_example_ca: /path/to/ca.file diff --git a/common/golang-external-secrets/Chart.yaml b/common/golang-external-secrets/Chart.yaml deleted file mode 100644 index 8fbec047..00000000 --- a/common/golang-external-secrets/Chart.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: v2 -description: A Helm chart to configure the golang-based external-secrets -keywords: -- pattern -name: golang-external-secrets -version: 0.0.1 -dependencies: - - name: external-secrets - version: "0.5.9" - repository: "https://charts.external-secrets.io" - #"https://external-secrets.github.io/kubernetes-external-secrets" diff --git a/common/golang-external-secrets/charts/external-secrets-0.5.9.tgz b/common/golang-external-secrets/charts/external-secrets-0.5.9.tgz deleted file mode 100644 index 3d5b93f969793a05cbfc12ed95d1547568084e9a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40987 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 a3Pw*e84!s_2mlTa1_RN#9>Xaj!~HKK%^wf| diff --git a/common/golang-external-secrets/templates/golang-external-secrets-hub-clusterrolebinding.yaml b/common/golang-external-secrets/templates/golang-external-secrets-hub-clusterrolebinding.yaml deleted file mode 100644 index a8ab9e78..00000000 --- a/common/golang-external-secrets/templates/golang-external-secrets-hub-clusterrolebinding.yaml +++ /dev/null @@ -1,23 +0,0 @@ ---- -apiVersion: v1 -kind: Secret -metadata: - name: golang-external-secrets - namespace: golang-external-secrets - annotations: - kubernetes.io/service-account.name: golang-external-secrets -type: kubernetes.io/service-account-token ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: role-tokenreview-binding - namespace: default -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:auth-delegator -subjects: -- kind: ServiceAccount - name: golang-external-secrets - namespace: golang-external-secrets diff --git a/common/golang-external-secrets/templates/golang-external-secrets-hub-secretstore.yaml b/common/golang-external-secrets/templates/golang-external-secrets-hub-secretstore.yaml deleted file mode 100644 index 6a95745d..00000000 --- a/common/golang-external-secrets/templates/golang-external-secrets-hub-secretstore.yaml +++ /dev/null @@ -1,25 +0,0 @@ -apiVersion: external-secrets.io/v1beta1 -kind: ClusterSecretStore -metadata: - name: vault-backend - namespace: golang-external-secrets -spec: - provider: - vault: - server: https://vault-vault.{{ .Values.global.hubClusterDomain }} - path: secret - # Version of KV backend - version: v2 - caProvider: - type: ConfigMap - name: kube-root-ca.crt - key: ca.crt - namespace: golang-external-secrets - auth: - kubernetes: - mountPath: {{ .Values.mountPath }} - role: {{ .Values.mountRole }} - secretRef: - name: golang-external-secrets - namespace: golang-external-secrets - key: "token" diff --git a/common/golang-external-secrets/values.yaml b/common/golang-external-secrets/values.yaml deleted file mode 100644 index b4656f3b..00000000 --- a/common/golang-external-secrets/values.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -mountPath: "hub" -mountRole: "hub-role" - -global: - hubClusterDomain: hub.example.com diff --git a/common/hashicorp-vault/Chart.yaml b/common/hashicorp-vault/Chart.yaml deleted file mode 100644 index 51ae676f..00000000 --- a/common/hashicorp-vault/Chart.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: v2 -description: A Helm chart to configure Hashicorp's vault -keywords: -- pattern -name: hashicorp-vault -version: 0.0.1 -dependencies: - - name: vault - version: "0.22.0" - repository: "https://helm.releases.hashicorp.com" diff --git a/common/hashicorp-vault/README.md b/common/hashicorp-vault/README.md deleted file mode 100644 index 153b516a..00000000 --- a/common/hashicorp-vault/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# VP hashicorp-vault - -**IMPORTANT**: Due to the fact that 'null' values do not work in helm charts ([GH#9136](https://github.com/helm/helm/issues/9136)), -we need to patch the chart to skip setting the host. - -Make sure to run "./update-helm-dependency.sh" - -We can drop this local patch when any one the two conditions is true: - -- [1] is fixed in helm and we can require the version that for installs -- [PR#779](https://github.com/hashicorp/vault-helm/pull/779) is merged in vault-helm *and* our minimum supported OCP version - is OCP 4.11 (route subdomain is broken in OCP < 4.11 due to missing [commit](https://github.com/openshift/router/commit/6f730c7cae966f0ed8def50c81d1bf10fe9eb77b) diff --git a/common/hashicorp-vault/charts/vault-0.22.0.tgz b/common/hashicorp-vault/charts/vault-0.22.0.tgz deleted file mode 100644 index e6111e1f7482f02b422e1341eca5d369e2f3cc98..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51863 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 Ly%<5xTYojN( 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 bYunSyd(&rT3oiTbU%q^$4TourIX}iX0ap0H diff --git a/common/hashicorp-vault/patch-server-route.diff b/common/hashicorp-vault/patch-server-route.diff deleted file mode 100644 index edc22c57..00000000 --- a/common/hashicorp-vault/patch-server-route.diff +++ /dev/null @@ -1,28 +0,0 @@ -diff -up vault/values.yaml.orig vault/values.yaml ---- vault/values.yaml.orig 2022-09-05 20:42:02.468428184 +0200 -+++ vault/values.yaml 2022-09-05 20:42:05.218435871 +0200 -@@ -406,7 +406,8 @@ server: - - labels: {} - annotations: {} -- host: chart-example.local -+ #host: chart-example.local -+ host: null - # tls will be passed directly to the route's TLS config, which - # can be used to configure other termination methods that terminate - # TLS at the router -diff -up vault/values.schema.json.orig vault/values.schema.json ---- vault/values.schema.json.orig 2022-09-11 21:00:34.834334961 +0200 -+++ vault/values.schema.json 2022-09-11 21:00:57.190368032 +0200 -@@ -838,7 +838,10 @@ - "type": "boolean" - }, - "host": { -- "type": "string" -+ "type": [ -+ "null", -+ "string" -+ ] - }, - "labels": { - "type": "object" diff --git a/common/hashicorp-vault/templates/vault-app.yaml b/common/hashicorp-vault/templates/vault-app.yaml deleted file mode 100644 index bbe16e14..00000000 --- a/common/hashicorp-vault/templates/vault-app.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: console.openshift.io/v1 -kind: ConsoleLink -metadata: - name: vault-link - namespace: vault -spec: - applicationMenu: - section: HashiCorp Vault - imageURL: data:image/png;base64,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 - href: 'https://vault-vault.{{ coalesce .Values.global.localClusterDomain .Values.global.hubClusterDomain }}' - location: ApplicationMenu - text: 'Vault' diff --git a/common/hashicorp-vault/update-helm-dependency.sh b/common/hashicorp-vault/update-helm-dependency.sh deleted file mode 100755 index afd6d522..00000000 --- a/common/hashicorp-vault/update-helm-dependency.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -set -eu - -# Get the version of the dependency and then unquote it -TMPVER=$(sed -e '1,/^version:/ d' "Chart.yaml" | grep "version:" | awk '{ print $2 }') -VERSION=$(eval echo "${TMPVER}") - -# Chart format is vault-0.21.0.tgz -NAME="vault" -TAR="${NAME}-${VERSION}.tgz" -CHARTDIR="charts" - -if [ ! -f "${CHARTDIR}/${TAR}" ]; then - echo "Charts $TAR not found" - exit 1 -fi - -pushd "${CHARTDIR}" -rm -rf "${NAME}" -tar xfz "${TAR}" -pushd "${NAME}" -patch -p1 < ../../patch-server-route.diff -popd -tar cvfz "${TAR}" "${NAME}" -rm -rf "${NAME}" -popd diff --git a/common/hashicorp-vault/values.yaml b/common/hashicorp-vault/values.yaml deleted file mode 100644 index e16cc0e3..00000000 --- a/common/hashicorp-vault/values.yaml +++ /dev/null @@ -1,20 +0,0 @@ ---- -global: - openshift: true - localClusterDomain: apps.foo.cluster.com - -vault: - injector: - enabled: false - ui: - enabled: true - serviceType: "LoadBalancer" - server: - route: - host: null - enabled: true - tls: - termination: "edge" - image: - repository: "registry.connect.redhat.com/hashicorp/vault" - tag: "1.11.3-ubi" diff --git a/common/install/.helmignore b/common/install/.helmignore deleted file mode 100644 index b25c15b8..00000000 --- a/common/install/.helmignore +++ /dev/null @@ -1 +0,0 @@ -*~ diff --git a/common/install/Chart.yaml b/common/install/Chart.yaml deleted file mode 100644 index d1c80ab3..00000000 --- a/common/install/Chart.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v2 -description: A Helm chart to build and deploy a Cloud Pattern -keywords: -- pattern -name: pattern-install -version: 0.0.1 diff --git a/common/install/crds/applications.argoproj.io.yaml b/common/install/crds/applications.argoproj.io.yaml deleted file mode 100644 index c9866d38..00000000 --- a/common/install/crds/applications.argoproj.io.yaml +++ /dev/null @@ -1,2312 +0,0 @@ -# oc get crd/applications.argoproj.io -o yaml > applications.argoproj.io.yaml -# Remove annotation, timestamps and other cluster-specific cruft -# Also remove any status leftovers at the end -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - generation: 1 - labels: - app.kubernetes.io/name: applications.argoproj.io - app.kubernetes.io/part-of: argocd - operators.coreos.com/openshift-gitops-operator.openshift-operators: "" - name: applications.argoproj.io -spec: - conversion: - strategy: None - group: argoproj.io - names: - kind: Application - listKind: ApplicationList - plural: applications - shortNames: - - app - - apps - singular: application - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.sync.status - name: Sync Status - type: string - - jsonPath: .status.health.status - name: Health Status - type: string - - jsonPath: .status.sync.revision - name: Revision - priority: 10 - type: string - name: v1alpha1 - schema: - openAPIV3Schema: - description: Application is a definition of Application resource. - 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 - operation: - description: Operation contains information about a requested or running - operation - properties: - info: - description: Info is a list of informational items for this operation - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - initiatedBy: - description: InitiatedBy contains information about who initiated - the operations - properties: - automated: - description: Automated is set to true if operation was initiated - automatically by the application controller. - type: boolean - username: - description: Username contains the name of a user who started - operation - type: string - type: object - retry: - description: Retry controls the strategy to apply if a sync fails - properties: - backoff: - description: Backoff controls how to backoff on subsequent retries - of failed syncs - properties: - duration: - description: Duration is the amount to back off. Default unit - is seconds, but could also be a duration (e.g. "2m", "1h") - type: string - factor: - description: Factor is a factor to multiply the base duration - after each failed retry - format: int64 - type: integer - maxDuration: - description: MaxDuration is the maximum amount of time allowed - for the backoff strategy - type: string - type: object - limit: - description: Limit is the maximum number of attempts for retrying - a failed sync. If set to 0, no retries will be performed. - format: int64 - type: integer - type: object - sync: - description: Sync contains parameters for the operation - properties: - dryRun: - description: DryRun specifies to perform a `kubectl apply --dry-run` - without actually performing the sync - type: boolean - manifests: - description: Manifests is an optional field that overrides sync - source with a local directory for development - items: - type: string - type: array - prune: - description: Prune specifies to delete resources from the cluster - that are no longer tracked in git - type: boolean - resources: - description: Resources describes which resources shall be part - of the sync - items: - description: SyncOperationResource contains resources to sync. - properties: - group: - type: string - kind: - type: string - name: - type: string - namespace: - type: string - required: - - kind - - name - type: object - type: array - revision: - description: Revision is the revision (Git) or chart version (Helm) - which to sync the application to If omitted, will use the revision - specified in app spec. - type: string - source: - description: Source overrides the source definition set in the - application. This is typically set in a Rollback operation and - is nil during a Sync operation - properties: - chart: - description: Chart is a Helm chart name, and must be specified - for applications sourced from a Helm repo. - type: string - directory: - description: Directory holds path/directory specific options - properties: - exclude: - description: Exclude contains a glob pattern to match - paths against that should be explicitly excluded from - being used during manifest generation - type: string - include: - description: Include contains a glob pattern to match - paths against that should be explicitly included during - manifest generation - type: string - jsonnet: - description: Jsonnet holds options specific to Jsonnet - properties: - extVars: - description: ExtVars is a list of Jsonnet External - Variables - items: - description: JsonnetVar represents a variable to - be passed to jsonnet during manifest generation - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - description: Additional library search dirs - items: - type: string - type: array - tlas: - description: TLAS is a list of Jsonnet Top-level Arguments - items: - description: JsonnetVar represents a variable to - be passed to jsonnet during manifest generation - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - description: Recurse specifies whether to scan a directory - recursively for manifests - type: boolean - type: object - helm: - description: Helm holds helm specific options - properties: - fileParameters: - description: FileParameters are file parameters to the - helm template - items: - description: HelmFileParameter is a file parameter that's - passed to helm template during manifest generation - properties: - name: - description: Name is the name of the Helm parameter - type: string - path: - description: Path is the path to the file containing - the values for the Helm parameter - type: string - type: object - type: array - ignoreMissingValueFiles: - description: IgnoreMissingValueFiles prevents helm template - from failing when valueFiles do not exist locally by - not appending them to helm template --values - type: boolean - parameters: - description: Parameters is a list of Helm parameters which - are passed to the helm template command upon manifest - generation - items: - description: HelmParameter is a parameter that's passed - to helm template during manifest generation - properties: - forceString: - description: ForceString determines whether to tell - Helm to interpret booleans and numbers as strings - type: boolean - name: - description: Name is the name of the Helm parameter - type: string - value: - description: Value is the value for the Helm parameter - type: string - type: object - type: array - passCredentials: - description: PassCredentials pass credentials to all domains - (Helm's --pass-credentials) - type: boolean - releaseName: - description: ReleaseName is the Helm release name to use. - If omitted it will use the application name - type: string - skipCrds: - description: SkipCrds skips custom resource definition - installation step (Helm's --skip-crds) - type: boolean - valueFiles: - description: ValuesFiles is a list of Helm value files - to use when generating a template - items: - type: string - type: array - values: - description: Values specifies Helm values to be passed - to helm template, typically defined as a block - type: string - version: - description: Version is the Helm version to use for templating - (either "2" or "3") - type: string - type: object - ksonnet: - description: Ksonnet holds ksonnet specific options - properties: - environment: - description: Environment is a ksonnet application environment - name - type: string - parameters: - description: Parameters are a list of ksonnet component - parameter override values - items: - description: KsonnetParameter is a ksonnet component - parameter - properties: - component: - type: string - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - kustomize: - description: Kustomize holds kustomize specific options - properties: - commonAnnotations: - additionalProperties: - type: string - description: CommonAnnotations is a list of additional - annotations to add to rendered manifests - type: object - commonLabels: - additionalProperties: - type: string - description: CommonLabels is a list of additional labels - to add to rendered manifests - type: object - forceCommonAnnotations: - description: ForceCommonAnnotations specifies whether - to force applying common annotations to resources for - Kustomize apps - type: boolean - forceCommonLabels: - description: ForceCommonLabels specifies whether to force - applying common labels to resources for Kustomize apps - type: boolean - images: - description: Images is a list of Kustomize image override - specifications - items: - description: KustomizeImage represents a Kustomize image - definition in the format [old_image_name=]: - type: string - type: array - namePrefix: - description: NamePrefix is a prefix appended to resources - for Kustomize apps - type: string - nameSuffix: - description: NameSuffix is a suffix appended to resources - for Kustomize apps - type: string - version: - description: Version controls which version of Kustomize - to use for rendering manifests - type: string - type: object - path: - description: Path is a directory path within the Git repository, - and is only valid for applications sourced from Git. - type: string - plugin: - description: ConfigManagementPlugin holds config management - plugin specific options - properties: - env: - description: Env is a list of environment variable entries - items: - description: EnvEntry represents an entry in the application's - environment - properties: - name: - description: Name is the name of the variable, usually - expressed in uppercase - type: string - value: - description: Value is the value of the variable - type: string - required: - - name - - value - type: object - type: array - name: - type: string - type: object - repoURL: - description: RepoURL is the URL to the repository (Git or - Helm) that contains the application manifests - type: string - targetRevision: - description: TargetRevision defines the revision of the source - to sync the application to. In case of Git, this can be - commit, tag, or branch. If omitted, will equal to HEAD. - In case of Helm, this is a semver tag for the Chart's version. - type: string - required: - - repoURL - type: object - syncOptions: - description: SyncOptions provide per-sync sync-options, e.g. Validate=false - items: - type: string - type: array - syncStrategy: - description: SyncStrategy describes how to perform the sync - properties: - apply: - description: Apply will perform a `kubectl apply` to perform - the sync. - properties: - force: - description: Force indicates whether or not to supply - the --force flag to `kubectl apply`. The --force flag - deletes and re-create the resource, when PATCH encounters - conflict and has retried for 5 times. - type: boolean - type: object - hook: - description: Hook will submit any referenced resources to - perform the sync. This is the default strategy - properties: - force: - description: Force indicates whether or not to supply - the --force flag to `kubectl apply`. The --force flag - deletes and re-create the resource, when PATCH encounters - conflict and has retried for 5 times. - type: boolean - type: object - type: object - type: object - type: object - spec: - description: ApplicationSpec represents desired application state. Contains - link to repository with application definition and additional parameters - link definition revision. - properties: - destination: - description: Destination is a reference to the target Kubernetes server - and namespace - properties: - name: - description: Name is an alternate way of specifying the target - cluster by its symbolic name - type: string - namespace: - description: Namespace specifies the target namespace for the - application's resources. The namespace will only be set for - namespace-scoped resources that have not set a value for .metadata.namespace - type: string - server: - description: Server specifies the URL of the target cluster and - must be set to the Kubernetes control plane API - type: string - type: object - ignoreDifferences: - description: IgnoreDifferences is a list of resources and their fields - which should be ignored during comparison - items: - description: ResourceIgnoreDifferences contains resource filter - and list of json paths which should be ignored during comparison - with live state. - properties: - group: - type: string - jqPathExpressions: - items: - type: string - type: array - jsonPointers: - items: - type: string - type: array - kind: - type: string - managedFieldsManagers: - description: ManagedFieldsManagers is a list of trusted managers. - Fields mutated by those managers will take precedence over - the desired state defined in the SCM and won't be displayed - in diffs - items: - type: string - type: array - name: - type: string - namespace: - type: string - required: - - kind - type: object - type: array - info: - description: Info contains a list of information (URLs, email addresses, - and plain text) that relates to the application - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - project: - description: Project is a reference to the project this application - belongs to. The empty string means that application belongs to the - 'default' project. - type: string - revisionHistoryLimit: - description: RevisionHistoryLimit limits the number of items kept - in the application's revision history, which is used for informational - purposes as well as for rollbacks to previous versions. This should - only be changed in exceptional circumstances. Setting to zero will - store no history. This will reduce storage used. Increasing will - increase the space used to store the history, so we do not recommend - increasing it. Default is 10. - format: int64 - type: integer - source: - description: Source is a reference to the location of the application's - manifests or chart - properties: - chart: - description: Chart is a Helm chart name, and must be specified - for applications sourced from a Helm repo. - type: string - directory: - description: Directory holds path/directory specific options - properties: - exclude: - description: Exclude contains a glob pattern to match paths - against that should be explicitly excluded from being used - during manifest generation - type: string - include: - description: Include contains a glob pattern to match paths - against that should be explicitly included during manifest - generation - type: string - jsonnet: - description: Jsonnet holds options specific to Jsonnet - properties: - extVars: - description: ExtVars is a list of Jsonnet External Variables - items: - description: JsonnetVar represents a variable to be - passed to jsonnet during manifest generation - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - description: Additional library search dirs - items: - type: string - type: array - tlas: - description: TLAS is a list of Jsonnet Top-level Arguments - items: - description: JsonnetVar represents a variable to be - passed to jsonnet during manifest generation - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - description: Recurse specifies whether to scan a directory - recursively for manifests - type: boolean - type: object - helm: - description: Helm holds helm specific options - properties: - fileParameters: - description: FileParameters are file parameters to the helm - template - items: - description: HelmFileParameter is a file parameter that's - passed to helm template during manifest generation - properties: - name: - description: Name is the name of the Helm parameter - type: string - path: - description: Path is the path to the file containing - the values for the Helm parameter - type: string - type: object - type: array - ignoreMissingValueFiles: - description: IgnoreMissingValueFiles prevents helm template - from failing when valueFiles do not exist locally by not - appending them to helm template --values - type: boolean - parameters: - description: Parameters is a list of Helm parameters which - are passed to the helm template command upon manifest generation - items: - description: HelmParameter is a parameter that's passed - to helm template during manifest generation - properties: - forceString: - description: ForceString determines whether to tell - Helm to interpret booleans and numbers as strings - type: boolean - name: - description: Name is the name of the Helm parameter - type: string - value: - description: Value is the value for the Helm parameter - type: string - type: object - type: array - passCredentials: - description: PassCredentials pass credentials to all domains - (Helm's --pass-credentials) - type: boolean - releaseName: - description: ReleaseName is the Helm release name to use. - If omitted it will use the application name - type: string - skipCrds: - description: SkipCrds skips custom resource definition installation - step (Helm's --skip-crds) - type: boolean - valueFiles: - description: ValuesFiles is a list of Helm value files to - use when generating a template - items: - type: string - type: array - values: - description: Values specifies Helm values to be passed to - helm template, typically defined as a block - type: string - version: - description: Version is the Helm version to use for templating - (either "2" or "3") - type: string - type: object - ksonnet: - description: Ksonnet holds ksonnet specific options - properties: - environment: - description: Environment is a ksonnet application environment - name - type: string - parameters: - description: Parameters are a list of ksonnet component parameter - override values - items: - description: KsonnetParameter is a ksonnet component parameter - properties: - component: - type: string - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - kustomize: - description: Kustomize holds kustomize specific options - properties: - commonAnnotations: - additionalProperties: - type: string - description: CommonAnnotations is a list of additional annotations - to add to rendered manifests - type: object - commonLabels: - additionalProperties: - type: string - description: CommonLabels is a list of additional labels to - add to rendered manifests - type: object - forceCommonAnnotations: - description: ForceCommonAnnotations specifies whether to force - applying common annotations to resources for Kustomize apps - type: boolean - forceCommonLabels: - description: ForceCommonLabels specifies whether to force - applying common labels to resources for Kustomize apps - type: boolean - images: - description: Images is a list of Kustomize image override - specifications - items: - description: KustomizeImage represents a Kustomize image - definition in the format [old_image_name=]: - type: string - type: array - namePrefix: - description: NamePrefix is a prefix appended to resources - for Kustomize apps - type: string - nameSuffix: - description: NameSuffix is a suffix appended to resources - for Kustomize apps - type: string - version: - description: Version controls which version of Kustomize to - use for rendering manifests - type: string - type: object - path: - description: Path is a directory path within the Git repository, - and is only valid for applications sourced from Git. - type: string - plugin: - description: ConfigManagementPlugin holds config management plugin - specific options - properties: - env: - description: Env is a list of environment variable entries - items: - description: EnvEntry represents an entry in the application's - environment - properties: - name: - description: Name is the name of the variable, usually - expressed in uppercase - type: string - value: - description: Value is the value of the variable - type: string - required: - - name - - value - type: object - type: array - name: - type: string - type: object - repoURL: - description: RepoURL is the URL to the repository (Git or Helm) - that contains the application manifests - type: string - targetRevision: - description: TargetRevision defines the revision of the source - to sync the application to. In case of Git, this can be commit, - tag, or branch. If omitted, will equal to HEAD. In case of Helm, - this is a semver tag for the Chart's version. - type: string - required: - - repoURL - type: object - syncPolicy: - description: SyncPolicy controls when and how a sync will be performed - properties: - automated: - description: Automated will keep an application synced to the - target revision - properties: - allowEmpty: - description: 'AllowEmpty allows apps have zero live resources - (default: false)' - type: boolean - prune: - description: 'Prune specifies whether to delete resources - from the cluster that are not found in the sources anymore - as part of automated sync (default: false)' - type: boolean - selfHeal: - description: 'SelfHeal specifes whether to revert resources - back to their desired state upon modification in the cluster - (default: false)' - type: boolean - type: object - retry: - description: Retry controls failed sync retry behavior - properties: - backoff: - description: Backoff controls how to backoff on subsequent - retries of failed syncs - properties: - duration: - description: Duration is the amount to back off. Default - unit is seconds, but could also be a duration (e.g. - "2m", "1h") - type: string - factor: - description: Factor is a factor to multiply the base duration - after each failed retry - format: int64 - type: integer - maxDuration: - description: MaxDuration is the maximum amount of time - allowed for the backoff strategy - type: string - type: object - limit: - description: Limit is the maximum number of attempts for retrying - a failed sync. If set to 0, no retries will be performed. - format: int64 - type: integer - type: object - syncOptions: - description: Options allow you to specify whole app sync-options - items: - type: string - type: array - type: object - required: - - destination - - project - - source - type: object - status: - description: ApplicationStatus contains status information for the application - properties: - conditions: - description: Conditions is a list of currently observed application - conditions - items: - description: ApplicationCondition contains details about an application - condition, which is usally an error or warning - properties: - lastTransitionTime: - description: LastTransitionTime is the time the condition was - last observed - format: date-time - type: string - message: - description: Message contains human-readable message indicating - details about condition - type: string - type: - description: Type is an application condition type - type: string - required: - - message - - type - type: object - type: array - health: - description: Health contains information about the application's current - health status - properties: - message: - description: Message is a human-readable informational message - describing the health status - type: string - status: - description: Status holds the status code of the application or - resource - type: string - type: object - history: - description: History contains information about the application's - sync history - items: - description: RevisionHistory contains history information about - a previous sync - properties: - deployStartedAt: - description: DeployStartedAt holds the time the sync operation - started - format: date-time - type: string - deployedAt: - description: DeployedAt holds the time the sync operation completed - format: date-time - type: string - id: - description: ID is an auto incrementing identifier of the RevisionHistory - format: int64 - type: integer - revision: - description: Revision holds the revision the sync was performed - against - type: string - source: - description: Source is a reference to the application source - used for the sync operation - properties: - chart: - description: Chart is a Helm chart name, and must be specified - for applications sourced from a Helm repo. - type: string - directory: - description: Directory holds path/directory specific options - properties: - exclude: - description: Exclude contains a glob pattern to match - paths against that should be explicitly excluded from - being used during manifest generation - type: string - include: - description: Include contains a glob pattern to match - paths against that should be explicitly included during - manifest generation - type: string - jsonnet: - description: Jsonnet holds options specific to Jsonnet - properties: - extVars: - description: ExtVars is a list of Jsonnet External - Variables - items: - description: JsonnetVar represents a variable - to be passed to jsonnet during manifest generation - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - description: Additional library search dirs - items: - type: string - type: array - tlas: - description: TLAS is a list of Jsonnet Top-level - Arguments - items: - description: JsonnetVar represents a variable - to be passed to jsonnet during manifest generation - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - description: Recurse specifies whether to scan a directory - recursively for manifests - type: boolean - type: object - helm: - description: Helm holds helm specific options - properties: - fileParameters: - description: FileParameters are file parameters to the - helm template - items: - description: HelmFileParameter is a file parameter - that's passed to helm template during manifest generation - properties: - name: - description: Name is the name of the Helm parameter - type: string - path: - description: Path is the path to the file containing - the values for the Helm parameter - type: string - type: object - type: array - ignoreMissingValueFiles: - description: IgnoreMissingValueFiles prevents helm template - from failing when valueFiles do not exist locally - by not appending them to helm template --values - type: boolean - parameters: - description: Parameters is a list of Helm parameters - which are passed to the helm template command upon - manifest generation - items: - description: HelmParameter is a parameter that's passed - to helm template during manifest generation - properties: - forceString: - description: ForceString determines whether to - tell Helm to interpret booleans and numbers - as strings - type: boolean - name: - description: Name is the name of the Helm parameter - type: string - value: - description: Value is the value for the Helm parameter - type: string - type: object - type: array - passCredentials: - description: PassCredentials pass credentials to all - domains (Helm's --pass-credentials) - type: boolean - releaseName: - description: ReleaseName is the Helm release name to - use. If omitted it will use the application name - type: string - skipCrds: - description: SkipCrds skips custom resource definition - installation step (Helm's --skip-crds) - type: boolean - valueFiles: - description: ValuesFiles is a list of Helm value files - to use when generating a template - items: - type: string - type: array - values: - description: Values specifies Helm values to be passed - to helm template, typically defined as a block - type: string - version: - description: Version is the Helm version to use for - templating (either "2" or "3") - type: string - type: object - ksonnet: - description: Ksonnet holds ksonnet specific options - properties: - environment: - description: Environment is a ksonnet application environment - name - type: string - parameters: - description: Parameters are a list of ksonnet component - parameter override values - items: - description: KsonnetParameter is a ksonnet component - parameter - properties: - component: - type: string - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - kustomize: - description: Kustomize holds kustomize specific options - properties: - commonAnnotations: - additionalProperties: - type: string - description: CommonAnnotations is a list of additional - annotations to add to rendered manifests - type: object - commonLabels: - additionalProperties: - type: string - description: CommonLabels is a list of additional labels - to add to rendered manifests - type: object - forceCommonAnnotations: - description: ForceCommonAnnotations specifies whether - to force applying common annotations to resources - for Kustomize apps - type: boolean - forceCommonLabels: - description: ForceCommonLabels specifies whether to - force applying common labels to resources for Kustomize - apps - type: boolean - images: - description: Images is a list of Kustomize image override - specifications - items: - description: KustomizeImage represents a Kustomize - image definition in the format [old_image_name=]: - type: string - type: array - namePrefix: - description: NamePrefix is a prefix appended to resources - for Kustomize apps - type: string - nameSuffix: - description: NameSuffix is a suffix appended to resources - for Kustomize apps - type: string - version: - description: Version controls which version of Kustomize - to use for rendering manifests - type: string - type: object - path: - description: Path is a directory path within the Git repository, - and is only valid for applications sourced from Git. - type: string - plugin: - description: ConfigManagementPlugin holds config management - plugin specific options - properties: - env: - description: Env is a list of environment variable entries - items: - description: EnvEntry represents an entry in the application's - environment - properties: - name: - description: Name is the name of the variable, - usually expressed in uppercase - type: string - value: - description: Value is the value of the variable - type: string - required: - - name - - value - type: object - type: array - name: - type: string - type: object - repoURL: - description: RepoURL is the URL to the repository (Git or - Helm) that contains the application manifests - type: string - targetRevision: - description: TargetRevision defines the revision of the - source to sync the application to. In case of Git, this - can be commit, tag, or branch. If omitted, will equal - to HEAD. In case of Helm, this is a semver tag for the - Chart's version. - type: string - required: - - repoURL - type: object - required: - - deployedAt - - id - - revision - type: object - type: array - observedAt: - description: 'ObservedAt indicates when the application state was - updated without querying latest git state Deprecated: controller - no longer updates ObservedAt field' - format: date-time - type: string - operationState: - description: OperationState contains information about any ongoing - operations, such as a sync - properties: - finishedAt: - description: FinishedAt contains time of operation completion - format: date-time - type: string - message: - description: Message holds any pertinent messages when attempting - to perform operation (typically errors). - type: string - operation: - description: Operation is the original requested operation - properties: - info: - description: Info is a list of informational items for this - operation - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - initiatedBy: - description: InitiatedBy contains information about who initiated - the operations - properties: - automated: - description: Automated is set to true if operation was - initiated automatically by the application controller. - type: boolean - username: - description: Username contains the name of a user who - started operation - type: string - type: object - retry: - description: Retry controls the strategy to apply if a sync - fails - properties: - backoff: - description: Backoff controls how to backoff on subsequent - retries of failed syncs - properties: - duration: - description: Duration is the amount to back off. Default - unit is seconds, but could also be a duration (e.g. - "2m", "1h") - type: string - factor: - description: Factor is a factor to multiply the base - duration after each failed retry - format: int64 - type: integer - maxDuration: - description: MaxDuration is the maximum amount of - time allowed for the backoff strategy - type: string - type: object - limit: - description: Limit is the maximum number of attempts for - retrying a failed sync. If set to 0, no retries will - be performed. - format: int64 - type: integer - type: object - sync: - description: Sync contains parameters for the operation - properties: - dryRun: - description: DryRun specifies to perform a `kubectl apply - --dry-run` without actually performing the sync - type: boolean - manifests: - description: Manifests is an optional field that overrides - sync source with a local directory for development - items: - type: string - type: array - prune: - description: Prune specifies to delete resources from - the cluster that are no longer tracked in git - type: boolean - resources: - description: Resources describes which resources shall - be part of the sync - items: - description: SyncOperationResource contains resources - to sync. - properties: - group: - type: string - kind: - type: string - name: - type: string - namespace: - type: string - required: - - kind - - name - type: object - type: array - revision: - description: Revision is the revision (Git) or chart version - (Helm) which to sync the application to If omitted, - will use the revision specified in app spec. - type: string - source: - description: Source overrides the source definition set - in the application. This is typically set in a Rollback - operation and is nil during a Sync operation - properties: - chart: - description: Chart is a Helm chart name, and must - be specified for applications sourced from a Helm - repo. - type: string - directory: - description: Directory holds path/directory specific - options - properties: - exclude: - description: Exclude contains a glob pattern to - match paths against that should be explicitly - excluded from being used during manifest generation - type: string - include: - description: Include contains a glob pattern to - match paths against that should be explicitly - included during manifest generation - type: string - jsonnet: - description: Jsonnet holds options specific to - Jsonnet - properties: - extVars: - description: ExtVars is a list of Jsonnet - External Variables - items: - description: JsonnetVar represents a variable - to be passed to jsonnet during manifest - generation - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - description: Additional library search dirs - items: - type: string - type: array - tlas: - description: TLAS is a list of Jsonnet Top-level - Arguments - items: - description: JsonnetVar represents a variable - to be passed to jsonnet during manifest - generation - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - description: Recurse specifies whether to scan - a directory recursively for manifests - type: boolean - type: object - helm: - description: Helm holds helm specific options - properties: - fileParameters: - description: FileParameters are file parameters - to the helm template - items: - description: HelmFileParameter is a file parameter - that's passed to helm template during manifest - generation - properties: - name: - description: Name is the name of the Helm - parameter - type: string - path: - description: Path is the path to the file - containing the values for the Helm parameter - type: string - type: object - type: array - ignoreMissingValueFiles: - description: IgnoreMissingValueFiles prevents - helm template from failing when valueFiles do - not exist locally by not appending them to helm - template --values - type: boolean - parameters: - description: Parameters is a list of Helm parameters - which are passed to the helm template command - upon manifest generation - items: - description: HelmParameter is a parameter that's - passed to helm template during manifest generation - properties: - forceString: - description: ForceString determines whether - to tell Helm to interpret booleans and - numbers as strings - type: boolean - name: - description: Name is the name of the Helm - parameter - type: string - value: - description: Value is the value for the - Helm parameter - type: string - type: object - type: array - passCredentials: - description: PassCredentials pass credentials - to all domains (Helm's --pass-credentials) - type: boolean - releaseName: - description: ReleaseName is the Helm release name - to use. If omitted it will use the application - name - type: string - skipCrds: - description: SkipCrds skips custom resource definition - installation step (Helm's --skip-crds) - type: boolean - valueFiles: - description: ValuesFiles is a list of Helm value - files to use when generating a template - items: - type: string - type: array - values: - description: Values specifies Helm values to be - passed to helm template, typically defined as - a block - type: string - version: - description: Version is the Helm version to use - for templating (either "2" or "3") - type: string - type: object - ksonnet: - description: Ksonnet holds ksonnet specific options - properties: - environment: - description: Environment is a ksonnet application - environment name - type: string - parameters: - description: Parameters are a list of ksonnet - component parameter override values - items: - description: KsonnetParameter is a ksonnet component - parameter - properties: - component: - type: string - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - kustomize: - description: Kustomize holds kustomize specific options - properties: - commonAnnotations: - additionalProperties: - type: string - description: CommonAnnotations is a list of additional - annotations to add to rendered manifests - type: object - commonLabels: - additionalProperties: - type: string - description: CommonLabels is a list of additional - labels to add to rendered manifests - type: object - forceCommonAnnotations: - description: ForceCommonAnnotations specifies - whether to force applying common annotations - to resources for Kustomize apps - type: boolean - forceCommonLabels: - description: ForceCommonLabels specifies whether - to force applying common labels to resources - for Kustomize apps - type: boolean - images: - description: Images is a list of Kustomize image - override specifications - items: - description: KustomizeImage represents a Kustomize - image definition in the format [old_image_name=]: - type: string - type: array - namePrefix: - description: NamePrefix is a prefix appended to - resources for Kustomize apps - type: string - nameSuffix: - description: NameSuffix is a suffix appended to - resources for Kustomize apps - type: string - version: - description: Version controls which version of - Kustomize to use for rendering manifests - type: string - type: object - path: - description: Path is a directory path within the Git - repository, and is only valid for applications sourced - from Git. - type: string - plugin: - description: ConfigManagementPlugin holds config management - plugin specific options - properties: - env: - description: Env is a list of environment variable - entries - items: - description: EnvEntry represents an entry in - the application's environment - properties: - name: - description: Name is the name of the variable, - usually expressed in uppercase - type: string - value: - description: Value is the value of the variable - type: string - required: - - name - - value - type: object - type: array - name: - type: string - type: object - repoURL: - description: RepoURL is the URL to the repository - (Git or Helm) that contains the application manifests - type: string - targetRevision: - description: TargetRevision defines the revision of - the source to sync the application to. In case of - Git, this can be commit, tag, or branch. If omitted, - will equal to HEAD. In case of Helm, this is a semver - tag for the Chart's version. - type: string - required: - - repoURL - type: object - syncOptions: - description: SyncOptions provide per-sync sync-options, - e.g. Validate=false - items: - type: string - type: array - syncStrategy: - description: SyncStrategy describes how to perform the - sync - properties: - apply: - description: Apply will perform a `kubectl apply` - to perform the sync. - properties: - force: - description: Force indicates whether or not to - supply the --force flag to `kubectl apply`. - The --force flag deletes and re-create the resource, - when PATCH encounters conflict and has retried - for 5 times. - type: boolean - type: object - hook: - description: Hook will submit any referenced resources - to perform the sync. This is the default strategy - properties: - force: - description: Force indicates whether or not to - supply the --force flag to `kubectl apply`. - The --force flag deletes and re-create the resource, - when PATCH encounters conflict and has retried - for 5 times. - type: boolean - type: object - type: object - type: object - type: object - phase: - description: Phase is the current phase of the operation - type: string - retryCount: - description: RetryCount contains time of operation retries - format: int64 - type: integer - startedAt: - description: StartedAt contains time of operation start - format: date-time - type: string - syncResult: - description: SyncResult is the result of a Sync operation - properties: - resources: - description: Resources contains a list of sync result items - for each individual resource in a sync operation - items: - description: ResourceResult holds the operation result details - of a specific resource - properties: - group: - description: Group specifies the API group of the resource - type: string - hookPhase: - description: HookPhase contains the state of any operation - associated with this resource OR hook This can also - contain values for non-hook resources. - type: string - hookType: - description: HookType specifies the type of the hook. - Empty for non-hook resources - type: string - kind: - description: Kind specifies the API kind of the resource - type: string - message: - description: Message contains an informational or error - message for the last sync OR operation - type: string - name: - description: Name specifies the name of the resource - type: string - namespace: - description: Namespace specifies the target namespace - of the resource - type: string - status: - description: Status holds the final result of the sync. - Will be empty if the resources is yet to be applied/pruned - and is always zero-value for hooks - type: string - syncPhase: - description: SyncPhase indicates the particular phase - of the sync that this result was acquired in - type: string - version: - description: Version specifies the API version of the - resource - type: string - required: - - group - - kind - - name - - namespace - - version - type: object - type: array - revision: - description: Revision holds the revision this sync operation - was performed to - type: string - source: - description: Source records the application source information - of the sync, used for comparing auto-sync - properties: - chart: - description: Chart is a Helm chart name, and must be specified - for applications sourced from a Helm repo. - type: string - directory: - description: Directory holds path/directory specific options - properties: - exclude: - description: Exclude contains a glob pattern to match - paths against that should be explicitly excluded - from being used during manifest generation - type: string - include: - description: Include contains a glob pattern to match - paths against that should be explicitly included - during manifest generation - type: string - jsonnet: - description: Jsonnet holds options specific to Jsonnet - properties: - extVars: - description: ExtVars is a list of Jsonnet External - Variables - items: - description: JsonnetVar represents a variable - to be passed to jsonnet during manifest generation - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - description: Additional library search dirs - items: - type: string - type: array - tlas: - description: TLAS is a list of Jsonnet Top-level - Arguments - items: - description: JsonnetVar represents a variable - to be passed to jsonnet during manifest generation - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - description: Recurse specifies whether to scan a directory - recursively for manifests - type: boolean - type: object - helm: - description: Helm holds helm specific options - properties: - fileParameters: - description: FileParameters are file parameters to - the helm template - items: - description: HelmFileParameter is a file parameter - that's passed to helm template during manifest - generation - properties: - name: - description: Name is the name of the Helm parameter - type: string - path: - description: Path is the path to the file containing - the values for the Helm parameter - type: string - type: object - type: array - ignoreMissingValueFiles: - description: IgnoreMissingValueFiles prevents helm - template from failing when valueFiles do not exist - locally by not appending them to helm template --values - type: boolean - parameters: - description: Parameters is a list of Helm parameters - which are passed to the helm template command upon - manifest generation - items: - description: HelmParameter is a parameter that's - passed to helm template during manifest generation - properties: - forceString: - description: ForceString determines whether - to tell Helm to interpret booleans and numbers - as strings - type: boolean - name: - description: Name is the name of the Helm parameter - type: string - value: - description: Value is the value for the Helm - parameter - type: string - type: object - type: array - passCredentials: - description: PassCredentials pass credentials to all - domains (Helm's --pass-credentials) - type: boolean - releaseName: - description: ReleaseName is the Helm release name - to use. If omitted it will use the application name - type: string - skipCrds: - description: SkipCrds skips custom resource definition - installation step (Helm's --skip-crds) - type: boolean - valueFiles: - description: ValuesFiles is a list of Helm value files - to use when generating a template - items: - type: string - type: array - values: - description: Values specifies Helm values to be passed - to helm template, typically defined as a block - type: string - version: - description: Version is the Helm version to use for - templating (either "2" or "3") - type: string - type: object - ksonnet: - description: Ksonnet holds ksonnet specific options - properties: - environment: - description: Environment is a ksonnet application - environment name - type: string - parameters: - description: Parameters are a list of ksonnet component - parameter override values - items: - description: KsonnetParameter is a ksonnet component - parameter - properties: - component: - type: string - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - kustomize: - description: Kustomize holds kustomize specific options - properties: - commonAnnotations: - additionalProperties: - type: string - description: CommonAnnotations is a list of additional - annotations to add to rendered manifests - type: object - commonLabels: - additionalProperties: - type: string - description: CommonLabels is a list of additional - labels to add to rendered manifests - type: object - forceCommonAnnotations: - description: ForceCommonAnnotations specifies whether - to force applying common annotations to resources - for Kustomize apps - type: boolean - forceCommonLabels: - description: ForceCommonLabels specifies whether to - force applying common labels to resources for Kustomize - apps - type: boolean - images: - description: Images is a list of Kustomize image override - specifications - items: - description: KustomizeImage represents a Kustomize - image definition in the format [old_image_name=]: - type: string - type: array - namePrefix: - description: NamePrefix is a prefix appended to resources - for Kustomize apps - type: string - nameSuffix: - description: NameSuffix is a suffix appended to resources - for Kustomize apps - type: string - version: - description: Version controls which version of Kustomize - to use for rendering manifests - type: string - type: object - path: - description: Path is a directory path within the Git repository, - and is only valid for applications sourced from Git. - type: string - plugin: - description: ConfigManagementPlugin holds config management - plugin specific options - properties: - env: - description: Env is a list of environment variable - entries - items: - description: EnvEntry represents an entry in the - application's environment - properties: - name: - description: Name is the name of the variable, - usually expressed in uppercase - type: string - value: - description: Value is the value of the variable - type: string - required: - - name - - value - type: object - type: array - name: - type: string - type: object - repoURL: - description: RepoURL is the URL to the repository (Git - or Helm) that contains the application manifests - type: string - targetRevision: - description: TargetRevision defines the revision of the - source to sync the application to. In case of Git, this - can be commit, tag, or branch. If omitted, will equal - to HEAD. In case of Helm, this is a semver tag for the - Chart's version. - type: string - required: - - repoURL - type: object - required: - - revision - type: object - required: - - operation - - phase - - startedAt - type: object - reconciledAt: - description: ReconciledAt indicates when the application state was - reconciled using the latest git version - format: date-time - type: string - resources: - description: Resources is a list of Kubernetes resources managed by - this application - items: - description: 'ResourceStatus holds the current sync and health status - of a resource TODO: describe members of this type' - properties: - group: - type: string - health: - description: HealthStatus contains information about the currently - observed health state of an application or resource - properties: - message: - description: Message is a human-readable informational message - describing the health status - type: string - status: - description: Status holds the status code of the application - or resource - type: string - type: object - hook: - type: boolean - kind: - type: string - name: - type: string - namespace: - type: string - requiresPruning: - type: boolean - status: - description: SyncStatusCode is a type which represents possible - comparison results - type: string - version: - type: string - type: object - type: array - sourceType: - description: SourceType specifies the type of this application - type: string - summary: - description: Summary contains a list of URLs and container images - used by this application - properties: - externalURLs: - description: ExternalURLs holds all external URLs of application - child resources. - items: - type: string - type: array - images: - description: Images holds all images of application child resources. - items: - type: string - type: array - type: object - sync: - description: Sync contains information about the application's current - sync status - properties: - comparedTo: - description: ComparedTo contains information about what has been - compared - properties: - destination: - description: Destination is a reference to the application's - destination used for comparison - properties: - name: - description: Name is an alternate way of specifying the - target cluster by its symbolic name - type: string - namespace: - description: Namespace specifies the target namespace - for the application's resources. The namespace will - only be set for namespace-scoped resources that have - not set a value for .metadata.namespace - type: string - server: - description: Server specifies the URL of the target cluster - and must be set to the Kubernetes control plane API - type: string - type: object - source: - description: Source is a reference to the application's source - used for comparison - properties: - chart: - description: Chart is a Helm chart name, and must be specified - for applications sourced from a Helm repo. - type: string - directory: - description: Directory holds path/directory specific options - properties: - exclude: - description: Exclude contains a glob pattern to match - paths against that should be explicitly excluded - from being used during manifest generation - type: string - include: - description: Include contains a glob pattern to match - paths against that should be explicitly included - during manifest generation - type: string - jsonnet: - description: Jsonnet holds options specific to Jsonnet - properties: - extVars: - description: ExtVars is a list of Jsonnet External - Variables - items: - description: JsonnetVar represents a variable - to be passed to jsonnet during manifest generation - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - description: Additional library search dirs - items: - type: string - type: array - tlas: - description: TLAS is a list of Jsonnet Top-level - Arguments - items: - description: JsonnetVar represents a variable - to be passed to jsonnet during manifest generation - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - description: Recurse specifies whether to scan a directory - recursively for manifests - type: boolean - type: object - helm: - description: Helm holds helm specific options - properties: - fileParameters: - description: FileParameters are file parameters to - the helm template - items: - description: HelmFileParameter is a file parameter - that's passed to helm template during manifest - generation - properties: - name: - description: Name is the name of the Helm parameter - type: string - path: - description: Path is the path to the file containing - the values for the Helm parameter - type: string - type: object - type: array - ignoreMissingValueFiles: - description: IgnoreMissingValueFiles prevents helm - template from failing when valueFiles do not exist - locally by not appending them to helm template --values - type: boolean - parameters: - description: Parameters is a list of Helm parameters - which are passed to the helm template command upon - manifest generation - items: - description: HelmParameter is a parameter that's - passed to helm template during manifest generation - properties: - forceString: - description: ForceString determines whether - to tell Helm to interpret booleans and numbers - as strings - type: boolean - name: - description: Name is the name of the Helm parameter - type: string - value: - description: Value is the value for the Helm - parameter - type: string - type: object - type: array - passCredentials: - description: PassCredentials pass credentials to all - domains (Helm's --pass-credentials) - type: boolean - releaseName: - description: ReleaseName is the Helm release name - to use. If omitted it will use the application name - type: string - skipCrds: - description: SkipCrds skips custom resource definition - installation step (Helm's --skip-crds) - type: boolean - valueFiles: - description: ValuesFiles is a list of Helm value files - to use when generating a template - items: - type: string - type: array - values: - description: Values specifies Helm values to be passed - to helm template, typically defined as a block - type: string - version: - description: Version is the Helm version to use for - templating (either "2" or "3") - type: string - type: object - ksonnet: - description: Ksonnet holds ksonnet specific options - properties: - environment: - description: Environment is a ksonnet application - environment name - type: string - parameters: - description: Parameters are a list of ksonnet component - parameter override values - items: - description: KsonnetParameter is a ksonnet component - parameter - properties: - component: - type: string - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - kustomize: - description: Kustomize holds kustomize specific options - properties: - commonAnnotations: - additionalProperties: - type: string - description: CommonAnnotations is a list of additional - annotations to add to rendered manifests - type: object - commonLabels: - additionalProperties: - type: string - description: CommonLabels is a list of additional - labels to add to rendered manifests - type: object - forceCommonAnnotations: - description: ForceCommonAnnotations specifies whether - to force applying common annotations to resources - for Kustomize apps - type: boolean - forceCommonLabels: - description: ForceCommonLabels specifies whether to - force applying common labels to resources for Kustomize - apps - type: boolean - images: - description: Images is a list of Kustomize image override - specifications - items: - description: KustomizeImage represents a Kustomize - image definition in the format [old_image_name=]: - type: string - type: array - namePrefix: - description: NamePrefix is a prefix appended to resources - for Kustomize apps - type: string - nameSuffix: - description: NameSuffix is a suffix appended to resources - for Kustomize apps - type: string - version: - description: Version controls which version of Kustomize - to use for rendering manifests - type: string - type: object - path: - description: Path is a directory path within the Git repository, - and is only valid for applications sourced from Git. - type: string - plugin: - description: ConfigManagementPlugin holds config management - plugin specific options - properties: - env: - description: Env is a list of environment variable - entries - items: - description: EnvEntry represents an entry in the - application's environment - properties: - name: - description: Name is the name of the variable, - usually expressed in uppercase - type: string - value: - description: Value is the value of the variable - type: string - required: - - name - - value - type: object - type: array - name: - type: string - type: object - repoURL: - description: RepoURL is the URL to the repository (Git - or Helm) that contains the application manifests - type: string - targetRevision: - description: TargetRevision defines the revision of the - source to sync the application to. In case of Git, this - can be commit, tag, or branch. If omitted, will equal - to HEAD. In case of Helm, this is a semver tag for the - Chart's version. - type: string - required: - - repoURL - type: object - required: - - destination - - source - type: object - revision: - description: Revision contains information about the revision - the comparison has been performed to - type: string - status: - description: Status is the sync state of the comparison - type: string - required: - - status - type: object - type: object - required: - - metadata - - spec - type: object - served: true - storage: true - subresources: {} diff --git a/common/install/templates/argocd/application.yaml b/common/install/templates/argocd/application.yaml deleted file mode 100644 index 324e1f32..00000000 --- a/common/install/templates/argocd/application.yaml +++ /dev/null @@ -1,37 +0,0 @@ -apiVersion: argoproj.io/v1alpha1 -kind: Application -metadata: - name: {{ .Release.Name }}-{{ .Values.main.clusterGroupName }} - namespace: openshift-gitops - finalizers: - - resources-finalizer.argocd.argoproj.io/foreground -spec: - destination: - name: in-cluster - namespace: {{ .Release.Name }}-{{ .Values.main.clusterGroupName }} - project: default - source: - repoURL: {{ .Values.main.git.repoURL }} - targetRevision: {{ .Values.main.git.revision }} - path: common/clustergroup - helm: - ignoreMissingValueFiles: true - valueFiles: - - "/values-global.yaml" - - "/values-{{ .Values.main.clusterGroupName }}.yaml" - # Track the progress of https://github.com/argoproj/argo-cd/pull/6280 - parameters: - - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL - - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION - - name: global.namespace - value: $ARGOCD_APP_NAMESPACE - - name: global.pattern - value: {{ .Release.Name }} - - name: global.hubClusterDomain - value: {{ .Values.global.hubClusterDomain }} -{{- if eq .Values.main.options.syncPolicy "Automatic" }} - syncPolicy: - automated: {} -{{- end }} diff --git a/common/install/templates/argocd/namespace.yaml b/common/install/templates/argocd/namespace.yaml deleted file mode 100644 index 9e9fafb2..00000000 --- a/common/install/templates/argocd/namespace.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# Pre-create so we can create our argo app for keeping subscriptions in sync -# Do it here so that we don't try to sync it in the future -apiVersion: v1 -kind: Namespace -metadata: - name: openshift-gitops diff --git a/common/install/templates/argocd/subscription.yaml b/common/install/templates/argocd/subscription.yaml deleted file mode 100644 index 22837b9a..00000000 --- a/common/install/templates/argocd/subscription.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: operators.coreos.com/v1alpha1 -kind: Subscription -metadata: - name: openshift-gitops-operator - namespace: openshift-operators - labels: - operators.coreos.com/openshift-gitops-operator.openshift-operators: "" -spec: - channel: {{ .Values.main.gitops.channel }} - installPlanApproval: {{ .Values.main.options.installPlanApproval }} - name: openshift-gitops-operator - source: redhat-operators - sourceNamespace: openshift-marketplace - config: - env: - - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES - value: {{ .Release.Name }}-{{ .Values.main.clusterGroupName }},openshift-gitops -{{- if .Values.main.options.useCSV }} - startingCSV: openshift-gitops-operator.{{ .Values.main.gitops.csv }} -{{- end }} diff --git a/common/install/values.yaml b/common/install/values.yaml deleted file mode 100644 index 370e6b15..00000000 --- a/common/install/values.yaml +++ /dev/null @@ -1,25 +0,0 @@ -main: - git: - repoURL: https://github.com/pattern-clone/mypattern - revision: main - - options: - syncPolicy: Automatic - installPlanApproval: Automatic - useCSV: False - - gitops: - channel: stable - source: redhat-operators - csv: v1.3.0 - - clusterGroupName: default - -global: - imageregistry: - type: quay - - git: - hostname: github.com - # Account is the user or organization under which the pattern repo lives - account: hybrid-cloud-patterns diff --git a/common/operator-install/Chart.yaml b/common/operator-install/Chart.yaml deleted file mode 100644 index 74adcf8f..00000000 --- a/common/operator-install/Chart.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v2 -description: A Helm chart to build and deploy a Cloud Pattern via the patterns operator -keywords: -- pattern -name: pattern-install -version: 0.0.1 diff --git a/common/operator-install/crds/gitops.hybrid-cloud-patterns.io_patterns.yaml b/common/operator-install/crds/gitops.hybrid-cloud-patterns.io_patterns.yaml deleted file mode 100644 index 1acd4ad2..00000000 --- a/common/operator-install/crds/gitops.hybrid-cloud-patterns.io_patterns.yaml +++ /dev/null @@ -1,157 +0,0 @@ - ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.7.0 - creationTimestamp: null - name: patterns.gitops.hybrid-cloud-patterns.io -spec: - group: gitops.hybrid-cloud-patterns.io - names: - kind: Pattern - listKind: PatternList - plural: patterns - shortNames: - - patt - singular: pattern - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.lastStep - name: Step - priority: 1 - type: string - - jsonPath: .status.lastError - name: Error - priority: 2 - type: string - name: v1alpha1 - schema: - openAPIV3Schema: - description: Pattern is the Schema for the patterns 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: PatternSpec defines the desired state of Pattern - properties: - clusterGroupName: - type: string - extraParameters: - description: '.Name is dot separated per the helm --set syntax, such - as: global.something.field' - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - extraValueFiles: - description: URLs to additional Helm parameter files - items: - type: string - type: array - gitOpsSpec: - properties: - manualApproval: - description: 'Require manual confirmation before installing and - upgrading operators. Default: False' - type: boolean - manualSync: - description: 'Require manual intervention before Argo will sync - new content. Default: False' - type: boolean - operatorCSV: - description: Specific version of openshift-gitops to deploy. Requires - UseCSV=True - type: string - operatorChannel: - description: 'Channel to deploy openshift-gitops from. Default: - stable' - type: string - operatorSource: - description: 'Source to deploy openshift-gitops from. Default: - redhat-operators' - type: string - useCSV: - description: 'Dangerous. Force a specific version to be installed. - Default: False' - type: boolean - type: object - gitSpec: - properties: - hostname: - description: Optional. FQDN of the git server if automatic parsing - from TargetRepo is broken - type: string - originRepo: - description: Unused - type: string - targetRepo: - description: Git repo containing the pattern to deploy. Must use - https/http - type: string - targetRevision: - description: 'Branch, tag, or commit to deploy. Does not support - short-sha''s. Default: main' - type: string - valuesDirectoryURL: - description: Optional. Alternate URL to obtain Helm values files - from instead of this pattern. - type: string - required: - - targetRepo - type: object - required: - - clusterGroupName - - gitSpec - type: object - status: - description: PatternStatus defines the observed state of Pattern - properties: - clusterDomain: - type: string - clusterID: - type: string - clusterName: - type: string - clusterPlatform: - type: string - lastError: - description: Last error encountered by the pattern - type: string - lastStep: - description: Last action related to the pattern - type: string - version: - description: Number of updates to the pattern - type: integer - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/common/operator-install/templates/pattern.yaml b/common/operator-install/templates/pattern.yaml deleted file mode 100644 index 2ac7b52a..00000000 --- a/common/operator-install/templates/pattern.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: gitops.hybrid-cloud-patterns.io/v1alpha1 -kind: Pattern -metadata: - name: {{ .Release.Name }} - namespace: openshift-operators -spec: - clusterGroupName: {{ .Values.main.clusterGroupName }} - gitSpec: - targetRepo: {{ .Values.main.git.repoURL }} - targetRevision: {{ .Values.main.git.revision }} - gitOpsSpec: - operatorChannel: {{ default "stable" .Values.main.gitops.channel }} diff --git a/common/operator-install/templates/subscription.yaml b/common/operator-install/templates/subscription.yaml deleted file mode 100644 index 381e185f..00000000 --- a/common/operator-install/templates/subscription.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: operators.coreos.com/v1alpha1 -kind: Subscription -metadata: - name: patterns-operator - namespace: openshift-operators - labels: - operators.coreos.com/patterns-operator.openshift-operators: "" -spec: - channel: fast - installPlanApproval: Automatic - name: patterns-operator - source: community-operators - sourceNamespace: openshift-marketplace diff --git a/common/operator-install/values.yaml b/common/operator-install/values.yaml deleted file mode 100644 index b6e67044..00000000 --- a/common/operator-install/values.yaml +++ /dev/null @@ -1,9 +0,0 @@ -main: - git: - repoURL: https://github.com/pattern-clone/mypattern - revision: main - - gitops: - channel: "stable" - - clusterGroupName: default diff --git a/common/reference-output.yaml b/common/reference-output.yaml deleted file mode 100644 index cd59ac24..00000000 --- a/common/reference-output.yaml +++ /dev/null @@ -1,119 +0,0 @@ ---- -# Source: pattern-install/templates/argocd/namespace.yaml -# Pre-create so we can create our argo app for keeping subscriptions in sync -# Do it here so that we don't try to sync it in the future -apiVersion: v1 -kind: Namespace -metadata: - name: openshift-gitops ---- -# Source: pattern-install/templates/namespace.yaml -apiVersion: v1 -kind: Namespace -metadata: - name: manuela-ci - labels: - manuela-role: pipeline - app.kubernetes.io/instance: manuela ---- -# Source: pattern-install/templates/pipeline/serviceaccount.yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: pipeline - namespace: manuela-ci -secrets: -- name: git-repo-credentials -- name: image-registry-credentials ---- -# Source: pattern-install/templates/secrets/s3-secret.yaml -kind: Secret -apiVersion: v1 -metadata: - name: s3-secret -type: Opaque -data: - # Pre-create as part of the initial 'helm install' chart - # Create a file with the following: - # s3.accessKey: KEY - # s3.secretKey: secret key - #application.properties: base64 encrypted value of the above file - # This should live in the values-secret.yaml file - application.properties: BASE64STRING ---- -# Source: pattern-install/templates/secrets/secret-git-repo-credentials.yaml -apiVersion: v1 -kind: Secret -metadata: - name: git-repo-credentials - namespace: manuela-ci - annotations: - # Tekton magic, see https://tekton.dev/vault/pipelines-v0.15.2/auth/ - tekton.dev/git-0: https://github.com/hybrid-cloud-patterns -type: kubernetes.io/basic-auth -stringData: - username: STRING - password: STRING ---- -# Source: pattern-install/templates/secrets/secret-image-registry-credentials.yaml -apiVersion: v1 -kind: Secret -metadata: - name: openshift-registry-credentials - namespace: manuela-ci - annotations: - # Tekton magic, see https://tekton.dev/vault/pipelines-v0.15.2/auth/ - tekton.dev/docker-0: "https://" -type: kubernetes.io/basic-auth -stringData: - username: STRING - password: STRING ---- -# Source: pattern-install/templates/argocd/application.yaml -apiVersion: argoproj.io/v1alpha1 -kind: Application -metadata: - name: common-example - namespace: openshift-gitops -spec: - destination: - name: in-cluster - namespace: common-example - project: default - source: - repoURL: https://github.com/beekhof/common.git - targetRevision: main - path: common/clustergroup - helm: - valueFiles: - - "https://github.com/beekhof/patterns/raw/main/values-global.yaml" - - "https://github.com/beekhof/patterns/raw/main/values-example.yaml" - # Track the progress of https://github.com/argoproj/argo-cd/pull/6280 - parameters: - - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL - - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION - - name: global.namespace - value: $ARGOCD_APP_NAMESPACE - - name: global.valuesDirectoryURL - value: https://github.com/beekhof/patterns/raw/main - - name: global.pattern - value: common - syncPolicy: - automated: {} ---- -# Source: pattern-install/templates/argocd/subscription.yaml -apiVersion: operators.coreos.com/v1alpha1 -kind: Subscription -metadata: - name: openshift-gitops-operator - namespace: openshift-operators - labels: - operators.coreos.com/openshift-gitops-operator.openshift-operators: "" -spec: - channel: stable - installPlanApproval: Automatic - name: openshift-gitops-operator - source: redhat-operators - sourceNamespace: openshift-marketplace diff --git a/common/scripts/make_common_subtree.sh b/common/scripts/make_common_subtree.sh deleted file mode 100755 index a5e406d8..00000000 --- a/common/scripts/make_common_subtree.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/sh - -if [ "$1" = "-h" ]; then - echo "This script will convert common into a subtree and add a remote to help manage it." - echo "The script takes three positional arguments, as follows:" - echo - echo "$0 " - echo - echo "Run without arguments, the script would run as if these arguments had been passed:" - echo "$0 https://github.com/hybrid-cloud-patterns/common.git main common-subtree" - echo - echo "Please ensure the git subtree command is available. On RHEL/Fedora, the git subtree command" - echo "is in a separate package called git-subtree" - exit 1 -fi - -if [ -f '/etc/redhat-release' ]; then - rpm -qa | grep git-subtree 2>&1 - if [ ! $? = 0 ]; then - echo "you need to install git-subtree" - echo "would you like to install it now?" - select ANS in yes no - do - case $ANS in - yes) - sudo dnf install git-subtree -y - break - ;; - no) - exit - break - ;; - *) - echo "You must enter yes or no" - ;; - esac - done - fi -fi - -if [ "$1" ]; then - subtree_repo=$1 -else - subtree_repo=https://github.com/hybrid-cloud-patterns/common.git -fi - -if [ "$2" ]; then - subtree_branch=$2 -else - subtree_branch=main -fi - -if [ "$3" ]; then - subtree_remote=$3 -else - subtree_remote=common-subtree -fi - -git diff --quiet || (echo "This script must be run on a clean working tree" && exit 1) - -echo "Changing directory to project root" -cd `git rev-parse --show-toplevel` - -echo "Removing existing common and replacing it with subtree from $subtree_repo $subtree_remote" -rm -rf common - -echo "Committing removal of common" -(git add -A :/ && git commit -m "Removed previous version of common to convert to subtree from $subtree_repo $subtree_branch") || exit 1 - -echo "Adding (possibly replacing) subtree remote $subtree_remote" -git remote rm "$subtree_remote" -git remote add -f "$subtree_remote" "$subtree_repo" || exit 1 -git subtree add --prefix=common "$subtree_remote" "$subtree_branch" || exit 1 - -echo "Complete. You may now push these results if you are satisfied" -exit 0 diff --git a/common/scripts/pattern-util.sh b/common/scripts/pattern-util.sh deleted file mode 100755 index d2be2e97..00000000 --- a/common/scripts/pattern-util.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -if [ -z "$PATTERN_UTILITY_CONTAINER" ]; then - PATTERN_UTILITY_CONTAINER="quay.io/hybridcloudpatterns/hybridcloudpatterns-utility-ee" -fi - -# Copy Kubeconfig from current environment. The utilities will pick up ~/.kube/config if set so it's not mandatory -# /home/runner is the normal homedir -# $HOME is mounted as itself for any files that are referenced with absolute paths -# $HOME is mounted to /root because the UID in the container is 0 and that's where SSH looks for credentials - -podman run -it \ - --security-opt label=disable \ - -e KUBECONFIG="${KUBECONFIG}" \ - -v ${HOME}:/home/runner \ - -v ${HOME}:${HOME} \ - -v ${HOME}:/root \ - -w $(pwd) \ - "$PATTERN_UTILITY_CONTAINER" \ - $@ diff --git a/common/scripts/test.sh b/common/scripts/test.sh deleted file mode 100755 index 5790b5de..00000000 --- a/common/scripts/test.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash - -# helm template (even with --dry-run) can interact with the cluster -# This won't protect us if a user has ~/.kube -# Also call helm template with a non existing --kubeconfig while we're at it -unset KUBECONFIG - -target=$1 -name=$(echo $1 | sed -e s@/@-@g -e s@charts-@@) -TEST_VARIANT="$2" -CHART_OPTS="$3" - -TESTDIR=tests -REFERENCE=${TESTDIR}/${name}-${TEST_VARIANT}.expected.yaml -OUTPUT=${TESTDIR}/.${name}-${TEST_VARIANT}.expected.yaml -#REFERENCE=${TESTDIR}/${name}.expected.yaml -#OUTPUT=${TESTDIR}/.${name}.expected.yaml - -echo "Testing $1 chart (${TEST_VARIANT})" >&2 -helm template --kubeconfig /tmp/doesnotexistever $target --name-template $name ${CHART_OPTS} > ${OUTPUT} -rc=$? -if [ $rc -ne 0 ]; then - echo "FAIL on helm template $target --name-template $name ${CHART_OPTS}" - exit 1 -fi -#cp ${OUTPUT} ${REFERENCE} -if [ ! -e ${REFERENCE} ]; then - touch ${REFERENCE} -fi -diff -u ${REFERENCE} ${OUTPUT} -rc=$? -if [ $rc = 0 ]; then - rm -f ${OUTPUT} -fi - -if [ $TEST_VARIANT = normal -a $rc = 0 ]; then - # Another method of finding variables missing from values.yaml, eg. - # - name: -datacenter - # + name: pattern-name-datacenter - # Alas we can't make it fatal because there *should* be some differences - diff -u ${TESTDIR}/${name}-naked.expected.yaml ${TESTDIR}/${name}-normal.expected.yaml -fi - -if [ $rc = 0 ]; then - echo "PASS on $target $TEST_VARIANT with opts [$CHART_OPTS]" -else - echo "FAIL on $target $TEST_VARIANT with opts [$CHART_OPTS]" -fi - -exit $rc diff --git a/common/scripts/vault-utils.sh b/common/scripts/vault-utils.sh deleted file mode 100755 index 2f014a45..00000000 --- a/common/scripts/vault-utils.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash -set -eu - -get_abs_filename() { - # $1 : relative filename - echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")" -} - -SCRIPT=$(get_abs_filename "$0") -SCRIPTPATH=$(dirname "$SCRIPT") -COMMONPATH=$(dirname "$SCRIPTPATH") -ANSIBLEPATH="$(dirname ${SCRIPTPATH})/ansible" -PLAYBOOKPATH="${ANSIBLEPATH}/playbooks" -export ANSIBLE_CONFIG="${ANSIBLEPATH}/ansible.cfg" - -# Parse arguments -if [ $# -lt 1 ]; then - echo "Specify at least the command ($#): $*" - exit 1 -fi - -TASK="${1}" -OUTFILE=${2:-"$COMMONPATH"/pattern-vault.init} - -if [ -z ${TASK} ]; then - echo "Task is unset" - exit 1 -fi - -ansible-playbook -t "${TASK}" -e output_file="${OUTFILE}" "${PLAYBOOKPATH}/vault/vault.yaml" diff --git a/common/tests/acm-naked.expected.yaml b/common/tests/acm-naked.expected.yaml deleted file mode 100644 index e94c6a51..00000000 --- a/common/tests/acm-naked.expected.yaml +++ /dev/null @@ -1,93 +0,0 @@ ---- -# Source: acm/templates/policies/application-policies.yaml -# TODO: Also create a GitOpsCluster.apps.open-cluster-management.io ---- -# Source: acm/templates/multiclusterhub.yaml -apiVersion: operator.open-cluster-management.io/v1 -kind: MultiClusterHub -metadata: - name: multiclusterhub - namespace: open-cluster-management - annotations: - argocd.argoproj.io/sync-wave: "-1" -spec: {} ---- -# Source: acm/templates/policies/ocp-gitops-policy.yaml -apiVersion: policy.open-cluster-management.io/v1 -kind: PlacementBinding -metadata: - name: openshift-gitops-placement-binding - annotations: - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true -placementRef: - name: openshift-gitops-placement - kind: PlacementRule - apiGroup: apps.open-cluster-management.io -subjects: - - name: openshift-gitops-policy - kind: Policy - apiGroup: policy.open-cluster-management.io ---- -# Source: acm/templates/policies/ocp-gitops-policy.yaml -apiVersion: apps.open-cluster-management.io/v1 -kind: PlacementRule -metadata: - name: openshift-gitops-placement -spec: - clusterConditions: - - status: 'True' - type: ManagedClusterConditionAvailable - clusterSelector: - matchExpressions: - - key: vendor - operator: In - values: - - OpenShift ---- -# Source: acm/templates/policies/ocp-gitops-policy.yaml -apiVersion: policy.open-cluster-management.io/v1 -kind: Policy -metadata: - name: openshift-gitops-policy - annotations: - policy.open-cluster-management.io/standards: NIST-CSF - policy.open-cluster-management.io/categories: PR.DS Data Security - policy.open-cluster-management.io/controls: PR.DS-1 Data-at-rest - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true - argocd.argoproj.io/compare-options: IgnoreExtraneous -spec: - remediationAction: enforce - disabled: false - policy-templates: - - objectDefinition: - apiVersion: policy.open-cluster-management.io/v1 - kind: ConfigurationPolicy - metadata: - name: openshift-gitops-config - spec: - remediationAction: enforce - severity: medium - namespaceSelector: - include: - - default - object-templates: - - complianceType: mustonlyhave - objectDefinition: - # This is an auto-generated file. DO NOT EDIT - apiVersion: operators.coreos.com/v1alpha1 - kind: Subscription - metadata: - name: openshift-gitops-operator - namespace: openshift-operators - labels: - operators.coreos.com/openshift-gitops-operator.openshift-operators: '' - spec: - channel: stable - installPlanApproval: Automatic - name: openshift-gitops-operator - source: redhat-operators - sourceNamespace: openshift-marketplace - config: - env: - - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES - value: "*" diff --git a/common/tests/acm-normal.expected.yaml b/common/tests/acm-normal.expected.yaml deleted file mode 100644 index 29af29a8..00000000 --- a/common/tests/acm-normal.expected.yaml +++ /dev/null @@ -1,204 +0,0 @@ ---- -# Source: acm/templates/multiclusterhub.yaml -apiVersion: operator.open-cluster-management.io/v1 -kind: MultiClusterHub -metadata: - name: multiclusterhub - namespace: open-cluster-management - annotations: - argocd.argoproj.io/sync-wave: "-1" -spec: {} ---- -# Source: acm/templates/policies/application-policies.yaml -apiVersion: policy.open-cluster-management.io/v1 -kind: PlacementBinding -metadata: - name: edge-placement-binding - annotations: - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true -placementRef: - name: edge-placement - kind: PlacementRule - apiGroup: apps.open-cluster-management.io -subjects: - - name: edge-clustergroup-policy - kind: Policy - apiGroup: policy.open-cluster-management.io ---- -# Source: acm/templates/policies/ocp-gitops-policy.yaml -apiVersion: policy.open-cluster-management.io/v1 -kind: PlacementBinding -metadata: - name: openshift-gitops-placement-binding - annotations: - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true -placementRef: - name: openshift-gitops-placement - kind: PlacementRule - apiGroup: apps.open-cluster-management.io -subjects: - - name: openshift-gitops-policy - kind: Policy - apiGroup: policy.open-cluster-management.io ---- -# Source: acm/templates/policies/application-policies.yaml -apiVersion: apps.open-cluster-management.io/v1 -kind: PlacementRule -metadata: - name: edge-placement -spec: - clusterConditions: - - status: 'True' - type: ManagedClusterConditionAvailable - clusterSelector: { - "matchExpressions": [ - { - "key": "vendor", - "operator": "In", - "values": [ - "OpenShift" - ] - } - ] -} ---- -# Source: acm/templates/policies/ocp-gitops-policy.yaml -apiVersion: apps.open-cluster-management.io/v1 -kind: PlacementRule -metadata: - name: openshift-gitops-placement -spec: - clusterConditions: - - status: 'True' - type: ManagedClusterConditionAvailable - clusterSelector: - matchExpressions: - - key: vendor - operator: In - values: - - OpenShift ---- -# Source: acm/templates/policies/application-policies.yaml -# TODO: Also create a GitOpsCluster.apps.open-cluster-management.io -apiVersion: policy.open-cluster-management.io/v1 -kind: Policy -metadata: - name: edge-clustergroup-policy - annotations: - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true - argocd.argoproj.io/compare-options: IgnoreExtraneous -spec: - remediationAction: enforce - disabled: false - policy-templates: - - objectDefinition: - apiVersion: policy.open-cluster-management.io/v1 - kind: ConfigurationPolicy - metadata: - name: edge-clustergroup-config - spec: - remediationAction: enforce - severity: medium - namespaceSelector: - include: - - default - object-templates: - - complianceType: mustonlyhave - objectDefinition: - apiVersion: argoproj.io/v1alpha1 - kind: Application - metadata: - name: mypattern-edge - namespace: openshift-gitops - finalizers: - - resources-finalizer.argocd.argoproj.io/foreground - spec: - project: default - source: - repoURL: https://github.com/pattern-clone/mypattern - targetRevision: main - path: common/clustergroup - helm: - ignoreMissingValueFiles: true - valueFiles: - - "/values-global.yaml" - - "/values-edge.yaml" - parameters: - - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL - - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION - - name: global.namespace - value: $ARGOCD_APP_NAMESPACE - - name: global.pattern - value: mypattern - - name: global.hubClusterDomain - value: hub.example.com - - name: global.localClusterDomain - value: '{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain }}' - - name: clusterGroup.isHubCluster - value: "false" - destination: - server: https://kubernetes.default.svc - namespace: mypattern-edge - syncPolicy: - automated: - prune: false - selfHeal: true - ignoreDifferences: - - group: apps - kind: Deployment - jsonPointers: - - /spec/replicas - - group: route.openshift.io - kind: Route - jsonPointers: - - /status ---- -# Source: acm/templates/policies/ocp-gitops-policy.yaml -apiVersion: policy.open-cluster-management.io/v1 -kind: Policy -metadata: - name: openshift-gitops-policy - annotations: - policy.open-cluster-management.io/standards: NIST-CSF - policy.open-cluster-management.io/categories: PR.DS Data Security - policy.open-cluster-management.io/controls: PR.DS-1 Data-at-rest - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true - argocd.argoproj.io/compare-options: IgnoreExtraneous -spec: - remediationAction: enforce - disabled: false - policy-templates: - - objectDefinition: - apiVersion: policy.open-cluster-management.io/v1 - kind: ConfigurationPolicy - metadata: - name: openshift-gitops-config - spec: - remediationAction: enforce - severity: medium - namespaceSelector: - include: - - default - object-templates: - - complianceType: mustonlyhave - objectDefinition: - # This is an auto-generated file. DO NOT EDIT - apiVersion: operators.coreos.com/v1alpha1 - kind: Subscription - metadata: - name: openshift-gitops-operator - namespace: openshift-operators - labels: - operators.coreos.com/openshift-gitops-operator.openshift-operators: '' - spec: - channel: stable - installPlanApproval: Automatic - name: openshift-gitops-operator - source: redhat-operators - sourceNamespace: openshift-marketplace - config: - env: - - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES - value: "*" diff --git a/common/tests/clustergroup-naked.expected.yaml b/common/tests/clustergroup-naked.expected.yaml deleted file mode 100644 index 993e6bb5..00000000 --- a/common/tests/clustergroup-naked.expected.yaml +++ /dev/null @@ -1,182 +0,0 @@ ---- -# Source: pattern-clustergroup/templates/gitops-namespace.yaml -apiVersion: v1 -kind: Namespace -metadata: - labels: - name: common-example - # The name here needs to be consistent with - # - acm/templates/policies/application-policies.yaml - # - clustergroup/templates/applications.yaml - # - any references to secrets and route URLs in documentation - name: common-example -spec: {} ---- -# Source: pattern-clustergroup/templates/argocd-super-role.yaml -# WARNING: ONLY USE THIS FOR MANAGING CLUSTERS NOT FOR REGULAR USERS -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: openshift-gitops-cluster-admin-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin -subjects: - - kind: ServiceAccount - name: openshift-gitops-argocd-application-controller - namespace: openshift-gitops - # NOTE: THIS MUST BE FIXED FOR MULTITENANT SETUP - - kind: ServiceAccount - name: openshift-gitops-argocd-server - namespace: openshift-gitops ---- -# Source: pattern-clustergroup/templates/argocd-super-role.yaml -# WARNING: ONLY USE THIS FOR MANAGING CLUSTERS NOT FOR REGULAR USERS -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: common-example-cluster-admin-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin -subjects: - - kind: ServiceAccount - # This is the {ArgoCD.name}-argocd-application-controller - name: example-gitops-argocd-application-controller - namespace: common-example - # NOTE: THIS MUST BE FIXED FOR MULTITENANT SETUP - - kind: ServiceAccount - # This is the {ArgoCD.name}-argocd-server - name: example-gitops-argocd-server - namespace: common-example - # NOTE: This is needed starting with gitops-1.5.0 (see issue common#76) - - kind: ServiceAccount - name: example-gitops-argocd-dex-server - namespace: common-example ---- -# Source: pattern-clustergroup/templates/argocd.yaml -apiVersion: argoproj.io/v1alpha1 -kind: ArgoCD -metadata: - finalizers: - - argoproj.io/finalizer - # Changing the name affects the ClusterRoleBinding, the generated secret, - # route URL, and argocd.argoproj.io/managed-by annotations - name: example-gitops - namespace: common-example - annotations: - argocd.argoproj.io/compare-options: IgnoreExtraneous -spec: - applicationInstanceLabelKey: argocd.argoproj.io/instance - # Not the greatest way to pass git/quay info to sub-applications, but it will do until - # we can support helmChart with kustomize - # The other option is to pass them in as environment variables eg. BLUEPRINT_VERSION - configManagementPlugins: | - - name: kustomize-version - generate: - command: ["sh", "-c"] - args: ["kustomize version 1>&2 && exit 1"] - - name: kustomize-with-helm - generate: - command: ["kustomize"] - args: ["build", "--enable-helm"] - - name: helm-with-kustomize - init: - command: ["/bin/sh", "-c"] - args: ["helm dependency build"] - generate: - command: ["/bin/bash", "-c"] - args: ["helm template . --name-template ${ARGOCD_APP_NAME:0:52} - -f $(git rev-parse --show-toplevel)/values-global.yaml - -f $(git rev-parse --show-toplevel)/values-example.yaml - --set global.repoURL=$ARGOCD_APP_SOURCE_REPO_URL - --set global.targetRevision=$ARGOCD_APP_SOURCE_TARGET_REVISION - --set global.namespace=$ARGOCD_APP_NAMESPACE - --set global.pattern=common - --set global.hubClusterDomain= - --set global.localClusterDomain= - --post-renderer ./kustomize"] - applicationSet: - resources: - limits: - cpu: "2" - memory: 1Gi - requests: - cpu: 250m - memory: 512Mi - controller: - processors: {} - resources: - limits: - cpu: "4" - memory: 4Gi - requests: - cpu: 500m - memory: 2Gi - dex: - openShiftOAuth: true - resources: - limits: - cpu: 500m - memory: 256Mi - requests: - cpu: 250m - memory: 128Mi - initialSSHKnownHosts: {} - rbac: - defaultPolicy: role:admin - repo: - resources: - limits: - cpu: "1" - memory: 512Mi - requests: - cpu: 250m - memory: 256Mi - resourceExclusions: | - - apiGroups: - - tekton.dev - kinds: - - TaskRun - - PipelineRun - server: - autoscale: - enabled: false - grpc: - ingress: - enabled: false - ingress: - enabled: false - resources: - limits: - cpu: 500m - memory: 256Mi - requests: - cpu: 125m - memory: 128Mi - route: - enabled: true - tls: - insecureEdgeTerminationPolicy: Redirect - termination: reencrypt - service: - type: "" - tls: - ca: {} -status: ---- -# Source: pattern-clustergroup/templates/argocd.yaml -apiVersion: console.openshift.io/v1 -kind: ConsoleLink -metadata: - name: example-gitops-link - namespace: common-example -spec: - applicationMenu: - section: OpenShift GitOps - imageURL: data:image/png;base64,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 - href: 'https://example-gitops-server-common-example.' - location: ApplicationMenu - text: 'Example ArgoCD' diff --git a/common/tests/clustergroup-normal.expected.yaml b/common/tests/clustergroup-normal.expected.yaml deleted file mode 100644 index 2af41cbb..00000000 --- a/common/tests/clustergroup-normal.expected.yaml +++ /dev/null @@ -1,802 +0,0 @@ ---- -# Source: pattern-clustergroup/templates/gitops-namespace.yaml -apiVersion: v1 -kind: Namespace -metadata: - labels: - name: mypattern-example - # The name here needs to be consistent with - # - acm/templates/policies/application-policies.yaml - # - clustergroup/templates/applications.yaml - # - any references to secrets and route URLs in documentation - name: mypattern-example -spec: {} ---- -# Source: pattern-clustergroup/templates/imperative/namespace.yaml -apiVersion: v1 -kind: Namespace -metadata: - labels: - name: imperative - argocd.argoproj.io/managed-by: mypattern-example - name: imperative ---- -# Source: pattern-clustergroup/templates/namespaces.yaml -apiVersion: v1 -kind: Namespace -metadata: - labels: - name: pattern - argocd.argoproj.io/managed-by: mypattern-example - name: open-cluster-management -spec: ---- -# Source: pattern-clustergroup/templates/namespaces.yaml -apiVersion: v1 -kind: Namespace -metadata: - labels: - name: pattern - argocd.argoproj.io/managed-by: mypattern-example - name: application-ci -spec: ---- -# Source: pattern-clustergroup/templates/imperative/serviceaccount.yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: imperative-sa - namespace: imperative ---- -# Source: pattern-clustergroup/templates/imperative/configmap.yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: helm-values-configmap - namespace: imperative -data: - values.yaml: | - clusterGroup: - applications: - acm: - ignoreDifferences: - - group: internal.open-cluster-management.io - jsonPointers: - - /spec/loggingCA - kind: ManagedClusterInfo - name: acm - namespace: open-cluster-management - path: common/acm - project: datacenter - external: - clusterName: example - name: external-app - namespace: demo - project: datacenter - pipe: - name: pipelines - namespace: application-ci - path: charts/datacenter/pipelines - project: datacenter - externalClusters: - - example - imperative: - activeDeadlineSeconds: 3600 - clusterRoleName: imperative-cluster-role - clusterRoleYaml: "" - cronJobName: imperative-cronjob - image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest - imagePullPolicy: Always - insecureUnsealVaultInsideClusterSchedule: '*/5 * * * *' - jobName: imperative-job - jobs: - - name: test - playbook: ansible/test.yml - namespace: imperative - roleName: imperative-role - roleYaml: "" - schedule: '*/10 * * * *' - serviceAccountCreate: true - serviceAccountName: imperative-sa - valuesConfigMap: helm-values-configmap - verbosity: "" - insecureUnsealVaultInsideCluster: true - isHubCluster: true - managedClusterGroups: - - clusterSelector: - matchExpressions: - - key: vendor - operator: In - values: - - OpenShift - helmOverrides: - - name: clusterGroup.isHubCluster - value: "false" - name: edge - targetRevision: main - name: example - namespaces: - - open-cluster-management - - application-ci - projects: - - datacenter - subscriptions: - acm: - channel: release-2.4 - csv: advanced-cluster-management.v2.4.1 - name: advanced-cluster-management - namespace: open-cluster-management - odh: - csv: opendatahub-operator.v1.1.0 - disabled: true - name: opendatahub-operator - source: community-operators - pipelines: - csv: redhat-openshift-pipelines.v1.5.2 - name: openshift-pipelines-operator-rh - files: - cluster_example_ca: /path/to/ca.file - global: - git: - account: hybrid-cloud-patterns - dev_revision: main - email: someone@somewhere.com - hostname: github.com - hubClusterDomain: hub.example.com - localClusterDomain: region.example.com - namespace: pattern-namespace - options: - installPlanApproval: Automatic - syncPolicy: Automatic - useCSV: false - pattern: mypattern - repoURL: https://github.com/pattern-clone/mypattern - main: - clusterGroupName: example - git: - repoURL: https://github.com/pattern-clone/mypattern - revision: main - secretStore: - kind: ClusterSecretStore - name: vault-backend - secrets: - aws: - s3Secret: test-secret - cluster_example: - bearerToken: - server: https://api.example.openshiftapps.com:6443 - git: - token: test-git-token - username: test-user - imageregistry: - account: test-account - token: test-quay-token - secretsBase: - key: secret/data/hub ---- -# Source: pattern-clustergroup/templates/imperative/clusterrole.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: imperative-cluster-role -rules: - - apiGroups: - - '*' - resources: - - '*' - verbs: - - get - - list - - watch ---- -# Source: pattern-clustergroup/templates/argocd-super-role.yaml -# WARNING: ONLY USE THIS FOR MANAGING CLUSTERS NOT FOR REGULAR USERS -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: openshift-gitops-cluster-admin-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin -subjects: - - kind: ServiceAccount - name: openshift-gitops-argocd-application-controller - namespace: openshift-gitops - # NOTE: THIS MUST BE FIXED FOR MULTITENANT SETUP - - kind: ServiceAccount - name: openshift-gitops-argocd-server - namespace: openshift-gitops ---- -# Source: pattern-clustergroup/templates/argocd-super-role.yaml -# WARNING: ONLY USE THIS FOR MANAGING CLUSTERS NOT FOR REGULAR USERS -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: mypattern-example-cluster-admin-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin -subjects: - - kind: ServiceAccount - # This is the {ArgoCD.name}-argocd-application-controller - name: example-gitops-argocd-application-controller - namespace: mypattern-example - # NOTE: THIS MUST BE FIXED FOR MULTITENANT SETUP - - kind: ServiceAccount - # This is the {ArgoCD.name}-argocd-server - name: example-gitops-argocd-server - namespace: mypattern-example - # NOTE: This is needed starting with gitops-1.5.0 (see issue common#76) - - kind: ServiceAccount - name: example-gitops-argocd-dex-server - namespace: mypattern-example ---- -# Source: pattern-clustergroup/templates/imperative/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: imperative-cluster-admin-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: imperative-cluster-role -subjects: - - kind: ServiceAccount - name: imperative-sa - namespace: imperative ---- -# Source: pattern-clustergroup/templates/imperative/role.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: imperative-role - namespace: imperative -rules: - - apiGroups: - - '*' - resources: - - '*' - verbs: - - '*' ---- -# Source: pattern-clustergroup/templates/imperative/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: imperative-admin-rolebinding - namespace: imperative -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: imperative-role -subjects: - - kind: ServiceAccount - name: imperative-sa - namespace: imperative ---- -# Source: pattern-clustergroup/templates/imperative/job.yaml -apiVersion: batch/v1 -kind: CronJob -metadata: - name: imperative-cronjob - namespace: imperative -spec: - schedule: "*/10 * * * *" - # if previous Job is still running, skip execution of a new Job - concurrencyPolicy: Forbid - jobTemplate: - spec: - activeDeadlineSeconds: 3600 - template: - metadata: - name: imperative-job - spec: - serviceAccountName: imperative-sa - initContainers: - # git init happens in /git/repo so that we can set the folder to 0770 permissions - # reason for that is ansible refuses to create temporary folders in there - - name: git-init - image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest - imagePullPolicy: Always - env: - - name: HOME - value: /git/home - command: - - 'sh' - - '-c' - - "mkdir /git/{repo,home};git clone --single-branch --branch --depth 1 -- https://github.com/pattern-clone/mypattern /git/repo;chmod 0770 /git/{repo,home}" - volumeMounts: - - name: git - mountPath: "/git" - - name: test - image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest - imagePullPolicy: Always - env: - - name: HOME - value: /git/home - workingDir: /git/repo - # We have a default timeout of 600s for each playbook. Can be overridden - # on a per-job basis - command: - - timeout - - "600" - - ansible-playbook - - -e - - "@/values/values.yaml" - - ansible/test.yml - volumeMounts: - - name: git - mountPath: "/git" - - name: values-volume - mountPath: /values/values.yaml - subPath: values.yaml - containers: - - name: "done" - image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest - imagePullPolicy: Always - command: - - 'sh' - - '-c' - - 'echo' - - 'done' - - '\n' - volumes: - - name: git - emptyDir: {} - - name: values-volume - configMap: - name: helm-values-configmap - restartPolicy: Never ---- -# Source: pattern-clustergroup/templates/imperative/unsealjob.yaml -apiVersion: batch/v1 -kind: CronJob -metadata: - name: unsealvault-cronjob - namespace: imperative -spec: - schedule: "*/5 * * * *" - # if previous Job is still running, skip execution of a new Job - concurrencyPolicy: Forbid - jobTemplate: - spec: - activeDeadlineSeconds: 3600 - template: - metadata: - name: unsealvault-job - spec: - serviceAccountName: imperative-sa - initContainers: - # git init happens in /git/repo so that we can set the folder to 0770 permissions - # reason for that is ansible refuses to create temporary folders in there - - name: git-init - image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest - imagePullPolicy: Always - env: - - name: HOME - value: /git/home - command: - - 'sh' - - '-c' - - "mkdir /git/{repo,home};git clone --single-branch --branch --depth 1 -- https://github.com/pattern-clone/mypattern /git/repo;chmod 0770 /git/{repo,home}" - volumeMounts: - - name: git - mountPath: "/git" - - name: unseal-playbook - image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest - imagePullPolicy: Always - env: - - name: HOME - value: /git/home - workingDir: /git/repo - # We have a default timeout of 600s for each playbook. Can be overridden - # on a per-job basis - command: - - timeout - - "600" - - ansible-playbook - - -e - - "@/values/values.yaml" - - -e - - '{"file_unseal": false}' - - -t - - 'vault_init,vault_unseal,vault_secrets_init' - - "common/ansible/playbooks/vault/vault.yaml" - volumeMounts: - - name: git - mountPath: "/git" - - name: values-volume - mountPath: /values/values.yaml - subPath: values.yaml - containers: - - name: "done" - image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest - imagePullPolicy: Always - command: - - 'sh' - - '-c' - - 'echo' - - 'done' - - '\n' - volumes: - - name: git - emptyDir: {} - - name: values-volume - configMap: - name: helm-values-configmap - restartPolicy: Never ---- -# Source: pattern-clustergroup/templates/subscriptions.yaml ---- ---- -# Source: pattern-clustergroup/templates/projects.yaml -apiVersion: argoproj.io/v1alpha1 -kind: AppProject -metadata: - name: datacenter - namespace: mypattern-example -spec: - description: "Pattern datacenter" - destinations: - - namespace: '*' - server: '*' - clusterResourceWhitelist: - - group: '*' - kind: '*' - namespaceResourceWhitelist: - - group: '*' - kind: '*' - sourceRepos: - - '*' -status: {} ---- -# Source: pattern-clustergroup/templates/applications.yaml -apiVersion: argoproj.io/v1alpha1 -kind: Application -metadata: - name: acm - namespace: mypattern-example - finalizers: - - resources-finalizer.argocd.argoproj.io/foreground -spec: - destination: - name: in-cluster - namespace: open-cluster-management - project: datacenter - source: - repoURL: https://github.com/pattern-clone/mypattern - targetRevision: - path: common/acm - helm: - ignoreMissingValueFiles: true - valueFiles: - - "/values-global.yaml" - - "/values-example.yaml" - # Watch the progress of https://issues.redhat.com/browse/GITOPS-891 and update accordingly - parameters: - - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL - - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION - - name: global.namespace - value: $ARGOCD_APP_NAMESPACE - - name: global.pattern - value: mypattern - - name: global.hubClusterDomain - value: hub.example.com - - name: global.localClusterDomain - value: region.example.com - ignoreDifferences: [ - { - "group": "internal.open-cluster-management.io", - "jsonPointers": [ - "/spec/loggingCA" - ], - "kind": "ManagedClusterInfo" - } -] - syncPolicy: - automated: {} - # selfHeal: true ---- -# Source: pattern-clustergroup/templates/applications.yaml -apiVersion: argoproj.io/v1alpha1 -kind: Application -metadata: - name: external-app - namespace: mypattern-example - finalizers: - - resources-finalizer.argocd.argoproj.io/foreground -spec: - destination: - name: example - namespace: demo - project: datacenter - source: - repoURL: https://github.com/pattern-clone/mypattern - targetRevision: - path: - helm: - ignoreMissingValueFiles: true - valueFiles: - - "/values-global.yaml" - - "/values-example.yaml" - # Watch the progress of https://issues.redhat.com/browse/GITOPS-891 and update accordingly - parameters: - - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL - - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION - - name: global.namespace - value: $ARGOCD_APP_NAMESPACE - - name: global.pattern - value: mypattern - - name: global.hubClusterDomain - value: hub.example.com - - name: global.localClusterDomain - value: region.example.com - syncPolicy: - automated: {} - # selfHeal: true ---- -# Source: pattern-clustergroup/templates/applications.yaml -apiVersion: argoproj.io/v1alpha1 -kind: Application -metadata: - name: pipelines - namespace: mypattern-example - finalizers: - - resources-finalizer.argocd.argoproj.io/foreground -spec: - destination: - name: in-cluster - namespace: application-ci - project: datacenter - source: - repoURL: https://github.com/pattern-clone/mypattern - targetRevision: - path: charts/datacenter/pipelines - helm: - ignoreMissingValueFiles: true - valueFiles: - - "/values-global.yaml" - - "/values-example.yaml" - # Watch the progress of https://issues.redhat.com/browse/GITOPS-891 and update accordingly - parameters: - - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL - - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION - - name: global.namespace - value: $ARGOCD_APP_NAMESPACE - - name: global.pattern - value: mypattern - - name: global.hubClusterDomain - value: hub.example.com - - name: global.localClusterDomain - value: region.example.com - syncPolicy: - automated: {} - # selfHeal: true ---- -# Source: pattern-clustergroup/templates/argocd.yaml -apiVersion: argoproj.io/v1alpha1 -kind: ArgoCD -metadata: - finalizers: - - argoproj.io/finalizer - # Changing the name affects the ClusterRoleBinding, the generated secret, - # route URL, and argocd.argoproj.io/managed-by annotations - name: example-gitops - namespace: mypattern-example - annotations: - argocd.argoproj.io/compare-options: IgnoreExtraneous -spec: - applicationInstanceLabelKey: argocd.argoproj.io/instance - # Not the greatest way to pass git/quay info to sub-applications, but it will do until - # we can support helmChart with kustomize - # The other option is to pass them in as environment variables eg. BLUEPRINT_VERSION - configManagementPlugins: | - - name: kustomize-version - generate: - command: ["sh", "-c"] - args: ["kustomize version 1>&2 && exit 1"] - - name: kustomize-with-helm - generate: - command: ["kustomize"] - args: ["build", "--enable-helm"] - - name: helm-with-kustomize - init: - command: ["/bin/sh", "-c"] - args: ["helm dependency build"] - generate: - command: ["/bin/bash", "-c"] - args: ["helm template . --name-template ${ARGOCD_APP_NAME:0:52} - -f $(git rev-parse --show-toplevel)/values-global.yaml - -f $(git rev-parse --show-toplevel)/values-example.yaml - --set global.repoURL=$ARGOCD_APP_SOURCE_REPO_URL - --set global.targetRevision=$ARGOCD_APP_SOURCE_TARGET_REVISION - --set global.namespace=$ARGOCD_APP_NAMESPACE - --set global.pattern=mypattern - --set global.hubClusterDomain=hub.example.com - --set global.localClusterDomain=region.example.com - --post-renderer ./kustomize"] - applicationSet: - resources: - limits: - cpu: "2" - memory: 1Gi - requests: - cpu: 250m - memory: 512Mi - controller: - processors: {} - resources: - limits: - cpu: "4" - memory: 4Gi - requests: - cpu: 500m - memory: 2Gi - dex: - openShiftOAuth: true - resources: - limits: - cpu: 500m - memory: 256Mi - requests: - cpu: 250m - memory: 128Mi - initialSSHKnownHosts: {} - rbac: - defaultPolicy: role:admin - repo: - resources: - limits: - cpu: "1" - memory: 512Mi - requests: - cpu: 250m - memory: 256Mi - resourceExclusions: | - - apiGroups: - - tekton.dev - kinds: - - TaskRun - - PipelineRun - server: - autoscale: - enabled: false - grpc: - ingress: - enabled: false - ingress: - enabled: false - resources: - limits: - cpu: 500m - memory: 256Mi - requests: - cpu: 125m - memory: 128Mi - route: - enabled: true - tls: - insecureEdgeTerminationPolicy: Redirect - termination: reencrypt - service: - type: "" - tls: - ca: {} -status: ---- -# Source: pattern-clustergroup/templates/argocd.yaml -apiVersion: console.openshift.io/v1 -kind: ConsoleLink -metadata: - name: example-gitops-link - namespace: mypattern-example -spec: - applicationMenu: - section: OpenShift GitOps - imageURL: data:image/png;base64,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 - href: 'https://example-gitops-server-mypattern-example.region.example.com' - location: ApplicationMenu - text: 'Example ArgoCD' ---- -# Source: pattern-clustergroup/templates/cluster-external-secrets.yaml -apiVersion: "external-secrets.io/v1beta1" -kind: ExternalSecret -metadata: - name: example-secret - namespace: mypattern-example - annotations: - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true - argocd.argoproj.io/sync-wave: "100" -spec: - refreshInterval: 15s - secretStoreRef: - name: vault-backend - kind: ClusterSecretStore - target: - name: example-secret - template: - type: Opaque - metadata: - labels: - argocd.argoproj.io/secret-type: cluster - data: - name: example - server: |- - {{ .kubeServer | toString }} - config: | - { - "bearerToken": {{ .kubeBearer | toString | quote }}, - "tlsClientConfig": { - "insecure": false, - "caData": {{ .kubeCA | toString | quote }} - } - } - data: - - secretKey: kubeServer - remoteRef: - key: secret/data/hub/cluster_example - property: server - - secretKey: kubeBearer - remoteRef: - key: secret/data/hub/cluster_example - property: bearerToken - - secretKey: kubeCA - remoteRef: - key: secret/data/hub/cluster_example_ca - property: b64content ---- -# Source: pattern-clustergroup/templates/operatorgroup.yaml -apiVersion: operators.coreos.com/v1 -kind: OperatorGroup -metadata: - name: open-cluster-management-operator-group - namespace: open-cluster-management -spec: - targetNamespaces: - - open-cluster-management ---- -# Source: pattern-clustergroup/templates/operatorgroup.yaml -apiVersion: operators.coreos.com/v1 -kind: OperatorGroup -metadata: - name: application-ci-operator-group - namespace: application-ci -spec: - targetNamespaces: - - application-ci ---- -# Source: pattern-clustergroup/templates/subscriptions.yaml -apiVersion: operators.coreos.com/v1alpha1 -kind: Subscription -metadata: - name: advanced-cluster-management - namespace: open-cluster-management -spec: - name: advanced-cluster-management - source: redhat-operators - sourceNamespace: openshift-marketplace - channel: release-2.4 - installPlanApproval: Automatic - startingCSV: advanced-cluster-management.v2.4.1 ---- -# Source: pattern-clustergroup/templates/subscriptions.yaml -apiVersion: operators.coreos.com/v1alpha1 -kind: Subscription -metadata: - name: openshift-pipelines-operator-rh - namespace: openshift-operators -spec: - name: openshift-pipelines-operator-rh - source: redhat-operators - sourceNamespace: openshift-marketplace - channel: stable - installPlanApproval: Automatic - startingCSV: redhat-openshift-pipelines.v1.5.2 diff --git a/common/tests/examples-blank-naked.expected.yaml b/common/tests/examples-blank-naked.expected.yaml deleted file mode 100644 index 51a92e5d..00000000 --- a/common/tests/examples-blank-naked.expected.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -# Source: blank/templates/manifest.yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: example diff --git a/common/tests/examples-blank-normal.expected.yaml b/common/tests/examples-blank-normal.expected.yaml deleted file mode 100644 index 51a92e5d..00000000 --- a/common/tests/examples-blank-normal.expected.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -# Source: blank/templates/manifest.yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: example diff --git a/common/tests/examples-kustomize-renderer-naked.expected.yaml b/common/tests/examples-kustomize-renderer-naked.expected.yaml deleted file mode 100644 index 0aa7ee5d..00000000 --- a/common/tests/examples-kustomize-renderer-naked.expected.yaml +++ /dev/null @@ -1,36 +0,0 @@ ---- -# Source: example/templates/environment.yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: environment -data: - IMAGE_PROVIDER: - IMAGE_ACCOUNT: PLAINTEXT - GIT_EMAIL: SOMEWHERE@EXAMPLE.COM - GIT_DEV_REPO_URL: https:///PLAINTEXT/manuela-dev.git - GIT_DEV_REPO_REVISION: main - GIT_OPS_REPO_TEST_URL: - GIT_OPS_REPO_TEST_REVISION: - GIT_OPS_REPO_PROD_URL: - GIT_OPS_REPO_PROD_REVISION: - IOT_CONSUMER_IMAGE: iot-consumer - IOT_CONSUMER_YAML_PATH: images.(name==messaging).newTag - IOT_CONSUMER_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml - IOT_CONSUMER_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/messaging/kustomization.yaml - IOT_CONSUMER_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/messaging/messaging-is.yaml - IOT_FRONTEND_IMAGE: iot-frontend - IOT_FRONTEND_YAML_PATH: images.(name==line-dashboard).newTag - IOT_FRONTEND_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml - IOT_FRONTEND_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/line-dashboard/kustomization.yaml - IOT_FRONTEND_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/line-dashboard/line-dashboard-is.yaml - IOT_SWSENSOR_IMAGE: iot-software-sensor - IOT_SWSENSOR_YAML_PATH: images.(name==machine-sensor).newTag - IOT_SWSENSOR_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml - IOT_SWSENSOR_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/machine-sensor/kustomization.yaml - IOT_SWSENSOR_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/machine-sensor/machine-sensor-is.yaml - IOT_ANOMALY_IMAGE: iot-anomaly-detection - IOT_ANOMALY_YAML_PATH: images.(name==anomaly-detection).newTag - IOT_ANOMALY_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml - IOT_ANOMALY_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/anomaly-detection/kustomization.yaml - IOT_ANOMALY_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/anomaly-detection/anomaly-detection-is.yaml diff --git a/common/tests/examples-kustomize-renderer-normal.expected.yaml b/common/tests/examples-kustomize-renderer-normal.expected.yaml deleted file mode 100644 index 09e04b22..00000000 --- a/common/tests/examples-kustomize-renderer-normal.expected.yaml +++ /dev/null @@ -1,36 +0,0 @@ ---- -# Source: example/templates/environment.yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: environment -data: - IMAGE_PROVIDER: - IMAGE_ACCOUNT: PLAINTEXT - GIT_EMAIL: someone@somewhere.com - GIT_DEV_REPO_URL: https://github.com/hybrid-cloud-patterns/manuela-dev.git - GIT_DEV_REPO_REVISION: main - GIT_OPS_REPO_TEST_URL: https://github.com/pattern-clone/mypattern - GIT_OPS_REPO_TEST_REVISION: - GIT_OPS_REPO_PROD_URL: https://github.com/pattern-clone/mypattern - GIT_OPS_REPO_PROD_REVISION: - IOT_CONSUMER_IMAGE: iot-consumer - IOT_CONSUMER_YAML_PATH: images.(name==messaging).newTag - IOT_CONSUMER_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml - IOT_CONSUMER_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/messaging/kustomization.yaml - IOT_CONSUMER_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/messaging/messaging-is.yaml - IOT_FRONTEND_IMAGE: iot-frontend - IOT_FRONTEND_YAML_PATH: images.(name==line-dashboard).newTag - IOT_FRONTEND_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml - IOT_FRONTEND_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/line-dashboard/kustomization.yaml - IOT_FRONTEND_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/line-dashboard/line-dashboard-is.yaml - IOT_SWSENSOR_IMAGE: iot-software-sensor - IOT_SWSENSOR_YAML_PATH: images.(name==machine-sensor).newTag - IOT_SWSENSOR_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml - IOT_SWSENSOR_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/machine-sensor/kustomization.yaml - IOT_SWSENSOR_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/machine-sensor/machine-sensor-is.yaml - IOT_ANOMALY_IMAGE: iot-anomaly-detection - IOT_ANOMALY_YAML_PATH: images.(name==anomaly-detection).newTag - IOT_ANOMALY_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml - IOT_ANOMALY_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/anomaly-detection/kustomization.yaml - IOT_ANOMALY_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/anomaly-detection/anomaly-detection-is.yaml diff --git a/common/tests/golang-external-secrets-naked.expected.yaml b/common/tests/golang-external-secrets-naked.expected.yaml deleted file mode 100644 index 7d9fa628..00000000 --- a/common/tests/golang-external-secrets-naked.expected.yaml +++ /dev/null @@ -1,5911 +0,0 @@ ---- -# Source: golang-external-secrets/charts/external-secrets/templates/cert-controller-serviceaccount.yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: external-secrets-cert-controller - namespace: "default" - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets-cert-controller - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm ---- -# Source: golang-external-secrets/charts/external-secrets/templates/serviceaccount.yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: golang-external-secrets - namespace: "default" - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm ---- -# Source: golang-external-secrets/charts/external-secrets/templates/webhook-serviceaccount.yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: external-secrets-webhook - namespace: "default" - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets-webhook - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm ---- -# Source: golang-external-secrets/charts/external-secrets/templates/webhook-secret.yaml -apiVersion: v1 -kind: Secret -metadata: - name: golang-external-secrets-webhook - namespace: "default" - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets-webhook - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm - external-secrets.io/component : webhook ---- -# Source: golang-external-secrets/templates/golang-external-secrets-hub-clusterrolebinding.yaml -apiVersion: v1 -kind: Secret -metadata: - name: golang-external-secrets - namespace: golang-external-secrets - annotations: - kubernetes.io/service-account.name: golang-external-secrets -type: kubernetes.io/service-account-token ---- -# Source: golang-external-secrets/charts/external-secrets/templates/crds/clusterexternalsecret.yaml -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - creationTimestamp: null - name: clusterexternalsecrets.external-secrets.io -spec: - group: external-secrets.io - names: - categories: - - externalsecrets - kind: ClusterExternalSecret - listKind: ClusterExternalSecretList - plural: clusterexternalsecrets - shortNames: - - ces - singular: clusterexternalsecret - scope: Cluster - versions: - - additionalPrinterColumns: - - jsonPath: .spec.secretStoreRef.name - name: Store - type: string - - jsonPath: .spec.refreshInterval - name: Refresh Interval - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].reason - name: Status - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - name: v1beta1 - schema: - openAPIV3Schema: - description: ClusterExternalSecret is the Schema for the clusterexternalsecrets 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: ClusterExternalSecretSpec defines the desired state of ClusterExternalSecret. - properties: - externalSecretName: - description: The name of the external secrets to be created defaults to the name of the ClusterExternalSecret - type: string - externalSecretSpec: - description: The spec for the ExternalSecrets to be created - properties: - data: - description: Data defines the connection between the Kubernetes Secret keys and the Provider data - items: - description: ExternalSecretData defines the connection between the Kubernetes Secret key (spec.data.) and the Provider data. - properties: - remoteRef: - description: ExternalSecretDataRemoteRef defines Provider data location. - properties: - conversionStrategy: - default: Default - description: Used to define a conversion Strategy - type: string - decodingStrategy: - default: None - description: Used to define a decoding Strategy - type: string - key: - description: Key is the key used in the Provider, mandatory - type: string - metadataPolicy: - description: Policy for fetching tags/labels from provider secrets, possible options are Fetch, None. Defaults to None - type: string - property: - description: Used to select a specific property of the Provider value (if a map), if supported - type: string - version: - description: Used to select a specific version of the Provider value, if supported - type: string - required: - - key - type: object - secretKey: - type: string - required: - - remoteRef - - secretKey - type: object - type: array - dataFrom: - description: DataFrom is used to fetch all properties from a specific Provider data If multiple entries are specified, the Secret keys are merged in the specified order - items: - properties: - extract: - description: Used to extract multiple key/value pairs from one secret - properties: - conversionStrategy: - default: Default - description: Used to define a conversion Strategy - type: string - decodingStrategy: - default: None - description: Used to define a decoding Strategy - type: string - key: - description: Key is the key used in the Provider, mandatory - type: string - metadataPolicy: - description: Policy for fetching tags/labels from provider secrets, possible options are Fetch, None. Defaults to None - type: string - property: - description: Used to select a specific property of the Provider value (if a map), if supported - type: string - version: - description: Used to select a specific version of the Provider value, if supported - type: string - required: - - key - type: object - find: - description: Used to find secrets based on tags or regular expressions - properties: - conversionStrategy: - default: Default - description: Used to define a conversion Strategy - type: string - decodingStrategy: - default: None - description: Used to define a decoding Strategy - type: string - name: - description: Finds secrets based on the name. - properties: - regexp: - description: Finds secrets base - type: string - type: object - path: - description: A root path to start the find operations. - type: string - tags: - additionalProperties: - type: string - description: Find secrets based on tags. - type: object - type: object - rewrite: - description: Used to rewrite secret Keys after getting them from the secret Provider Multiple Rewrite operations can be provided. They are applied in a layered order (first to last) - items: - properties: - regexp: - description: Used to rewrite with regular expressions. The resulting key will be the output of a regexp.ReplaceAll operation. - properties: - source: - description: Used to define the regular expression of a re.Compiler. - type: string - target: - description: Used to define the target pattern of a ReplaceAll operation. - type: string - required: - - source - - target - type: object - type: object - type: array - type: object - type: array - refreshInterval: - default: 1h - description: RefreshInterval is the amount of time before the values are read again from the SecretStore provider Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h" May be set to zero to fetch and create it once. Defaults to 1h. - type: string - secretStoreRef: - description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret data. - properties: - kind: - description: Kind of the SecretStore resource (SecretStore or ClusterSecretStore) Defaults to `SecretStore` - type: string - name: - description: Name of the SecretStore resource - type: string - required: - - name - type: object - target: - description: ExternalSecretTarget defines the Kubernetes Secret to be created There can be only one target per ExternalSecret. - properties: - creationPolicy: - default: Owner - description: CreationPolicy defines rules on how to create the resulting Secret Defaults to 'Owner' - enum: - - Owner - - Orphan - - Merge - - None - type: string - deletionPolicy: - default: Retain - description: DeletionPolicy defines rules on how to delete the resulting Secret Defaults to 'Retain' - enum: - - Delete - - Merge - - Retain - type: string - immutable: - description: Immutable defines if the final secret will be immutable - type: boolean - name: - description: Name defines the name of the Secret resource to be managed This field is immutable Defaults to the .metadata.name of the ExternalSecret resource - type: string - template: - description: Template defines a blueprint for the created Secret resource. - properties: - data: - additionalProperties: - type: string - type: object - engineVersion: - default: v2 - type: string - metadata: - description: ExternalSecretTemplateMetadata defines metadata fields for the Secret blueprint. - properties: - annotations: - additionalProperties: - type: string - type: object - labels: - additionalProperties: - type: string - type: object - type: object - templateFrom: - items: - maxProperties: 1 - minProperties: 1 - properties: - configMap: - properties: - items: - items: - properties: - key: - type: string - required: - - key - type: object - type: array - name: - type: string - required: - - items - - name - type: object - secret: - properties: - items: - items: - properties: - key: - type: string - required: - - key - type: object - type: array - name: - type: string - required: - - items - - name - type: object - type: object - type: array - type: - type: string - type: object - type: object - required: - - secretStoreRef - type: object - namespaceSelector: - description: The labels to select by to find the Namespaces to create the ExternalSecrets in. - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - refreshTime: - description: The time in which the controller should reconcile it's objects and recheck namespaces for labels. - type: string - required: - - externalSecretSpec - - namespaceSelector - type: object - status: - description: ClusterExternalSecretStatus defines the observed state of ClusterExternalSecret. - properties: - conditions: - items: - properties: - message: - type: string - status: - type: string - type: - type: string - required: - - status - - type - type: object - type: array - failedNamespaces: - description: Failed namespaces are the namespaces that failed to apply an ExternalSecret - items: - description: ClusterExternalSecretNamespaceFailure represents a failed namespace deployment and it's reason. - properties: - namespace: - description: Namespace is the namespace that failed when trying to apply an ExternalSecret - type: string - reason: - description: Reason is why the ExternalSecret failed to apply to the namespace - type: string - required: - - namespace - type: object - type: array - provisionedNamespaces: - description: ProvisionedNamespaces are the namespaces where the ClusterExternalSecret has secrets - items: - type: string - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} - conversion: - strategy: Webhook - webhook: - conversionReviewVersions: - - v1 - clientConfig: - service: - name: golang-external-secrets-webhook - namespace: "default" - path: /convert ---- -# Source: golang-external-secrets/charts/external-secrets/templates/crds/clustersecretstore.yaml -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - creationTimestamp: null - name: clustersecretstores.external-secrets.io -spec: - group: external-secrets.io - names: - categories: - - externalsecrets - kind: ClusterSecretStore - listKind: ClusterSecretStoreList - plural: clustersecretstores - shortNames: - - css - singular: clustersecretstore - scope: Cluster - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: AGE - type: date - - jsonPath: .status.conditions[?(@.type=="Ready")].reason - name: Status - type: string - deprecated: true - name: v1alpha1 - schema: - openAPIV3Schema: - description: ClusterSecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields. - 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: SecretStoreSpec defines the desired state of SecretStore. - properties: - controller: - description: 'Used to select the correct KES controller (think: ingress.ingressClassName) The KES controller is instantiated with a specific controller name and filters ES based on this property' - type: string - provider: - description: Used to configure the provider. Only one provider may be set - maxProperties: 1 - minProperties: 1 - properties: - akeyless: - description: Akeyless configures this store to sync secrets using Akeyless Vault provider - properties: - akeylessGWApiURL: - description: Akeyless GW API Url from which the secrets to be fetched from. - type: string - authSecretRef: - description: Auth configures how the operator authenticates with Akeyless. - properties: - secretRef: - description: 'AkeylessAuthSecretRef AKEYLESS_ACCESS_TYPE_PARAM: AZURE_OBJ_ID OR GCP_AUDIENCE OR ACCESS_KEY OR KUB_CONFIG_NAME.' - properties: - accessID: - description: The SecretAccessID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessType: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessTypeParam: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - secretRef - type: object - required: - - akeylessGWApiURL - - authSecretRef - type: object - alibaba: - description: Alibaba configures this store to sync secrets using Alibaba Cloud provider - properties: - auth: - description: AlibabaAuth contains a secretRef for credentials. - properties: - secretRef: - description: AlibabaAuthSecretRef holds secret references for Alibaba credentials. - properties: - accessKeyIDSecretRef: - description: The AccessKeyID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessKeySecretSecretRef: - description: The AccessKeySecret is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - accessKeyIDSecretRef - - accessKeySecretSecretRef - type: object - required: - - secretRef - type: object - endpoint: - type: string - regionID: - description: Alibaba Region to be used for the provider - type: string - required: - - auth - - regionID - type: object - aws: - description: AWS configures this store to sync secrets using AWS Secret Manager provider - properties: - auth: - description: 'Auth defines the information necessary to authenticate against AWS if not set aws sdk will infer credentials from your environment see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' - properties: - jwt: - description: Authenticate against AWS using service account tokens. - properties: - serviceAccountRef: - description: A reference to a ServiceAccount resource. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - type: object - secretRef: - description: AWSAuthSecretRef holds secret references for AWS credentials both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. - properties: - accessKeyIDSecretRef: - description: The AccessKeyID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - secretAccessKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - type: object - region: - description: AWS Region to be used for the provider - type: string - role: - description: Role is a Role ARN which the SecretManager provider will assume - type: string - service: - description: Service defines which service should be used to fetch the secrets - enum: - - SecretsManager - - ParameterStore - type: string - required: - - region - - service - type: object - azurekv: - description: AzureKV configures this store to sync secrets using Azure Key Vault provider - properties: - authSecretRef: - description: Auth configures how the operator authenticates with Azure. Required for ServicePrincipal auth type. - properties: - clientId: - description: The Azure clientId of the service principle used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - clientSecret: - description: The Azure ClientSecret of the service principle used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - authType: - default: ServicePrincipal - description: 'Auth type defines how to authenticate to the keyvault service. Valid values are: - "ServicePrincipal" (default): Using a service principal (tenantId, clientId, clientSecret) - "ManagedIdentity": Using Managed Identity assigned to the pod (see aad-pod-identity)' - enum: - - ServicePrincipal - - ManagedIdentity - - WorkloadIdentity - type: string - identityId: - description: If multiple Managed Identity is assigned to the pod, you can select the one to be used - type: string - serviceAccountRef: - description: ServiceAccountRef specified the service account that should be used when authenticating with WorkloadIdentity. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - tenantId: - description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. - type: string - vaultUrl: - description: Vault Url from which the secrets to be fetched from. - type: string - required: - - vaultUrl - type: object - fake: - description: Fake configures a store with static key/value pairs - properties: - data: - items: - properties: - key: - type: string - value: - type: string - valueMap: - additionalProperties: - type: string - type: object - version: - type: string - required: - - key - type: object - type: array - required: - - data - type: object - gcpsm: - description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider - properties: - auth: - description: Auth defines the information necessary to authenticate against GCP - properties: - secretRef: - properties: - secretAccessKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - workloadIdentity: - properties: - clusterLocation: - type: string - clusterName: - type: string - clusterProjectID: - type: string - serviceAccountRef: - description: A reference to a ServiceAccount resource. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - clusterLocation - - clusterName - - serviceAccountRef - type: object - type: object - projectID: - description: ProjectID project where secret is located - type: string - type: object - gitlab: - description: Gitlab configures this store to sync secrets using Gitlab Variables provider - properties: - auth: - description: Auth configures how secret-manager authenticates with a GitLab instance. - properties: - SecretRef: - properties: - accessToken: - description: AccessToken is used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - SecretRef - type: object - projectID: - description: ProjectID specifies a project where secrets are located. - type: string - url: - description: URL configures the GitLab instance URL. Defaults to https://gitlab.com/. - type: string - required: - - auth - type: object - ibm: - description: IBM configures this store to sync secrets using IBM Cloud provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the IBM secrets manager. - properties: - secretRef: - properties: - secretApiKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - secretRef - type: object - serviceUrl: - description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance - type: string - required: - - auth - type: object - kubernetes: - description: Kubernetes configures this store to sync secrets using a Kubernetes cluster provider - properties: - auth: - description: Auth configures how secret-manager authenticates with a Kubernetes instance. - maxProperties: 1 - minProperties: 1 - properties: - cert: - description: has both clientCert and clientKey as secretKeySelector - properties: - clientCert: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - clientKey: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - serviceAccount: - description: points to a service account that should be used for authentication - properties: - serviceAccount: - description: A reference to a ServiceAccount resource. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - type: object - token: - description: use static token to authenticate with - properties: - bearerToken: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - type: object - remoteNamespace: - default: default - description: Remote namespace to fetch the secrets from - type: string - server: - description: configures the Kubernetes server Address. - properties: - caBundle: - description: CABundle is a base64-encoded CA certificate - format: byte - type: string - caProvider: - description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider' - properties: - key: - description: The key the value inside of the provider type to use, only used with "Secret" type - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - url: - default: kubernetes.default - description: configures the Kubernetes server Address. - type: string - type: object - required: - - auth - type: object - oracle: - description: Oracle configures this store to sync secrets using Oracle Vault provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the Oracle Vault. If empty, use the instance principal, otherwise the user credentials specified in Auth. - properties: - secretRef: - description: SecretRef to pass through sensitive information. - properties: - fingerprint: - description: Fingerprint is the fingerprint of the API private key. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - privatekey: - description: PrivateKey is the user's API Signing Key in PEM format, used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - fingerprint - - privatekey - type: object - tenancy: - description: Tenancy is the tenancy OCID where user is located. - type: string - user: - description: User is an access OCID specific to the account. - type: string - required: - - secretRef - - tenancy - - user - type: object - region: - description: Region is the region where vault is located. - type: string - vault: - description: Vault is the vault's OCID of the specific vault where secret is located. - type: string - required: - - region - - vault - type: object - vault: - description: Vault configures this store to sync secrets using Hashi provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the Vault server. - properties: - appRole: - description: AppRole authenticates with Vault using the App Role auth mechanism, with the role and secret stored in a Kubernetes Secret resource. - properties: - path: - default: approle - description: 'Path where the App Role authentication backend is mounted in Vault, e.g: "approle"' - type: string - roleId: - description: RoleID configured in the App Role authentication backend when setting up the authentication backend in Vault. - type: string - secretRef: - description: Reference to a key in a Secret that contains the App Role secret used to authenticate with Vault. The `key` field must be specified and denotes which entry within the Secret resource is used as the app role secret. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - path - - roleId - - secretRef - type: object - cert: - description: Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate Cert authentication method - properties: - clientCert: - description: ClientCert is a certificate to authenticate using the Cert Vault authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - secretRef: - description: SecretRef to a key in a Secret resource containing client private key to authenticate with Vault using the Cert authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - jwt: - description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method - properties: - kubernetesServiceAccountToken: - description: Optional ServiceAccountToken specifies the Kubernetes service account for which to request a token for with the `TokenRequest` API. - properties: - audiences: - description: Optional audiences field that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to a single audience `vault` it not specified. - items: - type: string - type: array - expirationSeconds: - description: Optional expiration time in seconds that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to 10 minutes. - format: int64 - type: integer - serviceAccountRef: - description: Service account field containing the name of a kubernetes ServiceAccount. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - serviceAccountRef - type: object - path: - default: jwt - description: 'Path where the JWT authentication backend is mounted in Vault, e.g: "jwt"' - type: string - role: - description: Role is a JWT role to authenticate using the JWT/OIDC Vault authentication method - type: string - secretRef: - description: Optional SecretRef that refers to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - path - type: object - kubernetes: - description: Kubernetes authenticates with Vault by passing the ServiceAccount token stored in the named Secret resource to the Vault server. - properties: - mountPath: - default: kubernetes - description: 'Path where the Kubernetes authentication backend is mounted in Vault, e.g: "kubernetes"' - type: string - role: - description: A required field containing the Vault Role to assume. A Role binds a Kubernetes ServiceAccount with a set of Vault policies. - type: string - secretRef: - description: Optional secret field containing a Kubernetes ServiceAccount JWT used for authenticating with Vault. If a name is specified without a key, `token` is the default. If one is not specified, the one bound to the controller will be used. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - serviceAccountRef: - description: Optional service account field containing the name of a kubernetes ServiceAccount. If the service account is specified, the service account secret token JWT will be used for authenticating with Vault. If the service account selector is not supplied, the secretRef will be used instead. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - mountPath - - role - type: object - ldap: - description: Ldap authenticates with Vault by passing username/password pair using the LDAP authentication method - properties: - path: - default: ldap - description: 'Path where the LDAP authentication backend is mounted in Vault, e.g: "ldap"' - type: string - secretRef: - description: SecretRef to a key in a Secret resource containing password for the LDAP user used to authenticate with Vault using the LDAP authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - username: - description: Username is a LDAP user name used to authenticate using the LDAP Vault authentication method - type: string - required: - - path - - username - type: object - tokenSecretRef: - description: TokenSecretRef authenticates with Vault by presenting a token. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - caBundle: - description: PEM encoded CA bundle used to validate Vault server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. - format: byte - type: string - caProvider: - description: The provider for the CA bundle to use to validate Vault server certificate. - properties: - key: - description: The key the value inside of the provider type to use, only used with "Secret" type - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - forwardInconsistent: - description: ForwardInconsistent tells Vault to forward read-after-write requests to the Vault leader instead of simply retrying within a loop. This can increase performance if the option is enabled serverside. https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header - type: boolean - namespace: - description: 'Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1". More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces' - type: string - path: - description: 'Path is the mount path of the Vault KV backend endpoint, e.g: "secret". The v2 KV secret engine version specific "/data" path suffix for fetching secrets from Vault is optional and will be appended if not present in specified path.' - type: string - readYourWrites: - description: ReadYourWrites ensures isolated read-after-write semantics by providing discovered cluster replication states in each request. More information about eventual consistency in Vault can be found here https://www.vaultproject.io/docs/enterprise/consistency - type: boolean - server: - description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' - type: string - version: - default: v2 - description: Version is the Vault KV secret engine version. This can be either "v1" or "v2". Version defaults to "v2". - enum: - - v1 - - v2 - type: string - required: - - auth - - server - type: object - webhook: - description: Webhook configures this store to sync secrets using a generic templated webhook - properties: - body: - description: Body - type: string - caBundle: - description: PEM encoded CA bundle used to validate webhook server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. - format: byte - type: string - caProvider: - description: The provider for the CA bundle to use to validate webhook server certificate. - properties: - key: - description: The key the value inside of the provider type to use, only used with "Secret" type - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - headers: - additionalProperties: - type: string - description: Headers - type: object - method: - description: Webhook Method - type: string - result: - description: Result formatting - properties: - jsonPath: - description: Json path of return value - type: string - type: object - secrets: - description: Secrets to fill in templates These secrets will be passed to the templating function as key value pairs under the given name - items: - properties: - name: - description: Name of this secret in templates - type: string - secretRef: - description: Secret ref to fill in credentials - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - name - - secretRef - type: object - type: array - timeout: - description: Timeout - type: string - url: - description: Webhook url to call - type: string - required: - - result - - url - type: object - yandexlockbox: - description: YandexLockbox configures this store to sync secrets using Yandex Lockbox provider - properties: - apiEndpoint: - description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') - type: string - auth: - description: Auth defines the information necessary to authenticate against Yandex Lockbox - properties: - authorizedKeySecretRef: - description: The authorized key used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - caProvider: - description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. - properties: - certSecretRef: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - auth - type: object - type: object - retrySettings: - description: Used to configure http retries if failed - properties: - maxRetries: - format: int32 - type: integer - retryInterval: - type: string - type: object - required: - - provider - type: object - status: - description: SecretStoreStatus defines the observed state of the SecretStore. - properties: - conditions: - items: - properties: - lastTransitionTime: - format: date-time - type: string - message: - type: string - reason: - type: string - status: - type: string - type: - type: string - required: - - status - - type - type: object - type: array - type: object - type: object - served: true - storage: false - subresources: - status: {} - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: AGE - type: date - - jsonPath: .status.conditions[?(@.type=="Ready")].reason - name: Status - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - name: v1beta1 - schema: - openAPIV3Schema: - description: ClusterSecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields. - 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: SecretStoreSpec defines the desired state of SecretStore. - properties: - controller: - description: 'Used to select the correct KES controller (think: ingress.ingressClassName) The KES controller is instantiated with a specific controller name and filters ES based on this property' - type: string - provider: - description: Used to configure the provider. Only one provider may be set - maxProperties: 1 - minProperties: 1 - properties: - akeyless: - description: Akeyless configures this store to sync secrets using Akeyless Vault provider - properties: - akeylessGWApiURL: - description: Akeyless GW API Url from which the secrets to be fetched from. - type: string - authSecretRef: - description: Auth configures how the operator authenticates with Akeyless. - properties: - secretRef: - description: 'AkeylessAuthSecretRef AKEYLESS_ACCESS_TYPE_PARAM: AZURE_OBJ_ID OR GCP_AUDIENCE OR ACCESS_KEY OR KUB_CONFIG_NAME.' - properties: - accessID: - description: The SecretAccessID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessType: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessTypeParam: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - secretRef - type: object - required: - - akeylessGWApiURL - - authSecretRef - type: object - alibaba: - description: Alibaba configures this store to sync secrets using Alibaba Cloud provider - properties: - auth: - description: AlibabaAuth contains a secretRef for credentials. - properties: - secretRef: - description: AlibabaAuthSecretRef holds secret references for Alibaba credentials. - properties: - accessKeyIDSecretRef: - description: The AccessKeyID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessKeySecretSecretRef: - description: The AccessKeySecret is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - accessKeyIDSecretRef - - accessKeySecretSecretRef - type: object - required: - - secretRef - type: object - endpoint: - type: string - regionID: - description: Alibaba Region to be used for the provider - type: string - required: - - auth - - regionID - type: object - aws: - description: AWS configures this store to sync secrets using AWS Secret Manager provider - properties: - auth: - description: 'Auth defines the information necessary to authenticate against AWS if not set aws sdk will infer credentials from your environment see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' - properties: - jwt: - description: Authenticate against AWS using service account tokens. - properties: - serviceAccountRef: - description: A reference to a ServiceAccount resource. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - type: object - secretRef: - description: AWSAuthSecretRef holds secret references for AWS credentials both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. - properties: - accessKeyIDSecretRef: - description: The AccessKeyID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - secretAccessKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - type: object - region: - description: AWS Region to be used for the provider - type: string - role: - description: Role is a Role ARN which the SecretManager provider will assume - type: string - service: - description: Service defines which service should be used to fetch the secrets - enum: - - SecretsManager - - ParameterStore - type: string - required: - - region - - service - type: object - azurekv: - description: AzureKV configures this store to sync secrets using Azure Key Vault provider - properties: - authSecretRef: - description: Auth configures how the operator authenticates with Azure. Required for ServicePrincipal auth type. - properties: - clientId: - description: The Azure clientId of the service principle used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - clientSecret: - description: The Azure ClientSecret of the service principle used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - authType: - default: ServicePrincipal - description: 'Auth type defines how to authenticate to the keyvault service. Valid values are: - "ServicePrincipal" (default): Using a service principal (tenantId, clientId, clientSecret) - "ManagedIdentity": Using Managed Identity assigned to the pod (see aad-pod-identity)' - enum: - - ServicePrincipal - - ManagedIdentity - - WorkloadIdentity - type: string - identityId: - description: If multiple Managed Identity is assigned to the pod, you can select the one to be used - type: string - serviceAccountRef: - description: ServiceAccountRef specified the service account that should be used when authenticating with WorkloadIdentity. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - tenantId: - description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. - type: string - vaultUrl: - description: Vault Url from which the secrets to be fetched from. - type: string - required: - - vaultUrl - type: object - fake: - description: Fake configures a store with static key/value pairs - properties: - data: - items: - properties: - key: - type: string - value: - type: string - valueMap: - additionalProperties: - type: string - type: object - version: - type: string - required: - - key - type: object - type: array - required: - - data - type: object - gcpsm: - description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider - properties: - auth: - description: Auth defines the information necessary to authenticate against GCP - properties: - secretRef: - properties: - secretAccessKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - workloadIdentity: - properties: - clusterLocation: - type: string - clusterName: - type: string - clusterProjectID: - type: string - serviceAccountRef: - description: A reference to a ServiceAccount resource. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - clusterLocation - - clusterName - - serviceAccountRef - type: object - type: object - projectID: - description: ProjectID project where secret is located - type: string - type: object - gitlab: - description: Gitlab configures this store to sync secrets using Gitlab Variables provider - properties: - auth: - description: Auth configures how secret-manager authenticates with a GitLab instance. - properties: - SecretRef: - properties: - accessToken: - description: AccessToken is used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - SecretRef - type: object - projectID: - description: ProjectID specifies a project where secrets are located. - type: string - url: - description: URL configures the GitLab instance URL. Defaults to https://gitlab.com/. - type: string - required: - - auth - type: object - ibm: - description: IBM configures this store to sync secrets using IBM Cloud provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the IBM secrets manager. - maxProperties: 1 - minProperties: 1 - properties: - containerAuth: - description: IBM Container-based auth with IAM Trusted Profile. - properties: - iamEndpoint: - type: string - profile: - description: the IBM Trusted Profile - type: string - tokenLocation: - description: Location the token is mounted on the pod - type: string - required: - - profile - type: object - secretRef: - properties: - secretApiKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - type: object - serviceUrl: - description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance - type: string - required: - - auth - type: object - kubernetes: - description: Kubernetes configures this store to sync secrets using a Kubernetes cluster provider - properties: - auth: - description: Auth configures how secret-manager authenticates with a Kubernetes instance. - maxProperties: 1 - minProperties: 1 - properties: - cert: - description: has both clientCert and clientKey as secretKeySelector - properties: - clientCert: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - clientKey: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - serviceAccount: - description: points to a service account that should be used for authentication - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - token: - description: use static token to authenticate with - properties: - bearerToken: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - type: object - remoteNamespace: - default: default - description: Remote namespace to fetch the secrets from - type: string - server: - description: configures the Kubernetes server Address. - properties: - caBundle: - description: CABundle is a base64-encoded CA certificate - format: byte - type: string - caProvider: - description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider' - properties: - key: - description: The key where the CA certificate can be found in the Secret or ConfigMap. - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. Can only be defined when used in a ClusterSecretStore. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - url: - default: kubernetes.default - description: configures the Kubernetes server Address. - type: string - type: object - required: - - auth - type: object - onepassword: - description: OnePassword configures this store to sync secrets using the 1Password Cloud provider - properties: - auth: - description: Auth defines the information necessary to authenticate against OnePassword Connect Server - properties: - secretRef: - description: OnePasswordAuthSecretRef holds secret references for 1Password credentials. - properties: - connectTokenSecretRef: - description: The ConnectToken is used for authentication to a 1Password Connect Server. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - connectTokenSecretRef - type: object - required: - - secretRef - type: object - connectHost: - description: ConnectHost defines the OnePassword Connect Server to connect to - type: string - vaults: - additionalProperties: - type: integer - description: Vaults defines which OnePassword vaults to search in which order - type: object - required: - - auth - - connectHost - - vaults - type: object - oracle: - description: Oracle configures this store to sync secrets using Oracle Vault provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the Oracle Vault. If empty, use the instance principal, otherwise the user credentials specified in Auth. - properties: - secretRef: - description: SecretRef to pass through sensitive information. - properties: - fingerprint: - description: Fingerprint is the fingerprint of the API private key. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - privatekey: - description: PrivateKey is the user's API Signing Key in PEM format, used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - fingerprint - - privatekey - type: object - tenancy: - description: Tenancy is the tenancy OCID where user is located. - type: string - user: - description: User is an access OCID specific to the account. - type: string - required: - - secretRef - - tenancy - - user - type: object - region: - description: Region is the region where vault is located. - type: string - vault: - description: Vault is the vault's OCID of the specific vault where secret is located. - type: string - required: - - region - - vault - type: object - senhasegura: - description: Senhasegura configures this store to sync secrets using senhasegura provider - properties: - auth: - description: Auth defines parameters to authenticate in senhasegura - properties: - clientId: - type: string - clientSecretSecretRef: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - clientId - - clientSecretSecretRef - type: object - ignoreSslCertificate: - default: false - description: IgnoreSslCertificate defines if SSL certificate must be ignored - type: boolean - module: - description: Module defines which senhasegura module should be used to get secrets - type: string - url: - description: URL of senhasegura - type: string - required: - - auth - - module - - url - type: object - vault: - description: Vault configures this store to sync secrets using Hashi provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the Vault server. - properties: - appRole: - description: AppRole authenticates with Vault using the App Role auth mechanism, with the role and secret stored in a Kubernetes Secret resource. - properties: - path: - default: approle - description: 'Path where the App Role authentication backend is mounted in Vault, e.g: "approle"' - type: string - roleId: - description: RoleID configured in the App Role authentication backend when setting up the authentication backend in Vault. - type: string - secretRef: - description: Reference to a key in a Secret that contains the App Role secret used to authenticate with Vault. The `key` field must be specified and denotes which entry within the Secret resource is used as the app role secret. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - path - - roleId - - secretRef - type: object - cert: - description: Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate Cert authentication method - properties: - clientCert: - description: ClientCert is a certificate to authenticate using the Cert Vault authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - secretRef: - description: SecretRef to a key in a Secret resource containing client private key to authenticate with Vault using the Cert authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - jwt: - description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method - properties: - kubernetesServiceAccountToken: - description: Optional ServiceAccountToken specifies the Kubernetes service account for which to request a token for with the `TokenRequest` API. - properties: - audiences: - description: Optional audiences field that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to a single audience `vault` it not specified. - items: - type: string - type: array - expirationSeconds: - description: Optional expiration time in seconds that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to 10 minutes. - format: int64 - type: integer - serviceAccountRef: - description: Service account field containing the name of a kubernetes ServiceAccount. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - serviceAccountRef - type: object - path: - default: jwt - description: 'Path where the JWT authentication backend is mounted in Vault, e.g: "jwt"' - type: string - role: - description: Role is a JWT role to authenticate using the JWT/OIDC Vault authentication method - type: string - secretRef: - description: Optional SecretRef that refers to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - path - type: object - kubernetes: - description: Kubernetes authenticates with Vault by passing the ServiceAccount token stored in the named Secret resource to the Vault server. - properties: - mountPath: - default: kubernetes - description: 'Path where the Kubernetes authentication backend is mounted in Vault, e.g: "kubernetes"' - type: string - role: - description: A required field containing the Vault Role to assume. A Role binds a Kubernetes ServiceAccount with a set of Vault policies. - type: string - secretRef: - description: Optional secret field containing a Kubernetes ServiceAccount JWT used for authenticating with Vault. If a name is specified without a key, `token` is the default. If one is not specified, the one bound to the controller will be used. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - serviceAccountRef: - description: Optional service account field containing the name of a kubernetes ServiceAccount. If the service account is specified, the service account secret token JWT will be used for authenticating with Vault. If the service account selector is not supplied, the secretRef will be used instead. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - mountPath - - role - type: object - ldap: - description: Ldap authenticates with Vault by passing username/password pair using the LDAP authentication method - properties: - path: - default: ldap - description: 'Path where the LDAP authentication backend is mounted in Vault, e.g: "ldap"' - type: string - secretRef: - description: SecretRef to a key in a Secret resource containing password for the LDAP user used to authenticate with Vault using the LDAP authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - username: - description: Username is a LDAP user name used to authenticate using the LDAP Vault authentication method - type: string - required: - - path - - username - type: object - tokenSecretRef: - description: TokenSecretRef authenticates with Vault by presenting a token. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - caBundle: - description: PEM encoded CA bundle used to validate Vault server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. - format: byte - type: string - caProvider: - description: The provider for the CA bundle to use to validate Vault server certificate. - properties: - key: - description: The key where the CA certificate can be found in the Secret or ConfigMap. - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. Can only be defined when used in a ClusterSecretStore. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - forwardInconsistent: - description: ForwardInconsistent tells Vault to forward read-after-write requests to the Vault leader instead of simply retrying within a loop. This can increase performance if the option is enabled serverside. https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header - type: boolean - namespace: - description: 'Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1". More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces' - type: string - path: - description: 'Path is the mount path of the Vault KV backend endpoint, e.g: "secret". The v2 KV secret engine version specific "/data" path suffix for fetching secrets from Vault is optional and will be appended if not present in specified path.' - type: string - readYourWrites: - description: ReadYourWrites ensures isolated read-after-write semantics by providing discovered cluster replication states in each request. More information about eventual consistency in Vault can be found here https://www.vaultproject.io/docs/enterprise/consistency - type: boolean - server: - description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' - type: string - version: - default: v2 - description: Version is the Vault KV secret engine version. This can be either "v1" or "v2". Version defaults to "v2". - enum: - - v1 - - v2 - type: string - required: - - auth - - server - type: object - webhook: - description: Webhook configures this store to sync secrets using a generic templated webhook - properties: - body: - description: Body - type: string - caBundle: - description: PEM encoded CA bundle used to validate webhook server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. - format: byte - type: string - caProvider: - description: The provider for the CA bundle to use to validate webhook server certificate. - properties: - key: - description: The key the value inside of the provider type to use, only used with "Secret" type - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - headers: - additionalProperties: - type: string - description: Headers - type: object - method: - description: Webhook Method - type: string - result: - description: Result formatting - properties: - jsonPath: - description: Json path of return value - type: string - type: object - secrets: - description: Secrets to fill in templates These secrets will be passed to the templating function as key value pairs under the given name - items: - properties: - name: - description: Name of this secret in templates - type: string - secretRef: - description: Secret ref to fill in credentials - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - name - - secretRef - type: object - type: array - timeout: - description: Timeout - type: string - url: - description: Webhook url to call - type: string - required: - - result - - url - type: object - yandexcertificatemanager: - description: YandexCertificateManager configures this store to sync secrets using Yandex Certificate Manager provider - properties: - apiEndpoint: - description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') - type: string - auth: - description: Auth defines the information necessary to authenticate against Yandex Certificate Manager - properties: - authorizedKeySecretRef: - description: The authorized key used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - caProvider: - description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. - properties: - certSecretRef: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - auth - type: object - yandexlockbox: - description: YandexLockbox configures this store to sync secrets using Yandex Lockbox provider - properties: - apiEndpoint: - description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') - type: string - auth: - description: Auth defines the information necessary to authenticate against Yandex Lockbox - properties: - authorizedKeySecretRef: - description: The authorized key used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - caProvider: - description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. - properties: - certSecretRef: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - auth - type: object - type: object - refreshInterval: - description: Used to configure store refresh interval in seconds. Empty or 0 will default to the controller config. - type: integer - retrySettings: - description: Used to configure http retries if failed - properties: - maxRetries: - format: int32 - type: integer - retryInterval: - type: string - type: object - required: - - provider - type: object - status: - description: SecretStoreStatus defines the observed state of the SecretStore. - properties: - conditions: - items: - properties: - lastTransitionTime: - format: date-time - type: string - message: - type: string - reason: - type: string - status: - type: string - type: - type: string - required: - - status - - type - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} - conversion: - strategy: Webhook - webhook: - conversionReviewVersions: - - v1 - clientConfig: - service: - name: golang-external-secrets-webhook - namespace: "default" - path: /convert ---- -# Source: golang-external-secrets/charts/external-secrets/templates/crds/externalsecret.yaml -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - creationTimestamp: null - name: externalsecrets.external-secrets.io -spec: - group: external-secrets.io - names: - categories: - - externalsecrets - kind: ExternalSecret - listKind: ExternalSecretList - plural: externalsecrets - shortNames: - - es - singular: externalsecret - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.secretStoreRef.name - name: Store - type: string - - jsonPath: .spec.refreshInterval - name: Refresh Interval - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].reason - name: Status - type: string - deprecated: true - name: v1alpha1 - schema: - openAPIV3Schema: - description: ExternalSecret is the Schema for the external-secrets 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: ExternalSecretSpec defines the desired state of ExternalSecret. - properties: - data: - description: Data defines the connection between the Kubernetes Secret keys and the Provider data - items: - description: ExternalSecretData defines the connection between the Kubernetes Secret key (spec.data.) and the Provider data. - properties: - remoteRef: - description: ExternalSecretDataRemoteRef defines Provider data location. - properties: - conversionStrategy: - default: Default - description: Used to define a conversion Strategy - type: string - key: - description: Key is the key used in the Provider, mandatory - type: string - property: - description: Used to select a specific property of the Provider value (if a map), if supported - type: string - version: - description: Used to select a specific version of the Provider value, if supported - type: string - required: - - key - type: object - secretKey: - type: string - required: - - remoteRef - - secretKey - type: object - type: array - dataFrom: - description: DataFrom is used to fetch all properties from a specific Provider data If multiple entries are specified, the Secret keys are merged in the specified order - items: - description: ExternalSecretDataRemoteRef defines Provider data location. - properties: - conversionStrategy: - default: Default - description: Used to define a conversion Strategy - type: string - key: - description: Key is the key used in the Provider, mandatory - type: string - property: - description: Used to select a specific property of the Provider value (if a map), if supported - type: string - version: - description: Used to select a specific version of the Provider value, if supported - type: string - required: - - key - type: object - type: array - refreshInterval: - default: 1h - description: RefreshInterval is the amount of time before the values are read again from the SecretStore provider Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h" May be set to zero to fetch and create it once. Defaults to 1h. - type: string - secretStoreRef: - description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret data. - properties: - kind: - description: Kind of the SecretStore resource (SecretStore or ClusterSecretStore) Defaults to `SecretStore` - type: string - name: - description: Name of the SecretStore resource - type: string - required: - - name - type: object - target: - description: ExternalSecretTarget defines the Kubernetes Secret to be created There can be only one target per ExternalSecret. - properties: - creationPolicy: - default: Owner - description: CreationPolicy defines rules on how to create the resulting Secret Defaults to 'Owner' - type: string - immutable: - description: Immutable defines if the final secret will be immutable - type: boolean - name: - description: Name defines the name of the Secret resource to be managed This field is immutable Defaults to the .metadata.name of the ExternalSecret resource - type: string - template: - description: Template defines a blueprint for the created Secret resource. - properties: - data: - additionalProperties: - type: string - type: object - engineVersion: - default: v1 - description: EngineVersion specifies the template engine version that should be used to compile/execute the template specified in .data and .templateFrom[]. - type: string - metadata: - description: ExternalSecretTemplateMetadata defines metadata fields for the Secret blueprint. - properties: - annotations: - additionalProperties: - type: string - type: object - labels: - additionalProperties: - type: string - type: object - type: object - templateFrom: - items: - maxProperties: 1 - minProperties: 1 - properties: - configMap: - properties: - items: - items: - properties: - key: - type: string - required: - - key - type: object - type: array - name: - type: string - required: - - items - - name - type: object - secret: - properties: - items: - items: - properties: - key: - type: string - required: - - key - type: object - type: array - name: - type: string - required: - - items - - name - type: object - type: object - type: array - type: - type: string - type: object - type: object - required: - - secretStoreRef - - target - type: object - status: - properties: - conditions: - items: - properties: - lastTransitionTime: - format: date-time - type: string - message: - type: string - reason: - type: string - status: - type: string - type: - type: string - required: - - status - - type - type: object - type: array - refreshTime: - description: refreshTime is the time and date the external secret was fetched and the target secret updated - format: date-time - nullable: true - type: string - syncedResourceVersion: - description: SyncedResourceVersion keeps track of the last synced version - type: string - type: object - type: object - served: true - storage: false - subresources: - status: {} - - additionalPrinterColumns: - - jsonPath: .spec.secretStoreRef.name - name: Store - type: string - - jsonPath: .spec.refreshInterval - name: Refresh Interval - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].reason - name: Status - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - name: v1beta1 - schema: - openAPIV3Schema: - description: ExternalSecret is the Schema for the external-secrets 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: ExternalSecretSpec defines the desired state of ExternalSecret. - properties: - data: - description: Data defines the connection between the Kubernetes Secret keys and the Provider data - items: - description: ExternalSecretData defines the connection between the Kubernetes Secret key (spec.data.) and the Provider data. - properties: - remoteRef: - description: ExternalSecretDataRemoteRef defines Provider data location. - properties: - conversionStrategy: - default: Default - description: Used to define a conversion Strategy - type: string - decodingStrategy: - default: None - description: Used to define a decoding Strategy - type: string - key: - description: Key is the key used in the Provider, mandatory - type: string - metadataPolicy: - description: Policy for fetching tags/labels from provider secrets, possible options are Fetch, None. Defaults to None - type: string - property: - description: Used to select a specific property of the Provider value (if a map), if supported - type: string - version: - description: Used to select a specific version of the Provider value, if supported - type: string - required: - - key - type: object - secretKey: - type: string - required: - - remoteRef - - secretKey - type: object - type: array - dataFrom: - description: DataFrom is used to fetch all properties from a specific Provider data If multiple entries are specified, the Secret keys are merged in the specified order - items: - properties: - extract: - description: Used to extract multiple key/value pairs from one secret - properties: - conversionStrategy: - default: Default - description: Used to define a conversion Strategy - type: string - decodingStrategy: - default: None - description: Used to define a decoding Strategy - type: string - key: - description: Key is the key used in the Provider, mandatory - type: string - metadataPolicy: - description: Policy for fetching tags/labels from provider secrets, possible options are Fetch, None. Defaults to None - type: string - property: - description: Used to select a specific property of the Provider value (if a map), if supported - type: string - version: - description: Used to select a specific version of the Provider value, if supported - type: string - required: - - key - type: object - find: - description: Used to find secrets based on tags or regular expressions - properties: - conversionStrategy: - default: Default - description: Used to define a conversion Strategy - type: string - decodingStrategy: - default: None - description: Used to define a decoding Strategy - type: string - name: - description: Finds secrets based on the name. - properties: - regexp: - description: Finds secrets base - type: string - type: object - path: - description: A root path to start the find operations. - type: string - tags: - additionalProperties: - type: string - description: Find secrets based on tags. - type: object - type: object - rewrite: - description: Used to rewrite secret Keys after getting them from the secret Provider Multiple Rewrite operations can be provided. They are applied in a layered order (first to last) - items: - properties: - regexp: - description: Used to rewrite with regular expressions. The resulting key will be the output of a regexp.ReplaceAll operation. - properties: - source: - description: Used to define the regular expression of a re.Compiler. - type: string - target: - description: Used to define the target pattern of a ReplaceAll operation. - type: string - required: - - source - - target - type: object - type: object - type: array - type: object - type: array - refreshInterval: - default: 1h - description: RefreshInterval is the amount of time before the values are read again from the SecretStore provider Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h" May be set to zero to fetch and create it once. Defaults to 1h. - type: string - secretStoreRef: - description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret data. - properties: - kind: - description: Kind of the SecretStore resource (SecretStore or ClusterSecretStore) Defaults to `SecretStore` - type: string - name: - description: Name of the SecretStore resource - type: string - required: - - name - type: object - target: - description: ExternalSecretTarget defines the Kubernetes Secret to be created There can be only one target per ExternalSecret. - properties: - creationPolicy: - default: Owner - description: CreationPolicy defines rules on how to create the resulting Secret Defaults to 'Owner' - enum: - - Owner - - Orphan - - Merge - - None - type: string - deletionPolicy: - default: Retain - description: DeletionPolicy defines rules on how to delete the resulting Secret Defaults to 'Retain' - enum: - - Delete - - Merge - - Retain - type: string - immutable: - description: Immutable defines if the final secret will be immutable - type: boolean - name: - description: Name defines the name of the Secret resource to be managed This field is immutable Defaults to the .metadata.name of the ExternalSecret resource - type: string - template: - description: Template defines a blueprint for the created Secret resource. - properties: - data: - additionalProperties: - type: string - type: object - engineVersion: - default: v2 - type: string - metadata: - description: ExternalSecretTemplateMetadata defines metadata fields for the Secret blueprint. - properties: - annotations: - additionalProperties: - type: string - type: object - labels: - additionalProperties: - type: string - type: object - type: object - templateFrom: - items: - maxProperties: 1 - minProperties: 1 - properties: - configMap: - properties: - items: - items: - properties: - key: - type: string - required: - - key - type: object - type: array - name: - type: string - required: - - items - - name - type: object - secret: - properties: - items: - items: - properties: - key: - type: string - required: - - key - type: object - type: array - name: - type: string - required: - - items - - name - type: object - type: object - type: array - type: - type: string - type: object - type: object - required: - - secretStoreRef - type: object - status: - properties: - conditions: - items: - properties: - lastTransitionTime: - format: date-time - type: string - message: - type: string - reason: - type: string - status: - type: string - type: - type: string - required: - - status - - type - type: object - type: array - refreshTime: - description: refreshTime is the time and date the external secret was fetched and the target secret updated - format: date-time - nullable: true - type: string - syncedResourceVersion: - description: SyncedResourceVersion keeps track of the last synced version - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} - conversion: - strategy: Webhook - webhook: - conversionReviewVersions: - - v1 - clientConfig: - service: - name: golang-external-secrets-webhook - namespace: "default" - path: /convert ---- -# Source: golang-external-secrets/charts/external-secrets/templates/crds/secretstore.yaml -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - creationTimestamp: null - name: secretstores.external-secrets.io -spec: - group: external-secrets.io - names: - categories: - - externalsecrets - kind: SecretStore - listKind: SecretStoreList - plural: secretstores - shortNames: - - ss - singular: secretstore - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: AGE - type: date - - jsonPath: .status.conditions[?(@.type=="Ready")].reason - name: Status - type: string - deprecated: true - name: v1alpha1 - schema: - openAPIV3Schema: - description: SecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields. - 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: SecretStoreSpec defines the desired state of SecretStore. - properties: - controller: - description: 'Used to select the correct KES controller (think: ingress.ingressClassName) The KES controller is instantiated with a specific controller name and filters ES based on this property' - type: string - provider: - description: Used to configure the provider. Only one provider may be set - maxProperties: 1 - minProperties: 1 - properties: - akeyless: - description: Akeyless configures this store to sync secrets using Akeyless Vault provider - properties: - akeylessGWApiURL: - description: Akeyless GW API Url from which the secrets to be fetched from. - type: string - authSecretRef: - description: Auth configures how the operator authenticates with Akeyless. - properties: - secretRef: - description: 'AkeylessAuthSecretRef AKEYLESS_ACCESS_TYPE_PARAM: AZURE_OBJ_ID OR GCP_AUDIENCE OR ACCESS_KEY OR KUB_CONFIG_NAME.' - properties: - accessID: - description: The SecretAccessID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessType: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessTypeParam: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - secretRef - type: object - required: - - akeylessGWApiURL - - authSecretRef - type: object - alibaba: - description: Alibaba configures this store to sync secrets using Alibaba Cloud provider - properties: - auth: - description: AlibabaAuth contains a secretRef for credentials. - properties: - secretRef: - description: AlibabaAuthSecretRef holds secret references for Alibaba credentials. - properties: - accessKeyIDSecretRef: - description: The AccessKeyID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessKeySecretSecretRef: - description: The AccessKeySecret is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - accessKeyIDSecretRef - - accessKeySecretSecretRef - type: object - required: - - secretRef - type: object - endpoint: - type: string - regionID: - description: Alibaba Region to be used for the provider - type: string - required: - - auth - - regionID - type: object - aws: - description: AWS configures this store to sync secrets using AWS Secret Manager provider - properties: - auth: - description: 'Auth defines the information necessary to authenticate against AWS if not set aws sdk will infer credentials from your environment see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' - properties: - jwt: - description: Authenticate against AWS using service account tokens. - properties: - serviceAccountRef: - description: A reference to a ServiceAccount resource. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - type: object - secretRef: - description: AWSAuthSecretRef holds secret references for AWS credentials both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. - properties: - accessKeyIDSecretRef: - description: The AccessKeyID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - secretAccessKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - type: object - region: - description: AWS Region to be used for the provider - type: string - role: - description: Role is a Role ARN which the SecretManager provider will assume - type: string - service: - description: Service defines which service should be used to fetch the secrets - enum: - - SecretsManager - - ParameterStore - type: string - required: - - region - - service - type: object - azurekv: - description: AzureKV configures this store to sync secrets using Azure Key Vault provider - properties: - authSecretRef: - description: Auth configures how the operator authenticates with Azure. Required for ServicePrincipal auth type. - properties: - clientId: - description: The Azure clientId of the service principle used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - clientSecret: - description: The Azure ClientSecret of the service principle used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - authType: - default: ServicePrincipal - description: 'Auth type defines how to authenticate to the keyvault service. Valid values are: - "ServicePrincipal" (default): Using a service principal (tenantId, clientId, clientSecret) - "ManagedIdentity": Using Managed Identity assigned to the pod (see aad-pod-identity)' - enum: - - ServicePrincipal - - ManagedIdentity - - WorkloadIdentity - type: string - identityId: - description: If multiple Managed Identity is assigned to the pod, you can select the one to be used - type: string - serviceAccountRef: - description: ServiceAccountRef specified the service account that should be used when authenticating with WorkloadIdentity. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - tenantId: - description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. - type: string - vaultUrl: - description: Vault Url from which the secrets to be fetched from. - type: string - required: - - vaultUrl - type: object - fake: - description: Fake configures a store with static key/value pairs - properties: - data: - items: - properties: - key: - type: string - value: - type: string - valueMap: - additionalProperties: - type: string - type: object - version: - type: string - required: - - key - type: object - type: array - required: - - data - type: object - gcpsm: - description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider - properties: - auth: - description: Auth defines the information necessary to authenticate against GCP - properties: - secretRef: - properties: - secretAccessKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - workloadIdentity: - properties: - clusterLocation: - type: string - clusterName: - type: string - clusterProjectID: - type: string - serviceAccountRef: - description: A reference to a ServiceAccount resource. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - clusterLocation - - clusterName - - serviceAccountRef - type: object - type: object - projectID: - description: ProjectID project where secret is located - type: string - type: object - gitlab: - description: Gitlab configures this store to sync secrets using Gitlab Variables provider - properties: - auth: - description: Auth configures how secret-manager authenticates with a GitLab instance. - properties: - SecretRef: - properties: - accessToken: - description: AccessToken is used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - SecretRef - type: object - projectID: - description: ProjectID specifies a project where secrets are located. - type: string - url: - description: URL configures the GitLab instance URL. Defaults to https://gitlab.com/. - type: string - required: - - auth - type: object - ibm: - description: IBM configures this store to sync secrets using IBM Cloud provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the IBM secrets manager. - properties: - secretRef: - properties: - secretApiKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - secretRef - type: object - serviceUrl: - description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance - type: string - required: - - auth - type: object - kubernetes: - description: Kubernetes configures this store to sync secrets using a Kubernetes cluster provider - properties: - auth: - description: Auth configures how secret-manager authenticates with a Kubernetes instance. - maxProperties: 1 - minProperties: 1 - properties: - cert: - description: has both clientCert and clientKey as secretKeySelector - properties: - clientCert: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - clientKey: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - serviceAccount: - description: points to a service account that should be used for authentication - properties: - serviceAccount: - description: A reference to a ServiceAccount resource. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - type: object - token: - description: use static token to authenticate with - properties: - bearerToken: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - type: object - remoteNamespace: - default: default - description: Remote namespace to fetch the secrets from - type: string - server: - description: configures the Kubernetes server Address. - properties: - caBundle: - description: CABundle is a base64-encoded CA certificate - format: byte - type: string - caProvider: - description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider' - properties: - key: - description: The key the value inside of the provider type to use, only used with "Secret" type - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - url: - default: kubernetes.default - description: configures the Kubernetes server Address. - type: string - type: object - required: - - auth - type: object - oracle: - description: Oracle configures this store to sync secrets using Oracle Vault provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the Oracle Vault. If empty, use the instance principal, otherwise the user credentials specified in Auth. - properties: - secretRef: - description: SecretRef to pass through sensitive information. - properties: - fingerprint: - description: Fingerprint is the fingerprint of the API private key. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - privatekey: - description: PrivateKey is the user's API Signing Key in PEM format, used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - fingerprint - - privatekey - type: object - tenancy: - description: Tenancy is the tenancy OCID where user is located. - type: string - user: - description: User is an access OCID specific to the account. - type: string - required: - - secretRef - - tenancy - - user - type: object - region: - description: Region is the region where vault is located. - type: string - vault: - description: Vault is the vault's OCID of the specific vault where secret is located. - type: string - required: - - region - - vault - type: object - vault: - description: Vault configures this store to sync secrets using Hashi provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the Vault server. - properties: - appRole: - description: AppRole authenticates with Vault using the App Role auth mechanism, with the role and secret stored in a Kubernetes Secret resource. - properties: - path: - default: approle - description: 'Path where the App Role authentication backend is mounted in Vault, e.g: "approle"' - type: string - roleId: - description: RoleID configured in the App Role authentication backend when setting up the authentication backend in Vault. - type: string - secretRef: - description: Reference to a key in a Secret that contains the App Role secret used to authenticate with Vault. The `key` field must be specified and denotes which entry within the Secret resource is used as the app role secret. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - path - - roleId - - secretRef - type: object - cert: - description: Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate Cert authentication method - properties: - clientCert: - description: ClientCert is a certificate to authenticate using the Cert Vault authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - secretRef: - description: SecretRef to a key in a Secret resource containing client private key to authenticate with Vault using the Cert authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - jwt: - description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method - properties: - kubernetesServiceAccountToken: - description: Optional ServiceAccountToken specifies the Kubernetes service account for which to request a token for with the `TokenRequest` API. - properties: - audiences: - description: Optional audiences field that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to a single audience `vault` it not specified. - items: - type: string - type: array - expirationSeconds: - description: Optional expiration time in seconds that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to 10 minutes. - format: int64 - type: integer - serviceAccountRef: - description: Service account field containing the name of a kubernetes ServiceAccount. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - serviceAccountRef - type: object - path: - default: jwt - description: 'Path where the JWT authentication backend is mounted in Vault, e.g: "jwt"' - type: string - role: - description: Role is a JWT role to authenticate using the JWT/OIDC Vault authentication method - type: string - secretRef: - description: Optional SecretRef that refers to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - path - type: object - kubernetes: - description: Kubernetes authenticates with Vault by passing the ServiceAccount token stored in the named Secret resource to the Vault server. - properties: - mountPath: - default: kubernetes - description: 'Path where the Kubernetes authentication backend is mounted in Vault, e.g: "kubernetes"' - type: string - role: - description: A required field containing the Vault Role to assume. A Role binds a Kubernetes ServiceAccount with a set of Vault policies. - type: string - secretRef: - description: Optional secret field containing a Kubernetes ServiceAccount JWT used for authenticating with Vault. If a name is specified without a key, `token` is the default. If one is not specified, the one bound to the controller will be used. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - serviceAccountRef: - description: Optional service account field containing the name of a kubernetes ServiceAccount. If the service account is specified, the service account secret token JWT will be used for authenticating with Vault. If the service account selector is not supplied, the secretRef will be used instead. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - mountPath - - role - type: object - ldap: - description: Ldap authenticates with Vault by passing username/password pair using the LDAP authentication method - properties: - path: - default: ldap - description: 'Path where the LDAP authentication backend is mounted in Vault, e.g: "ldap"' - type: string - secretRef: - description: SecretRef to a key in a Secret resource containing password for the LDAP user used to authenticate with Vault using the LDAP authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - username: - description: Username is a LDAP user name used to authenticate using the LDAP Vault authentication method - type: string - required: - - path - - username - type: object - tokenSecretRef: - description: TokenSecretRef authenticates with Vault by presenting a token. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - caBundle: - description: PEM encoded CA bundle used to validate Vault server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. - format: byte - type: string - caProvider: - description: The provider for the CA bundle to use to validate Vault server certificate. - properties: - key: - description: The key the value inside of the provider type to use, only used with "Secret" type - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - forwardInconsistent: - description: ForwardInconsistent tells Vault to forward read-after-write requests to the Vault leader instead of simply retrying within a loop. This can increase performance if the option is enabled serverside. https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header - type: boolean - namespace: - description: 'Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1". More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces' - type: string - path: - description: 'Path is the mount path of the Vault KV backend endpoint, e.g: "secret". The v2 KV secret engine version specific "/data" path suffix for fetching secrets from Vault is optional and will be appended if not present in specified path.' - type: string - readYourWrites: - description: ReadYourWrites ensures isolated read-after-write semantics by providing discovered cluster replication states in each request. More information about eventual consistency in Vault can be found here https://www.vaultproject.io/docs/enterprise/consistency - type: boolean - server: - description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' - type: string - version: - default: v2 - description: Version is the Vault KV secret engine version. This can be either "v1" or "v2". Version defaults to "v2". - enum: - - v1 - - v2 - type: string - required: - - auth - - server - type: object - webhook: - description: Webhook configures this store to sync secrets using a generic templated webhook - properties: - body: - description: Body - type: string - caBundle: - description: PEM encoded CA bundle used to validate webhook server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. - format: byte - type: string - caProvider: - description: The provider for the CA bundle to use to validate webhook server certificate. - properties: - key: - description: The key the value inside of the provider type to use, only used with "Secret" type - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - headers: - additionalProperties: - type: string - description: Headers - type: object - method: - description: Webhook Method - type: string - result: - description: Result formatting - properties: - jsonPath: - description: Json path of return value - type: string - type: object - secrets: - description: Secrets to fill in templates These secrets will be passed to the templating function as key value pairs under the given name - items: - properties: - name: - description: Name of this secret in templates - type: string - secretRef: - description: Secret ref to fill in credentials - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - name - - secretRef - type: object - type: array - timeout: - description: Timeout - type: string - url: - description: Webhook url to call - type: string - required: - - result - - url - type: object - yandexlockbox: - description: YandexLockbox configures this store to sync secrets using Yandex Lockbox provider - properties: - apiEndpoint: - description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') - type: string - auth: - description: Auth defines the information necessary to authenticate against Yandex Lockbox - properties: - authorizedKeySecretRef: - description: The authorized key used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - caProvider: - description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. - properties: - certSecretRef: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - auth - type: object - type: object - retrySettings: - description: Used to configure http retries if failed - properties: - maxRetries: - format: int32 - type: integer - retryInterval: - type: string - type: object - required: - - provider - type: object - status: - description: SecretStoreStatus defines the observed state of the SecretStore. - properties: - conditions: - items: - properties: - lastTransitionTime: - format: date-time - type: string - message: - type: string - reason: - type: string - status: - type: string - type: - type: string - required: - - status - - type - type: object - type: array - type: object - type: object - served: true - storage: false - subresources: - status: {} - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: AGE - type: date - - jsonPath: .status.conditions[?(@.type=="Ready")].reason - name: Status - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - name: v1beta1 - schema: - openAPIV3Schema: - description: SecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields. - 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: SecretStoreSpec defines the desired state of SecretStore. - properties: - controller: - description: 'Used to select the correct KES controller (think: ingress.ingressClassName) The KES controller is instantiated with a specific controller name and filters ES based on this property' - type: string - provider: - description: Used to configure the provider. Only one provider may be set - maxProperties: 1 - minProperties: 1 - properties: - akeyless: - description: Akeyless configures this store to sync secrets using Akeyless Vault provider - properties: - akeylessGWApiURL: - description: Akeyless GW API Url from which the secrets to be fetched from. - type: string - authSecretRef: - description: Auth configures how the operator authenticates with Akeyless. - properties: - secretRef: - description: 'AkeylessAuthSecretRef AKEYLESS_ACCESS_TYPE_PARAM: AZURE_OBJ_ID OR GCP_AUDIENCE OR ACCESS_KEY OR KUB_CONFIG_NAME.' - properties: - accessID: - description: The SecretAccessID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessType: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessTypeParam: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - secretRef - type: object - required: - - akeylessGWApiURL - - authSecretRef - type: object - alibaba: - description: Alibaba configures this store to sync secrets using Alibaba Cloud provider - properties: - auth: - description: AlibabaAuth contains a secretRef for credentials. - properties: - secretRef: - description: AlibabaAuthSecretRef holds secret references for Alibaba credentials. - properties: - accessKeyIDSecretRef: - description: The AccessKeyID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessKeySecretSecretRef: - description: The AccessKeySecret is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - accessKeyIDSecretRef - - accessKeySecretSecretRef - type: object - required: - - secretRef - type: object - endpoint: - type: string - regionID: - description: Alibaba Region to be used for the provider - type: string - required: - - auth - - regionID - type: object - aws: - description: AWS configures this store to sync secrets using AWS Secret Manager provider - properties: - auth: - description: 'Auth defines the information necessary to authenticate against AWS if not set aws sdk will infer credentials from your environment see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' - properties: - jwt: - description: Authenticate against AWS using service account tokens. - properties: - serviceAccountRef: - description: A reference to a ServiceAccount resource. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - type: object - secretRef: - description: AWSAuthSecretRef holds secret references for AWS credentials both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. - properties: - accessKeyIDSecretRef: - description: The AccessKeyID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - secretAccessKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - type: object - region: - description: AWS Region to be used for the provider - type: string - role: - description: Role is a Role ARN which the SecretManager provider will assume - type: string - service: - description: Service defines which service should be used to fetch the secrets - enum: - - SecretsManager - - ParameterStore - type: string - required: - - region - - service - type: object - azurekv: - description: AzureKV configures this store to sync secrets using Azure Key Vault provider - properties: - authSecretRef: - description: Auth configures how the operator authenticates with Azure. Required for ServicePrincipal auth type. - properties: - clientId: - description: The Azure clientId of the service principle used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - clientSecret: - description: The Azure ClientSecret of the service principle used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - authType: - default: ServicePrincipal - description: 'Auth type defines how to authenticate to the keyvault service. Valid values are: - "ServicePrincipal" (default): Using a service principal (tenantId, clientId, clientSecret) - "ManagedIdentity": Using Managed Identity assigned to the pod (see aad-pod-identity)' - enum: - - ServicePrincipal - - ManagedIdentity - - WorkloadIdentity - type: string - identityId: - description: If multiple Managed Identity is assigned to the pod, you can select the one to be used - type: string - serviceAccountRef: - description: ServiceAccountRef specified the service account that should be used when authenticating with WorkloadIdentity. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - tenantId: - description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. - type: string - vaultUrl: - description: Vault Url from which the secrets to be fetched from. - type: string - required: - - vaultUrl - type: object - fake: - description: Fake configures a store with static key/value pairs - properties: - data: - items: - properties: - key: - type: string - value: - type: string - valueMap: - additionalProperties: - type: string - type: object - version: - type: string - required: - - key - type: object - type: array - required: - - data - type: object - gcpsm: - description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider - properties: - auth: - description: Auth defines the information necessary to authenticate against GCP - properties: - secretRef: - properties: - secretAccessKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - workloadIdentity: - properties: - clusterLocation: - type: string - clusterName: - type: string - clusterProjectID: - type: string - serviceAccountRef: - description: A reference to a ServiceAccount resource. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - clusterLocation - - clusterName - - serviceAccountRef - type: object - type: object - projectID: - description: ProjectID project where secret is located - type: string - type: object - gitlab: - description: Gitlab configures this store to sync secrets using Gitlab Variables provider - properties: - auth: - description: Auth configures how secret-manager authenticates with a GitLab instance. - properties: - SecretRef: - properties: - accessToken: - description: AccessToken is used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - SecretRef - type: object - projectID: - description: ProjectID specifies a project where secrets are located. - type: string - url: - description: URL configures the GitLab instance URL. Defaults to https://gitlab.com/. - type: string - required: - - auth - type: object - ibm: - description: IBM configures this store to sync secrets using IBM Cloud provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the IBM secrets manager. - maxProperties: 1 - minProperties: 1 - properties: - containerAuth: - description: IBM Container-based auth with IAM Trusted Profile. - properties: - iamEndpoint: - type: string - profile: - description: the IBM Trusted Profile - type: string - tokenLocation: - description: Location the token is mounted on the pod - type: string - required: - - profile - type: object - secretRef: - properties: - secretApiKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - type: object - serviceUrl: - description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance - type: string - required: - - auth - type: object - kubernetes: - description: Kubernetes configures this store to sync secrets using a Kubernetes cluster provider - properties: - auth: - description: Auth configures how secret-manager authenticates with a Kubernetes instance. - maxProperties: 1 - minProperties: 1 - properties: - cert: - description: has both clientCert and clientKey as secretKeySelector - properties: - clientCert: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - clientKey: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - serviceAccount: - description: points to a service account that should be used for authentication - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - token: - description: use static token to authenticate with - properties: - bearerToken: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - type: object - remoteNamespace: - default: default - description: Remote namespace to fetch the secrets from - type: string - server: - description: configures the Kubernetes server Address. - properties: - caBundle: - description: CABundle is a base64-encoded CA certificate - format: byte - type: string - caProvider: - description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider' - properties: - key: - description: The key where the CA certificate can be found in the Secret or ConfigMap. - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. Can only be defined when used in a ClusterSecretStore. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - url: - default: kubernetes.default - description: configures the Kubernetes server Address. - type: string - type: object - required: - - auth - type: object - onepassword: - description: OnePassword configures this store to sync secrets using the 1Password Cloud provider - properties: - auth: - description: Auth defines the information necessary to authenticate against OnePassword Connect Server - properties: - secretRef: - description: OnePasswordAuthSecretRef holds secret references for 1Password credentials. - properties: - connectTokenSecretRef: - description: The ConnectToken is used for authentication to a 1Password Connect Server. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - connectTokenSecretRef - type: object - required: - - secretRef - type: object - connectHost: - description: ConnectHost defines the OnePassword Connect Server to connect to - type: string - vaults: - additionalProperties: - type: integer - description: Vaults defines which OnePassword vaults to search in which order - type: object - required: - - auth - - connectHost - - vaults - type: object - oracle: - description: Oracle configures this store to sync secrets using Oracle Vault provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the Oracle Vault. If empty, use the instance principal, otherwise the user credentials specified in Auth. - properties: - secretRef: - description: SecretRef to pass through sensitive information. - properties: - fingerprint: - description: Fingerprint is the fingerprint of the API private key. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - privatekey: - description: PrivateKey is the user's API Signing Key in PEM format, used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - fingerprint - - privatekey - type: object - tenancy: - description: Tenancy is the tenancy OCID where user is located. - type: string - user: - description: User is an access OCID specific to the account. - type: string - required: - - secretRef - - tenancy - - user - type: object - region: - description: Region is the region where vault is located. - type: string - vault: - description: Vault is the vault's OCID of the specific vault where secret is located. - type: string - required: - - region - - vault - type: object - senhasegura: - description: Senhasegura configures this store to sync secrets using senhasegura provider - properties: - auth: - description: Auth defines parameters to authenticate in senhasegura - properties: - clientId: - type: string - clientSecretSecretRef: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - clientId - - clientSecretSecretRef - type: object - ignoreSslCertificate: - default: false - description: IgnoreSslCertificate defines if SSL certificate must be ignored - type: boolean - module: - description: Module defines which senhasegura module should be used to get secrets - type: string - url: - description: URL of senhasegura - type: string - required: - - auth - - module - - url - type: object - vault: - description: Vault configures this store to sync secrets using Hashi provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the Vault server. - properties: - appRole: - description: AppRole authenticates with Vault using the App Role auth mechanism, with the role and secret stored in a Kubernetes Secret resource. - properties: - path: - default: approle - description: 'Path where the App Role authentication backend is mounted in Vault, e.g: "approle"' - type: string - roleId: - description: RoleID configured in the App Role authentication backend when setting up the authentication backend in Vault. - type: string - secretRef: - description: Reference to a key in a Secret that contains the App Role secret used to authenticate with Vault. The `key` field must be specified and denotes which entry within the Secret resource is used as the app role secret. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - path - - roleId - - secretRef - type: object - cert: - description: Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate Cert authentication method - properties: - clientCert: - description: ClientCert is a certificate to authenticate using the Cert Vault authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - secretRef: - description: SecretRef to a key in a Secret resource containing client private key to authenticate with Vault using the Cert authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - jwt: - description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method - properties: - kubernetesServiceAccountToken: - description: Optional ServiceAccountToken specifies the Kubernetes service account for which to request a token for with the `TokenRequest` API. - properties: - audiences: - description: Optional audiences field that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to a single audience `vault` it not specified. - items: - type: string - type: array - expirationSeconds: - description: Optional expiration time in seconds that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to 10 minutes. - format: int64 - type: integer - serviceAccountRef: - description: Service account field containing the name of a kubernetes ServiceAccount. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - serviceAccountRef - type: object - path: - default: jwt - description: 'Path where the JWT authentication backend is mounted in Vault, e.g: "jwt"' - type: string - role: - description: Role is a JWT role to authenticate using the JWT/OIDC Vault authentication method - type: string - secretRef: - description: Optional SecretRef that refers to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - path - type: object - kubernetes: - description: Kubernetes authenticates with Vault by passing the ServiceAccount token stored in the named Secret resource to the Vault server. - properties: - mountPath: - default: kubernetes - description: 'Path where the Kubernetes authentication backend is mounted in Vault, e.g: "kubernetes"' - type: string - role: - description: A required field containing the Vault Role to assume. A Role binds a Kubernetes ServiceAccount with a set of Vault policies. - type: string - secretRef: - description: Optional secret field containing a Kubernetes ServiceAccount JWT used for authenticating with Vault. If a name is specified without a key, `token` is the default. If one is not specified, the one bound to the controller will be used. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - serviceAccountRef: - description: Optional service account field containing the name of a kubernetes ServiceAccount. If the service account is specified, the service account secret token JWT will be used for authenticating with Vault. If the service account selector is not supplied, the secretRef will be used instead. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - mountPath - - role - type: object - ldap: - description: Ldap authenticates with Vault by passing username/password pair using the LDAP authentication method - properties: - path: - default: ldap - description: 'Path where the LDAP authentication backend is mounted in Vault, e.g: "ldap"' - type: string - secretRef: - description: SecretRef to a key in a Secret resource containing password for the LDAP user used to authenticate with Vault using the LDAP authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - username: - description: Username is a LDAP user name used to authenticate using the LDAP Vault authentication method - type: string - required: - - path - - username - type: object - tokenSecretRef: - description: TokenSecretRef authenticates with Vault by presenting a token. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - caBundle: - description: PEM encoded CA bundle used to validate Vault server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. - format: byte - type: string - caProvider: - description: The provider for the CA bundle to use to validate Vault server certificate. - properties: - key: - description: The key where the CA certificate can be found in the Secret or ConfigMap. - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. Can only be defined when used in a ClusterSecretStore. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - forwardInconsistent: - description: ForwardInconsistent tells Vault to forward read-after-write requests to the Vault leader instead of simply retrying within a loop. This can increase performance if the option is enabled serverside. https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header - type: boolean - namespace: - description: 'Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1". More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces' - type: string - path: - description: 'Path is the mount path of the Vault KV backend endpoint, e.g: "secret". The v2 KV secret engine version specific "/data" path suffix for fetching secrets from Vault is optional and will be appended if not present in specified path.' - type: string - readYourWrites: - description: ReadYourWrites ensures isolated read-after-write semantics by providing discovered cluster replication states in each request. More information about eventual consistency in Vault can be found here https://www.vaultproject.io/docs/enterprise/consistency - type: boolean - server: - description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' - type: string - version: - default: v2 - description: Version is the Vault KV secret engine version. This can be either "v1" or "v2". Version defaults to "v2". - enum: - - v1 - - v2 - type: string - required: - - auth - - server - type: object - webhook: - description: Webhook configures this store to sync secrets using a generic templated webhook - properties: - body: - description: Body - type: string - caBundle: - description: PEM encoded CA bundle used to validate webhook server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. - format: byte - type: string - caProvider: - description: The provider for the CA bundle to use to validate webhook server certificate. - properties: - key: - description: The key the value inside of the provider type to use, only used with "Secret" type - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - headers: - additionalProperties: - type: string - description: Headers - type: object - method: - description: Webhook Method - type: string - result: - description: Result formatting - properties: - jsonPath: - description: Json path of return value - type: string - type: object - secrets: - description: Secrets to fill in templates These secrets will be passed to the templating function as key value pairs under the given name - items: - properties: - name: - description: Name of this secret in templates - type: string - secretRef: - description: Secret ref to fill in credentials - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - name - - secretRef - type: object - type: array - timeout: - description: Timeout - type: string - url: - description: Webhook url to call - type: string - required: - - result - - url - type: object - yandexcertificatemanager: - description: YandexCertificateManager configures this store to sync secrets using Yandex Certificate Manager provider - properties: - apiEndpoint: - description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') - type: string - auth: - description: Auth defines the information necessary to authenticate against Yandex Certificate Manager - properties: - authorizedKeySecretRef: - description: The authorized key used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - caProvider: - description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. - properties: - certSecretRef: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - auth - type: object - yandexlockbox: - description: YandexLockbox configures this store to sync secrets using Yandex Lockbox provider - properties: - apiEndpoint: - description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') - type: string - auth: - description: Auth defines the information necessary to authenticate against Yandex Lockbox - properties: - authorizedKeySecretRef: - description: The authorized key used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - caProvider: - description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. - properties: - certSecretRef: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - auth - type: object - type: object - refreshInterval: - description: Used to configure store refresh interval in seconds. Empty or 0 will default to the controller config. - type: integer - retrySettings: - description: Used to configure http retries if failed - properties: - maxRetries: - format: int32 - type: integer - retryInterval: - type: string - type: object - required: - - provider - type: object - status: - description: SecretStoreStatus defines the observed state of the SecretStore. - properties: - conditions: - items: - properties: - lastTransitionTime: - format: date-time - type: string - message: - type: string - reason: - type: string - status: - type: string - type: - type: string - required: - - status - - type - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} - conversion: - strategy: Webhook - webhook: - conversionReviewVersions: - - v1 - clientConfig: - service: - name: golang-external-secrets-webhook - namespace: "default" - path: /convert ---- -# Source: golang-external-secrets/charts/external-secrets/templates/cert-controller-rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: golang-external-secrets-cert-controller - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets-cert-controller - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm -rules: - - apiGroups: - - "apiextensions.k8s.io" - resources: - - "customresourcedefinitions" - verbs: - - "get" - - "list" - - "watch" - - "update" - - "patch" - - apiGroups: - - "admissionregistration.k8s.io" - resources: - - "validatingwebhookconfigurations" - verbs: - - "get" - - "list" - - "watch" - - "update" - - "patch" - - apiGroups: - - "" - resources: - - "endpoints" - verbs: - - "list" - - "get" - - "watch" - - apiGroups: - - "" - resources: - - "events" - verbs: - - "create" - - "patch" - - apiGroups: - - "" - resources: - - "secrets" - verbs: - - "get" - - "list" - - "watch" - - "update" - - "patch" ---- -# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: golang-external-secrets-controller - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm -rules: - - apiGroups: - - "external-secrets.io" - resources: - - "secretstores" - - "clustersecretstores" - - "externalsecrets" - - "clusterexternalsecrets" - verbs: - - "get" - - "list" - - "watch" - - apiGroups: - - "external-secrets.io" - resources: - - "externalsecrets" - - "externalsecrets/status" - - "externalsecrets/finalizers" - - "secretstores" - - "secretstores/status" - - "secretstores/finalizers" - - "clustersecretstores" - - "clustersecretstores/status" - - "clustersecretstores/finalizers" - - "clusterexternalsecrets" - - "clusterexternalsecrets/status" - - "clusterexternalsecrets/finalizers" - verbs: - - "update" - - "patch" - - apiGroups: - - "" - resources: - - "serviceaccounts" - - "namespaces" - verbs: - - "get" - - "list" - - "watch" - - apiGroups: - - "" - resources: - - "configmaps" - verbs: - - "get" - - "list" - - "watch" - - apiGroups: - - "" - resources: - - "secrets" - verbs: - - "get" - - "list" - - "watch" - - "create" - - "update" - - "delete" - - "patch" - - apiGroups: - - "" - resources: - - "serviceaccounts/token" - verbs: - - "create" - - apiGroups: - - "" - resources: - - "events" - verbs: - - "create" - - "patch" - - apiGroups: - - "external-secrets.io" - resources: - - "externalsecrets" - verbs: - - "create" - - "update" ---- -# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: golang-external-secrets-view - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm - rbac.authorization.k8s.io/aggregate-to-view: "true" - rbac.authorization.k8s.io/aggregate-to-edit: "true" - rbac.authorization.k8s.io/aggregate-to-admin: "true" -rules: - - apiGroups: - - "external-secrets.io" - resources: - - "externalsecrets" - - "secretstores" - - "clustersecretstores" - verbs: - - "get" - - "watch" - - "list" ---- -# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: golang-external-secrets-edit - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm - rbac.authorization.k8s.io/aggregate-to-edit: "true" - rbac.authorization.k8s.io/aggregate-to-admin: "true" -rules: - - apiGroups: - - "external-secrets.io" - resources: - - "externalsecrets" - - "secretstores" - - "clustersecretstores" - verbs: - - "create" - - "delete" - - "deletecollection" - - "patch" - - "update" ---- -# Source: golang-external-secrets/charts/external-secrets/templates/cert-controller-rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: golang-external-secrets-cert-controller - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets-cert-controller - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: golang-external-secrets-cert-controller -subjects: - - name: external-secrets-cert-controller - namespace: "default" - kind: ServiceAccount ---- -# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: golang-external-secrets-controller - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: golang-external-secrets-controller -subjects: - - name: golang-external-secrets - namespace: "default" - kind: ServiceAccount ---- -# Source: golang-external-secrets/templates/golang-external-secrets-hub-clusterrolebinding.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: role-tokenreview-binding - namespace: default -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:auth-delegator -subjects: -- kind: ServiceAccount - name: golang-external-secrets - namespace: golang-external-secrets ---- -# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: golang-external-secrets-leaderelection - namespace: "default" - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm -rules: - - apiGroups: - - "" - resources: - - "configmaps" - resourceNames: - - "external-secrets-controller" - verbs: - - "get" - - "update" - - "patch" - - apiGroups: - - "" - resources: - - "configmaps" - verbs: - - "create" - - apiGroups: - - "coordination.k8s.io" - resources: - - "leases" - verbs: - - "get" - - "create" - - "update" - - "patch" ---- -# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: golang-external-secrets-leaderelection - namespace: "default" - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: golang-external-secrets-leaderelection -subjects: - - kind: ServiceAccount - name: golang-external-secrets - namespace: "default" ---- -# Source: golang-external-secrets/charts/external-secrets/templates/webhook-service.yaml -apiVersion: v1 -kind: Service -metadata: - name: golang-external-secrets-webhook - namespace: "default" - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets-webhook - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm - external-secrets.io/component : webhook -spec: - type: ClusterIP - ports: - - port: 443 - targetPort: 10250 - protocol: TCP - name: webhook - selector: - app.kubernetes.io/name: external-secrets-webhook - app.kubernetes.io/instance: golang-external-secrets ---- -# Source: golang-external-secrets/charts/external-secrets/templates/cert-controller-deployment.yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: golang-external-secrets-cert-controller - namespace: "default" - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets-cert-controller - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: external-secrets-cert-controller - app.kubernetes.io/instance: golang-external-secrets - template: - metadata: - labels: - app.kubernetes.io/name: external-secrets-cert-controller - app.kubernetes.io/instance: golang-external-secrets - spec: - serviceAccountName: external-secrets-cert-controller - containers: - - name: cert-controller - image: "ghcr.io/external-secrets/external-secrets:v0.5.9" - imagePullPolicy: IfNotPresent - args: - - certcontroller - - --crd-requeue-interval=5m - - --service-name=golang-external-secrets-webhook - - --service-namespace=default - - --secret-name=golang-external-secrets-webhook - - --secret-namespace=default - ports: - - containerPort: 8080 - protocol: TCP - name: metrics - readinessProbe: - httpGet: - port: 8081 - path: /readyz - initialDelaySeconds: 20 - periodSeconds: 5 ---- -# Source: golang-external-secrets/charts/external-secrets/templates/deployment.yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: golang-external-secrets - namespace: "default" - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: external-secrets - app.kubernetes.io/instance: golang-external-secrets - template: - metadata: - labels: - app.kubernetes.io/name: external-secrets - app.kubernetes.io/instance: golang-external-secrets - spec: - serviceAccountName: golang-external-secrets - containers: - - name: external-secrets - image: "ghcr.io/external-secrets/external-secrets:v0.5.9" - imagePullPolicy: IfNotPresent - args: - - --concurrent=1 - ports: - - containerPort: 8080 - protocol: TCP - name: metrics ---- -# Source: golang-external-secrets/charts/external-secrets/templates/webhook-deployment.yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: golang-external-secrets-webhook - namespace: "default" - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets-webhook - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: external-secrets-webhook - app.kubernetes.io/instance: golang-external-secrets - template: - metadata: - labels: - app.kubernetes.io/name: external-secrets-webhook - app.kubernetes.io/instance: golang-external-secrets - spec: - hostNetwork: false - serviceAccountName: external-secrets-webhook - containers: - - name: webhook - image: "ghcr.io/external-secrets/external-secrets:v0.5.9" - imagePullPolicy: IfNotPresent - args: - - webhook - - --port=10250 - - --dns-name=golang-external-secrets-webhook.default.svc - - --cert-dir=/tmp/certs - - --check-interval=5m - ports: - - containerPort: 8080 - protocol: TCP - name: metrics - - containerPort: 10250 - protocol: TCP - name: webhook - readinessProbe: - httpGet: - port: 8081 - path: /readyz - initialDelaySeconds: 20 - periodSeconds: 5 - volumeMounts: - - name: certs - mountPath: /tmp/certs - readOnly: true - volumes: - - name: certs - secret: - secretName: golang-external-secrets-webhook ---- -# Source: golang-external-secrets/templates/golang-external-secrets-hub-secretstore.yaml -apiVersion: external-secrets.io/v1beta1 -kind: ClusterSecretStore -metadata: - name: vault-backend - namespace: golang-external-secrets -spec: - provider: - vault: - server: https://vault-vault.hub.example.com - path: secret - # Version of KV backend - version: v2 - caProvider: - type: ConfigMap - name: kube-root-ca.crt - key: ca.crt - namespace: golang-external-secrets - auth: - kubernetes: - mountPath: hub - role: hub-role - secretRef: - name: golang-external-secrets - namespace: golang-external-secrets - key: "token" ---- -# Source: golang-external-secrets/charts/external-secrets/templates/validatingwebhook.yaml -apiVersion: admissionregistration.k8s.io/v1 -kind: ValidatingWebhookConfiguration -metadata: - name: secretstore-validate - labels: - external-secrets.io/component: webhook -webhooks: -- name: "validate.secretstore.external-secrets.io" - rules: - - apiGroups: ["external-secrets.io"] - apiVersions: ["v1beta1"] - operations: ["CREATE", "UPDATE", "DELETE"] - resources: ["secretstores"] - scope: "Namespaced" - clientConfig: - service: - namespace: "default" - name: golang-external-secrets-webhook - path: /validate-external-secrets-io-v1beta1-secretstore - admissionReviewVersions: ["v1", "v1beta1"] - sideEffects: None - timeoutSeconds: 5 - -- name: "validate.clustersecretstore.external-secrets.io" - rules: - - apiGroups: ["external-secrets.io"] - apiVersions: ["v1beta1"] - operations: ["CREATE", "UPDATE", "DELETE"] - resources: ["clustersecretstores"] - scope: "Cluster" - clientConfig: - service: - namespace: "default" - name: golang-external-secrets-webhook - path: /validate-external-secrets-io-v1beta1-clustersecretstore - admissionReviewVersions: ["v1", "v1beta1"] - sideEffects: None - timeoutSeconds: 5 ---- -# Source: golang-external-secrets/charts/external-secrets/templates/validatingwebhook.yaml -apiVersion: admissionregistration.k8s.io/v1 -kind: ValidatingWebhookConfiguration -metadata: - name: externalsecret-validate - labels: - external-secrets.io/component: webhook -webhooks: -- name: "validate.externalsecret.external-secrets.io" - rules: - - apiGroups: ["external-secrets.io"] - apiVersions: ["v1beta1"] - operations: ["CREATE", "UPDATE", "DELETE"] - resources: ["externalsecrets"] - scope: "Namespaced" - clientConfig: - service: - namespace: "default" - name: golang-external-secrets-webhook - path: /validate-external-secrets-io-v1beta1-externalsecret - admissionReviewVersions: ["v1", "v1beta1"] - sideEffects: None - timeoutSeconds: 5 - failurePolicy: Fail diff --git a/common/tests/golang-external-secrets-normal.expected.yaml b/common/tests/golang-external-secrets-normal.expected.yaml deleted file mode 100644 index 7d9fa628..00000000 --- a/common/tests/golang-external-secrets-normal.expected.yaml +++ /dev/null @@ -1,5911 +0,0 @@ ---- -# Source: golang-external-secrets/charts/external-secrets/templates/cert-controller-serviceaccount.yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: external-secrets-cert-controller - namespace: "default" - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets-cert-controller - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm ---- -# Source: golang-external-secrets/charts/external-secrets/templates/serviceaccount.yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: golang-external-secrets - namespace: "default" - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm ---- -# Source: golang-external-secrets/charts/external-secrets/templates/webhook-serviceaccount.yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: external-secrets-webhook - namespace: "default" - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets-webhook - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm ---- -# Source: golang-external-secrets/charts/external-secrets/templates/webhook-secret.yaml -apiVersion: v1 -kind: Secret -metadata: - name: golang-external-secrets-webhook - namespace: "default" - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets-webhook - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm - external-secrets.io/component : webhook ---- -# Source: golang-external-secrets/templates/golang-external-secrets-hub-clusterrolebinding.yaml -apiVersion: v1 -kind: Secret -metadata: - name: golang-external-secrets - namespace: golang-external-secrets - annotations: - kubernetes.io/service-account.name: golang-external-secrets -type: kubernetes.io/service-account-token ---- -# Source: golang-external-secrets/charts/external-secrets/templates/crds/clusterexternalsecret.yaml -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - creationTimestamp: null - name: clusterexternalsecrets.external-secrets.io -spec: - group: external-secrets.io - names: - categories: - - externalsecrets - kind: ClusterExternalSecret - listKind: ClusterExternalSecretList - plural: clusterexternalsecrets - shortNames: - - ces - singular: clusterexternalsecret - scope: Cluster - versions: - - additionalPrinterColumns: - - jsonPath: .spec.secretStoreRef.name - name: Store - type: string - - jsonPath: .spec.refreshInterval - name: Refresh Interval - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].reason - name: Status - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - name: v1beta1 - schema: - openAPIV3Schema: - description: ClusterExternalSecret is the Schema for the clusterexternalsecrets 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: ClusterExternalSecretSpec defines the desired state of ClusterExternalSecret. - properties: - externalSecretName: - description: The name of the external secrets to be created defaults to the name of the ClusterExternalSecret - type: string - externalSecretSpec: - description: The spec for the ExternalSecrets to be created - properties: - data: - description: Data defines the connection between the Kubernetes Secret keys and the Provider data - items: - description: ExternalSecretData defines the connection between the Kubernetes Secret key (spec.data.) and the Provider data. - properties: - remoteRef: - description: ExternalSecretDataRemoteRef defines Provider data location. - properties: - conversionStrategy: - default: Default - description: Used to define a conversion Strategy - type: string - decodingStrategy: - default: None - description: Used to define a decoding Strategy - type: string - key: - description: Key is the key used in the Provider, mandatory - type: string - metadataPolicy: - description: Policy for fetching tags/labels from provider secrets, possible options are Fetch, None. Defaults to None - type: string - property: - description: Used to select a specific property of the Provider value (if a map), if supported - type: string - version: - description: Used to select a specific version of the Provider value, if supported - type: string - required: - - key - type: object - secretKey: - type: string - required: - - remoteRef - - secretKey - type: object - type: array - dataFrom: - description: DataFrom is used to fetch all properties from a specific Provider data If multiple entries are specified, the Secret keys are merged in the specified order - items: - properties: - extract: - description: Used to extract multiple key/value pairs from one secret - properties: - conversionStrategy: - default: Default - description: Used to define a conversion Strategy - type: string - decodingStrategy: - default: None - description: Used to define a decoding Strategy - type: string - key: - description: Key is the key used in the Provider, mandatory - type: string - metadataPolicy: - description: Policy for fetching tags/labels from provider secrets, possible options are Fetch, None. Defaults to None - type: string - property: - description: Used to select a specific property of the Provider value (if a map), if supported - type: string - version: - description: Used to select a specific version of the Provider value, if supported - type: string - required: - - key - type: object - find: - description: Used to find secrets based on tags or regular expressions - properties: - conversionStrategy: - default: Default - description: Used to define a conversion Strategy - type: string - decodingStrategy: - default: None - description: Used to define a decoding Strategy - type: string - name: - description: Finds secrets based on the name. - properties: - regexp: - description: Finds secrets base - type: string - type: object - path: - description: A root path to start the find operations. - type: string - tags: - additionalProperties: - type: string - description: Find secrets based on tags. - type: object - type: object - rewrite: - description: Used to rewrite secret Keys after getting them from the secret Provider Multiple Rewrite operations can be provided. They are applied in a layered order (first to last) - items: - properties: - regexp: - description: Used to rewrite with regular expressions. The resulting key will be the output of a regexp.ReplaceAll operation. - properties: - source: - description: Used to define the regular expression of a re.Compiler. - type: string - target: - description: Used to define the target pattern of a ReplaceAll operation. - type: string - required: - - source - - target - type: object - type: object - type: array - type: object - type: array - refreshInterval: - default: 1h - description: RefreshInterval is the amount of time before the values are read again from the SecretStore provider Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h" May be set to zero to fetch and create it once. Defaults to 1h. - type: string - secretStoreRef: - description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret data. - properties: - kind: - description: Kind of the SecretStore resource (SecretStore or ClusterSecretStore) Defaults to `SecretStore` - type: string - name: - description: Name of the SecretStore resource - type: string - required: - - name - type: object - target: - description: ExternalSecretTarget defines the Kubernetes Secret to be created There can be only one target per ExternalSecret. - properties: - creationPolicy: - default: Owner - description: CreationPolicy defines rules on how to create the resulting Secret Defaults to 'Owner' - enum: - - Owner - - Orphan - - Merge - - None - type: string - deletionPolicy: - default: Retain - description: DeletionPolicy defines rules on how to delete the resulting Secret Defaults to 'Retain' - enum: - - Delete - - Merge - - Retain - type: string - immutable: - description: Immutable defines if the final secret will be immutable - type: boolean - name: - description: Name defines the name of the Secret resource to be managed This field is immutable Defaults to the .metadata.name of the ExternalSecret resource - type: string - template: - description: Template defines a blueprint for the created Secret resource. - properties: - data: - additionalProperties: - type: string - type: object - engineVersion: - default: v2 - type: string - metadata: - description: ExternalSecretTemplateMetadata defines metadata fields for the Secret blueprint. - properties: - annotations: - additionalProperties: - type: string - type: object - labels: - additionalProperties: - type: string - type: object - type: object - templateFrom: - items: - maxProperties: 1 - minProperties: 1 - properties: - configMap: - properties: - items: - items: - properties: - key: - type: string - required: - - key - type: object - type: array - name: - type: string - required: - - items - - name - type: object - secret: - properties: - items: - items: - properties: - key: - type: string - required: - - key - type: object - type: array - name: - type: string - required: - - items - - name - type: object - type: object - type: array - type: - type: string - type: object - type: object - required: - - secretStoreRef - type: object - namespaceSelector: - description: The labels to select by to find the Namespaces to create the ExternalSecrets in. - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - refreshTime: - description: The time in which the controller should reconcile it's objects and recheck namespaces for labels. - type: string - required: - - externalSecretSpec - - namespaceSelector - type: object - status: - description: ClusterExternalSecretStatus defines the observed state of ClusterExternalSecret. - properties: - conditions: - items: - properties: - message: - type: string - status: - type: string - type: - type: string - required: - - status - - type - type: object - type: array - failedNamespaces: - description: Failed namespaces are the namespaces that failed to apply an ExternalSecret - items: - description: ClusterExternalSecretNamespaceFailure represents a failed namespace deployment and it's reason. - properties: - namespace: - description: Namespace is the namespace that failed when trying to apply an ExternalSecret - type: string - reason: - description: Reason is why the ExternalSecret failed to apply to the namespace - type: string - required: - - namespace - type: object - type: array - provisionedNamespaces: - description: ProvisionedNamespaces are the namespaces where the ClusterExternalSecret has secrets - items: - type: string - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} - conversion: - strategy: Webhook - webhook: - conversionReviewVersions: - - v1 - clientConfig: - service: - name: golang-external-secrets-webhook - namespace: "default" - path: /convert ---- -# Source: golang-external-secrets/charts/external-secrets/templates/crds/clustersecretstore.yaml -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - creationTimestamp: null - name: clustersecretstores.external-secrets.io -spec: - group: external-secrets.io - names: - categories: - - externalsecrets - kind: ClusterSecretStore - listKind: ClusterSecretStoreList - plural: clustersecretstores - shortNames: - - css - singular: clustersecretstore - scope: Cluster - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: AGE - type: date - - jsonPath: .status.conditions[?(@.type=="Ready")].reason - name: Status - type: string - deprecated: true - name: v1alpha1 - schema: - openAPIV3Schema: - description: ClusterSecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields. - 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: SecretStoreSpec defines the desired state of SecretStore. - properties: - controller: - description: 'Used to select the correct KES controller (think: ingress.ingressClassName) The KES controller is instantiated with a specific controller name and filters ES based on this property' - type: string - provider: - description: Used to configure the provider. Only one provider may be set - maxProperties: 1 - minProperties: 1 - properties: - akeyless: - description: Akeyless configures this store to sync secrets using Akeyless Vault provider - properties: - akeylessGWApiURL: - description: Akeyless GW API Url from which the secrets to be fetched from. - type: string - authSecretRef: - description: Auth configures how the operator authenticates with Akeyless. - properties: - secretRef: - description: 'AkeylessAuthSecretRef AKEYLESS_ACCESS_TYPE_PARAM: AZURE_OBJ_ID OR GCP_AUDIENCE OR ACCESS_KEY OR KUB_CONFIG_NAME.' - properties: - accessID: - description: The SecretAccessID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessType: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessTypeParam: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - secretRef - type: object - required: - - akeylessGWApiURL - - authSecretRef - type: object - alibaba: - description: Alibaba configures this store to sync secrets using Alibaba Cloud provider - properties: - auth: - description: AlibabaAuth contains a secretRef for credentials. - properties: - secretRef: - description: AlibabaAuthSecretRef holds secret references for Alibaba credentials. - properties: - accessKeyIDSecretRef: - description: The AccessKeyID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessKeySecretSecretRef: - description: The AccessKeySecret is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - accessKeyIDSecretRef - - accessKeySecretSecretRef - type: object - required: - - secretRef - type: object - endpoint: - type: string - regionID: - description: Alibaba Region to be used for the provider - type: string - required: - - auth - - regionID - type: object - aws: - description: AWS configures this store to sync secrets using AWS Secret Manager provider - properties: - auth: - description: 'Auth defines the information necessary to authenticate against AWS if not set aws sdk will infer credentials from your environment see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' - properties: - jwt: - description: Authenticate against AWS using service account tokens. - properties: - serviceAccountRef: - description: A reference to a ServiceAccount resource. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - type: object - secretRef: - description: AWSAuthSecretRef holds secret references for AWS credentials both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. - properties: - accessKeyIDSecretRef: - description: The AccessKeyID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - secretAccessKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - type: object - region: - description: AWS Region to be used for the provider - type: string - role: - description: Role is a Role ARN which the SecretManager provider will assume - type: string - service: - description: Service defines which service should be used to fetch the secrets - enum: - - SecretsManager - - ParameterStore - type: string - required: - - region - - service - type: object - azurekv: - description: AzureKV configures this store to sync secrets using Azure Key Vault provider - properties: - authSecretRef: - description: Auth configures how the operator authenticates with Azure. Required for ServicePrincipal auth type. - properties: - clientId: - description: The Azure clientId of the service principle used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - clientSecret: - description: The Azure ClientSecret of the service principle used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - authType: - default: ServicePrincipal - description: 'Auth type defines how to authenticate to the keyvault service. Valid values are: - "ServicePrincipal" (default): Using a service principal (tenantId, clientId, clientSecret) - "ManagedIdentity": Using Managed Identity assigned to the pod (see aad-pod-identity)' - enum: - - ServicePrincipal - - ManagedIdentity - - WorkloadIdentity - type: string - identityId: - description: If multiple Managed Identity is assigned to the pod, you can select the one to be used - type: string - serviceAccountRef: - description: ServiceAccountRef specified the service account that should be used when authenticating with WorkloadIdentity. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - tenantId: - description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. - type: string - vaultUrl: - description: Vault Url from which the secrets to be fetched from. - type: string - required: - - vaultUrl - type: object - fake: - description: Fake configures a store with static key/value pairs - properties: - data: - items: - properties: - key: - type: string - value: - type: string - valueMap: - additionalProperties: - type: string - type: object - version: - type: string - required: - - key - type: object - type: array - required: - - data - type: object - gcpsm: - description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider - properties: - auth: - description: Auth defines the information necessary to authenticate against GCP - properties: - secretRef: - properties: - secretAccessKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - workloadIdentity: - properties: - clusterLocation: - type: string - clusterName: - type: string - clusterProjectID: - type: string - serviceAccountRef: - description: A reference to a ServiceAccount resource. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - clusterLocation - - clusterName - - serviceAccountRef - type: object - type: object - projectID: - description: ProjectID project where secret is located - type: string - type: object - gitlab: - description: Gitlab configures this store to sync secrets using Gitlab Variables provider - properties: - auth: - description: Auth configures how secret-manager authenticates with a GitLab instance. - properties: - SecretRef: - properties: - accessToken: - description: AccessToken is used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - SecretRef - type: object - projectID: - description: ProjectID specifies a project where secrets are located. - type: string - url: - description: URL configures the GitLab instance URL. Defaults to https://gitlab.com/. - type: string - required: - - auth - type: object - ibm: - description: IBM configures this store to sync secrets using IBM Cloud provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the IBM secrets manager. - properties: - secretRef: - properties: - secretApiKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - secretRef - type: object - serviceUrl: - description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance - type: string - required: - - auth - type: object - kubernetes: - description: Kubernetes configures this store to sync secrets using a Kubernetes cluster provider - properties: - auth: - description: Auth configures how secret-manager authenticates with a Kubernetes instance. - maxProperties: 1 - minProperties: 1 - properties: - cert: - description: has both clientCert and clientKey as secretKeySelector - properties: - clientCert: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - clientKey: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - serviceAccount: - description: points to a service account that should be used for authentication - properties: - serviceAccount: - description: A reference to a ServiceAccount resource. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - type: object - token: - description: use static token to authenticate with - properties: - bearerToken: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - type: object - remoteNamespace: - default: default - description: Remote namespace to fetch the secrets from - type: string - server: - description: configures the Kubernetes server Address. - properties: - caBundle: - description: CABundle is a base64-encoded CA certificate - format: byte - type: string - caProvider: - description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider' - properties: - key: - description: The key the value inside of the provider type to use, only used with "Secret" type - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - url: - default: kubernetes.default - description: configures the Kubernetes server Address. - type: string - type: object - required: - - auth - type: object - oracle: - description: Oracle configures this store to sync secrets using Oracle Vault provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the Oracle Vault. If empty, use the instance principal, otherwise the user credentials specified in Auth. - properties: - secretRef: - description: SecretRef to pass through sensitive information. - properties: - fingerprint: - description: Fingerprint is the fingerprint of the API private key. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - privatekey: - description: PrivateKey is the user's API Signing Key in PEM format, used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - fingerprint - - privatekey - type: object - tenancy: - description: Tenancy is the tenancy OCID where user is located. - type: string - user: - description: User is an access OCID specific to the account. - type: string - required: - - secretRef - - tenancy - - user - type: object - region: - description: Region is the region where vault is located. - type: string - vault: - description: Vault is the vault's OCID of the specific vault where secret is located. - type: string - required: - - region - - vault - type: object - vault: - description: Vault configures this store to sync secrets using Hashi provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the Vault server. - properties: - appRole: - description: AppRole authenticates with Vault using the App Role auth mechanism, with the role and secret stored in a Kubernetes Secret resource. - properties: - path: - default: approle - description: 'Path where the App Role authentication backend is mounted in Vault, e.g: "approle"' - type: string - roleId: - description: RoleID configured in the App Role authentication backend when setting up the authentication backend in Vault. - type: string - secretRef: - description: Reference to a key in a Secret that contains the App Role secret used to authenticate with Vault. The `key` field must be specified and denotes which entry within the Secret resource is used as the app role secret. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - path - - roleId - - secretRef - type: object - cert: - description: Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate Cert authentication method - properties: - clientCert: - description: ClientCert is a certificate to authenticate using the Cert Vault authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - secretRef: - description: SecretRef to a key in a Secret resource containing client private key to authenticate with Vault using the Cert authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - jwt: - description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method - properties: - kubernetesServiceAccountToken: - description: Optional ServiceAccountToken specifies the Kubernetes service account for which to request a token for with the `TokenRequest` API. - properties: - audiences: - description: Optional audiences field that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to a single audience `vault` it not specified. - items: - type: string - type: array - expirationSeconds: - description: Optional expiration time in seconds that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to 10 minutes. - format: int64 - type: integer - serviceAccountRef: - description: Service account field containing the name of a kubernetes ServiceAccount. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - serviceAccountRef - type: object - path: - default: jwt - description: 'Path where the JWT authentication backend is mounted in Vault, e.g: "jwt"' - type: string - role: - description: Role is a JWT role to authenticate using the JWT/OIDC Vault authentication method - type: string - secretRef: - description: Optional SecretRef that refers to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - path - type: object - kubernetes: - description: Kubernetes authenticates with Vault by passing the ServiceAccount token stored in the named Secret resource to the Vault server. - properties: - mountPath: - default: kubernetes - description: 'Path where the Kubernetes authentication backend is mounted in Vault, e.g: "kubernetes"' - type: string - role: - description: A required field containing the Vault Role to assume. A Role binds a Kubernetes ServiceAccount with a set of Vault policies. - type: string - secretRef: - description: Optional secret field containing a Kubernetes ServiceAccount JWT used for authenticating with Vault. If a name is specified without a key, `token` is the default. If one is not specified, the one bound to the controller will be used. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - serviceAccountRef: - description: Optional service account field containing the name of a kubernetes ServiceAccount. If the service account is specified, the service account secret token JWT will be used for authenticating with Vault. If the service account selector is not supplied, the secretRef will be used instead. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - mountPath - - role - type: object - ldap: - description: Ldap authenticates with Vault by passing username/password pair using the LDAP authentication method - properties: - path: - default: ldap - description: 'Path where the LDAP authentication backend is mounted in Vault, e.g: "ldap"' - type: string - secretRef: - description: SecretRef to a key in a Secret resource containing password for the LDAP user used to authenticate with Vault using the LDAP authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - username: - description: Username is a LDAP user name used to authenticate using the LDAP Vault authentication method - type: string - required: - - path - - username - type: object - tokenSecretRef: - description: TokenSecretRef authenticates with Vault by presenting a token. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - caBundle: - description: PEM encoded CA bundle used to validate Vault server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. - format: byte - type: string - caProvider: - description: The provider for the CA bundle to use to validate Vault server certificate. - properties: - key: - description: The key the value inside of the provider type to use, only used with "Secret" type - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - forwardInconsistent: - description: ForwardInconsistent tells Vault to forward read-after-write requests to the Vault leader instead of simply retrying within a loop. This can increase performance if the option is enabled serverside. https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header - type: boolean - namespace: - description: 'Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1". More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces' - type: string - path: - description: 'Path is the mount path of the Vault KV backend endpoint, e.g: "secret". The v2 KV secret engine version specific "/data" path suffix for fetching secrets from Vault is optional and will be appended if not present in specified path.' - type: string - readYourWrites: - description: ReadYourWrites ensures isolated read-after-write semantics by providing discovered cluster replication states in each request. More information about eventual consistency in Vault can be found here https://www.vaultproject.io/docs/enterprise/consistency - type: boolean - server: - description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' - type: string - version: - default: v2 - description: Version is the Vault KV secret engine version. This can be either "v1" or "v2". Version defaults to "v2". - enum: - - v1 - - v2 - type: string - required: - - auth - - server - type: object - webhook: - description: Webhook configures this store to sync secrets using a generic templated webhook - properties: - body: - description: Body - type: string - caBundle: - description: PEM encoded CA bundle used to validate webhook server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. - format: byte - type: string - caProvider: - description: The provider for the CA bundle to use to validate webhook server certificate. - properties: - key: - description: The key the value inside of the provider type to use, only used with "Secret" type - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - headers: - additionalProperties: - type: string - description: Headers - type: object - method: - description: Webhook Method - type: string - result: - description: Result formatting - properties: - jsonPath: - description: Json path of return value - type: string - type: object - secrets: - description: Secrets to fill in templates These secrets will be passed to the templating function as key value pairs under the given name - items: - properties: - name: - description: Name of this secret in templates - type: string - secretRef: - description: Secret ref to fill in credentials - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - name - - secretRef - type: object - type: array - timeout: - description: Timeout - type: string - url: - description: Webhook url to call - type: string - required: - - result - - url - type: object - yandexlockbox: - description: YandexLockbox configures this store to sync secrets using Yandex Lockbox provider - properties: - apiEndpoint: - description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') - type: string - auth: - description: Auth defines the information necessary to authenticate against Yandex Lockbox - properties: - authorizedKeySecretRef: - description: The authorized key used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - caProvider: - description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. - properties: - certSecretRef: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - auth - type: object - type: object - retrySettings: - description: Used to configure http retries if failed - properties: - maxRetries: - format: int32 - type: integer - retryInterval: - type: string - type: object - required: - - provider - type: object - status: - description: SecretStoreStatus defines the observed state of the SecretStore. - properties: - conditions: - items: - properties: - lastTransitionTime: - format: date-time - type: string - message: - type: string - reason: - type: string - status: - type: string - type: - type: string - required: - - status - - type - type: object - type: array - type: object - type: object - served: true - storage: false - subresources: - status: {} - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: AGE - type: date - - jsonPath: .status.conditions[?(@.type=="Ready")].reason - name: Status - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - name: v1beta1 - schema: - openAPIV3Schema: - description: ClusterSecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields. - 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: SecretStoreSpec defines the desired state of SecretStore. - properties: - controller: - description: 'Used to select the correct KES controller (think: ingress.ingressClassName) The KES controller is instantiated with a specific controller name and filters ES based on this property' - type: string - provider: - description: Used to configure the provider. Only one provider may be set - maxProperties: 1 - minProperties: 1 - properties: - akeyless: - description: Akeyless configures this store to sync secrets using Akeyless Vault provider - properties: - akeylessGWApiURL: - description: Akeyless GW API Url from which the secrets to be fetched from. - type: string - authSecretRef: - description: Auth configures how the operator authenticates with Akeyless. - properties: - secretRef: - description: 'AkeylessAuthSecretRef AKEYLESS_ACCESS_TYPE_PARAM: AZURE_OBJ_ID OR GCP_AUDIENCE OR ACCESS_KEY OR KUB_CONFIG_NAME.' - properties: - accessID: - description: The SecretAccessID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessType: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessTypeParam: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - secretRef - type: object - required: - - akeylessGWApiURL - - authSecretRef - type: object - alibaba: - description: Alibaba configures this store to sync secrets using Alibaba Cloud provider - properties: - auth: - description: AlibabaAuth contains a secretRef for credentials. - properties: - secretRef: - description: AlibabaAuthSecretRef holds secret references for Alibaba credentials. - properties: - accessKeyIDSecretRef: - description: The AccessKeyID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessKeySecretSecretRef: - description: The AccessKeySecret is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - accessKeyIDSecretRef - - accessKeySecretSecretRef - type: object - required: - - secretRef - type: object - endpoint: - type: string - regionID: - description: Alibaba Region to be used for the provider - type: string - required: - - auth - - regionID - type: object - aws: - description: AWS configures this store to sync secrets using AWS Secret Manager provider - properties: - auth: - description: 'Auth defines the information necessary to authenticate against AWS if not set aws sdk will infer credentials from your environment see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' - properties: - jwt: - description: Authenticate against AWS using service account tokens. - properties: - serviceAccountRef: - description: A reference to a ServiceAccount resource. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - type: object - secretRef: - description: AWSAuthSecretRef holds secret references for AWS credentials both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. - properties: - accessKeyIDSecretRef: - description: The AccessKeyID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - secretAccessKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - type: object - region: - description: AWS Region to be used for the provider - type: string - role: - description: Role is a Role ARN which the SecretManager provider will assume - type: string - service: - description: Service defines which service should be used to fetch the secrets - enum: - - SecretsManager - - ParameterStore - type: string - required: - - region - - service - type: object - azurekv: - description: AzureKV configures this store to sync secrets using Azure Key Vault provider - properties: - authSecretRef: - description: Auth configures how the operator authenticates with Azure. Required for ServicePrincipal auth type. - properties: - clientId: - description: The Azure clientId of the service principle used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - clientSecret: - description: The Azure ClientSecret of the service principle used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - authType: - default: ServicePrincipal - description: 'Auth type defines how to authenticate to the keyvault service. Valid values are: - "ServicePrincipal" (default): Using a service principal (tenantId, clientId, clientSecret) - "ManagedIdentity": Using Managed Identity assigned to the pod (see aad-pod-identity)' - enum: - - ServicePrincipal - - ManagedIdentity - - WorkloadIdentity - type: string - identityId: - description: If multiple Managed Identity is assigned to the pod, you can select the one to be used - type: string - serviceAccountRef: - description: ServiceAccountRef specified the service account that should be used when authenticating with WorkloadIdentity. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - tenantId: - description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. - type: string - vaultUrl: - description: Vault Url from which the secrets to be fetched from. - type: string - required: - - vaultUrl - type: object - fake: - description: Fake configures a store with static key/value pairs - properties: - data: - items: - properties: - key: - type: string - value: - type: string - valueMap: - additionalProperties: - type: string - type: object - version: - type: string - required: - - key - type: object - type: array - required: - - data - type: object - gcpsm: - description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider - properties: - auth: - description: Auth defines the information necessary to authenticate against GCP - properties: - secretRef: - properties: - secretAccessKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - workloadIdentity: - properties: - clusterLocation: - type: string - clusterName: - type: string - clusterProjectID: - type: string - serviceAccountRef: - description: A reference to a ServiceAccount resource. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - clusterLocation - - clusterName - - serviceAccountRef - type: object - type: object - projectID: - description: ProjectID project where secret is located - type: string - type: object - gitlab: - description: Gitlab configures this store to sync secrets using Gitlab Variables provider - properties: - auth: - description: Auth configures how secret-manager authenticates with a GitLab instance. - properties: - SecretRef: - properties: - accessToken: - description: AccessToken is used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - SecretRef - type: object - projectID: - description: ProjectID specifies a project where secrets are located. - type: string - url: - description: URL configures the GitLab instance URL. Defaults to https://gitlab.com/. - type: string - required: - - auth - type: object - ibm: - description: IBM configures this store to sync secrets using IBM Cloud provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the IBM secrets manager. - maxProperties: 1 - minProperties: 1 - properties: - containerAuth: - description: IBM Container-based auth with IAM Trusted Profile. - properties: - iamEndpoint: - type: string - profile: - description: the IBM Trusted Profile - type: string - tokenLocation: - description: Location the token is mounted on the pod - type: string - required: - - profile - type: object - secretRef: - properties: - secretApiKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - type: object - serviceUrl: - description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance - type: string - required: - - auth - type: object - kubernetes: - description: Kubernetes configures this store to sync secrets using a Kubernetes cluster provider - properties: - auth: - description: Auth configures how secret-manager authenticates with a Kubernetes instance. - maxProperties: 1 - minProperties: 1 - properties: - cert: - description: has both clientCert and clientKey as secretKeySelector - properties: - clientCert: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - clientKey: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - serviceAccount: - description: points to a service account that should be used for authentication - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - token: - description: use static token to authenticate with - properties: - bearerToken: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - type: object - remoteNamespace: - default: default - description: Remote namespace to fetch the secrets from - type: string - server: - description: configures the Kubernetes server Address. - properties: - caBundle: - description: CABundle is a base64-encoded CA certificate - format: byte - type: string - caProvider: - description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider' - properties: - key: - description: The key where the CA certificate can be found in the Secret or ConfigMap. - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. Can only be defined when used in a ClusterSecretStore. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - url: - default: kubernetes.default - description: configures the Kubernetes server Address. - type: string - type: object - required: - - auth - type: object - onepassword: - description: OnePassword configures this store to sync secrets using the 1Password Cloud provider - properties: - auth: - description: Auth defines the information necessary to authenticate against OnePassword Connect Server - properties: - secretRef: - description: OnePasswordAuthSecretRef holds secret references for 1Password credentials. - properties: - connectTokenSecretRef: - description: The ConnectToken is used for authentication to a 1Password Connect Server. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - connectTokenSecretRef - type: object - required: - - secretRef - type: object - connectHost: - description: ConnectHost defines the OnePassword Connect Server to connect to - type: string - vaults: - additionalProperties: - type: integer - description: Vaults defines which OnePassword vaults to search in which order - type: object - required: - - auth - - connectHost - - vaults - type: object - oracle: - description: Oracle configures this store to sync secrets using Oracle Vault provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the Oracle Vault. If empty, use the instance principal, otherwise the user credentials specified in Auth. - properties: - secretRef: - description: SecretRef to pass through sensitive information. - properties: - fingerprint: - description: Fingerprint is the fingerprint of the API private key. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - privatekey: - description: PrivateKey is the user's API Signing Key in PEM format, used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - fingerprint - - privatekey - type: object - tenancy: - description: Tenancy is the tenancy OCID where user is located. - type: string - user: - description: User is an access OCID specific to the account. - type: string - required: - - secretRef - - tenancy - - user - type: object - region: - description: Region is the region where vault is located. - type: string - vault: - description: Vault is the vault's OCID of the specific vault where secret is located. - type: string - required: - - region - - vault - type: object - senhasegura: - description: Senhasegura configures this store to sync secrets using senhasegura provider - properties: - auth: - description: Auth defines parameters to authenticate in senhasegura - properties: - clientId: - type: string - clientSecretSecretRef: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - clientId - - clientSecretSecretRef - type: object - ignoreSslCertificate: - default: false - description: IgnoreSslCertificate defines if SSL certificate must be ignored - type: boolean - module: - description: Module defines which senhasegura module should be used to get secrets - type: string - url: - description: URL of senhasegura - type: string - required: - - auth - - module - - url - type: object - vault: - description: Vault configures this store to sync secrets using Hashi provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the Vault server. - properties: - appRole: - description: AppRole authenticates with Vault using the App Role auth mechanism, with the role and secret stored in a Kubernetes Secret resource. - properties: - path: - default: approle - description: 'Path where the App Role authentication backend is mounted in Vault, e.g: "approle"' - type: string - roleId: - description: RoleID configured in the App Role authentication backend when setting up the authentication backend in Vault. - type: string - secretRef: - description: Reference to a key in a Secret that contains the App Role secret used to authenticate with Vault. The `key` field must be specified and denotes which entry within the Secret resource is used as the app role secret. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - path - - roleId - - secretRef - type: object - cert: - description: Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate Cert authentication method - properties: - clientCert: - description: ClientCert is a certificate to authenticate using the Cert Vault authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - secretRef: - description: SecretRef to a key in a Secret resource containing client private key to authenticate with Vault using the Cert authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - jwt: - description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method - properties: - kubernetesServiceAccountToken: - description: Optional ServiceAccountToken specifies the Kubernetes service account for which to request a token for with the `TokenRequest` API. - properties: - audiences: - description: Optional audiences field that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to a single audience `vault` it not specified. - items: - type: string - type: array - expirationSeconds: - description: Optional expiration time in seconds that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to 10 minutes. - format: int64 - type: integer - serviceAccountRef: - description: Service account field containing the name of a kubernetes ServiceAccount. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - serviceAccountRef - type: object - path: - default: jwt - description: 'Path where the JWT authentication backend is mounted in Vault, e.g: "jwt"' - type: string - role: - description: Role is a JWT role to authenticate using the JWT/OIDC Vault authentication method - type: string - secretRef: - description: Optional SecretRef that refers to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - path - type: object - kubernetes: - description: Kubernetes authenticates with Vault by passing the ServiceAccount token stored in the named Secret resource to the Vault server. - properties: - mountPath: - default: kubernetes - description: 'Path where the Kubernetes authentication backend is mounted in Vault, e.g: "kubernetes"' - type: string - role: - description: A required field containing the Vault Role to assume. A Role binds a Kubernetes ServiceAccount with a set of Vault policies. - type: string - secretRef: - description: Optional secret field containing a Kubernetes ServiceAccount JWT used for authenticating with Vault. If a name is specified without a key, `token` is the default. If one is not specified, the one bound to the controller will be used. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - serviceAccountRef: - description: Optional service account field containing the name of a kubernetes ServiceAccount. If the service account is specified, the service account secret token JWT will be used for authenticating with Vault. If the service account selector is not supplied, the secretRef will be used instead. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - mountPath - - role - type: object - ldap: - description: Ldap authenticates with Vault by passing username/password pair using the LDAP authentication method - properties: - path: - default: ldap - description: 'Path where the LDAP authentication backend is mounted in Vault, e.g: "ldap"' - type: string - secretRef: - description: SecretRef to a key in a Secret resource containing password for the LDAP user used to authenticate with Vault using the LDAP authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - username: - description: Username is a LDAP user name used to authenticate using the LDAP Vault authentication method - type: string - required: - - path - - username - type: object - tokenSecretRef: - description: TokenSecretRef authenticates with Vault by presenting a token. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - caBundle: - description: PEM encoded CA bundle used to validate Vault server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. - format: byte - type: string - caProvider: - description: The provider for the CA bundle to use to validate Vault server certificate. - properties: - key: - description: The key where the CA certificate can be found in the Secret or ConfigMap. - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. Can only be defined when used in a ClusterSecretStore. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - forwardInconsistent: - description: ForwardInconsistent tells Vault to forward read-after-write requests to the Vault leader instead of simply retrying within a loop. This can increase performance if the option is enabled serverside. https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header - type: boolean - namespace: - description: 'Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1". More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces' - type: string - path: - description: 'Path is the mount path of the Vault KV backend endpoint, e.g: "secret". The v2 KV secret engine version specific "/data" path suffix for fetching secrets from Vault is optional and will be appended if not present in specified path.' - type: string - readYourWrites: - description: ReadYourWrites ensures isolated read-after-write semantics by providing discovered cluster replication states in each request. More information about eventual consistency in Vault can be found here https://www.vaultproject.io/docs/enterprise/consistency - type: boolean - server: - description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' - type: string - version: - default: v2 - description: Version is the Vault KV secret engine version. This can be either "v1" or "v2". Version defaults to "v2". - enum: - - v1 - - v2 - type: string - required: - - auth - - server - type: object - webhook: - description: Webhook configures this store to sync secrets using a generic templated webhook - properties: - body: - description: Body - type: string - caBundle: - description: PEM encoded CA bundle used to validate webhook server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. - format: byte - type: string - caProvider: - description: The provider for the CA bundle to use to validate webhook server certificate. - properties: - key: - description: The key the value inside of the provider type to use, only used with "Secret" type - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - headers: - additionalProperties: - type: string - description: Headers - type: object - method: - description: Webhook Method - type: string - result: - description: Result formatting - properties: - jsonPath: - description: Json path of return value - type: string - type: object - secrets: - description: Secrets to fill in templates These secrets will be passed to the templating function as key value pairs under the given name - items: - properties: - name: - description: Name of this secret in templates - type: string - secretRef: - description: Secret ref to fill in credentials - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - name - - secretRef - type: object - type: array - timeout: - description: Timeout - type: string - url: - description: Webhook url to call - type: string - required: - - result - - url - type: object - yandexcertificatemanager: - description: YandexCertificateManager configures this store to sync secrets using Yandex Certificate Manager provider - properties: - apiEndpoint: - description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') - type: string - auth: - description: Auth defines the information necessary to authenticate against Yandex Certificate Manager - properties: - authorizedKeySecretRef: - description: The authorized key used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - caProvider: - description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. - properties: - certSecretRef: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - auth - type: object - yandexlockbox: - description: YandexLockbox configures this store to sync secrets using Yandex Lockbox provider - properties: - apiEndpoint: - description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') - type: string - auth: - description: Auth defines the information necessary to authenticate against Yandex Lockbox - properties: - authorizedKeySecretRef: - description: The authorized key used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - caProvider: - description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. - properties: - certSecretRef: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - auth - type: object - type: object - refreshInterval: - description: Used to configure store refresh interval in seconds. Empty or 0 will default to the controller config. - type: integer - retrySettings: - description: Used to configure http retries if failed - properties: - maxRetries: - format: int32 - type: integer - retryInterval: - type: string - type: object - required: - - provider - type: object - status: - description: SecretStoreStatus defines the observed state of the SecretStore. - properties: - conditions: - items: - properties: - lastTransitionTime: - format: date-time - type: string - message: - type: string - reason: - type: string - status: - type: string - type: - type: string - required: - - status - - type - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} - conversion: - strategy: Webhook - webhook: - conversionReviewVersions: - - v1 - clientConfig: - service: - name: golang-external-secrets-webhook - namespace: "default" - path: /convert ---- -# Source: golang-external-secrets/charts/external-secrets/templates/crds/externalsecret.yaml -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - creationTimestamp: null - name: externalsecrets.external-secrets.io -spec: - group: external-secrets.io - names: - categories: - - externalsecrets - kind: ExternalSecret - listKind: ExternalSecretList - plural: externalsecrets - shortNames: - - es - singular: externalsecret - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.secretStoreRef.name - name: Store - type: string - - jsonPath: .spec.refreshInterval - name: Refresh Interval - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].reason - name: Status - type: string - deprecated: true - name: v1alpha1 - schema: - openAPIV3Schema: - description: ExternalSecret is the Schema for the external-secrets 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: ExternalSecretSpec defines the desired state of ExternalSecret. - properties: - data: - description: Data defines the connection between the Kubernetes Secret keys and the Provider data - items: - description: ExternalSecretData defines the connection between the Kubernetes Secret key (spec.data.) and the Provider data. - properties: - remoteRef: - description: ExternalSecretDataRemoteRef defines Provider data location. - properties: - conversionStrategy: - default: Default - description: Used to define a conversion Strategy - type: string - key: - description: Key is the key used in the Provider, mandatory - type: string - property: - description: Used to select a specific property of the Provider value (if a map), if supported - type: string - version: - description: Used to select a specific version of the Provider value, if supported - type: string - required: - - key - type: object - secretKey: - type: string - required: - - remoteRef - - secretKey - type: object - type: array - dataFrom: - description: DataFrom is used to fetch all properties from a specific Provider data If multiple entries are specified, the Secret keys are merged in the specified order - items: - description: ExternalSecretDataRemoteRef defines Provider data location. - properties: - conversionStrategy: - default: Default - description: Used to define a conversion Strategy - type: string - key: - description: Key is the key used in the Provider, mandatory - type: string - property: - description: Used to select a specific property of the Provider value (if a map), if supported - type: string - version: - description: Used to select a specific version of the Provider value, if supported - type: string - required: - - key - type: object - type: array - refreshInterval: - default: 1h - description: RefreshInterval is the amount of time before the values are read again from the SecretStore provider Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h" May be set to zero to fetch and create it once. Defaults to 1h. - type: string - secretStoreRef: - description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret data. - properties: - kind: - description: Kind of the SecretStore resource (SecretStore or ClusterSecretStore) Defaults to `SecretStore` - type: string - name: - description: Name of the SecretStore resource - type: string - required: - - name - type: object - target: - description: ExternalSecretTarget defines the Kubernetes Secret to be created There can be only one target per ExternalSecret. - properties: - creationPolicy: - default: Owner - description: CreationPolicy defines rules on how to create the resulting Secret Defaults to 'Owner' - type: string - immutable: - description: Immutable defines if the final secret will be immutable - type: boolean - name: - description: Name defines the name of the Secret resource to be managed This field is immutable Defaults to the .metadata.name of the ExternalSecret resource - type: string - template: - description: Template defines a blueprint for the created Secret resource. - properties: - data: - additionalProperties: - type: string - type: object - engineVersion: - default: v1 - description: EngineVersion specifies the template engine version that should be used to compile/execute the template specified in .data and .templateFrom[]. - type: string - metadata: - description: ExternalSecretTemplateMetadata defines metadata fields for the Secret blueprint. - properties: - annotations: - additionalProperties: - type: string - type: object - labels: - additionalProperties: - type: string - type: object - type: object - templateFrom: - items: - maxProperties: 1 - minProperties: 1 - properties: - configMap: - properties: - items: - items: - properties: - key: - type: string - required: - - key - type: object - type: array - name: - type: string - required: - - items - - name - type: object - secret: - properties: - items: - items: - properties: - key: - type: string - required: - - key - type: object - type: array - name: - type: string - required: - - items - - name - type: object - type: object - type: array - type: - type: string - type: object - type: object - required: - - secretStoreRef - - target - type: object - status: - properties: - conditions: - items: - properties: - lastTransitionTime: - format: date-time - type: string - message: - type: string - reason: - type: string - status: - type: string - type: - type: string - required: - - status - - type - type: object - type: array - refreshTime: - description: refreshTime is the time and date the external secret was fetched and the target secret updated - format: date-time - nullable: true - type: string - syncedResourceVersion: - description: SyncedResourceVersion keeps track of the last synced version - type: string - type: object - type: object - served: true - storage: false - subresources: - status: {} - - additionalPrinterColumns: - - jsonPath: .spec.secretStoreRef.name - name: Store - type: string - - jsonPath: .spec.refreshInterval - name: Refresh Interval - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].reason - name: Status - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - name: v1beta1 - schema: - openAPIV3Schema: - description: ExternalSecret is the Schema for the external-secrets 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: ExternalSecretSpec defines the desired state of ExternalSecret. - properties: - data: - description: Data defines the connection between the Kubernetes Secret keys and the Provider data - items: - description: ExternalSecretData defines the connection between the Kubernetes Secret key (spec.data.) and the Provider data. - properties: - remoteRef: - description: ExternalSecretDataRemoteRef defines Provider data location. - properties: - conversionStrategy: - default: Default - description: Used to define a conversion Strategy - type: string - decodingStrategy: - default: None - description: Used to define a decoding Strategy - type: string - key: - description: Key is the key used in the Provider, mandatory - type: string - metadataPolicy: - description: Policy for fetching tags/labels from provider secrets, possible options are Fetch, None. Defaults to None - type: string - property: - description: Used to select a specific property of the Provider value (if a map), if supported - type: string - version: - description: Used to select a specific version of the Provider value, if supported - type: string - required: - - key - type: object - secretKey: - type: string - required: - - remoteRef - - secretKey - type: object - type: array - dataFrom: - description: DataFrom is used to fetch all properties from a specific Provider data If multiple entries are specified, the Secret keys are merged in the specified order - items: - properties: - extract: - description: Used to extract multiple key/value pairs from one secret - properties: - conversionStrategy: - default: Default - description: Used to define a conversion Strategy - type: string - decodingStrategy: - default: None - description: Used to define a decoding Strategy - type: string - key: - description: Key is the key used in the Provider, mandatory - type: string - metadataPolicy: - description: Policy for fetching tags/labels from provider secrets, possible options are Fetch, None. Defaults to None - type: string - property: - description: Used to select a specific property of the Provider value (if a map), if supported - type: string - version: - description: Used to select a specific version of the Provider value, if supported - type: string - required: - - key - type: object - find: - description: Used to find secrets based on tags or regular expressions - properties: - conversionStrategy: - default: Default - description: Used to define a conversion Strategy - type: string - decodingStrategy: - default: None - description: Used to define a decoding Strategy - type: string - name: - description: Finds secrets based on the name. - properties: - regexp: - description: Finds secrets base - type: string - type: object - path: - description: A root path to start the find operations. - type: string - tags: - additionalProperties: - type: string - description: Find secrets based on tags. - type: object - type: object - rewrite: - description: Used to rewrite secret Keys after getting them from the secret Provider Multiple Rewrite operations can be provided. They are applied in a layered order (first to last) - items: - properties: - regexp: - description: Used to rewrite with regular expressions. The resulting key will be the output of a regexp.ReplaceAll operation. - properties: - source: - description: Used to define the regular expression of a re.Compiler. - type: string - target: - description: Used to define the target pattern of a ReplaceAll operation. - type: string - required: - - source - - target - type: object - type: object - type: array - type: object - type: array - refreshInterval: - default: 1h - description: RefreshInterval is the amount of time before the values are read again from the SecretStore provider Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h" May be set to zero to fetch and create it once. Defaults to 1h. - type: string - secretStoreRef: - description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret data. - properties: - kind: - description: Kind of the SecretStore resource (SecretStore or ClusterSecretStore) Defaults to `SecretStore` - type: string - name: - description: Name of the SecretStore resource - type: string - required: - - name - type: object - target: - description: ExternalSecretTarget defines the Kubernetes Secret to be created There can be only one target per ExternalSecret. - properties: - creationPolicy: - default: Owner - description: CreationPolicy defines rules on how to create the resulting Secret Defaults to 'Owner' - enum: - - Owner - - Orphan - - Merge - - None - type: string - deletionPolicy: - default: Retain - description: DeletionPolicy defines rules on how to delete the resulting Secret Defaults to 'Retain' - enum: - - Delete - - Merge - - Retain - type: string - immutable: - description: Immutable defines if the final secret will be immutable - type: boolean - name: - description: Name defines the name of the Secret resource to be managed This field is immutable Defaults to the .metadata.name of the ExternalSecret resource - type: string - template: - description: Template defines a blueprint for the created Secret resource. - properties: - data: - additionalProperties: - type: string - type: object - engineVersion: - default: v2 - type: string - metadata: - description: ExternalSecretTemplateMetadata defines metadata fields for the Secret blueprint. - properties: - annotations: - additionalProperties: - type: string - type: object - labels: - additionalProperties: - type: string - type: object - type: object - templateFrom: - items: - maxProperties: 1 - minProperties: 1 - properties: - configMap: - properties: - items: - items: - properties: - key: - type: string - required: - - key - type: object - type: array - name: - type: string - required: - - items - - name - type: object - secret: - properties: - items: - items: - properties: - key: - type: string - required: - - key - type: object - type: array - name: - type: string - required: - - items - - name - type: object - type: object - type: array - type: - type: string - type: object - type: object - required: - - secretStoreRef - type: object - status: - properties: - conditions: - items: - properties: - lastTransitionTime: - format: date-time - type: string - message: - type: string - reason: - type: string - status: - type: string - type: - type: string - required: - - status - - type - type: object - type: array - refreshTime: - description: refreshTime is the time and date the external secret was fetched and the target secret updated - format: date-time - nullable: true - type: string - syncedResourceVersion: - description: SyncedResourceVersion keeps track of the last synced version - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} - conversion: - strategy: Webhook - webhook: - conversionReviewVersions: - - v1 - clientConfig: - service: - name: golang-external-secrets-webhook - namespace: "default" - path: /convert ---- -# Source: golang-external-secrets/charts/external-secrets/templates/crds/secretstore.yaml -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - creationTimestamp: null - name: secretstores.external-secrets.io -spec: - group: external-secrets.io - names: - categories: - - externalsecrets - kind: SecretStore - listKind: SecretStoreList - plural: secretstores - shortNames: - - ss - singular: secretstore - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: AGE - type: date - - jsonPath: .status.conditions[?(@.type=="Ready")].reason - name: Status - type: string - deprecated: true - name: v1alpha1 - schema: - openAPIV3Schema: - description: SecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields. - 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: SecretStoreSpec defines the desired state of SecretStore. - properties: - controller: - description: 'Used to select the correct KES controller (think: ingress.ingressClassName) The KES controller is instantiated with a specific controller name and filters ES based on this property' - type: string - provider: - description: Used to configure the provider. Only one provider may be set - maxProperties: 1 - minProperties: 1 - properties: - akeyless: - description: Akeyless configures this store to sync secrets using Akeyless Vault provider - properties: - akeylessGWApiURL: - description: Akeyless GW API Url from which the secrets to be fetched from. - type: string - authSecretRef: - description: Auth configures how the operator authenticates with Akeyless. - properties: - secretRef: - description: 'AkeylessAuthSecretRef AKEYLESS_ACCESS_TYPE_PARAM: AZURE_OBJ_ID OR GCP_AUDIENCE OR ACCESS_KEY OR KUB_CONFIG_NAME.' - properties: - accessID: - description: The SecretAccessID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessType: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessTypeParam: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - secretRef - type: object - required: - - akeylessGWApiURL - - authSecretRef - type: object - alibaba: - description: Alibaba configures this store to sync secrets using Alibaba Cloud provider - properties: - auth: - description: AlibabaAuth contains a secretRef for credentials. - properties: - secretRef: - description: AlibabaAuthSecretRef holds secret references for Alibaba credentials. - properties: - accessKeyIDSecretRef: - description: The AccessKeyID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessKeySecretSecretRef: - description: The AccessKeySecret is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - accessKeyIDSecretRef - - accessKeySecretSecretRef - type: object - required: - - secretRef - type: object - endpoint: - type: string - regionID: - description: Alibaba Region to be used for the provider - type: string - required: - - auth - - regionID - type: object - aws: - description: AWS configures this store to sync secrets using AWS Secret Manager provider - properties: - auth: - description: 'Auth defines the information necessary to authenticate against AWS if not set aws sdk will infer credentials from your environment see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' - properties: - jwt: - description: Authenticate against AWS using service account tokens. - properties: - serviceAccountRef: - description: A reference to a ServiceAccount resource. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - type: object - secretRef: - description: AWSAuthSecretRef holds secret references for AWS credentials both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. - properties: - accessKeyIDSecretRef: - description: The AccessKeyID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - secretAccessKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - type: object - region: - description: AWS Region to be used for the provider - type: string - role: - description: Role is a Role ARN which the SecretManager provider will assume - type: string - service: - description: Service defines which service should be used to fetch the secrets - enum: - - SecretsManager - - ParameterStore - type: string - required: - - region - - service - type: object - azurekv: - description: AzureKV configures this store to sync secrets using Azure Key Vault provider - properties: - authSecretRef: - description: Auth configures how the operator authenticates with Azure. Required for ServicePrincipal auth type. - properties: - clientId: - description: The Azure clientId of the service principle used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - clientSecret: - description: The Azure ClientSecret of the service principle used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - authType: - default: ServicePrincipal - description: 'Auth type defines how to authenticate to the keyvault service. Valid values are: - "ServicePrincipal" (default): Using a service principal (tenantId, clientId, clientSecret) - "ManagedIdentity": Using Managed Identity assigned to the pod (see aad-pod-identity)' - enum: - - ServicePrincipal - - ManagedIdentity - - WorkloadIdentity - type: string - identityId: - description: If multiple Managed Identity is assigned to the pod, you can select the one to be used - type: string - serviceAccountRef: - description: ServiceAccountRef specified the service account that should be used when authenticating with WorkloadIdentity. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - tenantId: - description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. - type: string - vaultUrl: - description: Vault Url from which the secrets to be fetched from. - type: string - required: - - vaultUrl - type: object - fake: - description: Fake configures a store with static key/value pairs - properties: - data: - items: - properties: - key: - type: string - value: - type: string - valueMap: - additionalProperties: - type: string - type: object - version: - type: string - required: - - key - type: object - type: array - required: - - data - type: object - gcpsm: - description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider - properties: - auth: - description: Auth defines the information necessary to authenticate against GCP - properties: - secretRef: - properties: - secretAccessKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - workloadIdentity: - properties: - clusterLocation: - type: string - clusterName: - type: string - clusterProjectID: - type: string - serviceAccountRef: - description: A reference to a ServiceAccount resource. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - clusterLocation - - clusterName - - serviceAccountRef - type: object - type: object - projectID: - description: ProjectID project where secret is located - type: string - type: object - gitlab: - description: Gitlab configures this store to sync secrets using Gitlab Variables provider - properties: - auth: - description: Auth configures how secret-manager authenticates with a GitLab instance. - properties: - SecretRef: - properties: - accessToken: - description: AccessToken is used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - SecretRef - type: object - projectID: - description: ProjectID specifies a project where secrets are located. - type: string - url: - description: URL configures the GitLab instance URL. Defaults to https://gitlab.com/. - type: string - required: - - auth - type: object - ibm: - description: IBM configures this store to sync secrets using IBM Cloud provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the IBM secrets manager. - properties: - secretRef: - properties: - secretApiKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - secretRef - type: object - serviceUrl: - description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance - type: string - required: - - auth - type: object - kubernetes: - description: Kubernetes configures this store to sync secrets using a Kubernetes cluster provider - properties: - auth: - description: Auth configures how secret-manager authenticates with a Kubernetes instance. - maxProperties: 1 - minProperties: 1 - properties: - cert: - description: has both clientCert and clientKey as secretKeySelector - properties: - clientCert: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - clientKey: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - serviceAccount: - description: points to a service account that should be used for authentication - properties: - serviceAccount: - description: A reference to a ServiceAccount resource. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - type: object - token: - description: use static token to authenticate with - properties: - bearerToken: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - type: object - remoteNamespace: - default: default - description: Remote namespace to fetch the secrets from - type: string - server: - description: configures the Kubernetes server Address. - properties: - caBundle: - description: CABundle is a base64-encoded CA certificate - format: byte - type: string - caProvider: - description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider' - properties: - key: - description: The key the value inside of the provider type to use, only used with "Secret" type - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - url: - default: kubernetes.default - description: configures the Kubernetes server Address. - type: string - type: object - required: - - auth - type: object - oracle: - description: Oracle configures this store to sync secrets using Oracle Vault provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the Oracle Vault. If empty, use the instance principal, otherwise the user credentials specified in Auth. - properties: - secretRef: - description: SecretRef to pass through sensitive information. - properties: - fingerprint: - description: Fingerprint is the fingerprint of the API private key. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - privatekey: - description: PrivateKey is the user's API Signing Key in PEM format, used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - fingerprint - - privatekey - type: object - tenancy: - description: Tenancy is the tenancy OCID where user is located. - type: string - user: - description: User is an access OCID specific to the account. - type: string - required: - - secretRef - - tenancy - - user - type: object - region: - description: Region is the region where vault is located. - type: string - vault: - description: Vault is the vault's OCID of the specific vault where secret is located. - type: string - required: - - region - - vault - type: object - vault: - description: Vault configures this store to sync secrets using Hashi provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the Vault server. - properties: - appRole: - description: AppRole authenticates with Vault using the App Role auth mechanism, with the role and secret stored in a Kubernetes Secret resource. - properties: - path: - default: approle - description: 'Path where the App Role authentication backend is mounted in Vault, e.g: "approle"' - type: string - roleId: - description: RoleID configured in the App Role authentication backend when setting up the authentication backend in Vault. - type: string - secretRef: - description: Reference to a key in a Secret that contains the App Role secret used to authenticate with Vault. The `key` field must be specified and denotes which entry within the Secret resource is used as the app role secret. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - path - - roleId - - secretRef - type: object - cert: - description: Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate Cert authentication method - properties: - clientCert: - description: ClientCert is a certificate to authenticate using the Cert Vault authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - secretRef: - description: SecretRef to a key in a Secret resource containing client private key to authenticate with Vault using the Cert authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - jwt: - description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method - properties: - kubernetesServiceAccountToken: - description: Optional ServiceAccountToken specifies the Kubernetes service account for which to request a token for with the `TokenRequest` API. - properties: - audiences: - description: Optional audiences field that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to a single audience `vault` it not specified. - items: - type: string - type: array - expirationSeconds: - description: Optional expiration time in seconds that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to 10 minutes. - format: int64 - type: integer - serviceAccountRef: - description: Service account field containing the name of a kubernetes ServiceAccount. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - serviceAccountRef - type: object - path: - default: jwt - description: 'Path where the JWT authentication backend is mounted in Vault, e.g: "jwt"' - type: string - role: - description: Role is a JWT role to authenticate using the JWT/OIDC Vault authentication method - type: string - secretRef: - description: Optional SecretRef that refers to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - path - type: object - kubernetes: - description: Kubernetes authenticates with Vault by passing the ServiceAccount token stored in the named Secret resource to the Vault server. - properties: - mountPath: - default: kubernetes - description: 'Path where the Kubernetes authentication backend is mounted in Vault, e.g: "kubernetes"' - type: string - role: - description: A required field containing the Vault Role to assume. A Role binds a Kubernetes ServiceAccount with a set of Vault policies. - type: string - secretRef: - description: Optional secret field containing a Kubernetes ServiceAccount JWT used for authenticating with Vault. If a name is specified without a key, `token` is the default. If one is not specified, the one bound to the controller will be used. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - serviceAccountRef: - description: Optional service account field containing the name of a kubernetes ServiceAccount. If the service account is specified, the service account secret token JWT will be used for authenticating with Vault. If the service account selector is not supplied, the secretRef will be used instead. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - mountPath - - role - type: object - ldap: - description: Ldap authenticates with Vault by passing username/password pair using the LDAP authentication method - properties: - path: - default: ldap - description: 'Path where the LDAP authentication backend is mounted in Vault, e.g: "ldap"' - type: string - secretRef: - description: SecretRef to a key in a Secret resource containing password for the LDAP user used to authenticate with Vault using the LDAP authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - username: - description: Username is a LDAP user name used to authenticate using the LDAP Vault authentication method - type: string - required: - - path - - username - type: object - tokenSecretRef: - description: TokenSecretRef authenticates with Vault by presenting a token. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - caBundle: - description: PEM encoded CA bundle used to validate Vault server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. - format: byte - type: string - caProvider: - description: The provider for the CA bundle to use to validate Vault server certificate. - properties: - key: - description: The key the value inside of the provider type to use, only used with "Secret" type - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - forwardInconsistent: - description: ForwardInconsistent tells Vault to forward read-after-write requests to the Vault leader instead of simply retrying within a loop. This can increase performance if the option is enabled serverside. https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header - type: boolean - namespace: - description: 'Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1". More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces' - type: string - path: - description: 'Path is the mount path of the Vault KV backend endpoint, e.g: "secret". The v2 KV secret engine version specific "/data" path suffix for fetching secrets from Vault is optional and will be appended if not present in specified path.' - type: string - readYourWrites: - description: ReadYourWrites ensures isolated read-after-write semantics by providing discovered cluster replication states in each request. More information about eventual consistency in Vault can be found here https://www.vaultproject.io/docs/enterprise/consistency - type: boolean - server: - description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' - type: string - version: - default: v2 - description: Version is the Vault KV secret engine version. This can be either "v1" or "v2". Version defaults to "v2". - enum: - - v1 - - v2 - type: string - required: - - auth - - server - type: object - webhook: - description: Webhook configures this store to sync secrets using a generic templated webhook - properties: - body: - description: Body - type: string - caBundle: - description: PEM encoded CA bundle used to validate webhook server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. - format: byte - type: string - caProvider: - description: The provider for the CA bundle to use to validate webhook server certificate. - properties: - key: - description: The key the value inside of the provider type to use, only used with "Secret" type - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - headers: - additionalProperties: - type: string - description: Headers - type: object - method: - description: Webhook Method - type: string - result: - description: Result formatting - properties: - jsonPath: - description: Json path of return value - type: string - type: object - secrets: - description: Secrets to fill in templates These secrets will be passed to the templating function as key value pairs under the given name - items: - properties: - name: - description: Name of this secret in templates - type: string - secretRef: - description: Secret ref to fill in credentials - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - name - - secretRef - type: object - type: array - timeout: - description: Timeout - type: string - url: - description: Webhook url to call - type: string - required: - - result - - url - type: object - yandexlockbox: - description: YandexLockbox configures this store to sync secrets using Yandex Lockbox provider - properties: - apiEndpoint: - description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') - type: string - auth: - description: Auth defines the information necessary to authenticate against Yandex Lockbox - properties: - authorizedKeySecretRef: - description: The authorized key used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - caProvider: - description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. - properties: - certSecretRef: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - auth - type: object - type: object - retrySettings: - description: Used to configure http retries if failed - properties: - maxRetries: - format: int32 - type: integer - retryInterval: - type: string - type: object - required: - - provider - type: object - status: - description: SecretStoreStatus defines the observed state of the SecretStore. - properties: - conditions: - items: - properties: - lastTransitionTime: - format: date-time - type: string - message: - type: string - reason: - type: string - status: - type: string - type: - type: string - required: - - status - - type - type: object - type: array - type: object - type: object - served: true - storage: false - subresources: - status: {} - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: AGE - type: date - - jsonPath: .status.conditions[?(@.type=="Ready")].reason - name: Status - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - name: v1beta1 - schema: - openAPIV3Schema: - description: SecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields. - 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: SecretStoreSpec defines the desired state of SecretStore. - properties: - controller: - description: 'Used to select the correct KES controller (think: ingress.ingressClassName) The KES controller is instantiated with a specific controller name and filters ES based on this property' - type: string - provider: - description: Used to configure the provider. Only one provider may be set - maxProperties: 1 - minProperties: 1 - properties: - akeyless: - description: Akeyless configures this store to sync secrets using Akeyless Vault provider - properties: - akeylessGWApiURL: - description: Akeyless GW API Url from which the secrets to be fetched from. - type: string - authSecretRef: - description: Auth configures how the operator authenticates with Akeyless. - properties: - secretRef: - description: 'AkeylessAuthSecretRef AKEYLESS_ACCESS_TYPE_PARAM: AZURE_OBJ_ID OR GCP_AUDIENCE OR ACCESS_KEY OR KUB_CONFIG_NAME.' - properties: - accessID: - description: The SecretAccessID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessType: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessTypeParam: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - secretRef - type: object - required: - - akeylessGWApiURL - - authSecretRef - type: object - alibaba: - description: Alibaba configures this store to sync secrets using Alibaba Cloud provider - properties: - auth: - description: AlibabaAuth contains a secretRef for credentials. - properties: - secretRef: - description: AlibabaAuthSecretRef holds secret references for Alibaba credentials. - properties: - accessKeyIDSecretRef: - description: The AccessKeyID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - accessKeySecretSecretRef: - description: The AccessKeySecret is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - accessKeyIDSecretRef - - accessKeySecretSecretRef - type: object - required: - - secretRef - type: object - endpoint: - type: string - regionID: - description: Alibaba Region to be used for the provider - type: string - required: - - auth - - regionID - type: object - aws: - description: AWS configures this store to sync secrets using AWS Secret Manager provider - properties: - auth: - description: 'Auth defines the information necessary to authenticate against AWS if not set aws sdk will infer credentials from your environment see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' - properties: - jwt: - description: Authenticate against AWS using service account tokens. - properties: - serviceAccountRef: - description: A reference to a ServiceAccount resource. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - type: object - secretRef: - description: AWSAuthSecretRef holds secret references for AWS credentials both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. - properties: - accessKeyIDSecretRef: - description: The AccessKeyID is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - secretAccessKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - type: object - region: - description: AWS Region to be used for the provider - type: string - role: - description: Role is a Role ARN which the SecretManager provider will assume - type: string - service: - description: Service defines which service should be used to fetch the secrets - enum: - - SecretsManager - - ParameterStore - type: string - required: - - region - - service - type: object - azurekv: - description: AzureKV configures this store to sync secrets using Azure Key Vault provider - properties: - authSecretRef: - description: Auth configures how the operator authenticates with Azure. Required for ServicePrincipal auth type. - properties: - clientId: - description: The Azure clientId of the service principle used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - clientSecret: - description: The Azure ClientSecret of the service principle used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - authType: - default: ServicePrincipal - description: 'Auth type defines how to authenticate to the keyvault service. Valid values are: - "ServicePrincipal" (default): Using a service principal (tenantId, clientId, clientSecret) - "ManagedIdentity": Using Managed Identity assigned to the pod (see aad-pod-identity)' - enum: - - ServicePrincipal - - ManagedIdentity - - WorkloadIdentity - type: string - identityId: - description: If multiple Managed Identity is assigned to the pod, you can select the one to be used - type: string - serviceAccountRef: - description: ServiceAccountRef specified the service account that should be used when authenticating with WorkloadIdentity. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - tenantId: - description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. - type: string - vaultUrl: - description: Vault Url from which the secrets to be fetched from. - type: string - required: - - vaultUrl - type: object - fake: - description: Fake configures a store with static key/value pairs - properties: - data: - items: - properties: - key: - type: string - value: - type: string - valueMap: - additionalProperties: - type: string - type: object - version: - type: string - required: - - key - type: object - type: array - required: - - data - type: object - gcpsm: - description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider - properties: - auth: - description: Auth defines the information necessary to authenticate against GCP - properties: - secretRef: - properties: - secretAccessKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - workloadIdentity: - properties: - clusterLocation: - type: string - clusterName: - type: string - clusterProjectID: - type: string - serviceAccountRef: - description: A reference to a ServiceAccount resource. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - clusterLocation - - clusterName - - serviceAccountRef - type: object - type: object - projectID: - description: ProjectID project where secret is located - type: string - type: object - gitlab: - description: Gitlab configures this store to sync secrets using Gitlab Variables provider - properties: - auth: - description: Auth configures how secret-manager authenticates with a GitLab instance. - properties: - SecretRef: - properties: - accessToken: - description: AccessToken is used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - SecretRef - type: object - projectID: - description: ProjectID specifies a project where secrets are located. - type: string - url: - description: URL configures the GitLab instance URL. Defaults to https://gitlab.com/. - type: string - required: - - auth - type: object - ibm: - description: IBM configures this store to sync secrets using IBM Cloud provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the IBM secrets manager. - maxProperties: 1 - minProperties: 1 - properties: - containerAuth: - description: IBM Container-based auth with IAM Trusted Profile. - properties: - iamEndpoint: - type: string - profile: - description: the IBM Trusted Profile - type: string - tokenLocation: - description: Location the token is mounted on the pod - type: string - required: - - profile - type: object - secretRef: - properties: - secretApiKeySecretRef: - description: The SecretAccessKey is used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - type: object - serviceUrl: - description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance - type: string - required: - - auth - type: object - kubernetes: - description: Kubernetes configures this store to sync secrets using a Kubernetes cluster provider - properties: - auth: - description: Auth configures how secret-manager authenticates with a Kubernetes instance. - maxProperties: 1 - minProperties: 1 - properties: - cert: - description: has both clientCert and clientKey as secretKeySelector - properties: - clientCert: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - clientKey: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - serviceAccount: - description: points to a service account that should be used for authentication - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - token: - description: use static token to authenticate with - properties: - bearerToken: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - type: object - remoteNamespace: - default: default - description: Remote namespace to fetch the secrets from - type: string - server: - description: configures the Kubernetes server Address. - properties: - caBundle: - description: CABundle is a base64-encoded CA certificate - format: byte - type: string - caProvider: - description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider' - properties: - key: - description: The key where the CA certificate can be found in the Secret or ConfigMap. - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. Can only be defined when used in a ClusterSecretStore. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - url: - default: kubernetes.default - description: configures the Kubernetes server Address. - type: string - type: object - required: - - auth - type: object - onepassword: - description: OnePassword configures this store to sync secrets using the 1Password Cloud provider - properties: - auth: - description: Auth defines the information necessary to authenticate against OnePassword Connect Server - properties: - secretRef: - description: OnePasswordAuthSecretRef holds secret references for 1Password credentials. - properties: - connectTokenSecretRef: - description: The ConnectToken is used for authentication to a 1Password Connect Server. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - connectTokenSecretRef - type: object - required: - - secretRef - type: object - connectHost: - description: ConnectHost defines the OnePassword Connect Server to connect to - type: string - vaults: - additionalProperties: - type: integer - description: Vaults defines which OnePassword vaults to search in which order - type: object - required: - - auth - - connectHost - - vaults - type: object - oracle: - description: Oracle configures this store to sync secrets using Oracle Vault provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the Oracle Vault. If empty, use the instance principal, otherwise the user credentials specified in Auth. - properties: - secretRef: - description: SecretRef to pass through sensitive information. - properties: - fingerprint: - description: Fingerprint is the fingerprint of the API private key. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - privatekey: - description: PrivateKey is the user's API Signing Key in PEM format, used for authentication. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - fingerprint - - privatekey - type: object - tenancy: - description: Tenancy is the tenancy OCID where user is located. - type: string - user: - description: User is an access OCID specific to the account. - type: string - required: - - secretRef - - tenancy - - user - type: object - region: - description: Region is the region where vault is located. - type: string - vault: - description: Vault is the vault's OCID of the specific vault where secret is located. - type: string - required: - - region - - vault - type: object - senhasegura: - description: Senhasegura configures this store to sync secrets using senhasegura provider - properties: - auth: - description: Auth defines parameters to authenticate in senhasegura - properties: - clientId: - type: string - clientSecretSecretRef: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - clientId - - clientSecretSecretRef - type: object - ignoreSslCertificate: - default: false - description: IgnoreSslCertificate defines if SSL certificate must be ignored - type: boolean - module: - description: Module defines which senhasegura module should be used to get secrets - type: string - url: - description: URL of senhasegura - type: string - required: - - auth - - module - - url - type: object - vault: - description: Vault configures this store to sync secrets using Hashi provider - properties: - auth: - description: Auth configures how secret-manager authenticates with the Vault server. - properties: - appRole: - description: AppRole authenticates with Vault using the App Role auth mechanism, with the role and secret stored in a Kubernetes Secret resource. - properties: - path: - default: approle - description: 'Path where the App Role authentication backend is mounted in Vault, e.g: "approle"' - type: string - roleId: - description: RoleID configured in the App Role authentication backend when setting up the authentication backend in Vault. - type: string - secretRef: - description: Reference to a key in a Secret that contains the App Role secret used to authenticate with Vault. The `key` field must be specified and denotes which entry within the Secret resource is used as the app role secret. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - path - - roleId - - secretRef - type: object - cert: - description: Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate Cert authentication method - properties: - clientCert: - description: ClientCert is a certificate to authenticate using the Cert Vault authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - secretRef: - description: SecretRef to a key in a Secret resource containing client private key to authenticate with Vault using the Cert authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - jwt: - description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method - properties: - kubernetesServiceAccountToken: - description: Optional ServiceAccountToken specifies the Kubernetes service account for which to request a token for with the `TokenRequest` API. - properties: - audiences: - description: Optional audiences field that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to a single audience `vault` it not specified. - items: - type: string - type: array - expirationSeconds: - description: Optional expiration time in seconds that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to 10 minutes. - format: int64 - type: integer - serviceAccountRef: - description: Service account field containing the name of a kubernetes ServiceAccount. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - serviceAccountRef - type: object - path: - default: jwt - description: 'Path where the JWT authentication backend is mounted in Vault, e.g: "jwt"' - type: string - role: - description: Role is a JWT role to authenticate using the JWT/OIDC Vault authentication method - type: string - secretRef: - description: Optional SecretRef that refers to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - path - type: object - kubernetes: - description: Kubernetes authenticates with Vault by passing the ServiceAccount token stored in the named Secret resource to the Vault server. - properties: - mountPath: - default: kubernetes - description: 'Path where the Kubernetes authentication backend is mounted in Vault, e.g: "kubernetes"' - type: string - role: - description: A required field containing the Vault Role to assume. A Role binds a Kubernetes ServiceAccount with a set of Vault policies. - type: string - secretRef: - description: Optional secret field containing a Kubernetes ServiceAccount JWT used for authenticating with Vault. If a name is specified without a key, `token` is the default. If one is not specified, the one bound to the controller will be used. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - serviceAccountRef: - description: Optional service account field containing the name of a kubernetes ServiceAccount. If the service account is specified, the service account secret token JWT will be used for authenticating with Vault. If the service account selector is not supplied, the secretRef will be used instead. - properties: - name: - description: The name of the ServiceAccount resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - required: - - name - type: object - required: - - mountPath - - role - type: object - ldap: - description: Ldap authenticates with Vault by passing username/password pair using the LDAP authentication method - properties: - path: - default: ldap - description: 'Path where the LDAP authentication backend is mounted in Vault, e.g: "ldap"' - type: string - secretRef: - description: SecretRef to a key in a Secret resource containing password for the LDAP user used to authenticate with Vault using the LDAP authentication method - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - username: - description: Username is a LDAP user name used to authenticate using the LDAP Vault authentication method - type: string - required: - - path - - username - type: object - tokenSecretRef: - description: TokenSecretRef authenticates with Vault by presenting a token. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - caBundle: - description: PEM encoded CA bundle used to validate Vault server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. - format: byte - type: string - caProvider: - description: The provider for the CA bundle to use to validate Vault server certificate. - properties: - key: - description: The key where the CA certificate can be found in the Secret or ConfigMap. - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. Can only be defined when used in a ClusterSecretStore. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - forwardInconsistent: - description: ForwardInconsistent tells Vault to forward read-after-write requests to the Vault leader instead of simply retrying within a loop. This can increase performance if the option is enabled serverside. https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header - type: boolean - namespace: - description: 'Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1". More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces' - type: string - path: - description: 'Path is the mount path of the Vault KV backend endpoint, e.g: "secret". The v2 KV secret engine version specific "/data" path suffix for fetching secrets from Vault is optional and will be appended if not present in specified path.' - type: string - readYourWrites: - description: ReadYourWrites ensures isolated read-after-write semantics by providing discovered cluster replication states in each request. More information about eventual consistency in Vault can be found here https://www.vaultproject.io/docs/enterprise/consistency - type: boolean - server: - description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' - type: string - version: - default: v2 - description: Version is the Vault KV secret engine version. This can be either "v1" or "v2". Version defaults to "v2". - enum: - - v1 - - v2 - type: string - required: - - auth - - server - type: object - webhook: - description: Webhook configures this store to sync secrets using a generic templated webhook - properties: - body: - description: Body - type: string - caBundle: - description: PEM encoded CA bundle used to validate webhook server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. - format: byte - type: string - caProvider: - description: The provider for the CA bundle to use to validate webhook server certificate. - properties: - key: - description: The key the value inside of the provider type to use, only used with "Secret" type - type: string - name: - description: The name of the object located at the provider type. - type: string - namespace: - description: The namespace the Provider type is in. - type: string - type: - description: The type of provider to use such as "Secret", or "ConfigMap". - enum: - - Secret - - ConfigMap - type: string - required: - - name - - type - type: object - headers: - additionalProperties: - type: string - description: Headers - type: object - method: - description: Webhook Method - type: string - result: - description: Result formatting - properties: - jsonPath: - description: Json path of return value - type: string - type: object - secrets: - description: Secrets to fill in templates These secrets will be passed to the templating function as key value pairs under the given name - items: - properties: - name: - description: Name of this secret in templates - type: string - secretRef: - description: Secret ref to fill in credentials - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - required: - - name - - secretRef - type: object - type: array - timeout: - description: Timeout - type: string - url: - description: Webhook url to call - type: string - required: - - result - - url - type: object - yandexcertificatemanager: - description: YandexCertificateManager configures this store to sync secrets using Yandex Certificate Manager provider - properties: - apiEndpoint: - description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') - type: string - auth: - description: Auth defines the information necessary to authenticate against Yandex Certificate Manager - properties: - authorizedKeySecretRef: - description: The authorized key used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - caProvider: - description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. - properties: - certSecretRef: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - auth - type: object - yandexlockbox: - description: YandexLockbox configures this store to sync secrets using Yandex Lockbox provider - properties: - apiEndpoint: - description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') - type: string - auth: - description: Auth defines the information necessary to authenticate against Yandex Lockbox - properties: - authorizedKeySecretRef: - description: The authorized key used for authentication - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - caProvider: - description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. - properties: - certSecretRef: - description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: The name of the Secret resource being referred to. - type: string - namespace: - description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. - type: string - type: object - type: object - required: - - auth - type: object - type: object - refreshInterval: - description: Used to configure store refresh interval in seconds. Empty or 0 will default to the controller config. - type: integer - retrySettings: - description: Used to configure http retries if failed - properties: - maxRetries: - format: int32 - type: integer - retryInterval: - type: string - type: object - required: - - provider - type: object - status: - description: SecretStoreStatus defines the observed state of the SecretStore. - properties: - conditions: - items: - properties: - lastTransitionTime: - format: date-time - type: string - message: - type: string - reason: - type: string - status: - type: string - type: - type: string - required: - - status - - type - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} - conversion: - strategy: Webhook - webhook: - conversionReviewVersions: - - v1 - clientConfig: - service: - name: golang-external-secrets-webhook - namespace: "default" - path: /convert ---- -# Source: golang-external-secrets/charts/external-secrets/templates/cert-controller-rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: golang-external-secrets-cert-controller - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets-cert-controller - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm -rules: - - apiGroups: - - "apiextensions.k8s.io" - resources: - - "customresourcedefinitions" - verbs: - - "get" - - "list" - - "watch" - - "update" - - "patch" - - apiGroups: - - "admissionregistration.k8s.io" - resources: - - "validatingwebhookconfigurations" - verbs: - - "get" - - "list" - - "watch" - - "update" - - "patch" - - apiGroups: - - "" - resources: - - "endpoints" - verbs: - - "list" - - "get" - - "watch" - - apiGroups: - - "" - resources: - - "events" - verbs: - - "create" - - "patch" - - apiGroups: - - "" - resources: - - "secrets" - verbs: - - "get" - - "list" - - "watch" - - "update" - - "patch" ---- -# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: golang-external-secrets-controller - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm -rules: - - apiGroups: - - "external-secrets.io" - resources: - - "secretstores" - - "clustersecretstores" - - "externalsecrets" - - "clusterexternalsecrets" - verbs: - - "get" - - "list" - - "watch" - - apiGroups: - - "external-secrets.io" - resources: - - "externalsecrets" - - "externalsecrets/status" - - "externalsecrets/finalizers" - - "secretstores" - - "secretstores/status" - - "secretstores/finalizers" - - "clustersecretstores" - - "clustersecretstores/status" - - "clustersecretstores/finalizers" - - "clusterexternalsecrets" - - "clusterexternalsecrets/status" - - "clusterexternalsecrets/finalizers" - verbs: - - "update" - - "patch" - - apiGroups: - - "" - resources: - - "serviceaccounts" - - "namespaces" - verbs: - - "get" - - "list" - - "watch" - - apiGroups: - - "" - resources: - - "configmaps" - verbs: - - "get" - - "list" - - "watch" - - apiGroups: - - "" - resources: - - "secrets" - verbs: - - "get" - - "list" - - "watch" - - "create" - - "update" - - "delete" - - "patch" - - apiGroups: - - "" - resources: - - "serviceaccounts/token" - verbs: - - "create" - - apiGroups: - - "" - resources: - - "events" - verbs: - - "create" - - "patch" - - apiGroups: - - "external-secrets.io" - resources: - - "externalsecrets" - verbs: - - "create" - - "update" ---- -# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: golang-external-secrets-view - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm - rbac.authorization.k8s.io/aggregate-to-view: "true" - rbac.authorization.k8s.io/aggregate-to-edit: "true" - rbac.authorization.k8s.io/aggregate-to-admin: "true" -rules: - - apiGroups: - - "external-secrets.io" - resources: - - "externalsecrets" - - "secretstores" - - "clustersecretstores" - verbs: - - "get" - - "watch" - - "list" ---- -# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: golang-external-secrets-edit - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm - rbac.authorization.k8s.io/aggregate-to-edit: "true" - rbac.authorization.k8s.io/aggregate-to-admin: "true" -rules: - - apiGroups: - - "external-secrets.io" - resources: - - "externalsecrets" - - "secretstores" - - "clustersecretstores" - verbs: - - "create" - - "delete" - - "deletecollection" - - "patch" - - "update" ---- -# Source: golang-external-secrets/charts/external-secrets/templates/cert-controller-rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: golang-external-secrets-cert-controller - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets-cert-controller - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: golang-external-secrets-cert-controller -subjects: - - name: external-secrets-cert-controller - namespace: "default" - kind: ServiceAccount ---- -# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: golang-external-secrets-controller - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: golang-external-secrets-controller -subjects: - - name: golang-external-secrets - namespace: "default" - kind: ServiceAccount ---- -# Source: golang-external-secrets/templates/golang-external-secrets-hub-clusterrolebinding.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: role-tokenreview-binding - namespace: default -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:auth-delegator -subjects: -- kind: ServiceAccount - name: golang-external-secrets - namespace: golang-external-secrets ---- -# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: golang-external-secrets-leaderelection - namespace: "default" - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm -rules: - - apiGroups: - - "" - resources: - - "configmaps" - resourceNames: - - "external-secrets-controller" - verbs: - - "get" - - "update" - - "patch" - - apiGroups: - - "" - resources: - - "configmaps" - verbs: - - "create" - - apiGroups: - - "coordination.k8s.io" - resources: - - "leases" - verbs: - - "get" - - "create" - - "update" - - "patch" ---- -# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: golang-external-secrets-leaderelection - namespace: "default" - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: golang-external-secrets-leaderelection -subjects: - - kind: ServiceAccount - name: golang-external-secrets - namespace: "default" ---- -# Source: golang-external-secrets/charts/external-secrets/templates/webhook-service.yaml -apiVersion: v1 -kind: Service -metadata: - name: golang-external-secrets-webhook - namespace: "default" - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets-webhook - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm - external-secrets.io/component : webhook -spec: - type: ClusterIP - ports: - - port: 443 - targetPort: 10250 - protocol: TCP - name: webhook - selector: - app.kubernetes.io/name: external-secrets-webhook - app.kubernetes.io/instance: golang-external-secrets ---- -# Source: golang-external-secrets/charts/external-secrets/templates/cert-controller-deployment.yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: golang-external-secrets-cert-controller - namespace: "default" - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets-cert-controller - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: external-secrets-cert-controller - app.kubernetes.io/instance: golang-external-secrets - template: - metadata: - labels: - app.kubernetes.io/name: external-secrets-cert-controller - app.kubernetes.io/instance: golang-external-secrets - spec: - serviceAccountName: external-secrets-cert-controller - containers: - - name: cert-controller - image: "ghcr.io/external-secrets/external-secrets:v0.5.9" - imagePullPolicy: IfNotPresent - args: - - certcontroller - - --crd-requeue-interval=5m - - --service-name=golang-external-secrets-webhook - - --service-namespace=default - - --secret-name=golang-external-secrets-webhook - - --secret-namespace=default - ports: - - containerPort: 8080 - protocol: TCP - name: metrics - readinessProbe: - httpGet: - port: 8081 - path: /readyz - initialDelaySeconds: 20 - periodSeconds: 5 ---- -# Source: golang-external-secrets/charts/external-secrets/templates/deployment.yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: golang-external-secrets - namespace: "default" - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: external-secrets - app.kubernetes.io/instance: golang-external-secrets - template: - metadata: - labels: - app.kubernetes.io/name: external-secrets - app.kubernetes.io/instance: golang-external-secrets - spec: - serviceAccountName: golang-external-secrets - containers: - - name: external-secrets - image: "ghcr.io/external-secrets/external-secrets:v0.5.9" - imagePullPolicy: IfNotPresent - args: - - --concurrent=1 - ports: - - containerPort: 8080 - protocol: TCP - name: metrics ---- -# Source: golang-external-secrets/charts/external-secrets/templates/webhook-deployment.yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: golang-external-secrets-webhook - namespace: "default" - labels: - helm.sh/chart: external-secrets-0.5.9 - app.kubernetes.io/name: external-secrets-webhook - app.kubernetes.io/instance: golang-external-secrets - app.kubernetes.io/version: "v0.5.9" - app.kubernetes.io/managed-by: Helm -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: external-secrets-webhook - app.kubernetes.io/instance: golang-external-secrets - template: - metadata: - labels: - app.kubernetes.io/name: external-secrets-webhook - app.kubernetes.io/instance: golang-external-secrets - spec: - hostNetwork: false - serviceAccountName: external-secrets-webhook - containers: - - name: webhook - image: "ghcr.io/external-secrets/external-secrets:v0.5.9" - imagePullPolicy: IfNotPresent - args: - - webhook - - --port=10250 - - --dns-name=golang-external-secrets-webhook.default.svc - - --cert-dir=/tmp/certs - - --check-interval=5m - ports: - - containerPort: 8080 - protocol: TCP - name: metrics - - containerPort: 10250 - protocol: TCP - name: webhook - readinessProbe: - httpGet: - port: 8081 - path: /readyz - initialDelaySeconds: 20 - periodSeconds: 5 - volumeMounts: - - name: certs - mountPath: /tmp/certs - readOnly: true - volumes: - - name: certs - secret: - secretName: golang-external-secrets-webhook ---- -# Source: golang-external-secrets/templates/golang-external-secrets-hub-secretstore.yaml -apiVersion: external-secrets.io/v1beta1 -kind: ClusterSecretStore -metadata: - name: vault-backend - namespace: golang-external-secrets -spec: - provider: - vault: - server: https://vault-vault.hub.example.com - path: secret - # Version of KV backend - version: v2 - caProvider: - type: ConfigMap - name: kube-root-ca.crt - key: ca.crt - namespace: golang-external-secrets - auth: - kubernetes: - mountPath: hub - role: hub-role - secretRef: - name: golang-external-secrets - namespace: golang-external-secrets - key: "token" ---- -# Source: golang-external-secrets/charts/external-secrets/templates/validatingwebhook.yaml -apiVersion: admissionregistration.k8s.io/v1 -kind: ValidatingWebhookConfiguration -metadata: - name: secretstore-validate - labels: - external-secrets.io/component: webhook -webhooks: -- name: "validate.secretstore.external-secrets.io" - rules: - - apiGroups: ["external-secrets.io"] - apiVersions: ["v1beta1"] - operations: ["CREATE", "UPDATE", "DELETE"] - resources: ["secretstores"] - scope: "Namespaced" - clientConfig: - service: - namespace: "default" - name: golang-external-secrets-webhook - path: /validate-external-secrets-io-v1beta1-secretstore - admissionReviewVersions: ["v1", "v1beta1"] - sideEffects: None - timeoutSeconds: 5 - -- name: "validate.clustersecretstore.external-secrets.io" - rules: - - apiGroups: ["external-secrets.io"] - apiVersions: ["v1beta1"] - operations: ["CREATE", "UPDATE", "DELETE"] - resources: ["clustersecretstores"] - scope: "Cluster" - clientConfig: - service: - namespace: "default" - name: golang-external-secrets-webhook - path: /validate-external-secrets-io-v1beta1-clustersecretstore - admissionReviewVersions: ["v1", "v1beta1"] - sideEffects: None - timeoutSeconds: 5 ---- -# Source: golang-external-secrets/charts/external-secrets/templates/validatingwebhook.yaml -apiVersion: admissionregistration.k8s.io/v1 -kind: ValidatingWebhookConfiguration -metadata: - name: externalsecret-validate - labels: - external-secrets.io/component: webhook -webhooks: -- name: "validate.externalsecret.external-secrets.io" - rules: - - apiGroups: ["external-secrets.io"] - apiVersions: ["v1beta1"] - operations: ["CREATE", "UPDATE", "DELETE"] - resources: ["externalsecrets"] - scope: "Namespaced" - clientConfig: - service: - namespace: "default" - name: golang-external-secrets-webhook - path: /validate-external-secrets-io-v1beta1-externalsecret - admissionReviewVersions: ["v1", "v1beta1"] - sideEffects: None - timeoutSeconds: 5 - failurePolicy: Fail diff --git a/common/tests/hashicorp-vault-naked.expected.yaml b/common/tests/hashicorp-vault-naked.expected.yaml deleted file mode 100644 index 51800147..00000000 --- a/common/tests/hashicorp-vault-naked.expected.yaml +++ /dev/null @@ -1,409 +0,0 @@ ---- -# Source: hashicorp-vault/charts/vault/templates/server-serviceaccount.yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: hashicorp-vault - namespace: default - labels: - helm.sh/chart: vault-0.22.0 - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - app.kubernetes.io/managed-by: Helm ---- -# Source: hashicorp-vault/charts/vault/templates/server-config-configmap.yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: hashicorp-vault-config - namespace: default - labels: - helm.sh/chart: vault-0.22.0 - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - app.kubernetes.io/managed-by: Helm -data: - extraconfig-from-values.hcl: |- - disable_mlock = true - ui = true - - listener "tcp" { - tls_disable = 1 - address = "[::]:8200" - cluster_address = "[::]:8201" - # Enable unauthenticated metrics access (necessary for Prometheus Operator) - #telemetry { - # unauthenticated_metrics_access = "true" - #} - } - storage "file" { - path = "/vault/data" - } - - # Example configuration for using auto-unseal, using Google Cloud KMS. The - # GKMS keys must already exist, and the cluster must have a service account - # that is authorized to access GCP KMS. - #seal "gcpckms" { - # project = "vault-helm-dev" - # region = "global" - # key_ring = "vault-helm-unseal-kr" - # crypto_key = "vault-helm-unseal-key" - #} - - # Example configuration for enabling Prometheus metrics in your config. - #telemetry { - # prometheus_retention_time = "30s", - # disable_hostname = true - #} ---- -# Source: hashicorp-vault/charts/vault/templates/server-clusterrolebinding.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: hashicorp-vault-server-binding - labels: - helm.sh/chart: vault-0.22.0 - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - app.kubernetes.io/managed-by: Helm -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:auth-delegator -subjects: -- kind: ServiceAccount - name: hashicorp-vault - namespace: default ---- -# Source: hashicorp-vault/charts/vault/templates/server-headless-service.yaml -# Service for Vault cluster -apiVersion: v1 -kind: Service -metadata: - name: hashicorp-vault-internal - namespace: default - labels: - helm.sh/chart: vault-0.22.0 - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - app.kubernetes.io/managed-by: Helm - vault-internal: "true" - annotations: - -spec: - clusterIP: None - publishNotReadyAddresses: true - ports: - - name: "http" - port: 8200 - targetPort: 8200 - - name: https-internal - port: 8201 - targetPort: 8201 - selector: - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - component: server ---- -# Source: hashicorp-vault/charts/vault/templates/server-service.yaml -# Service for Vault cluster -apiVersion: v1 -kind: Service -metadata: - name: hashicorp-vault - namespace: default - labels: - helm.sh/chart: vault-0.22.0 - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - app.kubernetes.io/managed-by: Helm - annotations: - -spec: - # We want the servers to become available even if they're not ready - # since this DNS is also used for join operations. - publishNotReadyAddresses: true - ports: - - name: http - port: 8200 - targetPort: 8200 - - name: https-internal - port: 8201 - targetPort: 8201 - selector: - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - component: server ---- -# Source: hashicorp-vault/charts/vault/templates/ui-service.yaml -apiVersion: v1 -kind: Service -metadata: - name: hashicorp-vault-ui - namespace: default - labels: - helm.sh/chart: vault-0.22.0 - app.kubernetes.io/name: vault-ui - app.kubernetes.io/instance: hashicorp-vault - app.kubernetes.io/managed-by: Helm -spec: - selector: - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - component: server - publishNotReadyAddresses: true - ports: - - name: http - port: 8200 - targetPort: 8200 - type: LoadBalancer - externalTrafficPolicy: Cluster ---- -# Source: hashicorp-vault/charts/vault/templates/server-statefulset.yaml -# StatefulSet to run the actual vault server cluster. -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: hashicorp-vault - namespace: default - labels: - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - app.kubernetes.io/managed-by: Helm -spec: - serviceName: hashicorp-vault-internal - podManagementPolicy: Parallel - replicas: 1 - updateStrategy: - type: OnDelete - selector: - matchLabels: - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - component: server - template: - metadata: - labels: - helm.sh/chart: vault-0.22.0 - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - component: server - spec: - - affinity: - podAntiAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - - labelSelector: - matchLabels: - app.kubernetes.io/name: vault - app.kubernetes.io/instance: "hashicorp-vault" - component: server - topologyKey: kubernetes.io/hostname - - - - - terminationGracePeriodSeconds: 10 - serviceAccountName: hashicorp-vault - - volumes: - - - name: config - configMap: - name: hashicorp-vault-config - - - name: home - emptyDir: {} - containers: - - name: vault - - image: registry.connect.redhat.com/hashicorp/vault:1.11.3-ubi - imagePullPolicy: IfNotPresent - command: - - "/bin/sh" - - "-ec" - args: - - | - cp /vault/config/extraconfig-from-values.hcl /tmp/storageconfig.hcl; - [ -n "${HOST_IP}" ] && sed -Ei "s|HOST_IP|${HOST_IP?}|g" /tmp/storageconfig.hcl; - [ -n "${POD_IP}" ] && sed -Ei "s|POD_IP|${POD_IP?}|g" /tmp/storageconfig.hcl; - [ -n "${HOSTNAME}" ] && sed -Ei "s|HOSTNAME|${HOSTNAME?}|g" /tmp/storageconfig.hcl; - [ -n "${API_ADDR}" ] && sed -Ei "s|API_ADDR|${API_ADDR?}|g" /tmp/storageconfig.hcl; - [ -n "${TRANSIT_ADDR}" ] && sed -Ei "s|TRANSIT_ADDR|${TRANSIT_ADDR?}|g" /tmp/storageconfig.hcl; - [ -n "${RAFT_ADDR}" ] && sed -Ei "s|RAFT_ADDR|${RAFT_ADDR?}|g" /tmp/storageconfig.hcl; - /usr/local/bin/docker-entrypoint.sh vault server -config=/tmp/storageconfig.hcl - - env: - - name: HOST_IP - valueFrom: - fieldRef: - fieldPath: status.hostIP - - name: POD_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - - name: VAULT_K8S_POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: VAULT_K8S_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: VAULT_ADDR - value: "http://127.0.0.1:8200" - - name: VAULT_API_ADDR - value: "http://$(POD_IP):8200" - - name: SKIP_CHOWN - value: "true" - - name: SKIP_SETCAP - value: "true" - - name: HOSTNAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: VAULT_CLUSTER_ADDR - value: "https://$(HOSTNAME).hashicorp-vault-internal:8201" - - name: HOME - value: "/home/vault" - - - - volumeMounts: - - - - - name: data - mountPath: /vault/data - - - - - name: config - mountPath: /vault/config - - - name: home - mountPath: /home/vault - ports: - - containerPort: 8200 - name: http - - containerPort: 8201 - name: https-internal - - containerPort: 8202 - name: http-rep - readinessProbe: - # Check status; unsealed vault servers return 0 - # The exit code reflects the seal status: - # 0 - unsealed - # 1 - error - # 2 - sealed - exec: - command: ["/bin/sh", "-ec", "vault status -tls-skip-verify"] - failureThreshold: 2 - initialDelaySeconds: 5 - periodSeconds: 5 - successThreshold: 1 - timeoutSeconds: 3 - lifecycle: - # Vault container doesn't receive SIGTERM from Kubernetes - # and after the grace period ends, Kube sends SIGKILL. This - # causes issues with graceful shutdowns such as deregistering itself - # from Consul (zombie services). - preStop: - exec: - command: [ - "/bin/sh", "-c", - # Adding a sleep here to give the pod eviction a - # chance to propagate, so requests will not be made - # to this pod while it's terminating - "sleep 5 && kill -SIGTERM $(pidof vault)", - ] - - - volumeClaimTemplates: - - metadata: - name: data - - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10Gi ---- -# Source: hashicorp-vault/templates/vault-app.yaml -apiVersion: console.openshift.io/v1 -kind: ConsoleLink -metadata: - name: vault-link - namespace: vault -spec: - applicationMenu: - section: HashiCorp Vault - imageURL: data:image/png;base64,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 - href: 'https://vault-vault.apps.foo.cluster.com' - location: ApplicationMenu - text: 'Vault' ---- -# Source: hashicorp-vault/charts/vault/templates/server-route.yaml -kind: Route -apiVersion: route.openshift.io/v1 -metadata: - name: hashicorp-vault - namespace: default - labels: - helm.sh/chart: vault-0.22.0 - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - app.kubernetes.io/managed-by: Helm -spec: - host: - to: - kind: Service - name: hashicorp-vault - weight: 100 - port: - targetPort: 8200 - tls: - termination: edge ---- -# Source: hashicorp-vault/charts/vault/templates/tests/server-test.yaml -apiVersion: v1 -kind: Pod -metadata: - name: "hashicorp-vault-server-test" - namespace: default - annotations: - "helm.sh/hook": test -spec: - - containers: - - name: hashicorp-vault-server-test - image: registry.connect.redhat.com/hashicorp/vault:1.11.3-ubi - imagePullPolicy: IfNotPresent - env: - - name: VAULT_ADDR - value: http://hashicorp-vault.default.svc:8200 - - command: - - /bin/sh - - -c - - | - echo "Checking for sealed info in 'vault status' output" - ATTEMPTS=10 - n=0 - until [ "$n" -ge $ATTEMPTS ] - do - echo "Attempt" $n... - vault status -format yaml | grep -E '^sealed: (true|false)' && break - n=$((n+1)) - sleep 5 - done - if [ $n -ge $ATTEMPTS ]; then - echo "timed out looking for sealed info in 'vault status' output" - exit 1 - fi - - exit 0 - volumeMounts: - volumes: - restartPolicy: Never diff --git a/common/tests/hashicorp-vault-normal.expected.yaml b/common/tests/hashicorp-vault-normal.expected.yaml deleted file mode 100644 index d2af3d1b..00000000 --- a/common/tests/hashicorp-vault-normal.expected.yaml +++ /dev/null @@ -1,409 +0,0 @@ ---- -# Source: hashicorp-vault/charts/vault/templates/server-serviceaccount.yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: hashicorp-vault - namespace: default - labels: - helm.sh/chart: vault-0.22.0 - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - app.kubernetes.io/managed-by: Helm ---- -# Source: hashicorp-vault/charts/vault/templates/server-config-configmap.yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: hashicorp-vault-config - namespace: default - labels: - helm.sh/chart: vault-0.22.0 - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - app.kubernetes.io/managed-by: Helm -data: - extraconfig-from-values.hcl: |- - disable_mlock = true - ui = true - - listener "tcp" { - tls_disable = 1 - address = "[::]:8200" - cluster_address = "[::]:8201" - # Enable unauthenticated metrics access (necessary for Prometheus Operator) - #telemetry { - # unauthenticated_metrics_access = "true" - #} - } - storage "file" { - path = "/vault/data" - } - - # Example configuration for using auto-unseal, using Google Cloud KMS. The - # GKMS keys must already exist, and the cluster must have a service account - # that is authorized to access GCP KMS. - #seal "gcpckms" { - # project = "vault-helm-dev" - # region = "global" - # key_ring = "vault-helm-unseal-kr" - # crypto_key = "vault-helm-unseal-key" - #} - - # Example configuration for enabling Prometheus metrics in your config. - #telemetry { - # prometheus_retention_time = "30s", - # disable_hostname = true - #} ---- -# Source: hashicorp-vault/charts/vault/templates/server-clusterrolebinding.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: hashicorp-vault-server-binding - labels: - helm.sh/chart: vault-0.22.0 - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - app.kubernetes.io/managed-by: Helm -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:auth-delegator -subjects: -- kind: ServiceAccount - name: hashicorp-vault - namespace: default ---- -# Source: hashicorp-vault/charts/vault/templates/server-headless-service.yaml -# Service for Vault cluster -apiVersion: v1 -kind: Service -metadata: - name: hashicorp-vault-internal - namespace: default - labels: - helm.sh/chart: vault-0.22.0 - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - app.kubernetes.io/managed-by: Helm - vault-internal: "true" - annotations: - -spec: - clusterIP: None - publishNotReadyAddresses: true - ports: - - name: "http" - port: 8200 - targetPort: 8200 - - name: https-internal - port: 8201 - targetPort: 8201 - selector: - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - component: server ---- -# Source: hashicorp-vault/charts/vault/templates/server-service.yaml -# Service for Vault cluster -apiVersion: v1 -kind: Service -metadata: - name: hashicorp-vault - namespace: default - labels: - helm.sh/chart: vault-0.22.0 - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - app.kubernetes.io/managed-by: Helm - annotations: - -spec: - # We want the servers to become available even if they're not ready - # since this DNS is also used for join operations. - publishNotReadyAddresses: true - ports: - - name: http - port: 8200 - targetPort: 8200 - - name: https-internal - port: 8201 - targetPort: 8201 - selector: - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - component: server ---- -# Source: hashicorp-vault/charts/vault/templates/ui-service.yaml -apiVersion: v1 -kind: Service -metadata: - name: hashicorp-vault-ui - namespace: default - labels: - helm.sh/chart: vault-0.22.0 - app.kubernetes.io/name: vault-ui - app.kubernetes.io/instance: hashicorp-vault - app.kubernetes.io/managed-by: Helm -spec: - selector: - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - component: server - publishNotReadyAddresses: true - ports: - - name: http - port: 8200 - targetPort: 8200 - type: LoadBalancer - externalTrafficPolicy: Cluster ---- -# Source: hashicorp-vault/charts/vault/templates/server-statefulset.yaml -# StatefulSet to run the actual vault server cluster. -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: hashicorp-vault - namespace: default - labels: - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - app.kubernetes.io/managed-by: Helm -spec: - serviceName: hashicorp-vault-internal - podManagementPolicy: Parallel - replicas: 1 - updateStrategy: - type: OnDelete - selector: - matchLabels: - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - component: server - template: - metadata: - labels: - helm.sh/chart: vault-0.22.0 - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - component: server - spec: - - affinity: - podAntiAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - - labelSelector: - matchLabels: - app.kubernetes.io/name: vault - app.kubernetes.io/instance: "hashicorp-vault" - component: server - topologyKey: kubernetes.io/hostname - - - - - terminationGracePeriodSeconds: 10 - serviceAccountName: hashicorp-vault - - volumes: - - - name: config - configMap: - name: hashicorp-vault-config - - - name: home - emptyDir: {} - containers: - - name: vault - - image: registry.connect.redhat.com/hashicorp/vault:1.11.3-ubi - imagePullPolicy: IfNotPresent - command: - - "/bin/sh" - - "-ec" - args: - - | - cp /vault/config/extraconfig-from-values.hcl /tmp/storageconfig.hcl; - [ -n "${HOST_IP}" ] && sed -Ei "s|HOST_IP|${HOST_IP?}|g" /tmp/storageconfig.hcl; - [ -n "${POD_IP}" ] && sed -Ei "s|POD_IP|${POD_IP?}|g" /tmp/storageconfig.hcl; - [ -n "${HOSTNAME}" ] && sed -Ei "s|HOSTNAME|${HOSTNAME?}|g" /tmp/storageconfig.hcl; - [ -n "${API_ADDR}" ] && sed -Ei "s|API_ADDR|${API_ADDR?}|g" /tmp/storageconfig.hcl; - [ -n "${TRANSIT_ADDR}" ] && sed -Ei "s|TRANSIT_ADDR|${TRANSIT_ADDR?}|g" /tmp/storageconfig.hcl; - [ -n "${RAFT_ADDR}" ] && sed -Ei "s|RAFT_ADDR|${RAFT_ADDR?}|g" /tmp/storageconfig.hcl; - /usr/local/bin/docker-entrypoint.sh vault server -config=/tmp/storageconfig.hcl - - env: - - name: HOST_IP - valueFrom: - fieldRef: - fieldPath: status.hostIP - - name: POD_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - - name: VAULT_K8S_POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: VAULT_K8S_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: VAULT_ADDR - value: "http://127.0.0.1:8200" - - name: VAULT_API_ADDR - value: "http://$(POD_IP):8200" - - name: SKIP_CHOWN - value: "true" - - name: SKIP_SETCAP - value: "true" - - name: HOSTNAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: VAULT_CLUSTER_ADDR - value: "https://$(HOSTNAME).hashicorp-vault-internal:8201" - - name: HOME - value: "/home/vault" - - - - volumeMounts: - - - - - name: data - mountPath: /vault/data - - - - - name: config - mountPath: /vault/config - - - name: home - mountPath: /home/vault - ports: - - containerPort: 8200 - name: http - - containerPort: 8201 - name: https-internal - - containerPort: 8202 - name: http-rep - readinessProbe: - # Check status; unsealed vault servers return 0 - # The exit code reflects the seal status: - # 0 - unsealed - # 1 - error - # 2 - sealed - exec: - command: ["/bin/sh", "-ec", "vault status -tls-skip-verify"] - failureThreshold: 2 - initialDelaySeconds: 5 - periodSeconds: 5 - successThreshold: 1 - timeoutSeconds: 3 - lifecycle: - # Vault container doesn't receive SIGTERM from Kubernetes - # and after the grace period ends, Kube sends SIGKILL. This - # causes issues with graceful shutdowns such as deregistering itself - # from Consul (zombie services). - preStop: - exec: - command: [ - "/bin/sh", "-c", - # Adding a sleep here to give the pod eviction a - # chance to propagate, so requests will not be made - # to this pod while it's terminating - "sleep 5 && kill -SIGTERM $(pidof vault)", - ] - - - volumeClaimTemplates: - - metadata: - name: data - - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10Gi ---- -# Source: hashicorp-vault/templates/vault-app.yaml -apiVersion: console.openshift.io/v1 -kind: ConsoleLink -metadata: - name: vault-link - namespace: vault -spec: - applicationMenu: - section: HashiCorp Vault - imageURL: data:image/png;base64,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 - href: 'https://vault-vault.region.example.com' - location: ApplicationMenu - text: 'Vault' ---- -# Source: hashicorp-vault/charts/vault/templates/server-route.yaml -kind: Route -apiVersion: route.openshift.io/v1 -metadata: - name: hashicorp-vault - namespace: default - labels: - helm.sh/chart: vault-0.22.0 - app.kubernetes.io/name: vault - app.kubernetes.io/instance: hashicorp-vault - app.kubernetes.io/managed-by: Helm -spec: - host: - to: - kind: Service - name: hashicorp-vault - weight: 100 - port: - targetPort: 8200 - tls: - termination: edge ---- -# Source: hashicorp-vault/charts/vault/templates/tests/server-test.yaml -apiVersion: v1 -kind: Pod -metadata: - name: "hashicorp-vault-server-test" - namespace: default - annotations: - "helm.sh/hook": test -spec: - - containers: - - name: hashicorp-vault-server-test - image: registry.connect.redhat.com/hashicorp/vault:1.11.3-ubi - imagePullPolicy: IfNotPresent - env: - - name: VAULT_ADDR - value: http://hashicorp-vault.default.svc:8200 - - command: - - /bin/sh - - -c - - | - echo "Checking for sealed info in 'vault status' output" - ATTEMPTS=10 - n=0 - until [ "$n" -ge $ATTEMPTS ] - do - echo "Attempt" $n... - vault status -format yaml | grep -E '^sealed: (true|false)' && break - n=$((n+1)) - sleep 5 - done - if [ $n -ge $ATTEMPTS ]; then - echo "timed out looking for sealed info in 'vault status' output" - exit 1 - fi - - exit 0 - volumeMounts: - volumes: - restartPolicy: Never diff --git a/common/tests/install-naked.expected.yaml b/common/tests/install-naked.expected.yaml deleted file mode 100644 index 7272f0eb..00000000 --- a/common/tests/install-naked.expected.yaml +++ /dev/null @@ -1,64 +0,0 @@ ---- -# Source: pattern-install/templates/argocd/namespace.yaml -# Pre-create so we can create our argo app for keeping subscriptions in sync -# Do it here so that we don't try to sync it in the future -apiVersion: v1 -kind: Namespace -metadata: - name: openshift-gitops ---- -# Source: pattern-install/templates/argocd/application.yaml -apiVersion: argoproj.io/v1alpha1 -kind: Application -metadata: - name: install-default - namespace: openshift-gitops - finalizers: - - resources-finalizer.argocd.argoproj.io/foreground -spec: - destination: - name: in-cluster - namespace: install-default - project: default - source: - repoURL: https://github.com/pattern-clone/mypattern - targetRevision: main - path: common/clustergroup - helm: - ignoreMissingValueFiles: true - valueFiles: - - "/values-global.yaml" - - "/values-default.yaml" - # Track the progress of https://github.com/argoproj/argo-cd/pull/6280 - parameters: - - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL - - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION - - name: global.namespace - value: $ARGOCD_APP_NAMESPACE - - name: global.pattern - value: install - - name: global.hubClusterDomain - value: - syncPolicy: - automated: {} ---- -# Source: pattern-install/templates/argocd/subscription.yaml -apiVersion: operators.coreos.com/v1alpha1 -kind: Subscription -metadata: - name: openshift-gitops-operator - namespace: openshift-operators - labels: - operators.coreos.com/openshift-gitops-operator.openshift-operators: "" -spec: - channel: stable - installPlanApproval: Automatic - name: openshift-gitops-operator - source: redhat-operators - sourceNamespace: openshift-marketplace - config: - env: - - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES - value: install-default,openshift-gitops diff --git a/common/tests/install-normal.expected.yaml b/common/tests/install-normal.expected.yaml deleted file mode 100644 index d115d8ae..00000000 --- a/common/tests/install-normal.expected.yaml +++ /dev/null @@ -1,64 +0,0 @@ ---- -# Source: pattern-install/templates/argocd/namespace.yaml -# Pre-create so we can create our argo app for keeping subscriptions in sync -# Do it here so that we don't try to sync it in the future -apiVersion: v1 -kind: Namespace -metadata: - name: openshift-gitops ---- -# Source: pattern-install/templates/argocd/application.yaml -apiVersion: argoproj.io/v1alpha1 -kind: Application -metadata: - name: install-example - namespace: openshift-gitops - finalizers: - - resources-finalizer.argocd.argoproj.io/foreground -spec: - destination: - name: in-cluster - namespace: install-example - project: default - source: - repoURL: https://github.com/pattern-clone/mypattern - targetRevision: main - path: common/clustergroup - helm: - ignoreMissingValueFiles: true - valueFiles: - - "/values-global.yaml" - - "/values-example.yaml" - # Track the progress of https://github.com/argoproj/argo-cd/pull/6280 - parameters: - - name: global.repoURL - value: $ARGOCD_APP_SOURCE_REPO_URL - - name: global.targetRevision - value: $ARGOCD_APP_SOURCE_TARGET_REVISION - - name: global.namespace - value: $ARGOCD_APP_NAMESPACE - - name: global.pattern - value: install - - name: global.hubClusterDomain - value: hub.example.com - syncPolicy: - automated: {} ---- -# Source: pattern-install/templates/argocd/subscription.yaml -apiVersion: operators.coreos.com/v1alpha1 -kind: Subscription -metadata: - name: openshift-gitops-operator - namespace: openshift-operators - labels: - operators.coreos.com/openshift-gitops-operator.openshift-operators: "" -spec: - channel: stable - installPlanApproval: Automatic - name: openshift-gitops-operator - source: redhat-operators - sourceNamespace: openshift-marketplace - config: - env: - - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES - value: install-example,openshift-gitops diff --git a/common/tests/operator-install-naked.expected.yaml b/common/tests/operator-install-naked.expected.yaml deleted file mode 100644 index 6b4cddc7..00000000 --- a/common/tests/operator-install-naked.expected.yaml +++ /dev/null @@ -1,29 +0,0 @@ ---- -# Source: pattern-install/templates/pattern.yaml -apiVersion: gitops.hybrid-cloud-patterns.io/v1alpha1 -kind: Pattern -metadata: - name: operator-install - namespace: openshift-operators -spec: - clusterGroupName: default - gitSpec: - targetRepo: https://github.com/pattern-clone/mypattern - targetRevision: main - gitOpsSpec: - operatorChannel: stable ---- -# Source: pattern-install/templates/subscription.yaml -apiVersion: operators.coreos.com/v1alpha1 -kind: Subscription -metadata: - name: patterns-operator - namespace: openshift-operators - labels: - operators.coreos.com/patterns-operator.openshift-operators: "" -spec: - channel: fast - installPlanApproval: Automatic - name: patterns-operator - source: community-operators - sourceNamespace: openshift-marketplace diff --git a/common/tests/operator-install-normal.expected.yaml b/common/tests/operator-install-normal.expected.yaml deleted file mode 100644 index dc07be36..00000000 --- a/common/tests/operator-install-normal.expected.yaml +++ /dev/null @@ -1,29 +0,0 @@ ---- -# Source: pattern-install/templates/pattern.yaml -apiVersion: gitops.hybrid-cloud-patterns.io/v1alpha1 -kind: Pattern -metadata: - name: operator-install - namespace: openshift-operators -spec: - clusterGroupName: example - gitSpec: - targetRepo: https://github.com/pattern-clone/mypattern - targetRevision: main - gitOpsSpec: - operatorChannel: stable ---- -# Source: pattern-install/templates/subscription.yaml -apiVersion: operators.coreos.com/v1alpha1 -kind: Subscription -metadata: - name: patterns-operator - namespace: openshift-operators - labels: - operators.coreos.com/patterns-operator.openshift-operators: "" -spec: - channel: fast - installPlanApproval: Automatic - name: patterns-operator - source: community-operators - sourceNamespace: openshift-marketplace diff --git a/common/values-global.yaml b/common/values-global.yaml deleted file mode 100644 index 8a890f3d..00000000 --- a/common/values-global.yaml +++ /dev/null @@ -1,16 +0,0 @@ -global: - options: - useCSV: True - syncPolicy: Manual - installPlanApproval: Automatic - - git: - hostname: github.com - # Account is the user or organization under which the pattern repos lives - account: hybrid-cloud-patterns - email: someone@somewhere.com - dev_revision: main - -main: - clusterGroupName: example - From 90f35ebac0d5dcd162b918027151455781893db3 Mon Sep 17 00:00:00 2001 From: ruromero Date: Mon, 3 Oct 2022 10:20:01 +0200 Subject: [PATCH 2/4] Squashed 'common/' content from commit 5402a78 git-subtree-dir: common git-subtree-split: 5402a78731d5c85d2a33e32eebb8a408bf193b7e --- .ansible-lint | 7 + .github/linters/.markdown-lint.yml | 6 + .github/workflows/ansible-lint.yml | 18 + .github/workflows/linter.yml | 64 + .github/workflows/superlinter.yml | 38 + .gitignore | 9 + Changes.md | 24 + LICENSE | 202 + Makefile | 102 + README.md | 18 + acm/.helmignore | 1 + acm/Chart.yaml | 6 + acm/templates/multiclusterhub.yaml | 8 + .../policies/application-policies.yaml | 139 + acm/templates/policies/ocp-gitops-policy.yaml | 76 + acm/templates/provision/_install-config.tpl | 59 + acm/templates/provision/clusterpool.yaml | 87 + acm/templates/provision/secrets-aws.yaml | 84 + acm/templates/provision/secrets-azure.yaml | 84 + acm/templates/provision/secrets-common.yaml | 61 + acm/test.yaml | 35 + acm/values.yaml | 26 + ansible/ansible.cfg | 4 + ansible/playbooks/vault/push_secrets.yaml | 10 + ansible/playbooks/vault/vault.yaml | 7 + ansible/roles/vault_utils/README.md | 79 + ansible/roles/vault_utils/defaults/main.yml | 26 + ansible/roles/vault_utils/handlers/main.yml | 2 + ansible/roles/vault_utils/meta/main.yml | 31 + ansible/roles/vault_utils/tasks/main.yml | 20 + .../roles/vault_utils/tasks/pre_check.yaml | 26 + .../roles/vault_utils/tasks/push_secrets.yaml | 208 + .../roles/vault_utils/tasks/vault_delete.yaml | 23 + .../roles/vault_utils/tasks/vault_init.yaml | 85 + .../vault_utils/tasks/vault_pki_init.yaml | 50 + .../vault_utils/tasks/vault_secrets_init.yaml | 80 + .../roles/vault_utils/tasks/vault_status.yaml | 61 + .../roles/vault_utils/tasks/vault_unseal.yaml | 116 + ansible/roles/vault_utils/tests/inventory | 2 + ansible/roles/vault_utils/tests/test.yml | 5 + ansible/roles/vault_utils/vars/main.yml | 2 + clustergroup/.helmignore | 1 + clustergroup/Chart.yaml | 6 + .../templates/core/catalog-sources.yaml | 13 + clustergroup/templates/core/namespaces.yaml | 13 + .../templates/core/operatorgroup.yaml | 27 + .../templates/core/subscriptions.yaml | 69 + .../templates/imperative/_helpers.tpl | 38 + .../templates/imperative/clusterrole.yaml | 24 + .../templates/imperative/configmap.yaml | 15 + clustergroup/templates/imperative/job.yaml | 69 + .../templates/imperative/namespace.yaml | 13 + clustergroup/templates/imperative/rbac.yaml | 33 + clustergroup/templates/imperative/role.yaml | 23 + .../templates/imperative/serviceaccount.yaml | 13 + .../templates/imperative/unsealjob.yaml | 61 + .../templates/plumbing/applications.yaml | 218 + .../templates/plumbing/argocd-super-role.yaml | 43 + clustergroup/templates/plumbing/argocd.yaml | 127 + .../plumbing/cluster-external-secrets.yaml | 43 + .../templates/plumbing/gitops-namespace.yaml | 13 + .../templates/plumbing/hosted-sites.yaml | 177 + clustergroup/templates/plumbing/projects.yaml | 29 + clustergroup/test.yaml | 104 + clustergroup/values.yaml | 90 + common | 1 + examples/blank/Chart.yaml | 6 + examples/blank/templates/manifest.yaml | 4 + examples/blank/values.yaml | 2 + examples/kustomize-renderer/Chart.yaml | 6 + examples/kustomize-renderer/environment.yaml | 34 + .../kustomize-renderer/kustomization.yaml | 5 + examples/kustomize-renderer/kustomize | 15 + .../templates/environment.yaml | 34 + examples/kustomize-renderer/values.yaml | 12 + examples/values-example.yaml | 104 + examples/values-secret.yaml | 32 + golang-external-secrets/Chart.yaml | 11 + .../charts/external-secrets-0.5.9.tgz | Bin 0 -> 40987 bytes ...ternal-secrets-hub-clusterrolebinding.yaml | 23 + ...lang-external-secrets-hub-secretstore.yaml | 25 + golang-external-secrets/values.yaml | 6 + hashicorp-vault/Chart.yaml | 10 + hashicorp-vault/README.md | 12 + hashicorp-vault/charts/vault-0.22.0.tgz | Bin 0 -> 51863 bytes hashicorp-vault/patch-server-route.diff | 28 + hashicorp-vault/templates/vault-app.yaml | 12 + hashicorp-vault/update-helm-dependency.sh | 26 + hashicorp-vault/values.yaml | 20 + install/.helmignore | 1 + install/Chart.yaml | 6 + install/crds/applications.argoproj.io.yaml | 2312 +++++++ install/templates/argocd/application.yaml | 37 + install/templates/argocd/namespace.yaml | 6 + install/templates/argocd/subscription.yaml | 20 + install/values.yaml | 25 + operator-install/Chart.yaml | 6 + ...ops.hybrid-cloud-patterns.io_patterns.yaml | 157 + operator-install/templates/pattern.yaml | 12 + operator-install/templates/subscription.yaml | 13 + operator-install/values.yaml | 9 + reference-output.yaml | 119 + scripts/make_common_subtree.sh | 76 + scripts/pattern-util.sh | 33 + scripts/test.sh | 122 + scripts/vault-utils.sh | 30 + tests/acm-naked.expected.yml | 93 + tests/acm-normal.expected.yml | 694 ++ tests/acm.expected.diff | 633 ++ tests/clustergroup-naked.expected.yml | 184 + tests/clustergroup-normal.expected.yml | 1025 +++ tests/clustergroup.expected.diff | 930 +++ tests/examples-blank-naked.expected.yml | 6 + tests/examples-blank-normal.expected.yml | 6 + tests/examples-blank.expected.diff | 0 ...ples-kustomize-renderer-naked.expected.yml | 36 + ...les-kustomize-renderer-normal.expected.yml | 36 + .../examples-kustomize-renderer.expected.diff | 19 + ...golang-external-secrets-naked.expected.yml | 5911 +++++++++++++++++ ...olang-external-secrets-normal.expected.yml | 5911 +++++++++++++++++ tests/golang-external-secrets.expected.diff | 11 + tests/hashicorp-vault-naked.expected.yml | 409 ++ tests/hashicorp-vault-normal.expected.yml | 409 ++ tests/hashicorp-vault.expected.diff | 11 + tests/install-naked.expected.yml | 64 + tests/install-normal.expected.yml | 64 + tests/install.expected.diff | 43 + tests/operator-install-naked.expected.yml | 29 + tests/operator-install-normal.expected.yml | 29 + tests/operator-install.expected.diff | 11 + values-global.yaml | 16 + 131 files changed, 23245 insertions(+) create mode 100644 .ansible-lint create mode 100644 .github/linters/.markdown-lint.yml create mode 100644 .github/workflows/ansible-lint.yml create mode 100644 .github/workflows/linter.yml create mode 100644 .github/workflows/superlinter.yml create mode 100644 .gitignore create mode 100644 Changes.md create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 acm/.helmignore create mode 100644 acm/Chart.yaml create mode 100644 acm/templates/multiclusterhub.yaml create mode 100644 acm/templates/policies/application-policies.yaml create mode 100644 acm/templates/policies/ocp-gitops-policy.yaml create mode 100644 acm/templates/provision/_install-config.tpl create mode 100644 acm/templates/provision/clusterpool.yaml create mode 100644 acm/templates/provision/secrets-aws.yaml create mode 100644 acm/templates/provision/secrets-azure.yaml create mode 100644 acm/templates/provision/secrets-common.yaml create mode 100644 acm/test.yaml create mode 100644 acm/values.yaml create mode 100644 ansible/ansible.cfg create mode 100644 ansible/playbooks/vault/push_secrets.yaml create mode 100644 ansible/playbooks/vault/vault.yaml create mode 100644 ansible/roles/vault_utils/README.md create mode 100644 ansible/roles/vault_utils/defaults/main.yml create mode 100644 ansible/roles/vault_utils/handlers/main.yml create mode 100644 ansible/roles/vault_utils/meta/main.yml create mode 100644 ansible/roles/vault_utils/tasks/main.yml create mode 100644 ansible/roles/vault_utils/tasks/pre_check.yaml create mode 100644 ansible/roles/vault_utils/tasks/push_secrets.yaml create mode 100644 ansible/roles/vault_utils/tasks/vault_delete.yaml create mode 100644 ansible/roles/vault_utils/tasks/vault_init.yaml create mode 100644 ansible/roles/vault_utils/tasks/vault_pki_init.yaml create mode 100644 ansible/roles/vault_utils/tasks/vault_secrets_init.yaml create mode 100644 ansible/roles/vault_utils/tasks/vault_status.yaml create mode 100644 ansible/roles/vault_utils/tasks/vault_unseal.yaml create mode 100644 ansible/roles/vault_utils/tests/inventory create mode 100644 ansible/roles/vault_utils/tests/test.yml create mode 100644 ansible/roles/vault_utils/vars/main.yml create mode 100644 clustergroup/.helmignore create mode 100644 clustergroup/Chart.yaml create mode 100644 clustergroup/templates/core/catalog-sources.yaml create mode 100644 clustergroup/templates/core/namespaces.yaml create mode 100644 clustergroup/templates/core/operatorgroup.yaml create mode 100644 clustergroup/templates/core/subscriptions.yaml create mode 100644 clustergroup/templates/imperative/_helpers.tpl create mode 100644 clustergroup/templates/imperative/clusterrole.yaml create mode 100644 clustergroup/templates/imperative/configmap.yaml create mode 100644 clustergroup/templates/imperative/job.yaml create mode 100644 clustergroup/templates/imperative/namespace.yaml create mode 100644 clustergroup/templates/imperative/rbac.yaml create mode 100644 clustergroup/templates/imperative/role.yaml create mode 100644 clustergroup/templates/imperative/serviceaccount.yaml create mode 100644 clustergroup/templates/imperative/unsealjob.yaml create mode 100644 clustergroup/templates/plumbing/applications.yaml create mode 100644 clustergroup/templates/plumbing/argocd-super-role.yaml create mode 100644 clustergroup/templates/plumbing/argocd.yaml create mode 100644 clustergroup/templates/plumbing/cluster-external-secrets.yaml create mode 100644 clustergroup/templates/plumbing/gitops-namespace.yaml create mode 100644 clustergroup/templates/plumbing/hosted-sites.yaml create mode 100644 clustergroup/templates/plumbing/projects.yaml create mode 100644 clustergroup/test.yaml create mode 100644 clustergroup/values.yaml create mode 120000 common create mode 100644 examples/blank/Chart.yaml create mode 100644 examples/blank/templates/manifest.yaml create mode 100644 examples/blank/values.yaml create mode 100644 examples/kustomize-renderer/Chart.yaml create mode 100644 examples/kustomize-renderer/environment.yaml create mode 100644 examples/kustomize-renderer/kustomization.yaml create mode 100755 examples/kustomize-renderer/kustomize create mode 100644 examples/kustomize-renderer/templates/environment.yaml create mode 100644 examples/kustomize-renderer/values.yaml create mode 100644 examples/values-example.yaml create mode 100644 examples/values-secret.yaml create mode 100644 golang-external-secrets/Chart.yaml create mode 100644 golang-external-secrets/charts/external-secrets-0.5.9.tgz create mode 100644 golang-external-secrets/templates/golang-external-secrets-hub-clusterrolebinding.yaml create mode 100644 golang-external-secrets/templates/golang-external-secrets-hub-secretstore.yaml create mode 100644 golang-external-secrets/values.yaml create mode 100644 hashicorp-vault/Chart.yaml create mode 100644 hashicorp-vault/README.md create mode 100644 hashicorp-vault/charts/vault-0.22.0.tgz create mode 100644 hashicorp-vault/patch-server-route.diff create mode 100644 hashicorp-vault/templates/vault-app.yaml create mode 100755 hashicorp-vault/update-helm-dependency.sh create mode 100644 hashicorp-vault/values.yaml create mode 100644 install/.helmignore create mode 100644 install/Chart.yaml create mode 100644 install/crds/applications.argoproj.io.yaml create mode 100644 install/templates/argocd/application.yaml create mode 100644 install/templates/argocd/namespace.yaml create mode 100644 install/templates/argocd/subscription.yaml create mode 100644 install/values.yaml create mode 100644 operator-install/Chart.yaml create mode 100644 operator-install/crds/gitops.hybrid-cloud-patterns.io_patterns.yaml create mode 100644 operator-install/templates/pattern.yaml create mode 100644 operator-install/templates/subscription.yaml create mode 100644 operator-install/values.yaml create mode 100644 reference-output.yaml create mode 100755 scripts/make_common_subtree.sh create mode 100755 scripts/pattern-util.sh create mode 100755 scripts/test.sh create mode 100755 scripts/vault-utils.sh create mode 100644 tests/acm-naked.expected.yml create mode 100644 tests/acm-normal.expected.yml create mode 100644 tests/acm.expected.diff create mode 100644 tests/clustergroup-naked.expected.yml create mode 100644 tests/clustergroup-normal.expected.yml create mode 100644 tests/clustergroup.expected.diff create mode 100644 tests/examples-blank-naked.expected.yml create mode 100644 tests/examples-blank-normal.expected.yml create mode 100644 tests/examples-blank.expected.diff create mode 100644 tests/examples-kustomize-renderer-naked.expected.yml create mode 100644 tests/examples-kustomize-renderer-normal.expected.yml create mode 100644 tests/examples-kustomize-renderer.expected.diff create mode 100644 tests/golang-external-secrets-naked.expected.yml create mode 100644 tests/golang-external-secrets-normal.expected.yml create mode 100644 tests/golang-external-secrets.expected.diff create mode 100644 tests/hashicorp-vault-naked.expected.yml create mode 100644 tests/hashicorp-vault-normal.expected.yml create mode 100644 tests/hashicorp-vault.expected.diff create mode 100644 tests/install-naked.expected.yml create mode 100644 tests/install-normal.expected.yml create mode 100644 tests/install.expected.diff create mode 100644 tests/operator-install-naked.expected.yml create mode 100644 tests/operator-install-normal.expected.yml create mode 100644 tests/operator-install.expected.diff create mode 100644 values-global.yaml diff --git a/.ansible-lint b/.ansible-lint new file mode 100644 index 00000000..f8066ff0 --- /dev/null +++ b/.ansible-lint @@ -0,0 +1,7 @@ +# Vim filetype=yaml +--- +offline: false +skip_list: + - name[template] # Allow Jinja templating inside task and play names + - template-instead-of-copy # Templated files should use template instead of copy + - yaml[line-length] # too long lines diff --git a/.github/linters/.markdown-lint.yml b/.github/linters/.markdown-lint.yml new file mode 100644 index 00000000..a0bc47d1 --- /dev/null +++ b/.github/linters/.markdown-lint.yml @@ -0,0 +1,6 @@ +{ + "default": true, + "MD003": false, + "MD013": false, + "MD033": false +} \ No newline at end of file diff --git a/.github/workflows/ansible-lint.yml b/.github/workflows/ansible-lint.yml new file mode 100644 index 00000000..ae3e9caf --- /dev/null +++ b/.github/workflows/ansible-lint.yml @@ -0,0 +1,18 @@ +name: Ansible Lint # feel free to pick your own name + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + # Important: This sets up your GITHUB_WORKSPACE environment variable + - uses: actions/checkout@v2 + + - name: Lint Ansible Playbook + # Using the latest as of today (2022-09-02) v6.6.1 + uses: ansible/ansible-lint-action@v6.6.1 + # Let's point it to the path + with: + path: "ansible/" diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml new file mode 100644 index 00000000..81eee65b --- /dev/null +++ b/.github/workflows/linter.yml @@ -0,0 +1,64 @@ +--- +name: Unit test common + +# +# Documentation: +# https://help.github.com/en/articles/workflow-syntax-for-github-actions +# + +############################# +# Start the job on all push # +############################# +on: [push, pull_request] + +############### +# Set the Job # +############### +jobs: + build: + # Name the Job + name: Unit common/ Code Base + # Set the agent to run on + runs-on: ubuntu-latest + + ################## + # Load all steps # + ################## + steps: + ########################## + # Checkout the code base # + ########################## + - name: Checkout Code + uses: actions/checkout@v2 + with: + # Full git history is needed to get a proper list of changed files within `super-linter` + fetch-depth: 0 + - name: Setup helm + uses: azure/setup-helm@v1 + # with: + # version: '' # default is latest stable + id: install + + ################################ + # Run Linter against code base # + ################################ + # - name: Lint Code Base + # uses: github/super-linter@v4 + # env: + # VALIDATE_ALL_CODEBASE: false + # DEFAULT_BRANCH: main + # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Run make test + run: | + make test + + - name: Run make helmlint + run: | + make helmlint + + - name: Run make helm kubeconform + run: | + curl -L -O https://github.com/yannh/kubeconform/releases/download/v0.4.13/kubeconform-linux-amd64.tar.gz + tar xf kubeconform-linux-amd64.tar.gz + sudo mv -v kubeconform /usr/local/bin + make kubeconform diff --git a/.github/workflows/superlinter.yml b/.github/workflows/superlinter.yml new file mode 100644 index 00000000..a3e22028 --- /dev/null +++ b/.github/workflows/superlinter.yml @@ -0,0 +1,38 @@ +--- +name: Super linter + +on: [push, pull_request] + +jobs: + build: + # Name the Job + name: Super linter + # Set the agent to run on + runs-on: ubuntu-latest + + steps: + - name: Checkout Code + uses: actions/checkout@v2 + with: + # Full git history is needed to get a proper list of changed files within `super-linter` + fetch-depth: 0 + + ################################ + # Run Linter against code base # + ################################ + - name: Lint Code Base + uses: github/super-linter/slim@v4 + env: + VALIDATE_ALL_CODEBASE: true + DEFAULT_BRANCH: main + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # These are the validation we disable atm + VALIDATE_ANSIBLE: false + VALIDATE_BASH: false + VALIDATE_JSCPD: false + VALIDATE_KUBERNETES_KUBEVAL: false + VALIDATE_YAML: false + # VALIDATE_DOCKERFILE_HADOLINT: false + # VALIDATE_MARKDOWN: false + # VALIDATE_NATURAL_LANGUAGE: false + # VALIDATE_TEKTON: false diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..fd2282bc --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*~ +*.swp +*.swo +values-secret.yaml +.*.expected.yaml +pattern-vault.init +pattern-vault.init.bak +super-linter.log +golang-external-secrets/Chart.lock diff --git a/Changes.md b/Changes.md new file mode 100644 index 00000000..0c1f9731 --- /dev/null +++ b/Changes.md @@ -0,0 +1,24 @@ +# Changes + +## October 3, 2022 + +* Restore the ability to install a non-default site: `make TARGET_SITE=mysite install` +* Revised tests (new output and filenames, requires adding new result files to git) +* ACM 2.6 required for ACM-based managed sites +* Introduced global.clusterDomain template variable (without the `apps.` prefix) +* Removed the ability to send specific charts to another cluster, use hosted argo sites instead +* Added the ability to have the hub host `values-{site}.yaml` for spoke clusters. + + The following example would deploy the namespaces, subscriptions, and + applications defined in `values-group-one.yaml` to the `perth` cluster + directly from ArgoCD on the hub. + + ```yaml + managedClusterGroups: + - name: group-one + hostedArgoSites: + - name: perth + domain: perth1.beekhof.net + bearerKeyPath: secret/data/hub/cluster_perth + caKeyPath: secret/data/hub/cluster_perth_ca + ``` diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..7ddcc947 --- /dev/null +++ b/Makefile @@ -0,0 +1,102 @@ +NAME=$(shell basename `pwd`) +# This is to ensure that whether we start with a git@ or https:// URL, we end up with an https:// URL +# This is because we expect to use tokens for repo authentication as opposed to SSH keys +ifneq ($(origin TARGET_SITE), undefined) + TARGET_SITE_OPT=--set main.clusterGroupName=$(TARGET_SITE) +endif + +TARGET_ORIGIN ?= origin +TARGET_REPO=$(shell git remote show $(TARGET_ORIGIN) | grep Push | sed -e 's/.*URL:[[:space:]]*//' -e 's%^git@%%' -e 's%^https://%%' -e 's%:%/%' -e 's%^%https://%') +# git branch --show-current is also available as of git 2.22, but we will use this for compatibility +TARGET_BRANCH=$(shell git rev-parse --abbrev-ref HEAD) +HUBCLUSTER_APPS_DOMAIN=$(shell oc get ingresses.config/cluster -o jsonpath={.spec.domain}) + +# --set values always take precedence over the contents of -f +HELM_OPTS=-f values-global.yaml --set main.git.repoURL="$(TARGET_REPO)" --set main.git.revision=$(TARGET_BRANCH) \ + --set global.hubClusterDomain=$(HUBCLUSTER_APPS_DOMAIN) $(TARGET_SITE_OPT) +TEST_OPTS= -f common/examples/values-secret.yaml -f values-global.yaml --set global.repoURL="https://github.com/pattern-clone/mypattern" \ + --set main.git.repoURL="https://github.com/pattern-clone/mypattern" --set main.git.revision=main --set global.pattern="mypattern" \ + --set global.namespace="pattern-namespace" --set global.hubClusterDomain=apps.hub.example.com --set global.localClusterDomain=apps.region.example.com --set global.clusterDomain=region.example.com\ + --set "clusterGroup.imperative.jobs[0].name"="test" --set "clusterGroup.imperative.jobs[0].playbook"="ansible/test.yml" \ + --set clusterGroup.insecureUnsealVaultInsideCluster=true +PATTERN_OPTS=-f common/examples/values-example.yaml +EXECUTABLES=git helm oc ansible + +.PHONY: help +help: ## This help message + @printf "$$(grep -hE '^\S+:.*##' $(MAKEFILE_LIST) | sed -e 's/:.*##\s*/:/' -e 's/^\(.\+\):\(.*\)/\\x1b[36m\1\\x1b[m:\2/' | column -c2 -t -s :)\n" + +# Makefiles in the individual patterns should call these targets explicitly +# e.g. from industrial-edge: make -f common/Makefile show +show: ## show the starting template without installing it + helm template common/install/ --name-template $(NAME) $(HELM_OPTS) + +CHARTS=$(shell find . -type f -iname 'Chart.yaml' -exec dirname "{}" \; | sed -e 's/.\///') +test: ## run helm tests + @for t in $(CHARTS); do common/scripts/test.sh $$t all "$(TEST_OPTS) $(PATTERN_OPTS)"; if [ $$? != 0 ]; then exit 1; fi; done + +helmlint: ## run helm lint + @for t in $(CHARTS); do helm lint $(TEST_OPTS) $(PATTERN_OPTS) $$t; if [ $$? != 0 ]; then exit 1; fi; done + +API_URL ?= https://raw.githubusercontent.com/hybrid-cloud-patterns/ocp-schemas/main/openshift/4.10/ +KUBECONFORM_SKIP ?= -skip 'CustomResourceDefinition' +# We need to skip 'CustomResourceDefinition' as openapi2jsonschema seems to be unable to generate them ATM +kubeconform: ## run helm kubeconform + @for t in $(CHARTS); do helm template $(TEST_OPTS) $(PATTERN_OPTS) $$t | kubeconform -strict $(KUBECONFORM_SKIP) -verbose -schema-location $(API_URL); if [ $$? != 0 ]; then exit 1; fi; done + +validate-prereq: ## verify pre-requisites + @for t in $(EXECUTABLES); do if ! which $$t > /dev/null 2>&1; then echo "No $$t in PATH"; exit 1; fi; done + @echo "Prerequisites checked '$(EXECUTABLES)': OK" + @ansible -m ansible.builtin.command -a "{{ ansible_python_interpreter }} -c 'import kubernetes'" localhost > /dev/null 2>&1 + @echo "Python kubernetes module: OK" + @echo -n "Check for kubernetes.core collection: " + @if ! ansible-galaxy collection list | grep kubernetes.core > /dev/null 2>&1; then echo "Not found"; exit 1; fi + @echo "OK" + +validate-origin: ## verify the git origin is available + @echo Checking repo $(TARGET_REPO) - branch $(TARGET_BRANCH) + @git ls-remote --exit-code --heads $(TARGET_REPO) $(TARGET_BRANCH) >/dev/null && \ + echo "$(TARGET_REPO) - $(TARGET_BRANCH) exists" || \ + (echo "$(TARGET_BRANCH) not found in $(TARGET_REPO)"; exit 1) + +# Default targets are "deploy" and "upgrade"; they can "move" to whichever install mechanism should be default. +# legacy-deploy and legacy-upgrade should be present so that patterns don't need to depend on "deploy" and "upgrade" +# pointing to one place or another, and don't need to change when they do (provide they use either legacy- or operator- +# targets) +deploy upgrade legacy-deploy legacy-upgrade: validate-prereq validate-origin ## deploys the pattern + helm upgrade --install $(NAME) common/install/ $(HELM_OPTS) + +operator-deploy operator-upgrade: validate-origin ## runs helm install + helm upgrade --install $(NAME) common/operator-install/ $(HELM_OPTS) + +uninstall: ## runs helm uninstall + $(eval CSV := $(shell oc get subscriptions -n openshift-operators openshift-gitops-operator -ojsonpath={.status.currentCSV})) + helm uninstall $(NAME) + @oc delete csv -n openshift-operators $(CSV) + +vault-init: ## inits, unseals and configured the vault + common/scripts/vault-utils.sh vault_init common/pattern-vault.init + common/scripts/vault-utils.sh vault_unseal common/pattern-vault.init + common/scripts/vault-utils.sh vault_secrets_init common/pattern-vault.init + +vault-unseal: ## unseals the vault + common/scripts/vault-utils.sh vault_unseal common/pattern-vault.init + +load-secrets: ## loads the secrets into the vault + common/scripts/vault-utils.sh push_secrets common/pattern-vault.init + +super-linter: ## Runs super linter locally + podman run -e RUN_LOCAL=true -e USE_FIND_ALGORITHM=true \ + -e VALIDATE_BASH=false \ + -e VALIDATE_JSCPD=false \ + -e VALIDATE_KUBERNETES_KUBEVAL=false \ + -e VALIDATE_YAML=false \ + -e VALIDATE_ANSIBLE=false \ + $(DISABLE_LINTERS) \ + -v $(PWD):/tmp/lint:rw,z docker.io/github/super-linter:slim-v4 + +ansible-lint: ## run ansible lint on ansible/ folder + podman run -it -v $(PWD):/workspace:rw,z --workdir /workspace --entrypoint "/usr/local/bin/ansible-lint" quay.io/ansible/creator-ee:latest "-vvv" "ansible/" + +.phony: install test + diff --git a/README.md b/README.md new file mode 100644 index 00000000..9c6fa0cb --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# Validated Patterns common/ repository + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +## Start Here + +This repository is never used as standalone. It is usually imported in each pattern as a subtree. +In order to import the common/ the very first time you can use +`https://github.com/hybrid-cloud-patterns/multicloud-gitops/blob/main/common/scripts/make_common_subtree.sh` + +In order to update your common subtree inside your pattern repository you can either use +`https://github.com/hybrid-cloud-patterns/utilities/blob/main/scripts/update-common-everywhere.sh` or +do it manually by doing the following: + +```sh +git remote add -f upstream-common https://github.com/hybrid-cloud-patterns/common.git +git merge -s subtree -Xtheirs -Xsubtree=common upstream-common/ha-vault +``` diff --git a/acm/.helmignore b/acm/.helmignore new file mode 100644 index 00000000..b25c15b8 --- /dev/null +++ b/acm/.helmignore @@ -0,0 +1 @@ +*~ diff --git a/acm/Chart.yaml b/acm/Chart.yaml new file mode 100644 index 00000000..1c3db911 --- /dev/null +++ b/acm/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +description: A Helm chart to configure Advanced Cluster Manager for OpenShift +keywords: +- pattern +name: acm +version: 0.0.1 diff --git a/acm/templates/multiclusterhub.yaml b/acm/templates/multiclusterhub.yaml new file mode 100644 index 00000000..f925d5a6 --- /dev/null +++ b/acm/templates/multiclusterhub.yaml @@ -0,0 +1,8 @@ +apiVersion: operator.open-cluster-management.io/v1 +kind: MultiClusterHub +metadata: + name: multiclusterhub + namespace: open-cluster-management + annotations: + argocd.argoproj.io/sync-wave: "-1" +spec: {} diff --git a/acm/templates/policies/application-policies.yaml b/acm/templates/policies/application-policies.yaml new file mode 100644 index 00000000..dfb29a90 --- /dev/null +++ b/acm/templates/policies/application-policies.yaml @@ -0,0 +1,139 @@ +# TODO: Also create a GitOpsCluster.apps.open-cluster-management.io +{{- range .Values.clusterGroup.managedClusterGroups }} +{{- $group := . }} +{{- if not .hostedArgoSites }} +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: {{ .name }}-clustergroup-policy + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + argocd.argoproj.io/compare-options: IgnoreExtraneous +spec: + remediationAction: enforce + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: {{ .name }}-clustergroup-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + apiVersion: argoproj.io/v1alpha1 + kind: Application + metadata: + name: {{ $.Values.global.pattern }}-{{ .name }} + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground + spec: + project: default + source: + repoURL: {{ coalesce .repoURL $.Values.global.repoURL }} + targetRevision: {{ coalesce .targetRevision $.Values.global.targetRevision }} + path: {{ default "common/clustergroup" .path }} + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-{{ .name }}.yaml" + {{- range $valueFile := .extraValueFiles }} + - {{ $valueFile | quote }} + {{- end }} + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: {{ $.Values.global.pattern }} + - name: global.hubClusterDomain + value: {{ $.Values.global.hubClusterDomain }} + - name: global.localClusterDomain + value: '{{ `{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain }}` }}' + # Requires ACM 2.6 or higher + - name: global.clusterDomain + value: '{{ `{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain | replace "apps." "" }}` }}' + - name: clusterGroup.name + value: {{ $group.name }} + {{- range .helmOverrides }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end }} + {{- if .fileParameters }} + fileParameters: + {{- range .fileParameters }} + - name: {{ .name }} + path: {{ .path }} + {{- end }} + {{- end }} + destination: + server: https://kubernetes.default.svc + namespace: {{ $.Values.global.pattern }}-{{ .name }} + syncPolicy: + automated: + prune: false + selfHeal: true + ignoreDifferences: + - group: apps + kind: Deployment + jsonPointers: + - /spec/replicas + - group: route.openshift.io + kind: Route + jsonPointers: + - /status +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: {{ .name }}-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: {{ .name }}-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: {{ .name }}-clustergroup-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: {{ .name }}-placement +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + {{- if .clusterSelector }} + clusterSelector: {{ .clusterSelector | toPrettyJson }} + {{- else if (not $group.acmlabels) }} + clusterSelector: + matchLabels: + clusterGroup: {{ $group.name }} + {{- else if eq (len $group.acmlabels) 0 }} + clusterSelector: + matchLabels: + clusterGroup: {{ $group.name }} + {{- else }} + clusterSelector: + matchLabels: + {{- range .acmlabels }} + {{ .name }}: {{ .value }} + {{- end }} + {{- end }} +--- +{{- end }} +{{- end }} diff --git a/acm/templates/policies/ocp-gitops-policy.yaml b/acm/templates/policies/ocp-gitops-policy.yaml new file mode 100644 index 00000000..7ca61b0f --- /dev/null +++ b/acm/templates/policies/ocp-gitops-policy.yaml @@ -0,0 +1,76 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: openshift-gitops-policy + annotations: + policy.open-cluster-management.io/standards: NIST-CSF + policy.open-cluster-management.io/categories: PR.DS Data Security + policy.open-cluster-management.io/controls: PR.DS-1 Data-at-rest + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + argocd.argoproj.io/compare-options: IgnoreExtraneous +spec: + remediationAction: enforce + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: openshift-gitops-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + # This is an auto-generated file. DO NOT EDIT + apiVersion: operators.coreos.com/v1alpha1 + kind: Subscription + metadata: + name: openshift-gitops-operator + namespace: openshift-operators + labels: + operators.coreos.com/openshift-gitops-operator.openshift-operators: '' + spec: + channel: stable + installPlanApproval: Automatic + name: openshift-gitops-operator + source: redhat-operators + sourceNamespace: openshift-marketplace + config: + env: + - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES + value: "*" +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: openshift-gitops-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: openshift-gitops-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: openshift-gitops-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: openshift-gitops-placement +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: vendor + operator: In + values: + - OpenShift diff --git a/acm/templates/provision/_install-config.tpl b/acm/templates/provision/_install-config.tpl new file mode 100644 index 00000000..39aa03eb --- /dev/null +++ b/acm/templates/provision/_install-config.tpl @@ -0,0 +1,59 @@ +{{- define "cluster.install-config" -}} + +{{- $type := "None" }} +{{- $cloud := "None" }} +{{- $region := "None" }} + +{{- if .platform.aws }} +{{- $cloud = "aws" }} +{{- $region = .platform.aws.region }} +{{- $type = "m5.xlarge" }} +{{- else if .platform.azure }} +{{- $cloud = "azure" }} +{{- $region = .platform.azure.region }} +{{- $type = "Standard_D8s_v3" }} +{{- end }} + +apiVersion: v1 +metadata: + name: '{{ .name }}' +baseDomain: {{ .baseDomain }} +controlPlane: + architecture: amd64 + hyperthreading: Enabled + name: controlPlane + {{- if .controlPlane }} + replicas: {{ default 3 .controlPlane.count }} + platform: {{- .controlPlane.platform | toPrettyJson }} + {{- else }} + replicas: 3 + platform: + {{ $cloud }}: + type: {{ $type }} + {{- end }} +compute: +- hyperthreading: Enabled + architecture: amd64 + name: 'worker' + {{- if .workers }} + replicas: {{ default 3 .workers.count }} + platform: {{- .workers.platform | toPrettyJson }} + {{- else }} + replicas: 3 + platform: + {{ $cloud }}: + type: {{ $type }} + {{- end }} +networking: + clusterNetwork: + - cidr: 10.128.0.0/14 + hostPrefix: 23 + machineNetwork: + - cidr: 10.0.0.0/16 + networkType: OpenShiftSDN + serviceNetwork: + - 172.30.0.0/16 +platform: {{ .platform | toPrettyJson }} +pullSecret: "" # skip, hive will inject based on it's secrets +sshKey: "" # skip, hive will inject based on it's secrets +{{- end -}} \ No newline at end of file diff --git a/acm/templates/provision/clusterpool.yaml b/acm/templates/provision/clusterpool.yaml new file mode 100644 index 00000000..0ac851c5 --- /dev/null +++ b/acm/templates/provision/clusterpool.yaml @@ -0,0 +1,87 @@ +{{- range .Values.clusterGroup.managedClusterGroups }} +{{- $group := . }} +{{- if .clusterPools }}{{- /* We only create ManagedClusterSets if there are clusterPools defined */}} +apiVersion: cluster.open-cluster-management.io/v1beta1 +kind: ManagedClusterSet +metadata: + annotations: + cluster.open-cluster-management.io/submariner-broker-ns: {{ .name }}-broker + name: {{ .name }} +spec: + clusterSelector: + selectorType: LegacyClusterSetLabel +--- +{{- range .clusterPools }} + +{{- $pool := . }} +{{- $poolName := print .name "-" $group.name }} + +{{- $cloud := "None" }} +{{- $region := "None" }} + +{{- if .platform.aws }} +{{- $cloud = "aws" }} +{{- $region = .platform.aws.region }} +{{- else if .platform.azure }} +{{- $cloud = "azure" }} +{{- $region = .platform.azure.region }} +{{- end }} + +apiVersion: hive.openshift.io/v1 +kind: ClusterPool +metadata: + name: "{{ $poolName }}" + annotations: + argocd.argoproj.io/sync-wave: "10" + labels: + cloud: {{ $cloud }} + region: '{{ $region }}' + vendor: OpenShift + cluster.open-cluster-management.io/clusterset: {{ .name }} +spec: + {{- if .size }} + size: {{ .size }} + {{- else }} + size: {{ len .clusters }} + {{- end }} + runningCount: {{ len .clusters }} + baseDomain: {{ .baseDomain }} + installConfigSecretTemplateRef: + name: {{ $poolName }}-install-config + imageSetRef: + name: img{{ .openshiftVersion }}-x86-64-appsub + pullSecretRef: + name: {{ $poolName }}-pull-secret + skipMachinePools: true # Disable MachinePool as using custom install-config + platform: + {{ $cloud }}: + credentialsSecretRef: + name: {{ $poolName }}-creds + region: {{ $region }} +--- +{{- range .clusters }} +apiVersion: hive.openshift.io/v1 +kind: ClusterClaim +metadata: + name: '{{ . }}-{{ $group.name }}' + annotations: + argocd.argoproj.io/sync-wave: "20" + cluster.open-cluster-management.io/createmanagedcluster: "true" + labels: + clusterClaimName: {{ . }}-{{ $group.name }} + {{- if (not $group.acmlabels) }} + clusterGroup: {{ $group.name }} + {{- else if eq (len $group.acmlabels) 0 }} + clusterGroup: {{ $group.name }} + {{- else }} + {{- range $group.acmlabels }} + {{ .name }}: {{ .value }} + {{- end }} + {{- end }} +spec: + clusterPoolName: {{ $pool.name }} +--- +{{- end }}{{- /* range .range clusters */}} +{{- end }}{{- /* range .clusterPools */}} +{{- end }}{{- /* if .clusterPools) */}} +{{- end }}{{- /* range .Values.clusterGroup.managedClusterGroups */}} diff --git a/acm/templates/provision/secrets-aws.yaml b/acm/templates/provision/secrets-aws.yaml new file mode 100644 index 00000000..002c9247 --- /dev/null +++ b/acm/templates/provision/secrets-aws.yaml @@ -0,0 +1,84 @@ +{{- range .Values.clusterGroup.managedClusterGroups }} +{{- $group := . }} +{{- range .clusterPools }} +{{- $poolName := print .name "-" $group.name }} +{{- if .platform.aws }} +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: {{ $poolName }}-creds +spec: + dataFrom: + - extract: + # Expects entries called: aws_access_key_id and aws_secret_access_key + key: {{ default "secret/data/hub/aws" .awsKeyPath }} + refreshInterval: 24h0m0s + secretStoreRef: + name: {{ $.Values.secretStore.name }} + kind: {{ $.Values.secretStore.kind }} + target: + name: {{ $poolName }}-creds + creationPolicy: Owner + template: + type: Opaque +--- +# For use when manually creating clusters with ACM +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: {{ $poolName }}-infra-creds +spec: + data: + - secretKey: openshiftPullSecret + remoteRef: + key: {{ default "secret/data/hub/openshiftPullSecret" .pullSecretKeyPath }} + property: content + - secretKey: awsKeyId + remoteRef: + key: {{ default "secret/data/hub/aws" .awsKeyPath }} + property: aws_access_key_id + - secretKey: awsAccessKey + remoteRef: + key: {{ default "secret/data/hub/aws" .awsKeyPath }} + property: aws_secret_access_key + - secretKey: sshPublicKey + remoteRef: + key: {{ default "secret/data/hub/publickey" .sshPublicKeyPath }} + property: content + - secretKey: sshPrivateKey + remoteRef: + key: {{ default "secret/data/hub/privatekey" .sshPrivateKeyPath }} + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: {{ $.Values.secretStore.name }} + kind: {{ $.Values.secretStore.kind }} + target: + name: {{ $poolName }}-infra-creds + creationPolicy: Owner + template: + type: Opaque + metadata: + labels: + cluster.open-cluster-management.io/credentials: "" + cluster.open-cluster-management.io/type: aws + data: + baseDomain: "{{ .baseDomain }}" + pullSecret: |- + {{ "{{ .openshiftPullSecret | toString }}" }} + aws_access_key_id: |- + {{ "{{ .awsKeyId | toString }}" }} + aws_secret_access_key: |- + {{ "{{ .awsAccessKey | toString }}" }} + ssh-privatekey: |- + {{ "{{ .sshPrivateKey | toString }}" }} + ssh-publickey: |- + {{ "{{ .sshPublicKey | toString }}" }} + httpProxy: "" + httpsProxy: "" + noProxy: "" + additionalTrustBundle: "" +--- +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/acm/templates/provision/secrets-azure.yaml b/acm/templates/provision/secrets-azure.yaml new file mode 100644 index 00000000..7fe6271b --- /dev/null +++ b/acm/templates/provision/secrets-azure.yaml @@ -0,0 +1,84 @@ +{{- range .Values.clusterGroup.managedClusterGroups }} +{{- $group := . }} +{{- range .clusterPools }} +{{- $poolName := print .name "-" $group.name }} +{{- if .platform.azure }} +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: {{ $poolName }}-creds +spec: + data: + - secretKey: azureOsServicePrincipal + remoteRef: + key: {{ default "secret/data/hub/azureOsServicePrincipal" .azureKeyPath }} + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: {{ $.Values.secretStore.name }} + kind: {{ $.Values.secretStore.kind }} + target: + name: {{ $poolName }}-creds + creationPolicy: Owner + template: + type: Opaque + data: + osServicePrincipal.json: |- + {{ "{{ .azureOsServicePrincipal | toString }}" }} +--- +# For use when manually creating clusters with ACM +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: {{ $poolName }}-infra-creds +spec: + data: + - secretKey: openshiftPullSecret + remoteRef: + key: {{ default "secret/data/hub/openshiftPullSecret" .pullSecretKeyPath }} + property: content + - secretKey: sshPublicKey + remoteRef: + key: {{ default "secret/data/hub/publickey" .sshPublicKeyPath }} + property: content + - secretKey: sshPrivateKey + remoteRef: + key: {{ default "secret/data/hub/privatekey" .sshPrivateKeyPath }} + property: content + - secretKey: azureOsServicePrincipal + remoteRef: + key: {{ default "secret/data/hub/azureOsServicePrincipal" .azureKeyPath }} + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: {{ $.Values.secretStore.name }} + kind: {{ $.Values.secretStore.kind }} + target: + name: {{ $poolName }}-infra-creds + creationPolicy: Owner + template: + type: Opaque + metadata: + labels: + cluster.open-cluster-management.io/credentials: "" + cluster.open-cluster-management.io/type: aws + data: + cloudName: AzurePublicCloud + osServicePrincipal.json: |- + {{ "{{ .azureOsServicePrincipal | toString }}" }} + baseDomain: "{{ .baseDomain }}" + baseDomainResourceGroupName: "{{ .platform.azure.baseDomainResourceGroupName | toString }}" + pullSecret: |- + {{ "{{ .openshiftPullSecret | toString }}" }} + ssh-privatekey: |- + {{ "{{ .sshPrivateKey | toString }}" }} + ssh-publickey: |- + {{ "{{ .sshPublicKey | toString }}" }} + httpProxy: "" + httpsProxy: "" + noProxy: "" + additionalTrustBundle: "" +--- +{{- end }} +{{- end }} +{{- end }} diff --git a/acm/templates/provision/secrets-common.yaml b/acm/templates/provision/secrets-common.yaml new file mode 100644 index 00000000..21a03b73 --- /dev/null +++ b/acm/templates/provision/secrets-common.yaml @@ -0,0 +1,61 @@ +{{- range .Values.clusterGroup.managedClusterGroups }} +{{- $group := . }} +{{- range .clusterPools }} +{{- $poolName := print .name "-" $group.name }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ $poolName }}-install-config +data: + # Base64 encoding of install-config yaml + install-config.yaml: {{ include "cluster.install-config" . | b64enc }} +type: Opaque +--- +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: {{ $poolName }}-pull-secret +spec: + data: + - secretKey: openshiftPullSecret + remoteRef: + key: {{ default "secret/data/hub/openshiftPullSecret" .pullSecretKeyPath }} + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: {{ $.Values.secretStore.name }} + kind: {{ $.Values.secretStore.kind }} + target: + name: {{ $poolName }}-pull-secret + creationPolicy: Owner + template: + type: kubernetes.io/dockerconfigjson + data: + .dockerconfigjson: |- + {{ "{{ .openshiftPullSecret | toString }}" }} +--- +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: {{ $poolName }}-ssh-private-key +spec: + data: + - secretKey: sshPrivateKey + remoteRef: + key: {{ default "secret/data/hub/privatekey" .sshPrivateKeyPath }} + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: {{ $.Values.secretStore.name }} + kind: {{ $.Values.secretStore.kind }} + target: + name: {{ $poolName }}-ssh-private-key + creationPolicy: Owner + template: + type: Opaque + data: + ssh-privatekey: |- + {{ "{{ .sshPrivateKey | toString }}" }} +--- +{{- end }} +{{- end }} diff --git a/acm/test.yaml b/acm/test.yaml new file mode 100644 index 00000000..669daf07 --- /dev/null +++ b/acm/test.yaml @@ -0,0 +1,35 @@ +clusterGroup: + managedClusterGroups: + exampleRegion: + name: region-one + + # Before enabling cluster provisioning, ensure AWS/Azure credentials and OCP + # pull secrets are defined in Vault. See values-secret.yaml.template + # + clusterPools: + exampleAWSPool: + name: aws-ap + openshiftVersion: 4.10.18 + baseDomain: blueprints.rhecoeng.com + platform: + aws: + region: ap-southeast-2 + clusters: + - One + exampleAzurePool: + name: azure-us + openshiftVersion: 4.10.18 + baseDomain: blueprints.rhecoeng.com + platform: + azure: + baseDomainResourceGroupName: dojo-dns-zones + region: eastus + clusters: + - Two + - Three + acmlabels: + - name: clusterGroup + value: region-one + helmOverrides: + - name: clusterGroup.isHubCluster + value: false diff --git a/acm/values.yaml b/acm/values.yaml new file mode 100644 index 00000000..e423d531 --- /dev/null +++ b/acm/values.yaml @@ -0,0 +1,26 @@ +global: + pattern: none + repoURL: none + targetRevision: main + + +clusterGroup: + managedClusterGroups: +# testRegion: +# name: region-one +# clusterPools: +# testPool: +# name: spoke +# openshiftVersion: 4.10.18 +# provider: +# region: ap-southeast-2 +# baseDomain: blueprints.rhecoeng.com +# clusters: +# - spoke1 +# labels: +# - name: clusterGroup +# value: region-one + +secretStore: + name: vault-backend + kind: ClusterSecretStore \ No newline at end of file diff --git a/ansible/ansible.cfg b/ansible/ansible.cfg new file mode 100644 index 00000000..c8bec627 --- /dev/null +++ b/ansible/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +display_skipped_hosts=False +localhost_warning=False +roles_path=./roles:~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles diff --git a/ansible/playbooks/vault/push_secrets.yaml b/ansible/playbooks/vault/push_secrets.yaml new file mode 100644 index 00000000..ed3cad61 --- /dev/null +++ b/ansible/playbooks/vault/push_secrets.yaml @@ -0,0 +1,10 @@ +--- +- name: Secret injection of validated-patterns + hosts: localhost + connection: local + gather_facts: false + tasks: + - name: Run push secrets task + include_role: + name: vault_utils + tasks_from: push_secrets diff --git a/ansible/playbooks/vault/vault.yaml b/ansible/playbooks/vault/vault.yaml new file mode 100644 index 00000000..64711e47 --- /dev/null +++ b/ansible/playbooks/vault/vault.yaml @@ -0,0 +1,7 @@ +--- +- name: Vault initialization + hosts: localhost + connection: local + gather_facts: false + roles: + - vault_utils diff --git a/ansible/roles/vault_utils/README.md b/ansible/roles/vault_utils/README.md new file mode 100644 index 00000000..e83471b9 --- /dev/null +++ b/ansible/roles/vault_utils/README.md @@ -0,0 +1,79 @@ +Role Name +========= + +Bunch of utilities to manage the vault inside k8s imperatively + +Requirements +------------ + +ansible-galaxy collection install kubernetes.core (formerly known as community.kubernetes) + +Role Variables +-------------- + +Defaults as to where the values-secret.yaml file is and the two ways to connect to a kubernetes cluster +(KUBERCONFIG and ~/.kube/config respectively): + +```yaml +values_secret: "{{ lookup('env', 'HOME') }}/values-secret.yaml" +kubeconfig: "{{ lookup('env', 'KUBECONFIG') }}" +kubeconfig_backup: "{{ lookup('env', 'HOME') }}/.kube/config" +``` + +Default values for vault configuration: + +```yaml +vault_ns: "vault" +vault_pod: "vault-0" +vault_hub: "hub" +vault_hub_kubernetes_host: https://$KUBERNETES_PORT_443_TCP_ADDR:443 +# Needs extra escaping due to how it gets injected via shell in the vault +vault_hub_capabilities: '[\\\"read\\\"]' +vault_base_path: "secret" +vault_path: "{{ vault_base_path }}/{{ vault_hub }}" +vault_hub_ttl: "15m" +vault_pki_max_lease_ttl: "8760h" +external_secrets_ns: golang-external-secrets +external_secrets_sa: golang-external-secrets +``` + +Use the local file system (output_file variable) to store the vault's unseal keys. +If set to false they will be stored inside a secret defined by `unseal_secret` +in the `unseal_namespace` namespace: + +```yaml +file_unseal: true +# token inside a secret in the cluster. +# *Note* that this is fundamentally unsafe +output_file: "common/pattern-vault.init" +unseal_secret: "vaultkeys" +unseal_namespace: "imperative" +``` + +Dependencies +------------ + +This relies on [kubernetes.core](https://docs.ansible.com/ansible/latest/collections/kubernetes/core/k8s_module.html) + +Internals +--------- + +Here is the rough high-level algorithm used to unseal the vault: + +1. Check vault status. If vault is not initialized go to 2. If initialized go to 3. +2. Initialize vault and store unseal keys + login token either on a local file + or inside a secret in k8s (file_unseal var controls this) +3. Check vault status. If vault is unsealed go to 5. else to to 4. +4. Unseal the vault using the secrets read from the file or the secret + (file_unseal controls this) +5. Configure the vault (should be idempotent) + +License +------- + +Apache + +Author Information +------------------ + +Michele Baldessari diff --git a/ansible/roles/vault_utils/defaults/main.yml b/ansible/roles/vault_utils/defaults/main.yml new file mode 100644 index 00000000..04fccf7b --- /dev/null +++ b/ansible/roles/vault_utils/defaults/main.yml @@ -0,0 +1,26 @@ +--- +# defaults file for vault_utils +values_secret: "{{ lookup('env', 'HOME') }}/values-secret.yaml" +kubeconfig: "{{ lookup('env', 'KUBECONFIG') }}" +kubeconfig_backup: "{{ lookup('env', 'HOME') }}/.kube/config" +vault_ns: "vault" +vault_pod: "vault-0" +vault_hub: "hub" +vault_pvc: "data-vault-0" +vault_hub_kubernetes_host: https://$KUBERNETES_PORT_443_TCP_ADDR:443 +# Needs extra escaping due to how it gets injected via shell in the vault +vault_hub_capabilities: '[\\\"read\\\"]' +vault_base_path: "secret" +vault_path: "{{ vault_base_path }}/{{ vault_hub }}" +vault_hub_ttl: "15m" +vault_pki_max_lease_ttl: "8760h" +output_file: "common/pattern-vault.init" +external_secrets_ns: golang-external-secrets +external_secrets_sa: golang-external-secrets +external_secrets_secret: golang-external-secrets +# Setting this to false makes the role store the vault unseal keys and root login +# token inside a secret in the cluster. +# *Note* that this is fundamentally unsafe +file_unseal: true +unseal_secret: "vaultkeys" +unseal_namespace: "imperative" diff --git a/ansible/roles/vault_utils/handlers/main.yml b/ansible/roles/vault_utils/handlers/main.yml new file mode 100644 index 00000000..a983544d --- /dev/null +++ b/ansible/roles/vault_utils/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for vault_utils diff --git a/ansible/roles/vault_utils/meta/main.yml b/ansible/roles/vault_utils/meta/main.yml new file mode 100644 index 00000000..c99eb3a9 --- /dev/null +++ b/ansible/roles/vault_utils/meta/main.yml @@ -0,0 +1,31 @@ +galaxy_info: + author: Validated Patterns Team https://github.com/hybrid-cloud-patterns/ + description: Utilities to manage vault in kubernetes (init, unseal, etc) + + issue_tracker_url: https://github.com/hybrid-cloud-patterns/common/issues + license: Apache-2.0 + min_ansible_version: "2.1" + + # If this a Container Enabled role, provide the minimum Ansible Container version. + # min_ansible_container_version: + + platforms: + - name: Fedora + versions: + - all + - name: Ubuntu + versions: + - all + - name: Debian + versions: + - all + - name: EL + versions: + - "8" + - "9" + + galaxy_tags: [] + +dependencies: [] + # List your role dependencies here, one per line. Be sure to remove the '[]' above, + # if you add dependencies to this list. diff --git a/ansible/roles/vault_utils/tasks/main.yml b/ansible/roles/vault_utils/tasks/main.yml new file mode 100644 index 00000000..1da3e440 --- /dev/null +++ b/ansible/roles/vault_utils/tasks/main.yml @@ -0,0 +1,20 @@ +--- +- name: Delete vault + import_tasks: vault_delete.yaml + tags: vault_delete + +- name: Run vault init tasks + import_tasks: vault_init.yaml + tags: vault_init + +- name: Unseal vault + import_tasks: vault_unseal.yaml + tags: vault_unseal + +- name: Vault secrets init + import_tasks: vault_secrets_init.yaml + tags: vault_secrets_init + +- name: Load secrets + import_tasks: push_secrets.yaml + tags: push_secrets diff --git a/ansible/roles/vault_utils/tasks/pre_check.yaml b/ansible/roles/vault_utils/tasks/pre_check.yaml new file mode 100644 index 00000000..1dc5f445 --- /dev/null +++ b/ansible/roles/vault_utils/tasks/pre_check.yaml @@ -0,0 +1,26 @@ +--- +- name: Check if the kubernetes python module is usable from ansible + ansible.builtin.command: "{{ ansible_python_interpreter }} -c 'import kubernetes'" + changed_when: false + +- name: Check if KUBECONFIG is correctly set + ansible.builtin.debug: + msg: "KUBECONFIG is not set, falling back to ~/.kube/config" + when: kubeconfig is not defined or kubeconfig | length == 0 + +- name: Check if ~/.kube/config exists + ansible.builtin.stat: + path: "{{ kubeconfig_backup }}" + register: kubeconfig_result + +- name: Check if we're running inside an OCP cluster directly + ansible.builtin.set_fact: + running_in_ocp: "{{ lookup('env', 'KUBERNETES_SERVICE_HOST') | length > 0 | bool }}" + +- name: Fail if both KUBECONFIG and ~/.kube/config do not exist but only when not running in a cluster + ansible.builtin.fail: + msg: "{{ kubeconfig_backup }} not found and KUBECONFIG unset. Bailing out." + failed_when: + - not running_in_ocp + - not kubeconfig_result.stat.exists + - kubeconfig is not defined or kubeconfig | length == 0 diff --git a/ansible/roles/vault_utils/tasks/push_secrets.yaml b/ansible/roles/vault_utils/tasks/push_secrets.yaml new file mode 100644 index 00000000..784da4d2 --- /dev/null +++ b/ansible/roles/vault_utils/tasks/push_secrets.yaml @@ -0,0 +1,208 @@ +--- +- include_tasks: pre_check.yaml +- include_tasks: vault_status.yaml + +# Unfortunately we cannot loop vault_status and just check if the vault is unsealed +# https://github.com/ansible/proposals/issues/136 +# So here we keep running the 'vault status' command until sealed is set to false +- name: If the vault is still sealed we need to retry + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ vault_pod }}" + command: vault status -format=json + register: vault_status_json + until: "'stdout' in vault_status_json and (not (vault_status_json.stdout | from_json)['sealed'] | bool)" + retries: 20 + delay: 45 + failed_when: "'stdout_lines' not in vault_status_json" + +- name: Check for existence of "{{ values_secret }}" + ansible.builtin.stat: + path: "{{ values_secret }}" + register: result + failed_when: not result.stat.exists + +- name: Parse "{{ values_secret }}" + ansible.builtin.set_fact: + all_values: "{{ lookup('file', values_secret) | from_yaml | default({}, true) }}" + +- name: Check for secrets keys + ansible.builtin.assert: + that: + - "('secrets' in all_values.keys()) or ('files' in all_values.keys())" + fail_msg: "Was not able to parse any secrets from file {{ values_secret }}. Either 'secrets:' or 'files:' top-level keys (or both) must exist" + +- name: Set secrets and file_secrets facts + ansible.builtin.set_fact: + secrets: "{{ all_values['secrets'] | default({}) }}" + file_secrets: "{{ all_values['files'] | default({}) }}" + +- name: Verify we have any secrets at all + ansible.builtin.fail: + msg: "Was not able to parse any secrets from file {{ values_secret }}: {{ all_values }}" + failed_when: + secrets | combine(file_secrets) | length == 0 + +- name: Check the value-secret.yaml file for errors in the secrets section + ansible.builtin.fail: + msg: > + "{{ item }}" is not properly formatted. Each key under 'secrets:' + needs to point to a dictionary of key, value pairs. See values-secret.yaml.template. + when: > + item.key | length == 0 or + item.value is not mapping + loop: + "{{ secrets | dict2items }}" + loop_control: + label: "{{ item.key }}" + +- name: Validate file references in the files section of value-secret.yaml + ansible.builtin.stat: + path: '{{ file_stat.value }}' + register: file_values + loop_control: + loop_var: file_stat + loop: + "{{ file_secrets | dict2items }}" + +- name: Debug file_stat + ansible.builtin.debug: + var: file_stat + when: debug | default(False) | bool + +- name: Debug file_values + ansible.builtin.debug: + var: file_values + when: debug | default(False) | bool + +- name: Fail if referenced file does not exist + ansible.builtin.fail: + msg: > + "file {{ item.file_stat.key }} {{ item.file_stat.value }}" must exist and be a file + when: > + not item.stat.exists + loop: + "{{ file_values.results }}" + +# Detect here if we have only the following two keys under a password +# s3.accessKey: +# s3.secretKey: +# If we do, then detect it and calculate the b64 s3Secret token +# Note: the vars: line is due to https://github.com/ansible/ansible/issues/40239 +- name: Check if any of the passwords has only s3.[accessKey,secretKey] and generate the combined s3Secret in that case + ansible.builtin.set_fact: + s3keys: "{{ s3keys | default({}) | combine({ item.key: {'s3Secret': s3secret | b64encode } }) }}" + vars: + s3secret: "{{ 's3.accessKey: ' + item.value['s3.accessKey'] + '\ns3.secretKey: ' + item.value['s3.secretKey'] }}" + when: + - '"s3.accessKey" in item.value.keys()' + - '"s3.secretKey" in item.value.keys()' + - '"s3Secret" not in item.value.keys()' + loop: + "{{ secrets | dict2items }}" + loop_control: + label: "{{ item.key }}" + +- name: Merge any s3Secret into the secrets dictionary if we have any + ansible.builtin.set_fact: + secrets: "{{ secrets | combine(s3keys) }}" + when: + s3keys is defined and s3keys | length > 0 + +# The values-secret.yaml file is in the fairly loose form of: +# secrets: +# group1: +# key1: value1 +# key2: value2 +# group2: +# key1: valueA +# key4: valueC +# The above will generate: +# vault kv put 'secret/hub/group1' key1='value1' key2='value2' +# vault kv put 'secret/hub/group2' key1='valueA' key4='valueC' +# Below we loop on the top level keys (group1, group2) and for each +# sub-top-level key (key1, key2) we create a single 'key1=value1 key2=value2' string +# +# Special note is to be given to the regex_replace which is run against each value aka password: +# A. The need for it is to quote the passwords +# B. Since it needs to cater to multiline strings (certs) and ansible offers no way +# to specify re.DOTALL and re.MULTILINE we need to use (?ms) at the beginning +# See https://docs.python.org/3/library/re.html and (?aiLmsux) section +# and https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/filter/core.py#L124 +# C. The \\A and \\Z match the beginning and end of a string (in case of multiline strings +# do not want to match every line) + +- name: Set defaults for vault_cmds and secret_files_vault_cmds to prevent undefined variable errors + ansible.builtin.set_fact: + vault_cmds: "{{ vault_cmds | default({}) }}" + secret_files_vault_cmds: "{{ secret_files_vault_cmds | default({}) }}" + +- name: Set secrets vault commands fact + ansible.builtin.set_fact: + vault_cmds: "{{ vault_cmds | combine({ item.key: vault_cmd}) }}" + vars: + vault_cmd: "vault kv put '{{ vault_path }}/{{ item.key }}' + {{ item.value.keys() | zip(item.value.values() | map('regex_replace', '(?ms)\\A(.*)\\Z', \"'\\1'\")) | map('join', '=') | list | join(' ') }}" + loop: + "{{ secrets | dict2items }}" + loop_control: + label: "{{ item.key }}" + +- name: Set files vault commands fact + ansible.builtin.set_fact: + secret_files_vault_cmds: "{{ secret_files_vault_cmds | combine({ item.key: vault_cmd}) }}" + vars: + vault_cmd: "cat '{{ item.value | expanduser }}' | oc exec -n {{ vault_ns }} {{ vault_pod }} -it -- sh -c 'cat - > /tmp/vault_content'; oc exec -n {{ vault_ns }} {{ vault_pod }} -it -- sh -c 'base64 --wrap=0 /tmp/vault_content | vault kv put {{ vault_path }}/{{ item.key }} b64content=- content=@/tmp/vault_content; rm /tmp/vault_content'" # noqa yaml + loop: + "{{ file_secrets | dict2items }}" + loop_control: + label: "{{ item.key }}" + +- name: Debug vault commands + ansible.builtin.debug: + msg: "{{ vault_cmds }}" + when: debug | default(False) | bool + +- name: Debug files vault commands + ansible.builtin.debug: + msg: "{{ secret_files_vault_cmds }}" + when: debug | default(False) | bool + +# This step is not really needed when running make vault-init + load-secrets as +# everything is sequential +# It is needed when the vault is unsealed/configured inside the cluster and load-secrets +# gets run *while* the cronjob configures the vault. I.e. it might be half configured and return +# errors +- name: Make sure that the vault auth policy exists + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ vault_pod }}" + command: + sh -c "vault list auth/{{ vault_hub }}/role | grep '{{ vault_hub }}-role'" + register: vault_role_cmd + until: vault_role_cmd.rc == 0 + retries: 20 + delay: 45 + changed_when: false + +- name: Add the actual secrets to the vault + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ vault_pod }}" + command: | + sh -c "{{ item.value }}" + loop: + "{{ vault_cmds | dict2items }}" + loop_control: + label: "{{ item.key }}" + when: not debug | default(False) | bool + + # This has to be shell because of the use of stdin and pipes +- name: Add the file secrets to the vault + ansible.builtin.shell: # noqa: command-instead-of-shell + "{{ item.value }}" + loop: + "{{ secret_files_vault_cmds | dict2items }}" + loop_control: + label: "{{ item.key }}" + when: not debug | default(False) | bool diff --git a/ansible/roles/vault_utils/tasks/vault_delete.yaml b/ansible/roles/vault_utils/tasks/vault_delete.yaml new file mode 100644 index 00000000..f0e289e7 --- /dev/null +++ b/ansible/roles/vault_utils/tasks/vault_delete.yaml @@ -0,0 +1,23 @@ +--- +- include_tasks: pre_check.yaml +- include_tasks: vault_status.yaml + +# Note: We do not wait on purpose here as the pod will be recreated +# anyways and that would race. We are fine with having it gone once +- name: Delete vault pod + kubernetes.core.k8s: + state: absent + api_version: v1 + kind: Pod + namespace: "{{ vault_ns }}" + name: "{{ item }}" + loop: "{{ vault_pods }}" + +- name: Delete vault pvc + kubernetes.core.k8s: + state: absent + api_version: v1 + kind: PersistentVolumeClaim + namespace: "{{ vault_ns }}" + name: "data-{{ item }}" + loop: "{{ vault_pods }}" diff --git a/ansible/roles/vault_utils/tasks/vault_init.yaml b/ansible/roles/vault_utils/tasks/vault_init.yaml new file mode 100644 index 00000000..e3ba9cb6 --- /dev/null +++ b/ansible/roles/vault_utils/tasks/vault_init.yaml @@ -0,0 +1,85 @@ +--- +- include_tasks: pre_check.yaml +- include_tasks: vault_status.yaml + +# If the vault is already initialized we skip all the tasks below +- name: Is the vault initialized? + ansible.builtin.set_fact: + vault_initialized: "{{ vault_status['initialized'] | bool }}" + +# Note that the 'realpath' filter explicitely only resolves on the ansible/local box +# which is fine in our case +- name: Set absolute path for output_file + ansible.builtin.set_fact: + output_file_abs: "{{ output_file | realpath }}" + when: + - not vault_initialized + - file_unseal + +- name: Check for existence of "{{ output_file_abs }}" + ansible.builtin.stat: + path: "{{ output_file_abs }}" + register: result + when: + - not vault_initialized + - file_unseal + +- name: Rename "{{ output_file_abs }} if it exists" + ansible.builtin.copy: + src: "{{ output_file_abs }}" + dest: "{{ output_file_abs }}.bak" + mode: '0600' + when: + - not vault_initialized + - file_unseal + - result.stat.exists + +# We need to retry here because the vault service might be starting +# and can return a 500 internal server until its state is fully ready +- name: Init vault operator + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ vault_pod }}" + command: vault operator init -format=json + register: vault_init_json_out + until: vault_init_json_out is not failed + retries: 10 + delay: 15 + when: not vault_initialized + +- name: Set vault init output json fact + ansible.builtin.set_fact: + vault_init_json: "{{ vault_init_json_out.stdout | from_json }}" + when: not vault_initialized + +# We store the the operator unseal keys and root token to a file when +# the vault was not already initialized *and* when unseal_from_cluster +# is set to false +- name: Save vault operator output (local file) + ansible.builtin.copy: + follow: true + dest: "{{ output_file_abs }}" + content: "{{ vault_init_json | to_nice_json }}" + mode: '0600' + when: + - not vault_initialized + - file_unseal + +# We store the the operator unseal keys and root token to a secret inside +# the cluster when the vault was not already initialized *and* when +# unseal_from_cluster is set to true +- name: Save vault operator output (into a secret inside the cluster) + kubernetes.core.k8s: + state: present + definition: + apiVersion: v1 + kind: Secret + type: Opaque + metadata: + name: "{{ unseal_secret }}" + namespace: "{{ unseal_namespace }}" + data: + vault_data_json: "{{ vault_init_json | to_nice_json | b64encode }}" + when: + - not vault_initialized + - not file_unseal diff --git a/ansible/roles/vault_utils/tasks/vault_pki_init.yaml b/ansible/roles/vault_utils/tasks/vault_pki_init.yaml new file mode 100644 index 00000000..ca5fe697 --- /dev/null +++ b/ansible/roles/vault_utils/tasks/vault_pki_init.yaml @@ -0,0 +1,50 @@ +# NOTE: This task is currently not used +--- +- include_tasks: pre_check.yaml + +- name: Fetch Ingress object + kubernetes.core.k8s_info: + kind: Ingress + api_version: config.openshift.io/v1 + register: ingress_domain_raw + +# We split the domain and skip the first two parts +# apps.bandini-dc.blueprints.rhecoeng.com -> blueprints.rhecoeng.com +- name: Set ingress domain + ansible.builtin.set_fact: + ingress_domain_out: "{{ ingress_raw.resources[0].spec.domain.split('.')[2:] | join('.') }}" + +- name: Set ingress domain cleaned up + ansible.builtin.set_fact: + ingress_domain: "{{ ingress_domain_out.stdout }}" + cert_role: "{{ ingress_domain_out.stdout | replace('.', '_') }}" + +- name: Enable vault pki backend + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ vault_pod }}" + command: vault secrets enable pki + +- name: Set vault pki max-lease-ttl + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ vault_pod }}" + command: vault secrets tune --max-lease-ttl="{{ vault_pki_max_lease_ttl }}" pki + +- name: Set vault pki generate/internal CN + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ vault_pod }}" + command: vault write pki/root/generate/internal common_name="{{ ingress_domain }}" ttl="{{ vault_pki_max_lease_ttl }}" + +- name: Set vault pki CRL + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ vault_pod }}" + command: vault write pki/config/urls issuing_certificates="http://127.0.0.1:8200/v1/pki/ca" crl_distribution_points="http://127.0.0.1:8200/v1/pki/crl" + +- name: Set vault pki roles + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ vault_pod }}" + command: vault write pki/roles/"{{ cert_role }}" allowed_domains="{{ ingress_domain }}" allow_subdomains=true max_ttl="{{ vault_pki_max_lease_ttl }}" diff --git a/ansible/roles/vault_utils/tasks/vault_secrets_init.yaml b/ansible/roles/vault_utils/tasks/vault_secrets_init.yaml new file mode 100644 index 00000000..9fdb9024 --- /dev/null +++ b/ansible/roles/vault_utils/tasks/vault_secrets_init.yaml @@ -0,0 +1,80 @@ +--- +- include_tasks: pre_check.yaml + +- name: Is secrets backend already enabled + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ vault_pod }}" + command: > + bash -e -c "vault secrets list | grep -e '^{{ vault_base_path }}'" + register: secrets_enabled + failed_when: false + +- name: Create secrets backend kv-v2 + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ vault_pod }}" + command: vault secrets enable -path="{{ vault_base_path }}" kv-v2 + when: secrets_enabled.rc != 0 + +- name: Is kubernetes backend already enabled + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ vault_pod }}" + command: > + bash -e -c "vault auth list | grep -e '^{{ vault_hub }}'" + register: kubernetes_enabled + failed_when: false + +- name: Enable kubernetes backend on hub + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ vault_pod }}" + command: "vault auth enable -path={{ vault_hub }} kubernetes" + when: kubernetes_enabled.rc != 0 + +- name: Get token from service account secret {{ external_secrets_ns }}/{{ external_secrets_secret }} + kubernetes.core.k8s_info: + kind: Secret + namespace: "{{ external_secrets_ns }}" + name: "{{ external_secrets_secret }}" + api_version: v1 + register: token_data + failed_when: token_data.resources | length == 0 + +- name: Set sa_token fact + ansible.builtin.set_fact: + sa_token: "{{ token_data.resources[0].data.token | b64decode }}" + +- name: Configure hub kubernetes backend + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ vault_pod }}" + command: bash -e -c "vault write auth/{{ vault_hub }}/config token_reviewer_jwt={{ sa_token }} + kubernetes_host={{ vault_hub_kubernetes_host }} + kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt + issuer=https://kubernetes.default.svc" + +- name: Configure policy template for hub + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ vault_pod }}" + command: > + bash -e -c "echo \"path \\\"secret/data/{{ vault_hub }}/*\\\" { + capabilities = {{ vault_hub_capabilities }} }\" > /tmp/policy-{{ vault_hub }}.hcl" + +- name: Configure policy for hub + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ vault_pod }}" + command: "vault policy write {{ vault_hub }}-secret /tmp/policy-{{ vault_hub }}.hcl" + +- name: Configure kubernetes role for hub + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ vault_pod }}" + command: > + vault write auth/"{{ vault_hub }}"/role/"{{ vault_hub }}"-role + bound_service_account_names="{{ external_secrets_sa }}" + bound_service_account_namespaces="{{ external_secrets_ns }}" + policies="default,{{ vault_hub }}-secret" ttl="{{ vault_hub_ttl }}" diff --git a/ansible/roles/vault_utils/tasks/vault_status.yaml b/ansible/roles/vault_utils/tasks/vault_status.yaml new file mode 100644 index 00000000..9dc3e426 --- /dev/null +++ b/ansible/roles/vault_utils/tasks/vault_status.yaml @@ -0,0 +1,61 @@ +--- +# Registers a variable valled vault_status containing the vault's status json dict +- name: Check for vault namespace + kubernetes.core.k8s_info: + kind: Namespace + name: "{{ vault_ns }}" + register: vault_ns_rc + until: vault_ns_rc.resources | length > 0 + retries: 20 + delay: 45 + +- name: Check if the vault pod is present + kubernetes.core.k8s_info: + kind: Pod + namespace: "{{ vault_ns }}" + name: "{{ vault_pod }}" + register: vault_pod_rc + until: vault_pod_rc.resources | length > 0 + retries: 20 + delay: 45 + +# This needs retrying because during startup we can just get +# Failed to execute on pod vault-0 due to : (0)\nReason: Handshake status 500 Internal Server Error +# In the above case there is no 'rc' in vault_status. So first we wait for 'rc' to show up and ignore +# any errors, and then we bail out if rc is 2 as it means the vault is already initialized +- name: Check for the vault status + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ vault_pod }}" + command: vault status -format=json + register: vault_status_json + until: "'rc' in vault_status_json" + retries: 20 + delay: 45 + failed_when: "'stdout_lines' not in vault_status_json" + +- name: Set vault status output json fact + ansible.builtin.set_fact: + vault_status: "{{ vault_status_json.stdout | from_json }}" + when: vault_status_json.stdout_lines | length > 0 + +- name: List Vault pods + kubernetes.core.k8s_info: + namespace: "{{ vault_ns }}" + kind: Pod + label_selectors: + - "component = server" + register: vault_pods_list + +- name: "Get pods" + ansible.builtin.set_fact: + vault_pods: "{{ vault_pods + [item.metadata.name] }}" + loop: "{{ vault_pods_list.resources }}" + loop_control: + label: "{{ item.metadata.name }}" + vars: + vault_pods: [] + +- name: "Followers" + ansible.builtin.set_fact: + followers: "{{ vault_pods | difference(vault_pod) }}" diff --git a/ansible/roles/vault_utils/tasks/vault_unseal.yaml b/ansible/roles/vault_utils/tasks/vault_unseal.yaml new file mode 100644 index 00000000..10e63629 --- /dev/null +++ b/ansible/roles/vault_utils/tasks/vault_unseal.yaml @@ -0,0 +1,116 @@ +--- +- include_tasks: pre_check.yaml +- include_tasks: vault_status.yaml + +# If the vault is already unsealed we skip all the tasks below +- name: Is the vault sealed? + ansible.builtin.set_fact: + vault_sealed: "{{ vault_status['sealed'] | bool }}" + +# Note that the 'realpath' filter explicitely only resolves on the ansible/local box +# which is fine in our case +- name: Set absolute path for output_file + ansible.builtin.set_fact: + output_file_abs: "{{ output_file | realpath }}" + when: + - vault_sealed + - file_unseal + +- name: Check for existence of "{{ output_file_abs }}" + ansible.builtin.stat: + path: "{{ output_file_abs }}" + register: result + when: + - vault_sealed + - file_unseal + +- name: Fail if "{{ output_file_abs }}" does not exists + ansible.builtin.fail: + msg: "{{ output_file_abs }} does not exist. Stopping here" + failed_when: not result.stat.exists + when: + - vault_sealed + - file_unseal + +# We reparse the json vault init file in case unseal was called without operator init before +# and if file_unseal is true +- name: Parse "{{ output_file_abs }}" + ansible.builtin.set_fact: + vault_init_json: "{{ lookup('file', output_file_abs) | from_json }}" + when: + - vault_sealed + - file_unseal + +# We reparse the json vault init secret in case unseal was called without operator init before +# and if file_unseal is false +- name: Parse "{{ output_file_abs }}" + kubernetes.core.k8s_info: + kind: Secret + namespace: "{{ unseal_namespace }}" + name: "{{ unseal_secret }}" + api_version: v1 + register: vault_init_data + when: + - vault_sealed + - not file_unseal + +- name: Set vault init json + ansible.builtin.set_fact: + vault_init_json: "{{ vault_init_data.resources[0].data.vault_data_json | b64decode | from_json }}" + when: + - vault_sealed + - not file_unseal + +- name: Set root token and unseal_keys + ansible.builtin.set_fact: + root_token: "{{ vault_init_json['root_token'] }}" + unseal_keys: "{{ vault_init_json['unseal_keys_hex'] }}" + when: vault_sealed + +- name: Unseal leader + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ vault_pod }}" + command: vault operator unseal "{{ item }}" + loop: "{{ unseal_keys }}" + loop_control: + extended: true + label: "Unsealing with key {{ ansible_loop.index }}" + when: vault_sealed + +- name: Join Raft cluster + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ item }}" + command: vault operator raft join http://{{ vault_pod }}.{{ vault_ns }}-internal:8200 + register: join_raft_cluster_out + until: join_raft_cluster_out is not failed + retries: 10 + delay: 15 + loop: "{{ followers }}" + loop_control: + extended: true + label: "Joining Raft Cluster on http://{{ vault_pod }}.{{ vault_ns }}-internal:8200" + when: + - vault_sealed + - followers | length > 0 + +- name: Unseal followers + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ item.0 }}" + command: vault operator unseal "{{ item.1 }}" + loop: "{{ followers | product(unseal_keys) | list }}" + loop_control: + extended: true + label: "Unsealing {{ item.0 }} with key {{ ansible_loop.index }}" + when: + - vault_sealed + - followers | length > 0 + +- name: Login into vault + kubernetes.core.k8s_exec: + namespace: "{{ vault_ns }}" + pod: "{{ vault_pod }}" + command: vault login "{{ root_token }}" + when: vault_sealed diff --git a/ansible/roles/vault_utils/tests/inventory b/ansible/roles/vault_utils/tests/inventory new file mode 100644 index 00000000..878877b0 --- /dev/null +++ b/ansible/roles/vault_utils/tests/inventory @@ -0,0 +1,2 @@ +localhost + diff --git a/ansible/roles/vault_utils/tests/test.yml b/ansible/roles/vault_utils/tests/test.yml new file mode 100644 index 00000000..0998beb6 --- /dev/null +++ b/ansible/roles/vault_utils/tests/test.yml @@ -0,0 +1,5 @@ +--- +- hosts: localhost + remote_user: root + roles: + - vault_utils diff --git a/ansible/roles/vault_utils/vars/main.yml b/ansible/roles/vault_utils/vars/main.yml new file mode 100644 index 00000000..f6e02b93 --- /dev/null +++ b/ansible/roles/vault_utils/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for vault_utils diff --git a/clustergroup/.helmignore b/clustergroup/.helmignore new file mode 100644 index 00000000..b25c15b8 --- /dev/null +++ b/clustergroup/.helmignore @@ -0,0 +1 @@ +*~ diff --git a/clustergroup/Chart.yaml b/clustergroup/Chart.yaml new file mode 100644 index 00000000..249163ae --- /dev/null +++ b/clustergroup/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +description: A Helm chart to create per-clustergroup ArgoCD applications and any required namespaces or subscriptions +keywords: +- pattern +name: pattern-clustergroup +version: 0.0.1 diff --git a/clustergroup/templates/core/catalog-sources.yaml b/clustergroup/templates/core/catalog-sources.yaml new file mode 100644 index 00000000..2f0c2a95 --- /dev/null +++ b/clustergroup/templates/core/catalog-sources.yaml @@ -0,0 +1,13 @@ +{{- if not (eq .Values.enabled "plumbing") }} +{{- range .Values.clusterGroup.indexImages }} +apiVersion: operators.coreos.com/v1alpha1 +kind: CatalogSource +metadata: + name: {{ .name }} + namespace: openshift-marketplace +spec: + sourceType: grpc + image: {{ .image }}:{{ .version }} +--- +{{- end -}} +{{- end -}} diff --git a/clustergroup/templates/core/namespaces.yaml b/clustergroup/templates/core/namespaces.yaml new file mode 100644 index 00000000..6d2ad164 --- /dev/null +++ b/clustergroup/templates/core/namespaces.yaml @@ -0,0 +1,13 @@ +{{- if not (eq .Values.enabled "plumbing") }} +{{- range .Values.clusterGroup.namespaces }} +apiVersion: v1 +kind: Namespace +metadata: + labels: + name: {{ default "pattern" $.Release.name }} + argocd.argoproj.io/managed-by: {{ $.Values.global.pattern }}-{{ $.Values.clusterGroup.name }} + name: {{ . }} +spec: +--- +{{- end }} +{{- end }} diff --git a/clustergroup/templates/core/operatorgroup.yaml b/clustergroup/templates/core/operatorgroup.yaml new file mode 100644 index 00000000..74febe94 --- /dev/null +++ b/clustergroup/templates/core/operatorgroup.yaml @@ -0,0 +1,27 @@ +{{- if not (eq .Values.enabled "plumbing") }} +{{- range .Values.clusterGroup.namespaces }} + +{{- if empty $.Values.clusterGroup.operatorgroupExcludes }} +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: {{ . }}-operator-group + namespace: {{ . }} +spec: + targetNamespaces: + - {{ . }} +--- +{{- else if not (has . $.Values.clusterGroup.operatorgroupExcludes) }} +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: {{ . }}-operator-group + namespace: {{ . }} +spec: + targetNamespaces: + - {{ . }} +--- +{{- end }} + +{{- end }} +{{- end }} diff --git a/clustergroup/templates/core/subscriptions.yaml b/clustergroup/templates/core/subscriptions.yaml new file mode 100644 index 00000000..bdaeff84 --- /dev/null +++ b/clustergroup/templates/core/subscriptions.yaml @@ -0,0 +1,69 @@ +{{- if not (eq .Values.enabled "plumbing") }} +{{- range .Values.clusterGroup.subscriptions }} +{{- $subs := . }} +{{- $installPlanValue := .installPlanApproval }} + +{{- if $subs.namespaces }} +{{- if not $subs.disabled }} +{{- range .namespaces }} +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: {{ $subs.name }} + namespace: {{ . }} +spec: + name: {{ $subs.name }} + source: {{ default "redhat-operators" $subs.source }} + sourceNamespace: {{ default "openshift-marketplace" $subs.sourceNamespace }} + channel: {{ default "stable" $subs.channel }} + installPlanApproval: {{ coalesce $installPlanValue $.Values.global.options.installPlanApproval }} + {{- if $subs.config }} + {{- if $subs.config.env }} + config: + env: + {{- range $subs.config.env }} + - name: {{ .name }} + value: {{ .value }} + {{- end }} + {{- end }} + {{- end }} + {{- if $.Values.global.options.useCSV }} + startingCSV: {{ $subs.csv }} + {{- else if $subs.csv }} + startingCSV: {{ $subs.csv }} + {{- end }} +--- +{{- end }} +{{- end }} +{{- else if not $subs.disabled }} +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: {{ $subs.name }} + namespace: {{ default "openshift-operators" $subs.namespace }} +spec: + name: {{ $subs.name }} + source: {{ default "redhat-operators" $subs.source }} + sourceNamespace: {{ default "openshift-marketplace" $subs.sourceNamespace }} + channel: {{ default "stable" $subs.channel }} + installPlanApproval: {{ coalesce $installPlanValue $.Values.global.options.installPlanApproval }} + {{- if $subs.config }} + {{- if $subs.config.env }} + config: + env: + {{- range $subs.config.env }} + - name: {{ .name }} + value: {{ .value }} + {{- end }} + {{- end }} + {{- end }} + {{- if $.Values.global.options.useCSV }} + startingCSV: {{ $subs.csv }} + {{- else if $subs.csv }} + startingCSV: {{ $subs.csv }} + {{- end }} +--- +{{- end }} +{{- end }} +--- +{{- end }} diff --git a/clustergroup/templates/imperative/_helpers.tpl b/clustergroup/templates/imperative/_helpers.tpl new file mode 100644 index 00000000..8a946b3c --- /dev/null +++ b/clustergroup/templates/imperative/_helpers.tpl @@ -0,0 +1,38 @@ +{{/* git-init InitContainer */}} +{{- define "imperative.initcontainers.gitinit" }} +- name: git-init + image: {{ $.Values.clusterGroup.imperative.image }} + imagePullPolicy: {{ $.Values.clusterGroup.imperative.imagePullPolicy }} + env: + - name: HOME + value: /git/home + command: + - 'sh' + - '-c' + - "mkdir /git/{repo,home};git clone --single-branch --branch {{ $.Values.global.targetRevision }} --depth 1 -- {{ $.Values.global.repoURL }} /git/repo;chmod 0770 /git/{repo,home}" + volumeMounts: + - name: git + mountPath: "/git" +{{- end }} + +{{/* Final done container */}} +{{- define "imperative.containers.done" }} +- name: "done" + image: {{ $.Values.clusterGroup.imperative.image }} + imagePullPolicy: {{ $.Values.clusterGroup.imperative.imagePullPolicy }} + command: + - 'sh' + - '-c' + - 'echo' + - 'done' + - '\n' +{{- end }} + +{{/* volume-mounts for all containers */}} +{{- define "imperative.volumemounts" }} +- name: git + mountPath: "/git" +- name: values-volume + mountPath: /values/values.yaml + subPath: values.yaml +{{- end }} diff --git a/clustergroup/templates/imperative/clusterrole.yaml b/clustergroup/templates/imperative/clusterrole.yaml new file mode 100644 index 00000000..b893d0e2 --- /dev/null +++ b/clustergroup/templates/imperative/clusterrole.yaml @@ -0,0 +1,24 @@ +{{- if not (eq .Values.enabled "plumbing") }} +{{/* Define this if needed (jobs defined or insecure unseal configured) */}} +{{- if or (gt (len $.Values.clusterGroup.imperative.jobs) 0) + (and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster) -}} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ $.Values.clusterGroup.imperative.clusterRoleName }} +rules: +{{- if $.Values.clusterGroup.imperative.clusterRoleYaml -}} + {{ toYaml $.Values.clusterGroup.imperative.clusterRoleYaml | nindent 2 }} +{{- else }} + - apiGroups: + - '*' + resources: + - '*' + verbs: + - get + - list + - watch +{{- end }} +{{- end }} +{{- end }} diff --git a/clustergroup/templates/imperative/configmap.yaml b/clustergroup/templates/imperative/configmap.yaml new file mode 100644 index 00000000..5abb473b --- /dev/null +++ b/clustergroup/templates/imperative/configmap.yaml @@ -0,0 +1,15 @@ +{{- if not (eq .Values.enabled "plumbing") }} +{{/* Define this if needed (jobs defined or insecure unseal configured) */}} +{{- if or (gt (len $.Values.clusterGroup.imperative.jobs) 0) + (and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster) -}} +{{- $valuesyaml := toYaml $.Values -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ $.Values.clusterGroup.imperative.valuesConfigMap }}-{{ $.Values.clusterGroup.name }} + namespace: {{ $.Values.clusterGroup.imperative.namespace}} +data: + values.yaml: | +{{ tpl $valuesyaml . | indent 4 }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/clustergroup/templates/imperative/job.yaml b/clustergroup/templates/imperative/job.yaml new file mode 100644 index 00000000..b9437c3f --- /dev/null +++ b/clustergroup/templates/imperative/job.yaml @@ -0,0 +1,69 @@ +{{- if not (eq .Values.enabled "plumbing") }} +{{/* Define this if needed (jobs defined */}} +{{- if (gt (len $.Values.clusterGroup.imperative.jobs) 0) -}} +--- +apiVersion: batch/v1 +kind: CronJob +metadata: + name: {{ $.Values.clusterGroup.imperative.cronJobName }} + namespace: {{ $.Values.clusterGroup.imperative.namespace}} +spec: + schedule: {{ $.Values.clusterGroup.imperative.schedule | quote }} + # if previous Job is still running, skip execution of a new Job + concurrencyPolicy: Forbid + jobTemplate: + spec: + activeDeadlineSeconds: {{ $.Values.clusterGroup.imperative.activeDeadlineSeconds }} + template: + metadata: + name: {{ $.Values.clusterGroup.imperative.jobName }} + spec: + serviceAccountName: {{ $.Values.clusterGroup.imperative.serviceAccountName }} + initContainers: + # git init happens in /git/repo so that we can set the folder to 0770 permissions + # reason for that is ansible refuses to create temporary folders in there + {{- include "imperative.initcontainers.gitinit" . | indent 12 }} + {{- range $.Values.clusterGroup.imperative.jobs }} + {{- if ne (.disabled | default "false" | toString | lower ) "true" }} + - name: {{ .name }} + image: {{ .image | default $.Values.clusterGroup.imperative.image }} + imagePullPolicy: {{ $.Values.clusterGroup.imperative.imagePullPolicy }} + env: + - name: HOME + value: /git/home + workingDir: /git/repo + # We have a default timeout of 600s for each playbook. Can be overridden + # on a per-job basis + command: + - timeout + - {{ .timeout | default "600" | quote }} + - ansible-playbook + {{- if .verbosity }} + - {{ .verbosity }} + {{- end }} + {{- if .tags }} + - -t + - {{ .tags }} + {{- end }} + - -e + - "@/values/values.yaml" + {{- range .extravars }} + - -e + - {{ . | quote }} + {{- end }} + - {{ .playbook }} + volumeMounts: + {{- include "imperative.volumemounts" . | indent 16 }} + {{- end }} + {{- end }} + containers: + {{- include "imperative.containers.done" . | indent 12 }} + volumes: + - name: git + emptyDir: {} + - name: values-volume + configMap: + name: {{ $.Values.clusterGroup.imperative.valuesConfigMap }}-{{ $.Values.clusterGroup.name }} + restartPolicy: Never +{{- end }} +{{- end }} \ No newline at end of file diff --git a/clustergroup/templates/imperative/namespace.yaml b/clustergroup/templates/imperative/namespace.yaml new file mode 100644 index 00000000..fd4569c6 --- /dev/null +++ b/clustergroup/templates/imperative/namespace.yaml @@ -0,0 +1,13 @@ +{{- if not (eq .Values.enabled "plumbing") }} +{{/* Define this if needed (jobs defined or insecure unseal configured) */}} +{{- if or (gt (len $.Values.clusterGroup.imperative.jobs) 0) + (and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster) -}} +apiVersion: v1 +kind: Namespace +metadata: + labels: + name: {{ $.Values.clusterGroup.imperative.namespace }} + argocd.argoproj.io/managed-by: {{ $.Values.global.pattern }}-{{ $.Values.clusterGroup.name }} + name: {{ $.Values.clusterGroup.imperative.namespace }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/clustergroup/templates/imperative/rbac.yaml b/clustergroup/templates/imperative/rbac.yaml new file mode 100644 index 00000000..1b73ca3e --- /dev/null +++ b/clustergroup/templates/imperative/rbac.yaml @@ -0,0 +1,33 @@ +{{- if not (eq .Values.enabled "plumbing") }} +{{/* Define this if needed (jobs defined or insecure unseal configured) */}} +{{- if or (gt (len $.Values.clusterGroup.imperative.jobs) 0) + (and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster) -}} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ $.Values.clusterGroup.imperative.namespace }}-cluster-admin-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ $.Values.clusterGroup.imperative.clusterRoleName }} +subjects: + - kind: ServiceAccount + name: {{ $.Values.clusterGroup.imperative.serviceAccountName }} + namespace: {{ $.Values.clusterGroup.imperative.namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ $.Values.clusterGroup.imperative.namespace }}-admin-rolebinding + namespace: {{ $.Values.clusterGroup.imperative.namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ $.Values.clusterGroup.imperative.roleName }} +subjects: + - kind: ServiceAccount + name: {{ $.Values.clusterGroup.imperative.serviceAccountName }} + namespace: {{ $.Values.clusterGroup.imperative.namespace }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/clustergroup/templates/imperative/role.yaml b/clustergroup/templates/imperative/role.yaml new file mode 100644 index 00000000..79b7b7a7 --- /dev/null +++ b/clustergroup/templates/imperative/role.yaml @@ -0,0 +1,23 @@ +{{- if not (eq .Values.enabled "plumbing") }} +{{/* Define this if needed (jobs defined or insecure unseal configured) */}} +{{- if or (gt (len $.Values.clusterGroup.imperative.jobs) 0) + (and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster) -}} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ $.Values.clusterGroup.imperative.roleName }} + namespace: {{ $.Values.clusterGroup.imperative.namespace }} +rules: +{{- if $.Values.clusterGroup.imperative.roleYaml -}} + {{ toYaml $.Values.clusterGroup.imperative.roleYaml | nindent 2 }} +{{- else }} + - apiGroups: + - '*' + resources: + - '*' + verbs: + - '*' +{{- end }} +{{- end }} +{{- end }} diff --git a/clustergroup/templates/imperative/serviceaccount.yaml b/clustergroup/templates/imperative/serviceaccount.yaml new file mode 100644 index 00000000..b90ac2a4 --- /dev/null +++ b/clustergroup/templates/imperative/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if not (eq .Values.enabled "plumbing") }} +{{/* Define this if needed (jobs defined or insecure unseal configured) */}} +{{- if or (gt (len $.Values.clusterGroup.imperative.jobs) 0) + (and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster) -}} +{{- if $.Values.clusterGroup.imperative.serviceAccountCreate -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ $.Values.clusterGroup.imperative.serviceAccountName }} + namespace: {{ $.Values.clusterGroup.imperative.namespace }} +{{- end }} +{{- end }} +{{- end }} diff --git a/clustergroup/templates/imperative/unsealjob.yaml b/clustergroup/templates/imperative/unsealjob.yaml new file mode 100644 index 00000000..76fbd135 --- /dev/null +++ b/clustergroup/templates/imperative/unsealjob.yaml @@ -0,0 +1,61 @@ +{{- if not (eq .Values.enabled "plumbing") }} +{{/* Only define this if the values.insecureUnsealVaultInsideCluster is set to tre and we're on the cluster */}} +{{- if and $.Values.clusterGroup.insecureUnsealVaultInsideCluster $.Values.clusterGroup.isHubCluster }} +--- +apiVersion: batch/v1 +kind: CronJob +metadata: + name: unsealvault-cronjob + namespace: {{ $.Values.clusterGroup.imperative.namespace}} +spec: + schedule: {{ $.Values.clusterGroup.imperative.insecureUnsealVaultInsideClusterSchedule | quote }} + # if previous Job is still running, skip execution of a new Job + concurrencyPolicy: Forbid + jobTemplate: + spec: + activeDeadlineSeconds: {{ $.Values.clusterGroup.imperative.activeDeadlineSeconds }} + template: + metadata: + name: unsealvault-job + spec: + serviceAccountName: {{ $.Values.clusterGroup.imperative.serviceAccountName }} + initContainers: + # git init happens in /git/repo so that we can set the folder to 0770 permissions + # reason for that is ansible refuses to create temporary folders in there + {{- include "imperative.initcontainers.gitinit" . | indent 12 }} + - name: unseal-playbook + image: {{ $.Values.clusterGroup.imperative.image }} + imagePullPolicy: {{ $.Values.clusterGroup.imperative.imagePullPolicy }} + env: + - name: HOME + value: /git/home + workingDir: /git/repo + # We have a default timeout of 600s for each playbook. Can be overridden + # on a per-job basis + command: + - timeout + - {{ .timeout | default "600" | quote }} + - ansible-playbook + {{- if $.Values.clusterGroup.imperative.verbosity }} + - {{ $.Values.clusterGroup.imperative.verbosity }} + {{- end }} + - -e + - "@/values/values.yaml" + - -e + - '{"file_unseal": false}' + - -t + - 'vault_init,vault_unseal,vault_secrets_init' + - "common/ansible/playbooks/vault/vault.yaml" + volumeMounts: + {{- include "imperative.volumemounts" . | indent 16 }} + containers: + {{- include "imperative.containers.done" . | indent 12 }} + volumes: + - name: git + emptyDir: {} + - name: values-volume + configMap: + name: {{ $.Values.clusterGroup.imperative.valuesConfigMap }}-{{ $.Values.clusterGroup.name }} + restartPolicy: Never +{{- end }} +{{- end }} diff --git a/clustergroup/templates/plumbing/applications.yaml b/clustergroup/templates/plumbing/applications.yaml new file mode 100644 index 00000000..c9a6667d --- /dev/null +++ b/clustergroup/templates/plumbing/applications.yaml @@ -0,0 +1,218 @@ +{{- if not (eq .Values.enabled "core") }} +{{- $namespace := print $.Values.global.pattern "-" $.Values.clusterGroup.name }} +{{- if (eq .Values.enabled "plumbing") }} +{{- $namespace = "openshift-gitops" }} +{{- end }} +{{- range .Values.clusterGroup.applications }} +{{- if or (.generators) (.generatorFile) (.useGeneratorValues) (.destinationServer) (.destinationNamespace) }} +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: {{ .name }} + namespace: {{ $namespace }} + labels: + app: {{ .name }} +spec: + {{- if .generators }} + generators: {{ .generators | toPrettyJson }} + {{- else }} + generators: + - git: + repoURL: {{ $.Values.global.repoURL }} + revision: {{ $.Values.global.targetRevision }} + {{- if .generatorFile }} + files: + - path: {{ .generatorFile | quote }} + {{- end }} + {{- end }} + template: + metadata: + name: {{ coalesce .namespace $namespace }} + spec: + project: {{ .project }} + {{- if .syncPolicy }} + syncPolicy: {{ .syncPolicy | toPrettyJson }} + {{- else }} + syncPolicy: + automated: {} + {{- end }} + {{- if .ignoreDifferences }} + ignoreDifferences: {{ .ignoreDifferences | toPrettyJson }} + {{- end }} + source: + repoURL: {{ coalesce .repoURL $.Values.global.repoURL }} + targetRevision: {{ coalesce .targetRevision $.Values.global.targetRevision }} + {{- if .chart }} + chart: {{ .chart }} + {{- end }} + {{- if .path }} + path: {{ .path }} + {{- end }} + {{- if .plugin }} + plugin: {{ .plugin }} + {{- end }} + {{- if not .kustomize }} + helm: + ignoreMissingValueFiles: true + valueFiles: + - "values.yaml" + {{- range .extraValueFiles }} + - {{ . | quote }} + {{- end }} + {{- if .useGeneratorValues }} + values: |- + {{ `{{ values }}` }} + {{- end }} + parameters: + - name: global.clusterDomain + value: {{ $.Values.global.clusterDomain }} + - name: global.hubClusterDomain + value: {{ $.Values.global.hubClusterDomain }} + - name: global.localClusterDomain + value: {{ coalesce $.Values.global.localClusterDomain $.Values.global.hubClusterDomain }} + - name: global.repoURL + value: {{ $.Values.global.repoURL }} + - name: global.targetRevision + value: {{ $.Values.global.targetRevision }} + - name: global.namespace + value: {{ $.Values.global.namespace }} + - name: global.pattern + value: {{ $.Values.global.pattern }} + - name: clusterGroup.name + value: {{ .Values.clusterGroup.name }} + {{- range .extraHubClusterDomainFields }} + - name: {{ . }} + value: {{ $.Values.global.hubClusterDomain }} + {{- end }} + {{- range .extraLocalClusterDomainFields }} + - name: {{ . }} + value: {{ $.Values.global.localClusterDomain }} + {{- end }} + {{- range .extraRepoURLFields }} + - name: {{ . }} + value: {{ $.Values.global.repoURL }} + {{- end }} + {{- range .extraTargetRevisionFields }} + - name: {{ . }} + value: {{ $.Values.global.targetRevision }} + {{- end }} + {{- range .extraNamespaceFields }} + - name: {{ . }} + value: {{ $.Values.global.namespace }} + {{- end }} + {{- range .extraPatternNameFields }} + - name: {{ . }} + value: {{ $.Values.global.pattern }} + {{- end }} + {{- range .overrides }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- if .forceString }} + forceString: true + {{- end }} + {{- end }} + {{- end }} + destination: + server: {{ coalesce .destinationServer "https://kubernetes.default.svc" }} + namespace: {{ coalesce .destinationNamespace .namespace $namespace }} +{{- else }} +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: {{ .name }} + namespace: {{ $namespace }} + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground +spec: + destination: + name: {{ $.Values.clusterGroup.targetCluster }} + namespace: {{ default $namespace .namespace }} + project: {{ .project }} + source: + repoURL: {{ coalesce .repoURL $.Values.global.repoURL }} + targetRevision: {{ coalesce .targetRevision $.Values.global.targetRevision }} + {{- if .chart }} + chart: {{ .chart }} + {{- else }} + path: {{ .path }} + {{- end }} + {{- if .plugin }} + plugin: {{ .plugin | toPrettyJson }} + {{- else if not .kustomize }} + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-{{ $.Values.clusterGroup.name }}.yaml" + {{- range $valueFile := .extraValueFiles }} + - {{ $valueFile | quote }} + {{- end }} + # Watch the progress of https://issues.redhat.com/browse/GITOPS-891 and update accordingly + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: {{ $.Values.global.pattern }} + - name: global.clusterDomain + value: {{ $.Values.global.clusterDomain }} + - name: global.hubClusterDomain + value: {{ $.Values.global.hubClusterDomain }} + - name: global.localClusterDomain + value: {{ coalesce $.Values.global.localClusterDomain $.Values.global.hubClusterDomain }} + {{- range .extraHubClusterDomainFields }} + - name: {{ . }} + value: {{ $.Values.global.hubClusterDomain }} + {{- end }} + {{- range .extraLocalClusterDomainFields }} + - name: {{ . }} + value: {{ $.Values.global.localClusterDomain }} + {{- end }} + {{- range .extraRepoURLFields }} + - name: {{ . }} + value: $ARGOCD_APP_SOURCE_REPO_URL + {{- end }} + {{- range .extraTargetRevisionFields }} + - name: {{ . }} + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + {{- end }} + {{- range .extraNamespaceFields }} + - name: {{ . }} + value: $ARGOCD_APP_NAMESPACE + {{- end }} + {{- range .extraPatternNameFields }} + - name: {{ . }} + value: {{ $.Values.global.pattern }} + {{- end }} + {{- range .overrides }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- if .forceString }} + forceString: true + {{- end }} + {{- end }} + {{- if .fileParameters }} + fileParameters: + {{- range .fileParameters }} + - name: {{ .name }} + path: {{ .path }} + {{- end }} + {{- end }} + {{- end }} + {{- if .ignoreDifferences }} + ignoreDifferences: {{ .ignoreDifferences | toPrettyJson }} + {{- end }} + {{- if .syncPolicy }} + syncPolicy: {{ .syncPolicy | toPrettyJson }} + {{- else }} + syncPolicy: + automated: {} + # selfHeal: true + {{- end }} +--- +{{- end }} +{{- end }} +{{- end }} diff --git a/clustergroup/templates/plumbing/argocd-super-role.yaml b/clustergroup/templates/plumbing/argocd-super-role.yaml new file mode 100644 index 00000000..2d5f8f76 --- /dev/null +++ b/clustergroup/templates/plumbing/argocd-super-role.yaml @@ -0,0 +1,43 @@ +{{- if (eq .Values.enabled "all") }} +# WARNING: ONLY USE THIS FOR MANAGING CLUSTERS NOT FOR REGULAR USERS +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: openshift-gitops-cluster-admin-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: + - kind: ServiceAccount + name: openshift-gitops-argocd-application-controller + namespace: openshift-gitops + # NOTE: THIS MUST BE FIXED FOR MULTITENANT SETUP + - kind: ServiceAccount + name: openshift-gitops-argocd-server + namespace: openshift-gitops +--- +# WARNING: ONLY USE THIS FOR MANAGING CLUSTERS NOT FOR REGULAR USERS +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ $.Values.global.pattern }}-{{ .Values.clusterGroup.name }}-cluster-admin-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: + - kind: ServiceAccount + # This is the {ArgoCD.name}-argocd-application-controller + name: {{ .Values.clusterGroup.name }}-gitops-argocd-application-controller + namespace: {{ $.Values.global.pattern }}-{{ .Values.clusterGroup.name }} + # NOTE: THIS MUST BE FIXED FOR MULTITENANT SETUP + - kind: ServiceAccount + # This is the {ArgoCD.name}-argocd-server + name: {{ .Values.clusterGroup.name }}-gitops-argocd-server + namespace: {{ $.Values.global.pattern }}-{{ .Values.clusterGroup.name }} + # NOTE: This is needed starting with gitops-1.5.0 (see issue common#76) + - kind: ServiceAccount + name: {{ .Values.clusterGroup.name }}-gitops-argocd-dex-server + namespace: {{ $.Values.global.pattern }}-{{ .Values.clusterGroup.name }} +{{- end }} diff --git a/clustergroup/templates/plumbing/argocd.yaml b/clustergroup/templates/plumbing/argocd.yaml new file mode 100644 index 00000000..68400b95 --- /dev/null +++ b/clustergroup/templates/plumbing/argocd.yaml @@ -0,0 +1,127 @@ +{{- if (eq .Values.enabled "all") }} +{{- $namespace := print $.Values.global.pattern "-" $.Values.clusterGroup.name }} +apiVersion: argoproj.io/v1alpha1 +kind: ArgoCD +metadata: + finalizers: + - argoproj.io/finalizer + # Changing the name affects the ClusterRoleBinding, the generated secret, + # route URL, and argocd.argoproj.io/managed-by annotations + name: {{ .Values.clusterGroup.name }}-gitops + namespace: {{ $namespace }} + annotations: + argocd.argoproj.io/compare-options: IgnoreExtraneous +spec: + applicationInstanceLabelKey: argocd.argoproj.io/instance + # Not the greatest way to pass git/quay info to sub-applications, but it will do until + # we can support helmChart with kustomize + # The other option is to pass them in as environment variables eg. BLUEPRINT_VERSION + configManagementPlugins: | + - name: kustomize-version + generate: + command: ["sh", "-c"] + args: ["kustomize version 1>&2 && exit 1"] + - name: kustomize-with-helm + generate: + command: ["kustomize"] + args: ["build", "--enable-helm"] + - name: helm-with-kustomize + init: + command: ["/bin/sh", "-c"] + args: ["helm dependency build"] + generate: + command: ["/bin/bash", "-c"] + args: ["helm template . --name-template ${ARGOCD_APP_NAME:0:52} + -f $(git rev-parse --show-toplevel)/values-global.yaml + -f $(git rev-parse --show-toplevel)/values-{{ .Values.clusterGroup.name }}.yaml + --set global.repoURL=$ARGOCD_APP_SOURCE_REPO_URL + --set global.targetRevision=$ARGOCD_APP_SOURCE_TARGET_REVISION + --set global.namespace=$ARGOCD_APP_NAMESPACE + --set global.pattern={{ .Values.global.pattern }} + --set global.clusterDomain={{ .Values.global.clusterDomain }} + --set global.hubClusterDomain={{ .Values.global.hubClusterDomain }} + --set global.localClusterDomain={{ coalesce .Values.global.localClusterDomain .Values.global.hubClusterDomain }} + --set clusterGroup.name={{ .Values.clusterGroup.name }} + --post-renderer ./kustomize"] + applicationSet: + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: 250m + memory: 512Mi + controller: + processors: {} + resources: + limits: + cpu: "4" + memory: 4Gi + requests: + cpu: 500m + memory: 2Gi + dex: + openShiftOAuth: true + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + initialSSHKnownHosts: {} + rbac: + defaultPolicy: role:admin + repo: + resources: + limits: + cpu: "1" + memory: 512Mi + requests: + cpu: 250m + memory: 256Mi + resourceExclusions: | + - apiGroups: + - tekton.dev + kinds: + - TaskRun + - PipelineRun + server: + autoscale: + enabled: false + grpc: + ingress: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 125m + memory: 128Mi + route: + enabled: true + tls: + insecureEdgeTerminationPolicy: Redirect + termination: reencrypt + service: + type: "" + tls: + ca: {} +status: +--- +apiVersion: console.openshift.io/v1 +kind: ConsoleLink +metadata: + name: {{ .Values.clusterGroup.name }}-gitops-link + namespace: {{ $namespace }} +spec: + applicationMenu: + section: OpenShift GitOps + imageURL: data:image/png;base64,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 + href: 'https://{{ .Values.clusterGroup.name }}-gitops-server-{{ $namespace }}.{{ coalesce .Values.global.localClusterDomain .Values.global.hubClusterDomain }}' + location: ApplicationMenu + text: '{{ title .Values.clusterGroup.name }} ArgoCD' +{{- end }} diff --git a/clustergroup/templates/plumbing/cluster-external-secrets.yaml b/clustergroup/templates/plumbing/cluster-external-secrets.yaml new file mode 100644 index 00000000..dfb6bc6b --- /dev/null +++ b/clustergroup/templates/plumbing/cluster-external-secrets.yaml @@ -0,0 +1,43 @@ +{{- if (eq .Values.enabled "plumbing") }} +{{- $namespace := print $.Values.global.pattern "-" $.Values.clusterGroup.name }} +apiVersion: "external-secrets.io/v1beta1" +kind: ExternalSecret +metadata: + name: {{ .Values.clusterGroup.targetCluster | kebabcase }}-secret + namespace: openshift-gitops + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + argocd.argoproj.io/sync-wave: "100" +spec: + refreshInterval: 15s + secretStoreRef: + name: {{ $.Values.secretStore.name }} + kind: {{ $.Values.secretStore.kind }} + target: + name: {{ .Values.clusterGroup.targetCluster | kebabcase }}-secret + template: + type: Opaque + metadata: + labels: + argocd.argoproj.io/secret-type: cluster + data: + name: {{ .Values.clusterGroup.targetCluster }} + server: https://api.{{ .Values.global.clusterDomain }}:6443 + config: | + { + "bearerToken": {{ "{{ .kubeBearer | toString | quote }}" }}, + "tlsClientConfig": { + "insecure": false, + "caData": {{ "{{ .kubeCA | toString | quote }}" }} + } + } + data: + - secretKey: kubeBearer + remoteRef: + key: {{ $.Values.clusterGroup.hostedSite.bearerKeyPath }} + property: bearerToken + - secretKey: kubeCA + remoteRef: + key: {{ $.Values.clusterGroup.hostedSite.caKeyPath }} + property: b64content +{{- end }} diff --git a/clustergroup/templates/plumbing/gitops-namespace.yaml b/clustergroup/templates/plumbing/gitops-namespace.yaml new file mode 100644 index 00000000..3cd7608d --- /dev/null +++ b/clustergroup/templates/plumbing/gitops-namespace.yaml @@ -0,0 +1,13 @@ +{{- if not (eq .Values.enabled "plumbing") }} +apiVersion: v1 +kind: Namespace +metadata: + labels: + name: {{ $.Values.global.pattern }}-{{ .Values.clusterGroup.name }} + # The name here needs to be consistent with + # - acm/templates/policies/application-policies.yaml + # - clustergroup/templates/applications.yaml + # - any references to secrets and route URLs in documentation + name: {{ $.Values.global.pattern }}-{{ .Values.clusterGroup.name }} +spec: {} +{{- end }} diff --git a/clustergroup/templates/plumbing/hosted-sites.yaml b/clustergroup/templates/plumbing/hosted-sites.yaml new file mode 100644 index 00000000..1f11dbe4 --- /dev/null +++ b/clustergroup/templates/plumbing/hosted-sites.yaml @@ -0,0 +1,177 @@ +{{- if (eq .Values.enabled "all") }} +{{- range .Values.clusterGroup.managedClusterGroups }} +{{- $group := . }} +{{- if .hostedArgoSites }} +apiVersion: argoproj.io/v1alpha1 +kind: AppProject +metadata: + name: {{ .name }} + namespace: openshift-gitops +spec: + description: "Cluster Group {{ $group.name }}" + destinations: + - namespace: '*' + server: '*' + clusterResourceWhitelist: + - group: '*' + kind: '*' + namespaceResourceWhitelist: + - group: '*' + kind: '*' + sourceRepos: + - '*' +status: {} +--- +{{- end }} +{{- range .hostedArgoSites }} +{{ $bearerDefault := print "secret/data/hub/cluster_" .name }} +{{ $caDefault := print "secret/data/hub/cluster_" .name "_ca" }} +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: {{ $.Values.global.pattern }}-{{ $group.name }}-{{ .name }} + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground +spec: + project: {{ $group.name }} + source: + repoURL: {{ coalesce $group.repoURL $.Values.global.repoURL }} + targetRevision: {{ coalesce $group.targetRevision $.Values.global.targetRevision }} + path: {{ default "common/clustergroup" $group.path }} + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-{{ $group.name }}.yaml" + {{- range $valueFile := $group.extraValueFiles }} + - {{ $valueFile | quote }} + {{- end }} + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: {{ $.Values.global.pattern }} + - name: global.hubClusterDomain + value: {{ $.Values.global.hubClusterDomain }} + - name: global.localClusterDomain + value: apps.{{ .domain }} + - name: global.clusterDomain + value: {{ .domain }} + - name: enabled + value: core + - name: clusterGroup.name + value: {{ $group.name }} + - name: clusterGroup.targetCluster + value: {{ .name }} + - name: clusterGroup.hostedSite.bearerKeyPath + value: {{ default $bearerDefault .bearerKeyPath }} + - name: clusterGroup.hostedSite.caKeyPath + value: {{ default $caDefault .caKeyPath }} + {{- range $group.helmOverrides }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end }} + {{- if $group.fileParameters }} + fileParameters: + {{- range $group.fileParameters }} + - name: {{ .name }} + path: {{ .path }} + {{- end }} + {{- end }} + destination: + name: {{ .name }} + namespace: {{ $.Values.global.pattern }}-{{ $group.name }} + syncPolicy: + automated: + selfHeal: true + ignoreDifferences: + - group: apps + kind: Deployment + jsonPointers: + - /spec/replicas + - group: route.openshift.io + kind: Route + jsonPointers: + - /status +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: {{ $.Values.global.pattern }}-{{ $group.name }}-{{ .name }}-plumbing + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground +spec: + project: {{ $group.name }} + source: + repoURL: {{ coalesce $group.repoURL $.Values.global.repoURL }} + targetRevision: {{ coalesce $group.targetRevision $.Values.global.targetRevision }} + path: {{ default "common/clustergroup" $group.path }} + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-{{ $group.name }}.yaml" + {{- range $valueFile := $group.extraValueFiles }} + - {{ $valueFile | quote }} + {{- end }} + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: {{ $.Values.global.pattern }} + - name: global.hubClusterDomain + value: {{ $.Values.global.hubClusterDomain }} + - name: global.localClusterDomain + value: apps.{{ .domain }} + - name: global.clusterDomain + value: {{ .domain }} + - name: enabled + value: plumbing + - name: clusterGroup.name + value: {{ $group.name }} + - name: clusterGroup.targetCluster + value: {{ .name }} + - name: clusterGroup.hostedSite.bearerKeyPath + value: {{ default $bearerDefault .bearerKeyPath }} + - name: clusterGroup.hostedSite.caKeyPath + value: {{ default $caDefault .caKeyPath }} + {{- range $group.helmOverrides }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end }} + {{- if $group.fileParameters }} + fileParameters: + {{- range $group.fileParameters }} + - name: {{ .name }} + path: {{ .path }} + {{- end }} + {{- end }} + destination: + name: in-cluster + namespace: openshift-gitops + syncPolicy: + automated: + selfHeal: true + ignoreDifferences: + - group: apps + kind: Deployment + jsonPointers: + - /spec/replicas + - group: route.openshift.io + kind: Route + jsonPointers: + - /status +--- +{{- end }} +{{- end }} +{{- end }} diff --git a/clustergroup/templates/plumbing/projects.yaml b/clustergroup/templates/plumbing/projects.yaml new file mode 100644 index 00000000..7f3b8c22 --- /dev/null +++ b/clustergroup/templates/plumbing/projects.yaml @@ -0,0 +1,29 @@ +{{- if not (eq .Values.enabled "core") }} +{{- $namespace := print $.Values.global.pattern "-" $.Values.clusterGroup.name }} +{{- range .Values.clusterGroup.projects }} +apiVersion: argoproj.io/v1alpha1 +kind: AppProject +metadata: + name: {{ . }} +{{- if (eq $.Values.enabled "plumbing") }} + namespace: openshift-gitops +{{- else }} + namespace: {{ $namespace }} +{{- end }} +spec: + description: "Pattern {{ . }}" + destinations: + - namespace: '*' + server: '*' + clusterResourceWhitelist: + - group: '*' + kind: '*' + namespaceResourceWhitelist: + - group: '*' + kind: '*' + sourceRepos: + - '*' +status: {} +--- +{{- end }} +{{- end }} diff --git a/clustergroup/test.yaml b/clustergroup/test.yaml new file mode 100644 index 00000000..5db2e4a6 --- /dev/null +++ b/clustergroup/test.yaml @@ -0,0 +1,104 @@ +clusterGroup: + name: hub + isHubCluster: true + # Note: setting this to true stores the vault unseal keys inside a cluster secret and + # is fundamentally insecure + insecureUnsealVaultInsideCluster: false + + namespaces: + - open-cluster-management + - vault + - golang-external-secrets + - config-demo + + indexImages: + - name: snr + image: quay.io/mshitrit/self-node-remediation-manager-index + version: 0.0.104 + + subscriptions: + acm: + name: advanced-cluster-management + namespace: open-cluster-management + channel: release-2.5 + csv: advanced-cluster-management.v2.5.0 + + projects: + - hub + - config-demo + + applications: + acm: + name: acm + namespace: open-cluster-management + project: hub + path: common/acm + ignoreDifferences: + - group: internal.open-cluster-management.io + kind: ManagedClusterInfo + jsonPointers: + - /spec/loggingCA + + vault: + name: vault + namespace: vault + project: hub + chart: vault + repoURL: https://helm.releases.hashicorp.com + targetRevision: v0.21.0 + overrides: + - name: global.openshift + value: "true" + - name: injector.enabled + value: "false" + - name: ui.enabled + value: "true" + - name: ui.serviceType + value: LoadBalancer + - name: server.route.enabled + value: "true" + - name: server.route.host + value: null + - name: server.route.tls.termination + value: edge + - name: server.image.repository + value: "registry.connect.redhat.com/hashicorp/vault" + - name: server.image.tag + value: "1.11.2-ubi" + + golang-external-secrets: + name: golang-external-secrets + namespace: golang-external-secrets + project: hub + path: common/golang-external-secrets + + config-demo: + name: config-demo + namespace: config-demo + project: config-demo + path: charts/all/config-demo + + imperative: + # NOTE: We *must* use lists and not hashes. As hashes lose ordering once parsed by helm + # The default schedule is every 10 minutes: imperative.schedule + # Total timeout of all jobs is 1h: imperative.activeDeadlineSeconds + # imagePullPolicy is set to always: imperative.imagePullPolicy + # For additional overrides that apply to the jobs, please refer to + # https://hybrid-cloud-patterns.io/imperative-actions/#additional-job-customizations + jobs: + - name: regional-ca + # ansible playbook to be run + playbook: ansible/playbooks/on-hub-get-regional-ca.yml + # per playbook timeout in seconds + timeout: 234 + # verbosity: "-v" + + managedClusterGroups: + region-one: + name: region-one + hostedArgoSites: + - perth + - sydney + helmOverrides: + - name: clusterGroup.isHubCluster + value: false diff --git a/clustergroup/values.yaml b/clustergroup/values.yaml new file mode 100644 index 00000000..fac5d56c --- /dev/null +++ b/clustergroup/values.yaml @@ -0,0 +1,90 @@ +global: + pattern: common + targetRevision: main + options: + useCSV: True + syncPolicy: Automatic + installPlanApproval: Automatic + +enabled: "all" + +# Note that sometimes changing helm values might require a hard refresh (https://github.com/helm/helm/issues/3486) +clusterGroup: + name: example + isHubCluster: true + targetCluster: in-cluster + # Note: setting this to true stores the vault unseal keys inside a cluster secret and + # is fundamentally insecure + insecureUnsealVaultInsideCluster: false + + imperative: + jobs: [] + # This image contains ansible + kubernetes.core by default and is used to run the jobs + image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest + namespace: "imperative" + # configmap name in the namespace that will contain all helm values + valuesConfigMap: "helm-values-configmap" + cronJobName: "imperative-cronjob" + jobName: "imperative-job" + imagePullPolicy: Always + # This is the maximum timeout of all the jobs (1h) + activeDeadlineSeconds: 3600 + # By default we run this every 10minutes + schedule: "*/10 * * * *" + # Schedule used to trigger the vault unsealing (if explicitely enabled) + # Set to run every 5 minutes in order for load-secrets to succeed within + # a reasonable amount of time (it waits up to 15 mins) + insecureUnsealVaultInsideClusterSchedule: "*/5 * * * *" + # Increase ansible verbosity with '-v' or '-vv..' + verbosity: "" + serviceAccountCreate: true + # service account to be used to run the cron pods + serviceAccountName: imperative-sa + clusterRoleName: imperative-cluster-role + clusterRoleYaml: "" + roleName: imperative-role + roleYaml: "" + +secretStore: + name: vault-backend + kind: ClusterSecretStore + +# Depends on the value of 'vault_hub' ansible variable used +# during the installation +secretsBase: + key: secret/data/hub + +# managedClusterGroups: +# - name: factory +# # repoURL: https://github.com/dagger-refuse-cool/manuela-factory.git +# # Location of values-global.yaml, values-{name}.yaml, values-{app}.yaml +# targetRevision: main +# path: applications/factory +# helmOverrides: +# - name: clusterGroup.isHubCluster +# value: false +# clusterSelector: +# matchExpressions: +# - key: vendor +# operator: In +# values: +# - OpenShift +# +# namespaces: +# - open-cluster-management +# +# subscriptions: +# - name: advanced-cluster-management +# namespace: open-cluster-management +# source: redhat-operators +# channel: release-2.3 +# csv: v2.3.2 +# +# projects: +# - datacenter +# +# applications: +# - name: acm +# namespace: default +# project: datacenter +# path: applications/acm diff --git a/common b/common new file mode 120000 index 00000000..945c9b46 --- /dev/null +++ b/common @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/examples/blank/Chart.yaml b/examples/blank/Chart.yaml new file mode 100644 index 00000000..c552610d --- /dev/null +++ b/examples/blank/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +description: An empty Helm chart +keywords: +- pattern +name: blank +version: 0.0.1 diff --git a/examples/blank/templates/manifest.yaml b/examples/blank/templates/manifest.yaml new file mode 100644 index 00000000..3f160b02 --- /dev/null +++ b/examples/blank/templates/manifest.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: example diff --git a/examples/blank/values.yaml b/examples/blank/values.yaml new file mode 100644 index 00000000..35e4a6f4 --- /dev/null +++ b/examples/blank/values.yaml @@ -0,0 +1,2 @@ +tree: + of: "values" diff --git a/examples/kustomize-renderer/Chart.yaml b/examples/kustomize-renderer/Chart.yaml new file mode 100644 index 00000000..88a786c9 --- /dev/null +++ b/examples/kustomize-renderer/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +description: A Helm chart to demonstrate how to use with kustomize +keywords: +- pattern +name: example +version: 0.0.1 diff --git a/examples/kustomize-renderer/environment.yaml b/examples/kustomize-renderer/environment.yaml new file mode 100644 index 00000000..de4c48a9 --- /dev/null +++ b/examples/kustomize-renderer/environment.yaml @@ -0,0 +1,34 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: environment +data: + IMAGE_PROVIDER: {{ .Values.global.imageregistry.hostname }} + IMAGE_ACCOUNT: {{ .Values.global.imageregistry.account }} + GIT_EMAIL: {{ .Values.global.git.email }} + GIT_DEV_REPO_URL: https://{{ .Values.global.git.hostname }}/{{ .Values.global.git.account }}/manuela-dev.git + GIT_DEV_REPO_REVISION: {{ .Values.global.git.dev_revision }} + GIT_OPS_REPO_TEST_URL: {{ .Values.global.repoURL }} + GIT_OPS_REPO_TEST_REVISION: {{ .Values.global.targetRevision }} + GIT_OPS_REPO_PROD_URL: {{ .Values.global.repoURL }} + GIT_OPS_REPO_PROD_REVISION: {{ .Values.global.targetRevision }} + IOT_CONSUMER_IMAGE: iot-consumer + IOT_CONSUMER_YAML_PATH: images.(name==messaging).newTag + IOT_CONSUMER_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml + IOT_CONSUMER_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/messaging/kustomization.yaml + IOT_CONSUMER_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/messaging/messaging-is.yaml + IOT_FRONTEND_IMAGE: iot-frontend + IOT_FRONTEND_YAML_PATH: images.(name==line-dashboard).newTag + IOT_FRONTEND_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml + IOT_FRONTEND_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/line-dashboard/kustomization.yaml + IOT_FRONTEND_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/line-dashboard/line-dashboard-is.yaml + IOT_SWSENSOR_IMAGE: iot-software-sensor + IOT_SWSENSOR_YAML_PATH: images.(name==machine-sensor).newTag + IOT_SWSENSOR_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml + IOT_SWSENSOR_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/machine-sensor/kustomization.yaml + IOT_SWSENSOR_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/machine-sensor/machine-sensor-is.yaml + IOT_ANOMALY_IMAGE: iot-anomaly-detection + IOT_ANOMALY_YAML_PATH: images.(name==anomaly-detection).newTag + IOT_ANOMALY_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml + IOT_ANOMALY_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/anomaly-detection/kustomization.yaml + IOT_ANOMALY_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/anomaly-detection/anomaly-detection-is.yaml diff --git a/examples/kustomize-renderer/kustomization.yaml b/examples/kustomize-renderer/kustomization.yaml new file mode 100644 index 00000000..8d8bcd10 --- /dev/null +++ b/examples/kustomize-renderer/kustomization.yaml @@ -0,0 +1,5 @@ +resources: + - environment.yaml + +patches: +- helm.patch.yaml diff --git a/examples/kustomize-renderer/kustomize b/examples/kustomize-renderer/kustomize new file mode 100755 index 00000000..5f62b40c --- /dev/null +++ b/examples/kustomize-renderer/kustomize @@ -0,0 +1,15 @@ +#!/bin/bash -x + +BASE=`dirname $0` +if [ $BASE = $PWD ]; then + BASE=./ +fi + +cat <&0 > "$BASE/helm.patch.yaml" + +# Including at least one log to stderr allows us to see the full -x output +echo $HOME $PWD 1>&2 +ls -al 1>&2 + +kubectl kustomize "$BASE" && rm "$BASE/helm.patch.yaml" +#kubectl kustomize "$BASE" > "$BASE/result.yaml" diff --git a/examples/kustomize-renderer/templates/environment.yaml b/examples/kustomize-renderer/templates/environment.yaml new file mode 100644 index 00000000..de4c48a9 --- /dev/null +++ b/examples/kustomize-renderer/templates/environment.yaml @@ -0,0 +1,34 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: environment +data: + IMAGE_PROVIDER: {{ .Values.global.imageregistry.hostname }} + IMAGE_ACCOUNT: {{ .Values.global.imageregistry.account }} + GIT_EMAIL: {{ .Values.global.git.email }} + GIT_DEV_REPO_URL: https://{{ .Values.global.git.hostname }}/{{ .Values.global.git.account }}/manuela-dev.git + GIT_DEV_REPO_REVISION: {{ .Values.global.git.dev_revision }} + GIT_OPS_REPO_TEST_URL: {{ .Values.global.repoURL }} + GIT_OPS_REPO_TEST_REVISION: {{ .Values.global.targetRevision }} + GIT_OPS_REPO_PROD_URL: {{ .Values.global.repoURL }} + GIT_OPS_REPO_PROD_REVISION: {{ .Values.global.targetRevision }} + IOT_CONSUMER_IMAGE: iot-consumer + IOT_CONSUMER_YAML_PATH: images.(name==messaging).newTag + IOT_CONSUMER_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml + IOT_CONSUMER_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/messaging/kustomization.yaml + IOT_CONSUMER_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/messaging/messaging-is.yaml + IOT_FRONTEND_IMAGE: iot-frontend + IOT_FRONTEND_YAML_PATH: images.(name==line-dashboard).newTag + IOT_FRONTEND_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml + IOT_FRONTEND_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/line-dashboard/kustomization.yaml + IOT_FRONTEND_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/line-dashboard/line-dashboard-is.yaml + IOT_SWSENSOR_IMAGE: iot-software-sensor + IOT_SWSENSOR_YAML_PATH: images.(name==machine-sensor).newTag + IOT_SWSENSOR_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml + IOT_SWSENSOR_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/machine-sensor/kustomization.yaml + IOT_SWSENSOR_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/machine-sensor/machine-sensor-is.yaml + IOT_ANOMALY_IMAGE: iot-anomaly-detection + IOT_ANOMALY_YAML_PATH: images.(name==anomaly-detection).newTag + IOT_ANOMALY_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml + IOT_ANOMALY_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/anomaly-detection/kustomization.yaml + IOT_ANOMALY_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/anomaly-detection/anomaly-detection-is.yaml diff --git a/examples/kustomize-renderer/values.yaml b/examples/kustomize-renderer/values.yaml new file mode 100644 index 00000000..cb80a03a --- /dev/null +++ b/examples/kustomize-renderer/values.yaml @@ -0,0 +1,12 @@ +global: + git: + provider: github.com + account: PLAINTEXT + username: PLAINTEXT + email: SOMEWHERE@EXAMPLE.COM + dev_revision: main + + imageregistry: + provider: quay.io + account: PLAINTEXT + diff --git a/examples/values-example.yaml b/examples/values-example.yaml new file mode 100644 index 00000000..81bbcf10 --- /dev/null +++ b/examples/values-example.yaml @@ -0,0 +1,104 @@ +global: + options: + useCSV: False + syncPolicy: Automatic + installPlanApproval: Automatic + +clusterGroup: + name: example + + namespaces: + - open-cluster-management + - application-ci + + subscriptions: + acm: + name: advanced-cluster-management + namespace: open-cluster-management + channel: release-2.4 + csv: advanced-cluster-management.v2.4.1 + + odh: + name: opendatahub-operator + source: community-operators + csv: opendatahub-operator.v1.1.0 + disabled: true + + pipelines: + name: openshift-pipelines-operator-rh + csv: redhat-openshift-pipelines.v1.5.2 + + projects: + - datacenter + + applications: + acm: + name: acm + namespace: open-cluster-management + project: datacenter + path: common/acm + ignoreDifferences: + - group: internal.open-cluster-management.io + kind: ManagedClusterInfo + jsonPointers: + - /spec/loggingCA + pipe: + name: pipelines + namespace: application-ci + project: datacenter + path: charts/datacenter/pipelines + + managedClusterGroups: + - name: acm-edge + # Optional - Point to a different repo + # repoURL: https://github.com/hybrid-cloud-patterns/mySite.git + # Must contain values-{clustergroupname}.yaml at the top level + targetRevision: main + helmOverrides: + # Values must be strings! + - name: clusterGroup.isHubCluster + value: "false" + acmlabels: + - name: clusterGroup + value: acm-region + - name: acm-provision-edge + targetRevision: main + helmOverrides: + - name: clusterGroup.isHubCluster + value: "false" + clusterPools: + exampleAWSPool: + size: 3 + name: aws-ap + openshiftVersion: 4.10.18 + baseDomain: blueprints.rhecoeng.com + platform: + aws: + region: ap-southeast-2 + clusters: + - One + exampleAzurePool: + name: azure-us + openshiftVersion: 4.10.18 + baseDomain: blueprints.rhecoeng.com + platform: + azure: + baseDomainResourceGroupName: dojo-dns-zones + region: eastus + clusters: + - Two + - Three + acmlabels: + - name: clusterGroup + value: region + - name: argo-edge + hostedArgoSites: + - name: perth + domain: perth1.beekhof.net + bearerKeyPath: secret/data/hub/cluster_perth + caKeyPath: secret/data/hub/cluster_perth_ca + - name: sydney + domain: syd.beekhof.net + helmOverrides: + - name: clusterGroup.isHubCluster + value: "false" diff --git a/examples/values-secret.yaml b/examples/values-secret.yaml new file mode 100644 index 00000000..1b6fec08 --- /dev/null +++ b/examples/values-secret.yaml @@ -0,0 +1,32 @@ +main: + git: + repoURL: https://github.com/example/common + +secrets: + # NEVER COMMIT THESE VALUES TO GIT + imageregistry: + # Quay -> Robot Accounts -> Robot Login + account: test-account + token: test-quay-token + + git: + # Go to: https://github.com/settings/tokens + username: test-user + token: test-git-token + + aws: + s3Secret: test-secret + + # The cluster_xxxx pattern is used for creating externalSecrets that + # will be used by ArgoCD to push manifests to other clusters. + # + # Create a service account with enough permissions and extract the token + # + # CLUSTER_TOKEN=$(oc describe secret -n default argocd-external-token | grep 'token:' | awk '{print$2}') + # CLUSTER_CA=$(oc extract -n openshift-config cm/kube-root-ca.crt --to=- --keys=ca.crt | base64 | awk '{print}' ORS='') + cluster_example: + server: https://api.example.openshiftapps.com:6443 + bearerToken: + +files: + cluster_example_ca: /path/to/ca.file diff --git a/golang-external-secrets/Chart.yaml b/golang-external-secrets/Chart.yaml new file mode 100644 index 00000000..8fbec047 --- /dev/null +++ b/golang-external-secrets/Chart.yaml @@ -0,0 +1,11 @@ +apiVersion: v2 +description: A Helm chart to configure the golang-based external-secrets +keywords: +- pattern +name: golang-external-secrets +version: 0.0.1 +dependencies: + - name: external-secrets + version: "0.5.9" + repository: "https://charts.external-secrets.io" + #"https://external-secrets.github.io/kubernetes-external-secrets" diff --git a/golang-external-secrets/charts/external-secrets-0.5.9.tgz b/golang-external-secrets/charts/external-secrets-0.5.9.tgz new file mode 100644 index 0000000000000000000000000000000000000000..3d5b93f969793a05cbfc12ed95d1547568084e9a GIT binary patch literal 40987 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 a3Pw*e84!s_2mlTa1_RN#9>Xaj!~HKK%^wf| literal 0 HcmV?d00001 diff --git a/golang-external-secrets/templates/golang-external-secrets-hub-clusterrolebinding.yaml b/golang-external-secrets/templates/golang-external-secrets-hub-clusterrolebinding.yaml new file mode 100644 index 00000000..a8ab9e78 --- /dev/null +++ b/golang-external-secrets/templates/golang-external-secrets-hub-clusterrolebinding.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: golang-external-secrets + namespace: golang-external-secrets + annotations: + kubernetes.io/service-account.name: golang-external-secrets +type: kubernetes.io/service-account-token +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: role-tokenreview-binding + namespace: default +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator +subjects: +- kind: ServiceAccount + name: golang-external-secrets + namespace: golang-external-secrets diff --git a/golang-external-secrets/templates/golang-external-secrets-hub-secretstore.yaml b/golang-external-secrets/templates/golang-external-secrets-hub-secretstore.yaml new file mode 100644 index 00000000..6a95745d --- /dev/null +++ b/golang-external-secrets/templates/golang-external-secrets-hub-secretstore.yaml @@ -0,0 +1,25 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ClusterSecretStore +metadata: + name: vault-backend + namespace: golang-external-secrets +spec: + provider: + vault: + server: https://vault-vault.{{ .Values.global.hubClusterDomain }} + path: secret + # Version of KV backend + version: v2 + caProvider: + type: ConfigMap + name: kube-root-ca.crt + key: ca.crt + namespace: golang-external-secrets + auth: + kubernetes: + mountPath: {{ .Values.mountPath }} + role: {{ .Values.mountRole }} + secretRef: + name: golang-external-secrets + namespace: golang-external-secrets + key: "token" diff --git a/golang-external-secrets/values.yaml b/golang-external-secrets/values.yaml new file mode 100644 index 00000000..b4656f3b --- /dev/null +++ b/golang-external-secrets/values.yaml @@ -0,0 +1,6 @@ +--- +mountPath: "hub" +mountRole: "hub-role" + +global: + hubClusterDomain: hub.example.com diff --git a/hashicorp-vault/Chart.yaml b/hashicorp-vault/Chart.yaml new file mode 100644 index 00000000..51ae676f --- /dev/null +++ b/hashicorp-vault/Chart.yaml @@ -0,0 +1,10 @@ +apiVersion: v2 +description: A Helm chart to configure Hashicorp's vault +keywords: +- pattern +name: hashicorp-vault +version: 0.0.1 +dependencies: + - name: vault + version: "0.22.0" + repository: "https://helm.releases.hashicorp.com" diff --git a/hashicorp-vault/README.md b/hashicorp-vault/README.md new file mode 100644 index 00000000..153b516a --- /dev/null +++ b/hashicorp-vault/README.md @@ -0,0 +1,12 @@ +# VP hashicorp-vault + +**IMPORTANT**: Due to the fact that 'null' values do not work in helm charts ([GH#9136](https://github.com/helm/helm/issues/9136)), +we need to patch the chart to skip setting the host. + +Make sure to run "./update-helm-dependency.sh" + +We can drop this local patch when any one the two conditions is true: + +- [1] is fixed in helm and we can require the version that for installs +- [PR#779](https://github.com/hashicorp/vault-helm/pull/779) is merged in vault-helm *and* our minimum supported OCP version + is OCP 4.11 (route subdomain is broken in OCP < 4.11 due to missing [commit](https://github.com/openshift/router/commit/6f730c7cae966f0ed8def50c81d1bf10fe9eb77b) diff --git a/hashicorp-vault/charts/vault-0.22.0.tgz b/hashicorp-vault/charts/vault-0.22.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..e6111e1f7482f02b422e1341eca5d369e2f3cc98 GIT binary patch literal 51863 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 Ly%<5xTYojN( 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 bYunSyd(&rT3oiTbU%q^$4TourIX}iX0ap0H literal 0 HcmV?d00001 diff --git a/hashicorp-vault/patch-server-route.diff b/hashicorp-vault/patch-server-route.diff new file mode 100644 index 00000000..edc22c57 --- /dev/null +++ b/hashicorp-vault/patch-server-route.diff @@ -0,0 +1,28 @@ +diff -up vault/values.yaml.orig vault/values.yaml +--- vault/values.yaml.orig 2022-09-05 20:42:02.468428184 +0200 ++++ vault/values.yaml 2022-09-05 20:42:05.218435871 +0200 +@@ -406,7 +406,8 @@ server: + + labels: {} + annotations: {} +- host: chart-example.local ++ #host: chart-example.local ++ host: null + # tls will be passed directly to the route's TLS config, which + # can be used to configure other termination methods that terminate + # TLS at the router +diff -up vault/values.schema.json.orig vault/values.schema.json +--- vault/values.schema.json.orig 2022-09-11 21:00:34.834334961 +0200 ++++ vault/values.schema.json 2022-09-11 21:00:57.190368032 +0200 +@@ -838,7 +838,10 @@ + "type": "boolean" + }, + "host": { +- "type": "string" ++ "type": [ ++ "null", ++ "string" ++ ] + }, + "labels": { + "type": "object" diff --git a/hashicorp-vault/templates/vault-app.yaml b/hashicorp-vault/templates/vault-app.yaml new file mode 100644 index 00000000..bbe16e14 --- /dev/null +++ b/hashicorp-vault/templates/vault-app.yaml @@ -0,0 +1,12 @@ +apiVersion: console.openshift.io/v1 +kind: ConsoleLink +metadata: + name: vault-link + namespace: vault +spec: + applicationMenu: + section: HashiCorp Vault + imageURL: data:image/png;base64,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 + href: 'https://vault-vault.{{ coalesce .Values.global.localClusterDomain .Values.global.hubClusterDomain }}' + location: ApplicationMenu + text: 'Vault' diff --git a/hashicorp-vault/update-helm-dependency.sh b/hashicorp-vault/update-helm-dependency.sh new file mode 100755 index 00000000..afd6d522 --- /dev/null +++ b/hashicorp-vault/update-helm-dependency.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -eu + +# Get the version of the dependency and then unquote it +TMPVER=$(sed -e '1,/^version:/ d' "Chart.yaml" | grep "version:" | awk '{ print $2 }') +VERSION=$(eval echo "${TMPVER}") + +# Chart format is vault-0.21.0.tgz +NAME="vault" +TAR="${NAME}-${VERSION}.tgz" +CHARTDIR="charts" + +if [ ! -f "${CHARTDIR}/${TAR}" ]; then + echo "Charts $TAR not found" + exit 1 +fi + +pushd "${CHARTDIR}" +rm -rf "${NAME}" +tar xfz "${TAR}" +pushd "${NAME}" +patch -p1 < ../../patch-server-route.diff +popd +tar cvfz "${TAR}" "${NAME}" +rm -rf "${NAME}" +popd diff --git a/hashicorp-vault/values.yaml b/hashicorp-vault/values.yaml new file mode 100644 index 00000000..e16cc0e3 --- /dev/null +++ b/hashicorp-vault/values.yaml @@ -0,0 +1,20 @@ +--- +global: + openshift: true + localClusterDomain: apps.foo.cluster.com + +vault: + injector: + enabled: false + ui: + enabled: true + serviceType: "LoadBalancer" + server: + route: + host: null + enabled: true + tls: + termination: "edge" + image: + repository: "registry.connect.redhat.com/hashicorp/vault" + tag: "1.11.3-ubi" diff --git a/install/.helmignore b/install/.helmignore new file mode 100644 index 00000000..b25c15b8 --- /dev/null +++ b/install/.helmignore @@ -0,0 +1 @@ +*~ diff --git a/install/Chart.yaml b/install/Chart.yaml new file mode 100644 index 00000000..d1c80ab3 --- /dev/null +++ b/install/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +description: A Helm chart to build and deploy a Cloud Pattern +keywords: +- pattern +name: pattern-install +version: 0.0.1 diff --git a/install/crds/applications.argoproj.io.yaml b/install/crds/applications.argoproj.io.yaml new file mode 100644 index 00000000..c9866d38 --- /dev/null +++ b/install/crds/applications.argoproj.io.yaml @@ -0,0 +1,2312 @@ +# oc get crd/applications.argoproj.io -o yaml > applications.argoproj.io.yaml +# Remove annotation, timestamps and other cluster-specific cruft +# Also remove any status leftovers at the end +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + generation: 1 + labels: + app.kubernetes.io/name: applications.argoproj.io + app.kubernetes.io/part-of: argocd + operators.coreos.com/openshift-gitops-operator.openshift-operators: "" + name: applications.argoproj.io +spec: + conversion: + strategy: None + group: argoproj.io + names: + kind: Application + listKind: ApplicationList + plural: applications + shortNames: + - app + - apps + singular: application + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.sync.status + name: Sync Status + type: string + - jsonPath: .status.health.status + name: Health Status + type: string + - jsonPath: .status.sync.revision + name: Revision + priority: 10 + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Application is a definition of Application resource. + 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 + operation: + description: Operation contains information about a requested or running + operation + properties: + info: + description: Info is a list of informational items for this operation + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + initiatedBy: + description: InitiatedBy contains information about who initiated + the operations + properties: + automated: + description: Automated is set to true if operation was initiated + automatically by the application controller. + type: boolean + username: + description: Username contains the name of a user who started + operation + type: string + type: object + retry: + description: Retry controls the strategy to apply if a sync fails + properties: + backoff: + description: Backoff controls how to backoff on subsequent retries + of failed syncs + properties: + duration: + description: Duration is the amount to back off. Default unit + is seconds, but could also be a duration (e.g. "2m", "1h") + type: string + factor: + description: Factor is a factor to multiply the base duration + after each failed retry + format: int64 + type: integer + maxDuration: + description: MaxDuration is the maximum amount of time allowed + for the backoff strategy + type: string + type: object + limit: + description: Limit is the maximum number of attempts for retrying + a failed sync. If set to 0, no retries will be performed. + format: int64 + type: integer + type: object + sync: + description: Sync contains parameters for the operation + properties: + dryRun: + description: DryRun specifies to perform a `kubectl apply --dry-run` + without actually performing the sync + type: boolean + manifests: + description: Manifests is an optional field that overrides sync + source with a local directory for development + items: + type: string + type: array + prune: + description: Prune specifies to delete resources from the cluster + that are no longer tracked in git + type: boolean + resources: + description: Resources describes which resources shall be part + of the sync + items: + description: SyncOperationResource contains resources to sync. + properties: + group: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + type: array + revision: + description: Revision is the revision (Git) or chart version (Helm) + which to sync the application to If omitted, will use the revision + specified in app spec. + type: string + source: + description: Source overrides the source definition set in the + application. This is typically set in a Rollback operation and + is nil during a Sync operation + properties: + chart: + description: Chart is a Helm chart name, and must be specified + for applications sourced from a Helm repo. + type: string + directory: + description: Directory holds path/directory specific options + properties: + exclude: + description: Exclude contains a glob pattern to match + paths against that should be explicitly excluded from + being used during manifest generation + type: string + include: + description: Include contains a glob pattern to match + paths against that should be explicitly included during + manifest generation + type: string + jsonnet: + description: Jsonnet holds options specific to Jsonnet + properties: + extVars: + description: ExtVars is a list of Jsonnet External + Variables + items: + description: JsonnetVar represents a variable to + be passed to jsonnet during manifest generation + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + description: Additional library search dirs + items: + type: string + type: array + tlas: + description: TLAS is a list of Jsonnet Top-level Arguments + items: + description: JsonnetVar represents a variable to + be passed to jsonnet during manifest generation + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + description: Recurse specifies whether to scan a directory + recursively for manifests + type: boolean + type: object + helm: + description: Helm holds helm specific options + properties: + fileParameters: + description: FileParameters are file parameters to the + helm template + items: + description: HelmFileParameter is a file parameter that's + passed to helm template during manifest generation + properties: + name: + description: Name is the name of the Helm parameter + type: string + path: + description: Path is the path to the file containing + the values for the Helm parameter + type: string + type: object + type: array + ignoreMissingValueFiles: + description: IgnoreMissingValueFiles prevents helm template + from failing when valueFiles do not exist locally by + not appending them to helm template --values + type: boolean + parameters: + description: Parameters is a list of Helm parameters which + are passed to the helm template command upon manifest + generation + items: + description: HelmParameter is a parameter that's passed + to helm template during manifest generation + properties: + forceString: + description: ForceString determines whether to tell + Helm to interpret booleans and numbers as strings + type: boolean + name: + description: Name is the name of the Helm parameter + type: string + value: + description: Value is the value for the Helm parameter + type: string + type: object + type: array + passCredentials: + description: PassCredentials pass credentials to all domains + (Helm's --pass-credentials) + type: boolean + releaseName: + description: ReleaseName is the Helm release name to use. + If omitted it will use the application name + type: string + skipCrds: + description: SkipCrds skips custom resource definition + installation step (Helm's --skip-crds) + type: boolean + valueFiles: + description: ValuesFiles is a list of Helm value files + to use when generating a template + items: + type: string + type: array + values: + description: Values specifies Helm values to be passed + to helm template, typically defined as a block + type: string + version: + description: Version is the Helm version to use for templating + (either "2" or "3") + type: string + type: object + ksonnet: + description: Ksonnet holds ksonnet specific options + properties: + environment: + description: Environment is a ksonnet application environment + name + type: string + parameters: + description: Parameters are a list of ksonnet component + parameter override values + items: + description: KsonnetParameter is a ksonnet component + parameter + properties: + component: + type: string + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + kustomize: + description: Kustomize holds kustomize specific options + properties: + commonAnnotations: + additionalProperties: + type: string + description: CommonAnnotations is a list of additional + annotations to add to rendered manifests + type: object + commonLabels: + additionalProperties: + type: string + description: CommonLabels is a list of additional labels + to add to rendered manifests + type: object + forceCommonAnnotations: + description: ForceCommonAnnotations specifies whether + to force applying common annotations to resources for + Kustomize apps + type: boolean + forceCommonLabels: + description: ForceCommonLabels specifies whether to force + applying common labels to resources for Kustomize apps + type: boolean + images: + description: Images is a list of Kustomize image override + specifications + items: + description: KustomizeImage represents a Kustomize image + definition in the format [old_image_name=]: + type: string + type: array + namePrefix: + description: NamePrefix is a prefix appended to resources + for Kustomize apps + type: string + nameSuffix: + description: NameSuffix is a suffix appended to resources + for Kustomize apps + type: string + version: + description: Version controls which version of Kustomize + to use for rendering manifests + type: string + type: object + path: + description: Path is a directory path within the Git repository, + and is only valid for applications sourced from Git. + type: string + plugin: + description: ConfigManagementPlugin holds config management + plugin specific options + properties: + env: + description: Env is a list of environment variable entries + items: + description: EnvEntry represents an entry in the application's + environment + properties: + name: + description: Name is the name of the variable, usually + expressed in uppercase + type: string + value: + description: Value is the value of the variable + type: string + required: + - name + - value + type: object + type: array + name: + type: string + type: object + repoURL: + description: RepoURL is the URL to the repository (Git or + Helm) that contains the application manifests + type: string + targetRevision: + description: TargetRevision defines the revision of the source + to sync the application to. In case of Git, this can be + commit, tag, or branch. If omitted, will equal to HEAD. + In case of Helm, this is a semver tag for the Chart's version. + type: string + required: + - repoURL + type: object + syncOptions: + description: SyncOptions provide per-sync sync-options, e.g. Validate=false + items: + type: string + type: array + syncStrategy: + description: SyncStrategy describes how to perform the sync + properties: + apply: + description: Apply will perform a `kubectl apply` to perform + the sync. + properties: + force: + description: Force indicates whether or not to supply + the --force flag to `kubectl apply`. The --force flag + deletes and re-create the resource, when PATCH encounters + conflict and has retried for 5 times. + type: boolean + type: object + hook: + description: Hook will submit any referenced resources to + perform the sync. This is the default strategy + properties: + force: + description: Force indicates whether or not to supply + the --force flag to `kubectl apply`. The --force flag + deletes and re-create the resource, when PATCH encounters + conflict and has retried for 5 times. + type: boolean + type: object + type: object + type: object + type: object + spec: + description: ApplicationSpec represents desired application state. Contains + link to repository with application definition and additional parameters + link definition revision. + properties: + destination: + description: Destination is a reference to the target Kubernetes server + and namespace + properties: + name: + description: Name is an alternate way of specifying the target + cluster by its symbolic name + type: string + namespace: + description: Namespace specifies the target namespace for the + application's resources. The namespace will only be set for + namespace-scoped resources that have not set a value for .metadata.namespace + type: string + server: + description: Server specifies the URL of the target cluster and + must be set to the Kubernetes control plane API + type: string + type: object + ignoreDifferences: + description: IgnoreDifferences is a list of resources and their fields + which should be ignored during comparison + items: + description: ResourceIgnoreDifferences contains resource filter + and list of json paths which should be ignored during comparison + with live state. + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + description: ManagedFieldsManagers is a list of trusted managers. + Fields mutated by those managers will take precedence over + the desired state defined in the SCM and won't be displayed + in diffs + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array + info: + description: Info contains a list of information (URLs, email addresses, + and plain text) that relates to the application + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + project: + description: Project is a reference to the project this application + belongs to. The empty string means that application belongs to the + 'default' project. + type: string + revisionHistoryLimit: + description: RevisionHistoryLimit limits the number of items kept + in the application's revision history, which is used for informational + purposes as well as for rollbacks to previous versions. This should + only be changed in exceptional circumstances. Setting to zero will + store no history. This will reduce storage used. Increasing will + increase the space used to store the history, so we do not recommend + increasing it. Default is 10. + format: int64 + type: integer + source: + description: Source is a reference to the location of the application's + manifests or chart + properties: + chart: + description: Chart is a Helm chart name, and must be specified + for applications sourced from a Helm repo. + type: string + directory: + description: Directory holds path/directory specific options + properties: + exclude: + description: Exclude contains a glob pattern to match paths + against that should be explicitly excluded from being used + during manifest generation + type: string + include: + description: Include contains a glob pattern to match paths + against that should be explicitly included during manifest + generation + type: string + jsonnet: + description: Jsonnet holds options specific to Jsonnet + properties: + extVars: + description: ExtVars is a list of Jsonnet External Variables + items: + description: JsonnetVar represents a variable to be + passed to jsonnet during manifest generation + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + description: Additional library search dirs + items: + type: string + type: array + tlas: + description: TLAS is a list of Jsonnet Top-level Arguments + items: + description: JsonnetVar represents a variable to be + passed to jsonnet during manifest generation + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + description: Recurse specifies whether to scan a directory + recursively for manifests + type: boolean + type: object + helm: + description: Helm holds helm specific options + properties: + fileParameters: + description: FileParameters are file parameters to the helm + template + items: + description: HelmFileParameter is a file parameter that's + passed to helm template during manifest generation + properties: + name: + description: Name is the name of the Helm parameter + type: string + path: + description: Path is the path to the file containing + the values for the Helm parameter + type: string + type: object + type: array + ignoreMissingValueFiles: + description: IgnoreMissingValueFiles prevents helm template + from failing when valueFiles do not exist locally by not + appending them to helm template --values + type: boolean + parameters: + description: Parameters is a list of Helm parameters which + are passed to the helm template command upon manifest generation + items: + description: HelmParameter is a parameter that's passed + to helm template during manifest generation + properties: + forceString: + description: ForceString determines whether to tell + Helm to interpret booleans and numbers as strings + type: boolean + name: + description: Name is the name of the Helm parameter + type: string + value: + description: Value is the value for the Helm parameter + type: string + type: object + type: array + passCredentials: + description: PassCredentials pass credentials to all domains + (Helm's --pass-credentials) + type: boolean + releaseName: + description: ReleaseName is the Helm release name to use. + If omitted it will use the application name + type: string + skipCrds: + description: SkipCrds skips custom resource definition installation + step (Helm's --skip-crds) + type: boolean + valueFiles: + description: ValuesFiles is a list of Helm value files to + use when generating a template + items: + type: string + type: array + values: + description: Values specifies Helm values to be passed to + helm template, typically defined as a block + type: string + version: + description: Version is the Helm version to use for templating + (either "2" or "3") + type: string + type: object + ksonnet: + description: Ksonnet holds ksonnet specific options + properties: + environment: + description: Environment is a ksonnet application environment + name + type: string + parameters: + description: Parameters are a list of ksonnet component parameter + override values + items: + description: KsonnetParameter is a ksonnet component parameter + properties: + component: + type: string + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + kustomize: + description: Kustomize holds kustomize specific options + properties: + commonAnnotations: + additionalProperties: + type: string + description: CommonAnnotations is a list of additional annotations + to add to rendered manifests + type: object + commonLabels: + additionalProperties: + type: string + description: CommonLabels is a list of additional labels to + add to rendered manifests + type: object + forceCommonAnnotations: + description: ForceCommonAnnotations specifies whether to force + applying common annotations to resources for Kustomize apps + type: boolean + forceCommonLabels: + description: ForceCommonLabels specifies whether to force + applying common labels to resources for Kustomize apps + type: boolean + images: + description: Images is a list of Kustomize image override + specifications + items: + description: KustomizeImage represents a Kustomize image + definition in the format [old_image_name=]: + type: string + type: array + namePrefix: + description: NamePrefix is a prefix appended to resources + for Kustomize apps + type: string + nameSuffix: + description: NameSuffix is a suffix appended to resources + for Kustomize apps + type: string + version: + description: Version controls which version of Kustomize to + use for rendering manifests + type: string + type: object + path: + description: Path is a directory path within the Git repository, + and is only valid for applications sourced from Git. + type: string + plugin: + description: ConfigManagementPlugin holds config management plugin + specific options + properties: + env: + description: Env is a list of environment variable entries + items: + description: EnvEntry represents an entry in the application's + environment + properties: + name: + description: Name is the name of the variable, usually + expressed in uppercase + type: string + value: + description: Value is the value of the variable + type: string + required: + - name + - value + type: object + type: array + name: + type: string + type: object + repoURL: + description: RepoURL is the URL to the repository (Git or Helm) + that contains the application manifests + type: string + targetRevision: + description: TargetRevision defines the revision of the source + to sync the application to. In case of Git, this can be commit, + tag, or branch. If omitted, will equal to HEAD. In case of Helm, + this is a semver tag for the Chart's version. + type: string + required: + - repoURL + type: object + syncPolicy: + description: SyncPolicy controls when and how a sync will be performed + properties: + automated: + description: Automated will keep an application synced to the + target revision + properties: + allowEmpty: + description: 'AllowEmpty allows apps have zero live resources + (default: false)' + type: boolean + prune: + description: 'Prune specifies whether to delete resources + from the cluster that are not found in the sources anymore + as part of automated sync (default: false)' + type: boolean + selfHeal: + description: 'SelfHeal specifes whether to revert resources + back to their desired state upon modification in the cluster + (default: false)' + type: boolean + type: object + retry: + description: Retry controls failed sync retry behavior + properties: + backoff: + description: Backoff controls how to backoff on subsequent + retries of failed syncs + properties: + duration: + description: Duration is the amount to back off. Default + unit is seconds, but could also be a duration (e.g. + "2m", "1h") + type: string + factor: + description: Factor is a factor to multiply the base duration + after each failed retry + format: int64 + type: integer + maxDuration: + description: MaxDuration is the maximum amount of time + allowed for the backoff strategy + type: string + type: object + limit: + description: Limit is the maximum number of attempts for retrying + a failed sync. If set to 0, no retries will be performed. + format: int64 + type: integer + type: object + syncOptions: + description: Options allow you to specify whole app sync-options + items: + type: string + type: array + type: object + required: + - destination + - project + - source + type: object + status: + description: ApplicationStatus contains status information for the application + properties: + conditions: + description: Conditions is a list of currently observed application + conditions + items: + description: ApplicationCondition contains details about an application + condition, which is usally an error or warning + properties: + lastTransitionTime: + description: LastTransitionTime is the time the condition was + last observed + format: date-time + type: string + message: + description: Message contains human-readable message indicating + details about condition + type: string + type: + description: Type is an application condition type + type: string + required: + - message + - type + type: object + type: array + health: + description: Health contains information about the application's current + health status + properties: + message: + description: Message is a human-readable informational message + describing the health status + type: string + status: + description: Status holds the status code of the application or + resource + type: string + type: object + history: + description: History contains information about the application's + sync history + items: + description: RevisionHistory contains history information about + a previous sync + properties: + deployStartedAt: + description: DeployStartedAt holds the time the sync operation + started + format: date-time + type: string + deployedAt: + description: DeployedAt holds the time the sync operation completed + format: date-time + type: string + id: + description: ID is an auto incrementing identifier of the RevisionHistory + format: int64 + type: integer + revision: + description: Revision holds the revision the sync was performed + against + type: string + source: + description: Source is a reference to the application source + used for the sync operation + properties: + chart: + description: Chart is a Helm chart name, and must be specified + for applications sourced from a Helm repo. + type: string + directory: + description: Directory holds path/directory specific options + properties: + exclude: + description: Exclude contains a glob pattern to match + paths against that should be explicitly excluded from + being used during manifest generation + type: string + include: + description: Include contains a glob pattern to match + paths against that should be explicitly included during + manifest generation + type: string + jsonnet: + description: Jsonnet holds options specific to Jsonnet + properties: + extVars: + description: ExtVars is a list of Jsonnet External + Variables + items: + description: JsonnetVar represents a variable + to be passed to jsonnet during manifest generation + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + description: Additional library search dirs + items: + type: string + type: array + tlas: + description: TLAS is a list of Jsonnet Top-level + Arguments + items: + description: JsonnetVar represents a variable + to be passed to jsonnet during manifest generation + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + description: Recurse specifies whether to scan a directory + recursively for manifests + type: boolean + type: object + helm: + description: Helm holds helm specific options + properties: + fileParameters: + description: FileParameters are file parameters to the + helm template + items: + description: HelmFileParameter is a file parameter + that's passed to helm template during manifest generation + properties: + name: + description: Name is the name of the Helm parameter + type: string + path: + description: Path is the path to the file containing + the values for the Helm parameter + type: string + type: object + type: array + ignoreMissingValueFiles: + description: IgnoreMissingValueFiles prevents helm template + from failing when valueFiles do not exist locally + by not appending them to helm template --values + type: boolean + parameters: + description: Parameters is a list of Helm parameters + which are passed to the helm template command upon + manifest generation + items: + description: HelmParameter is a parameter that's passed + to helm template during manifest generation + properties: + forceString: + description: ForceString determines whether to + tell Helm to interpret booleans and numbers + as strings + type: boolean + name: + description: Name is the name of the Helm parameter + type: string + value: + description: Value is the value for the Helm parameter + type: string + type: object + type: array + passCredentials: + description: PassCredentials pass credentials to all + domains (Helm's --pass-credentials) + type: boolean + releaseName: + description: ReleaseName is the Helm release name to + use. If omitted it will use the application name + type: string + skipCrds: + description: SkipCrds skips custom resource definition + installation step (Helm's --skip-crds) + type: boolean + valueFiles: + description: ValuesFiles is a list of Helm value files + to use when generating a template + items: + type: string + type: array + values: + description: Values specifies Helm values to be passed + to helm template, typically defined as a block + type: string + version: + description: Version is the Helm version to use for + templating (either "2" or "3") + type: string + type: object + ksonnet: + description: Ksonnet holds ksonnet specific options + properties: + environment: + description: Environment is a ksonnet application environment + name + type: string + parameters: + description: Parameters are a list of ksonnet component + parameter override values + items: + description: KsonnetParameter is a ksonnet component + parameter + properties: + component: + type: string + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + kustomize: + description: Kustomize holds kustomize specific options + properties: + commonAnnotations: + additionalProperties: + type: string + description: CommonAnnotations is a list of additional + annotations to add to rendered manifests + type: object + commonLabels: + additionalProperties: + type: string + description: CommonLabels is a list of additional labels + to add to rendered manifests + type: object + forceCommonAnnotations: + description: ForceCommonAnnotations specifies whether + to force applying common annotations to resources + for Kustomize apps + type: boolean + forceCommonLabels: + description: ForceCommonLabels specifies whether to + force applying common labels to resources for Kustomize + apps + type: boolean + images: + description: Images is a list of Kustomize image override + specifications + items: + description: KustomizeImage represents a Kustomize + image definition in the format [old_image_name=]: + type: string + type: array + namePrefix: + description: NamePrefix is a prefix appended to resources + for Kustomize apps + type: string + nameSuffix: + description: NameSuffix is a suffix appended to resources + for Kustomize apps + type: string + version: + description: Version controls which version of Kustomize + to use for rendering manifests + type: string + type: object + path: + description: Path is a directory path within the Git repository, + and is only valid for applications sourced from Git. + type: string + plugin: + description: ConfigManagementPlugin holds config management + plugin specific options + properties: + env: + description: Env is a list of environment variable entries + items: + description: EnvEntry represents an entry in the application's + environment + properties: + name: + description: Name is the name of the variable, + usually expressed in uppercase + type: string + value: + description: Value is the value of the variable + type: string + required: + - name + - value + type: object + type: array + name: + type: string + type: object + repoURL: + description: RepoURL is the URL to the repository (Git or + Helm) that contains the application manifests + type: string + targetRevision: + description: TargetRevision defines the revision of the + source to sync the application to. In case of Git, this + can be commit, tag, or branch. If omitted, will equal + to HEAD. In case of Helm, this is a semver tag for the + Chart's version. + type: string + required: + - repoURL + type: object + required: + - deployedAt + - id + - revision + type: object + type: array + observedAt: + description: 'ObservedAt indicates when the application state was + updated without querying latest git state Deprecated: controller + no longer updates ObservedAt field' + format: date-time + type: string + operationState: + description: OperationState contains information about any ongoing + operations, such as a sync + properties: + finishedAt: + description: FinishedAt contains time of operation completion + format: date-time + type: string + message: + description: Message holds any pertinent messages when attempting + to perform operation (typically errors). + type: string + operation: + description: Operation is the original requested operation + properties: + info: + description: Info is a list of informational items for this + operation + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + initiatedBy: + description: InitiatedBy contains information about who initiated + the operations + properties: + automated: + description: Automated is set to true if operation was + initiated automatically by the application controller. + type: boolean + username: + description: Username contains the name of a user who + started operation + type: string + type: object + retry: + description: Retry controls the strategy to apply if a sync + fails + properties: + backoff: + description: Backoff controls how to backoff on subsequent + retries of failed syncs + properties: + duration: + description: Duration is the amount to back off. Default + unit is seconds, but could also be a duration (e.g. + "2m", "1h") + type: string + factor: + description: Factor is a factor to multiply the base + duration after each failed retry + format: int64 + type: integer + maxDuration: + description: MaxDuration is the maximum amount of + time allowed for the backoff strategy + type: string + type: object + limit: + description: Limit is the maximum number of attempts for + retrying a failed sync. If set to 0, no retries will + be performed. + format: int64 + type: integer + type: object + sync: + description: Sync contains parameters for the operation + properties: + dryRun: + description: DryRun specifies to perform a `kubectl apply + --dry-run` without actually performing the sync + type: boolean + manifests: + description: Manifests is an optional field that overrides + sync source with a local directory for development + items: + type: string + type: array + prune: + description: Prune specifies to delete resources from + the cluster that are no longer tracked in git + type: boolean + resources: + description: Resources describes which resources shall + be part of the sync + items: + description: SyncOperationResource contains resources + to sync. + properties: + group: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + type: array + revision: + description: Revision is the revision (Git) or chart version + (Helm) which to sync the application to If omitted, + will use the revision specified in app spec. + type: string + source: + description: Source overrides the source definition set + in the application. This is typically set in a Rollback + operation and is nil during a Sync operation + properties: + chart: + description: Chart is a Helm chart name, and must + be specified for applications sourced from a Helm + repo. + type: string + directory: + description: Directory holds path/directory specific + options + properties: + exclude: + description: Exclude contains a glob pattern to + match paths against that should be explicitly + excluded from being used during manifest generation + type: string + include: + description: Include contains a glob pattern to + match paths against that should be explicitly + included during manifest generation + type: string + jsonnet: + description: Jsonnet holds options specific to + Jsonnet + properties: + extVars: + description: ExtVars is a list of Jsonnet + External Variables + items: + description: JsonnetVar represents a variable + to be passed to jsonnet during manifest + generation + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + description: Additional library search dirs + items: + type: string + type: array + tlas: + description: TLAS is a list of Jsonnet Top-level + Arguments + items: + description: JsonnetVar represents a variable + to be passed to jsonnet during manifest + generation + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + description: Recurse specifies whether to scan + a directory recursively for manifests + type: boolean + type: object + helm: + description: Helm holds helm specific options + properties: + fileParameters: + description: FileParameters are file parameters + to the helm template + items: + description: HelmFileParameter is a file parameter + that's passed to helm template during manifest + generation + properties: + name: + description: Name is the name of the Helm + parameter + type: string + path: + description: Path is the path to the file + containing the values for the Helm parameter + type: string + type: object + type: array + ignoreMissingValueFiles: + description: IgnoreMissingValueFiles prevents + helm template from failing when valueFiles do + not exist locally by not appending them to helm + template --values + type: boolean + parameters: + description: Parameters is a list of Helm parameters + which are passed to the helm template command + upon manifest generation + items: + description: HelmParameter is a parameter that's + passed to helm template during manifest generation + properties: + forceString: + description: ForceString determines whether + to tell Helm to interpret booleans and + numbers as strings + type: boolean + name: + description: Name is the name of the Helm + parameter + type: string + value: + description: Value is the value for the + Helm parameter + type: string + type: object + type: array + passCredentials: + description: PassCredentials pass credentials + to all domains (Helm's --pass-credentials) + type: boolean + releaseName: + description: ReleaseName is the Helm release name + to use. If omitted it will use the application + name + type: string + skipCrds: + description: SkipCrds skips custom resource definition + installation step (Helm's --skip-crds) + type: boolean + valueFiles: + description: ValuesFiles is a list of Helm value + files to use when generating a template + items: + type: string + type: array + values: + description: Values specifies Helm values to be + passed to helm template, typically defined as + a block + type: string + version: + description: Version is the Helm version to use + for templating (either "2" or "3") + type: string + type: object + ksonnet: + description: Ksonnet holds ksonnet specific options + properties: + environment: + description: Environment is a ksonnet application + environment name + type: string + parameters: + description: Parameters are a list of ksonnet + component parameter override values + items: + description: KsonnetParameter is a ksonnet component + parameter + properties: + component: + type: string + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + kustomize: + description: Kustomize holds kustomize specific options + properties: + commonAnnotations: + additionalProperties: + type: string + description: CommonAnnotations is a list of additional + annotations to add to rendered manifests + type: object + commonLabels: + additionalProperties: + type: string + description: CommonLabels is a list of additional + labels to add to rendered manifests + type: object + forceCommonAnnotations: + description: ForceCommonAnnotations specifies + whether to force applying common annotations + to resources for Kustomize apps + type: boolean + forceCommonLabels: + description: ForceCommonLabels specifies whether + to force applying common labels to resources + for Kustomize apps + type: boolean + images: + description: Images is a list of Kustomize image + override specifications + items: + description: KustomizeImage represents a Kustomize + image definition in the format [old_image_name=]: + type: string + type: array + namePrefix: + description: NamePrefix is a prefix appended to + resources for Kustomize apps + type: string + nameSuffix: + description: NameSuffix is a suffix appended to + resources for Kustomize apps + type: string + version: + description: Version controls which version of + Kustomize to use for rendering manifests + type: string + type: object + path: + description: Path is a directory path within the Git + repository, and is only valid for applications sourced + from Git. + type: string + plugin: + description: ConfigManagementPlugin holds config management + plugin specific options + properties: + env: + description: Env is a list of environment variable + entries + items: + description: EnvEntry represents an entry in + the application's environment + properties: + name: + description: Name is the name of the variable, + usually expressed in uppercase + type: string + value: + description: Value is the value of the variable + type: string + required: + - name + - value + type: object + type: array + name: + type: string + type: object + repoURL: + description: RepoURL is the URL to the repository + (Git or Helm) that contains the application manifests + type: string + targetRevision: + description: TargetRevision defines the revision of + the source to sync the application to. In case of + Git, this can be commit, tag, or branch. If omitted, + will equal to HEAD. In case of Helm, this is a semver + tag for the Chart's version. + type: string + required: + - repoURL + type: object + syncOptions: + description: SyncOptions provide per-sync sync-options, + e.g. Validate=false + items: + type: string + type: array + syncStrategy: + description: SyncStrategy describes how to perform the + sync + properties: + apply: + description: Apply will perform a `kubectl apply` + to perform the sync. + properties: + force: + description: Force indicates whether or not to + supply the --force flag to `kubectl apply`. + The --force flag deletes and re-create the resource, + when PATCH encounters conflict and has retried + for 5 times. + type: boolean + type: object + hook: + description: Hook will submit any referenced resources + to perform the sync. This is the default strategy + properties: + force: + description: Force indicates whether or not to + supply the --force flag to `kubectl apply`. + The --force flag deletes and re-create the resource, + when PATCH encounters conflict and has retried + for 5 times. + type: boolean + type: object + type: object + type: object + type: object + phase: + description: Phase is the current phase of the operation + type: string + retryCount: + description: RetryCount contains time of operation retries + format: int64 + type: integer + startedAt: + description: StartedAt contains time of operation start + format: date-time + type: string + syncResult: + description: SyncResult is the result of a Sync operation + properties: + resources: + description: Resources contains a list of sync result items + for each individual resource in a sync operation + items: + description: ResourceResult holds the operation result details + of a specific resource + properties: + group: + description: Group specifies the API group of the resource + type: string + hookPhase: + description: HookPhase contains the state of any operation + associated with this resource OR hook This can also + contain values for non-hook resources. + type: string + hookType: + description: HookType specifies the type of the hook. + Empty for non-hook resources + type: string + kind: + description: Kind specifies the API kind of the resource + type: string + message: + description: Message contains an informational or error + message for the last sync OR operation + type: string + name: + description: Name specifies the name of the resource + type: string + namespace: + description: Namespace specifies the target namespace + of the resource + type: string + status: + description: Status holds the final result of the sync. + Will be empty if the resources is yet to be applied/pruned + and is always zero-value for hooks + type: string + syncPhase: + description: SyncPhase indicates the particular phase + of the sync that this result was acquired in + type: string + version: + description: Version specifies the API version of the + resource + type: string + required: + - group + - kind + - name + - namespace + - version + type: object + type: array + revision: + description: Revision holds the revision this sync operation + was performed to + type: string + source: + description: Source records the application source information + of the sync, used for comparing auto-sync + properties: + chart: + description: Chart is a Helm chart name, and must be specified + for applications sourced from a Helm repo. + type: string + directory: + description: Directory holds path/directory specific options + properties: + exclude: + description: Exclude contains a glob pattern to match + paths against that should be explicitly excluded + from being used during manifest generation + type: string + include: + description: Include contains a glob pattern to match + paths against that should be explicitly included + during manifest generation + type: string + jsonnet: + description: Jsonnet holds options specific to Jsonnet + properties: + extVars: + description: ExtVars is a list of Jsonnet External + Variables + items: + description: JsonnetVar represents a variable + to be passed to jsonnet during manifest generation + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + description: Additional library search dirs + items: + type: string + type: array + tlas: + description: TLAS is a list of Jsonnet Top-level + Arguments + items: + description: JsonnetVar represents a variable + to be passed to jsonnet during manifest generation + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + description: Recurse specifies whether to scan a directory + recursively for manifests + type: boolean + type: object + helm: + description: Helm holds helm specific options + properties: + fileParameters: + description: FileParameters are file parameters to + the helm template + items: + description: HelmFileParameter is a file parameter + that's passed to helm template during manifest + generation + properties: + name: + description: Name is the name of the Helm parameter + type: string + path: + description: Path is the path to the file containing + the values for the Helm parameter + type: string + type: object + type: array + ignoreMissingValueFiles: + description: IgnoreMissingValueFiles prevents helm + template from failing when valueFiles do not exist + locally by not appending them to helm template --values + type: boolean + parameters: + description: Parameters is a list of Helm parameters + which are passed to the helm template command upon + manifest generation + items: + description: HelmParameter is a parameter that's + passed to helm template during manifest generation + properties: + forceString: + description: ForceString determines whether + to tell Helm to interpret booleans and numbers + as strings + type: boolean + name: + description: Name is the name of the Helm parameter + type: string + value: + description: Value is the value for the Helm + parameter + type: string + type: object + type: array + passCredentials: + description: PassCredentials pass credentials to all + domains (Helm's --pass-credentials) + type: boolean + releaseName: + description: ReleaseName is the Helm release name + to use. If omitted it will use the application name + type: string + skipCrds: + description: SkipCrds skips custom resource definition + installation step (Helm's --skip-crds) + type: boolean + valueFiles: + description: ValuesFiles is a list of Helm value files + to use when generating a template + items: + type: string + type: array + values: + description: Values specifies Helm values to be passed + to helm template, typically defined as a block + type: string + version: + description: Version is the Helm version to use for + templating (either "2" or "3") + type: string + type: object + ksonnet: + description: Ksonnet holds ksonnet specific options + properties: + environment: + description: Environment is a ksonnet application + environment name + type: string + parameters: + description: Parameters are a list of ksonnet component + parameter override values + items: + description: KsonnetParameter is a ksonnet component + parameter + properties: + component: + type: string + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + kustomize: + description: Kustomize holds kustomize specific options + properties: + commonAnnotations: + additionalProperties: + type: string + description: CommonAnnotations is a list of additional + annotations to add to rendered manifests + type: object + commonLabels: + additionalProperties: + type: string + description: CommonLabels is a list of additional + labels to add to rendered manifests + type: object + forceCommonAnnotations: + description: ForceCommonAnnotations specifies whether + to force applying common annotations to resources + for Kustomize apps + type: boolean + forceCommonLabels: + description: ForceCommonLabels specifies whether to + force applying common labels to resources for Kustomize + apps + type: boolean + images: + description: Images is a list of Kustomize image override + specifications + items: + description: KustomizeImage represents a Kustomize + image definition in the format [old_image_name=]: + type: string + type: array + namePrefix: + description: NamePrefix is a prefix appended to resources + for Kustomize apps + type: string + nameSuffix: + description: NameSuffix is a suffix appended to resources + for Kustomize apps + type: string + version: + description: Version controls which version of Kustomize + to use for rendering manifests + type: string + type: object + path: + description: Path is a directory path within the Git repository, + and is only valid for applications sourced from Git. + type: string + plugin: + description: ConfigManagementPlugin holds config management + plugin specific options + properties: + env: + description: Env is a list of environment variable + entries + items: + description: EnvEntry represents an entry in the + application's environment + properties: + name: + description: Name is the name of the variable, + usually expressed in uppercase + type: string + value: + description: Value is the value of the variable + type: string + required: + - name + - value + type: object + type: array + name: + type: string + type: object + repoURL: + description: RepoURL is the URL to the repository (Git + or Helm) that contains the application manifests + type: string + targetRevision: + description: TargetRevision defines the revision of the + source to sync the application to. In case of Git, this + can be commit, tag, or branch. If omitted, will equal + to HEAD. In case of Helm, this is a semver tag for the + Chart's version. + type: string + required: + - repoURL + type: object + required: + - revision + type: object + required: + - operation + - phase + - startedAt + type: object + reconciledAt: + description: ReconciledAt indicates when the application state was + reconciled using the latest git version + format: date-time + type: string + resources: + description: Resources is a list of Kubernetes resources managed by + this application + items: + description: 'ResourceStatus holds the current sync and health status + of a resource TODO: describe members of this type' + properties: + group: + type: string + health: + description: HealthStatus contains information about the currently + observed health state of an application or resource + properties: + message: + description: Message is a human-readable informational message + describing the health status + type: string + status: + description: Status holds the status code of the application + or resource + type: string + type: object + hook: + type: boolean + kind: + type: string + name: + type: string + namespace: + type: string + requiresPruning: + type: boolean + status: + description: SyncStatusCode is a type which represents possible + comparison results + type: string + version: + type: string + type: object + type: array + sourceType: + description: SourceType specifies the type of this application + type: string + summary: + description: Summary contains a list of URLs and container images + used by this application + properties: + externalURLs: + description: ExternalURLs holds all external URLs of application + child resources. + items: + type: string + type: array + images: + description: Images holds all images of application child resources. + items: + type: string + type: array + type: object + sync: + description: Sync contains information about the application's current + sync status + properties: + comparedTo: + description: ComparedTo contains information about what has been + compared + properties: + destination: + description: Destination is a reference to the application's + destination used for comparison + properties: + name: + description: Name is an alternate way of specifying the + target cluster by its symbolic name + type: string + namespace: + description: Namespace specifies the target namespace + for the application's resources. The namespace will + only be set for namespace-scoped resources that have + not set a value for .metadata.namespace + type: string + server: + description: Server specifies the URL of the target cluster + and must be set to the Kubernetes control plane API + type: string + type: object + source: + description: Source is a reference to the application's source + used for comparison + properties: + chart: + description: Chart is a Helm chart name, and must be specified + for applications sourced from a Helm repo. + type: string + directory: + description: Directory holds path/directory specific options + properties: + exclude: + description: Exclude contains a glob pattern to match + paths against that should be explicitly excluded + from being used during manifest generation + type: string + include: + description: Include contains a glob pattern to match + paths against that should be explicitly included + during manifest generation + type: string + jsonnet: + description: Jsonnet holds options specific to Jsonnet + properties: + extVars: + description: ExtVars is a list of Jsonnet External + Variables + items: + description: JsonnetVar represents a variable + to be passed to jsonnet during manifest generation + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + description: Additional library search dirs + items: + type: string + type: array + tlas: + description: TLAS is a list of Jsonnet Top-level + Arguments + items: + description: JsonnetVar represents a variable + to be passed to jsonnet during manifest generation + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + description: Recurse specifies whether to scan a directory + recursively for manifests + type: boolean + type: object + helm: + description: Helm holds helm specific options + properties: + fileParameters: + description: FileParameters are file parameters to + the helm template + items: + description: HelmFileParameter is a file parameter + that's passed to helm template during manifest + generation + properties: + name: + description: Name is the name of the Helm parameter + type: string + path: + description: Path is the path to the file containing + the values for the Helm parameter + type: string + type: object + type: array + ignoreMissingValueFiles: + description: IgnoreMissingValueFiles prevents helm + template from failing when valueFiles do not exist + locally by not appending them to helm template --values + type: boolean + parameters: + description: Parameters is a list of Helm parameters + which are passed to the helm template command upon + manifest generation + items: + description: HelmParameter is a parameter that's + passed to helm template during manifest generation + properties: + forceString: + description: ForceString determines whether + to tell Helm to interpret booleans and numbers + as strings + type: boolean + name: + description: Name is the name of the Helm parameter + type: string + value: + description: Value is the value for the Helm + parameter + type: string + type: object + type: array + passCredentials: + description: PassCredentials pass credentials to all + domains (Helm's --pass-credentials) + type: boolean + releaseName: + description: ReleaseName is the Helm release name + to use. If omitted it will use the application name + type: string + skipCrds: + description: SkipCrds skips custom resource definition + installation step (Helm's --skip-crds) + type: boolean + valueFiles: + description: ValuesFiles is a list of Helm value files + to use when generating a template + items: + type: string + type: array + values: + description: Values specifies Helm values to be passed + to helm template, typically defined as a block + type: string + version: + description: Version is the Helm version to use for + templating (either "2" or "3") + type: string + type: object + ksonnet: + description: Ksonnet holds ksonnet specific options + properties: + environment: + description: Environment is a ksonnet application + environment name + type: string + parameters: + description: Parameters are a list of ksonnet component + parameter override values + items: + description: KsonnetParameter is a ksonnet component + parameter + properties: + component: + type: string + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + kustomize: + description: Kustomize holds kustomize specific options + properties: + commonAnnotations: + additionalProperties: + type: string + description: CommonAnnotations is a list of additional + annotations to add to rendered manifests + type: object + commonLabels: + additionalProperties: + type: string + description: CommonLabels is a list of additional + labels to add to rendered manifests + type: object + forceCommonAnnotations: + description: ForceCommonAnnotations specifies whether + to force applying common annotations to resources + for Kustomize apps + type: boolean + forceCommonLabels: + description: ForceCommonLabels specifies whether to + force applying common labels to resources for Kustomize + apps + type: boolean + images: + description: Images is a list of Kustomize image override + specifications + items: + description: KustomizeImage represents a Kustomize + image definition in the format [old_image_name=]: + type: string + type: array + namePrefix: + description: NamePrefix is a prefix appended to resources + for Kustomize apps + type: string + nameSuffix: + description: NameSuffix is a suffix appended to resources + for Kustomize apps + type: string + version: + description: Version controls which version of Kustomize + to use for rendering manifests + type: string + type: object + path: + description: Path is a directory path within the Git repository, + and is only valid for applications sourced from Git. + type: string + plugin: + description: ConfigManagementPlugin holds config management + plugin specific options + properties: + env: + description: Env is a list of environment variable + entries + items: + description: EnvEntry represents an entry in the + application's environment + properties: + name: + description: Name is the name of the variable, + usually expressed in uppercase + type: string + value: + description: Value is the value of the variable + type: string + required: + - name + - value + type: object + type: array + name: + type: string + type: object + repoURL: + description: RepoURL is the URL to the repository (Git + or Helm) that contains the application manifests + type: string + targetRevision: + description: TargetRevision defines the revision of the + source to sync the application to. In case of Git, this + can be commit, tag, or branch. If omitted, will equal + to HEAD. In case of Helm, this is a semver tag for the + Chart's version. + type: string + required: + - repoURL + type: object + required: + - destination + - source + type: object + revision: + description: Revision contains information about the revision + the comparison has been performed to + type: string + status: + description: Status is the sync state of the comparison + type: string + required: + - status + type: object + type: object + required: + - metadata + - spec + type: object + served: true + storage: true + subresources: {} diff --git a/install/templates/argocd/application.yaml b/install/templates/argocd/application.yaml new file mode 100644 index 00000000..324e1f32 --- /dev/null +++ b/install/templates/argocd/application.yaml @@ -0,0 +1,37 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: {{ .Release.Name }}-{{ .Values.main.clusterGroupName }} + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground +spec: + destination: + name: in-cluster + namespace: {{ .Release.Name }}-{{ .Values.main.clusterGroupName }} + project: default + source: + repoURL: {{ .Values.main.git.repoURL }} + targetRevision: {{ .Values.main.git.revision }} + path: common/clustergroup + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-{{ .Values.main.clusterGroupName }}.yaml" + # Track the progress of https://github.com/argoproj/argo-cd/pull/6280 + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: {{ .Release.Name }} + - name: global.hubClusterDomain + value: {{ .Values.global.hubClusterDomain }} +{{- if eq .Values.main.options.syncPolicy "Automatic" }} + syncPolicy: + automated: {} +{{- end }} diff --git a/install/templates/argocd/namespace.yaml b/install/templates/argocd/namespace.yaml new file mode 100644 index 00000000..9e9fafb2 --- /dev/null +++ b/install/templates/argocd/namespace.yaml @@ -0,0 +1,6 @@ +# Pre-create so we can create our argo app for keeping subscriptions in sync +# Do it here so that we don't try to sync it in the future +apiVersion: v1 +kind: Namespace +metadata: + name: openshift-gitops diff --git a/install/templates/argocd/subscription.yaml b/install/templates/argocd/subscription.yaml new file mode 100644 index 00000000..22837b9a --- /dev/null +++ b/install/templates/argocd/subscription.yaml @@ -0,0 +1,20 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: openshift-gitops-operator + namespace: openshift-operators + labels: + operators.coreos.com/openshift-gitops-operator.openshift-operators: "" +spec: + channel: {{ .Values.main.gitops.channel }} + installPlanApproval: {{ .Values.main.options.installPlanApproval }} + name: openshift-gitops-operator + source: redhat-operators + sourceNamespace: openshift-marketplace + config: + env: + - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES + value: {{ .Release.Name }}-{{ .Values.main.clusterGroupName }},openshift-gitops +{{- if .Values.main.options.useCSV }} + startingCSV: openshift-gitops-operator.{{ .Values.main.gitops.csv }} +{{- end }} diff --git a/install/values.yaml b/install/values.yaml new file mode 100644 index 00000000..370e6b15 --- /dev/null +++ b/install/values.yaml @@ -0,0 +1,25 @@ +main: + git: + repoURL: https://github.com/pattern-clone/mypattern + revision: main + + options: + syncPolicy: Automatic + installPlanApproval: Automatic + useCSV: False + + gitops: + channel: stable + source: redhat-operators + csv: v1.3.0 + + clusterGroupName: default + +global: + imageregistry: + type: quay + + git: + hostname: github.com + # Account is the user or organization under which the pattern repo lives + account: hybrid-cloud-patterns diff --git a/operator-install/Chart.yaml b/operator-install/Chart.yaml new file mode 100644 index 00000000..74adcf8f --- /dev/null +++ b/operator-install/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +description: A Helm chart to build and deploy a Cloud Pattern via the patterns operator +keywords: +- pattern +name: pattern-install +version: 0.0.1 diff --git a/operator-install/crds/gitops.hybrid-cloud-patterns.io_patterns.yaml b/operator-install/crds/gitops.hybrid-cloud-patterns.io_patterns.yaml new file mode 100644 index 00000000..1acd4ad2 --- /dev/null +++ b/operator-install/crds/gitops.hybrid-cloud-patterns.io_patterns.yaml @@ -0,0 +1,157 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + name: patterns.gitops.hybrid-cloud-patterns.io +spec: + group: gitops.hybrid-cloud-patterns.io + names: + kind: Pattern + listKind: PatternList + plural: patterns + shortNames: + - patt + singular: pattern + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.lastStep + name: Step + priority: 1 + type: string + - jsonPath: .status.lastError + name: Error + priority: 2 + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Pattern is the Schema for the patterns 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: PatternSpec defines the desired state of Pattern + properties: + clusterGroupName: + type: string + extraParameters: + description: '.Name is dot separated per the helm --set syntax, such + as: global.something.field' + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + extraValueFiles: + description: URLs to additional Helm parameter files + items: + type: string + type: array + gitOpsSpec: + properties: + manualApproval: + description: 'Require manual confirmation before installing and + upgrading operators. Default: False' + type: boolean + manualSync: + description: 'Require manual intervention before Argo will sync + new content. Default: False' + type: boolean + operatorCSV: + description: Specific version of openshift-gitops to deploy. Requires + UseCSV=True + type: string + operatorChannel: + description: 'Channel to deploy openshift-gitops from. Default: + stable' + type: string + operatorSource: + description: 'Source to deploy openshift-gitops from. Default: + redhat-operators' + type: string + useCSV: + description: 'Dangerous. Force a specific version to be installed. + Default: False' + type: boolean + type: object + gitSpec: + properties: + hostname: + description: Optional. FQDN of the git server if automatic parsing + from TargetRepo is broken + type: string + originRepo: + description: Unused + type: string + targetRepo: + description: Git repo containing the pattern to deploy. Must use + https/http + type: string + targetRevision: + description: 'Branch, tag, or commit to deploy. Does not support + short-sha''s. Default: main' + type: string + valuesDirectoryURL: + description: Optional. Alternate URL to obtain Helm values files + from instead of this pattern. + type: string + required: + - targetRepo + type: object + required: + - clusterGroupName + - gitSpec + type: object + status: + description: PatternStatus defines the observed state of Pattern + properties: + clusterDomain: + type: string + clusterID: + type: string + clusterName: + type: string + clusterPlatform: + type: string + lastError: + description: Last error encountered by the pattern + type: string + lastStep: + description: Last action related to the pattern + type: string + version: + description: Number of updates to the pattern + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/operator-install/templates/pattern.yaml b/operator-install/templates/pattern.yaml new file mode 100644 index 00000000..2ac7b52a --- /dev/null +++ b/operator-install/templates/pattern.yaml @@ -0,0 +1,12 @@ +apiVersion: gitops.hybrid-cloud-patterns.io/v1alpha1 +kind: Pattern +metadata: + name: {{ .Release.Name }} + namespace: openshift-operators +spec: + clusterGroupName: {{ .Values.main.clusterGroupName }} + gitSpec: + targetRepo: {{ .Values.main.git.repoURL }} + targetRevision: {{ .Values.main.git.revision }} + gitOpsSpec: + operatorChannel: {{ default "stable" .Values.main.gitops.channel }} diff --git a/operator-install/templates/subscription.yaml b/operator-install/templates/subscription.yaml new file mode 100644 index 00000000..381e185f --- /dev/null +++ b/operator-install/templates/subscription.yaml @@ -0,0 +1,13 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: patterns-operator + namespace: openshift-operators + labels: + operators.coreos.com/patterns-operator.openshift-operators: "" +spec: + channel: fast + installPlanApproval: Automatic + name: patterns-operator + source: community-operators + sourceNamespace: openshift-marketplace diff --git a/operator-install/values.yaml b/operator-install/values.yaml new file mode 100644 index 00000000..b6e67044 --- /dev/null +++ b/operator-install/values.yaml @@ -0,0 +1,9 @@ +main: + git: + repoURL: https://github.com/pattern-clone/mypattern + revision: main + + gitops: + channel: "stable" + + clusterGroupName: default diff --git a/reference-output.yaml b/reference-output.yaml new file mode 100644 index 00000000..cd59ac24 --- /dev/null +++ b/reference-output.yaml @@ -0,0 +1,119 @@ +--- +# Source: pattern-install/templates/argocd/namespace.yaml +# Pre-create so we can create our argo app for keeping subscriptions in sync +# Do it here so that we don't try to sync it in the future +apiVersion: v1 +kind: Namespace +metadata: + name: openshift-gitops +--- +# Source: pattern-install/templates/namespace.yaml +apiVersion: v1 +kind: Namespace +metadata: + name: manuela-ci + labels: + manuela-role: pipeline + app.kubernetes.io/instance: manuela +--- +# Source: pattern-install/templates/pipeline/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: pipeline + namespace: manuela-ci +secrets: +- name: git-repo-credentials +- name: image-registry-credentials +--- +# Source: pattern-install/templates/secrets/s3-secret.yaml +kind: Secret +apiVersion: v1 +metadata: + name: s3-secret +type: Opaque +data: + # Pre-create as part of the initial 'helm install' chart + # Create a file with the following: + # s3.accessKey: KEY + # s3.secretKey: secret key + #application.properties: base64 encrypted value of the above file + # This should live in the values-secret.yaml file + application.properties: BASE64STRING +--- +# Source: pattern-install/templates/secrets/secret-git-repo-credentials.yaml +apiVersion: v1 +kind: Secret +metadata: + name: git-repo-credentials + namespace: manuela-ci + annotations: + # Tekton magic, see https://tekton.dev/vault/pipelines-v0.15.2/auth/ + tekton.dev/git-0: https://github.com/hybrid-cloud-patterns +type: kubernetes.io/basic-auth +stringData: + username: STRING + password: STRING +--- +# Source: pattern-install/templates/secrets/secret-image-registry-credentials.yaml +apiVersion: v1 +kind: Secret +metadata: + name: openshift-registry-credentials + namespace: manuela-ci + annotations: + # Tekton magic, see https://tekton.dev/vault/pipelines-v0.15.2/auth/ + tekton.dev/docker-0: "https://" +type: kubernetes.io/basic-auth +stringData: + username: STRING + password: STRING +--- +# Source: pattern-install/templates/argocd/application.yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: common-example + namespace: openshift-gitops +spec: + destination: + name: in-cluster + namespace: common-example + project: default + source: + repoURL: https://github.com/beekhof/common.git + targetRevision: main + path: common/clustergroup + helm: + valueFiles: + - "https://github.com/beekhof/patterns/raw/main/values-global.yaml" + - "https://github.com/beekhof/patterns/raw/main/values-example.yaml" + # Track the progress of https://github.com/argoproj/argo-cd/pull/6280 + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.valuesDirectoryURL + value: https://github.com/beekhof/patterns/raw/main + - name: global.pattern + value: common + syncPolicy: + automated: {} +--- +# Source: pattern-install/templates/argocd/subscription.yaml +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: openshift-gitops-operator + namespace: openshift-operators + labels: + operators.coreos.com/openshift-gitops-operator.openshift-operators: "" +spec: + channel: stable + installPlanApproval: Automatic + name: openshift-gitops-operator + source: redhat-operators + sourceNamespace: openshift-marketplace diff --git a/scripts/make_common_subtree.sh b/scripts/make_common_subtree.sh new file mode 100755 index 00000000..a5e406d8 --- /dev/null +++ b/scripts/make_common_subtree.sh @@ -0,0 +1,76 @@ +#!/bin/sh + +if [ "$1" = "-h" ]; then + echo "This script will convert common into a subtree and add a remote to help manage it." + echo "The script takes three positional arguments, as follows:" + echo + echo "$0 " + echo + echo "Run without arguments, the script would run as if these arguments had been passed:" + echo "$0 https://github.com/hybrid-cloud-patterns/common.git main common-subtree" + echo + echo "Please ensure the git subtree command is available. On RHEL/Fedora, the git subtree command" + echo "is in a separate package called git-subtree" + exit 1 +fi + +if [ -f '/etc/redhat-release' ]; then + rpm -qa | grep git-subtree 2>&1 + if [ ! $? = 0 ]; then + echo "you need to install git-subtree" + echo "would you like to install it now?" + select ANS in yes no + do + case $ANS in + yes) + sudo dnf install git-subtree -y + break + ;; + no) + exit + break + ;; + *) + echo "You must enter yes or no" + ;; + esac + done + fi +fi + +if [ "$1" ]; then + subtree_repo=$1 +else + subtree_repo=https://github.com/hybrid-cloud-patterns/common.git +fi + +if [ "$2" ]; then + subtree_branch=$2 +else + subtree_branch=main +fi + +if [ "$3" ]; then + subtree_remote=$3 +else + subtree_remote=common-subtree +fi + +git diff --quiet || (echo "This script must be run on a clean working tree" && exit 1) + +echo "Changing directory to project root" +cd `git rev-parse --show-toplevel` + +echo "Removing existing common and replacing it with subtree from $subtree_repo $subtree_remote" +rm -rf common + +echo "Committing removal of common" +(git add -A :/ && git commit -m "Removed previous version of common to convert to subtree from $subtree_repo $subtree_branch") || exit 1 + +echo "Adding (possibly replacing) subtree remote $subtree_remote" +git remote rm "$subtree_remote" +git remote add -f "$subtree_remote" "$subtree_repo" || exit 1 +git subtree add --prefix=common "$subtree_remote" "$subtree_branch" || exit 1 + +echo "Complete. You may now push these results if you are satisfied" +exit 0 diff --git a/scripts/pattern-util.sh b/scripts/pattern-util.sh new file mode 100755 index 00000000..5d2c9bae --- /dev/null +++ b/scripts/pattern-util.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +if [ -z "$PATTERN_UTILITY_CONTAINER" ]; then + PATTERN_UTILITY_CONTAINER="quay.io/hybridcloudpatterns/hybridcloudpatterns-utility-ee" +fi + +# This is one of the most concise ways to get a readlink -f command work without going too complicated +# Across Linux and MacOSX +function real_path() { + echo $(cd $(dirname $1) ; pwd -P) +} + +# Copy Kubeconfig from current environment. The utilities will pick up ~/.kube/config if set so it's not mandatory +# /home/runner is the normal homedir +# $HOME is mounted as itself for any files that are referenced with absolute paths +# $HOME is mounted to /root because the UID in the container is 0 and that's where SSH looks for credentials +# We bind mount the SSH_AUTH_SOCK socket if it is set, so ssh works without user prompting +SSH_SOCK_MOUNTS="" +if [ -n "$SSH_AUTH_SOCK" ]; then + SSH_SOCK_MOUNTS="-v $(real_path $SSH_AUTH_SOCK):/ssh-agent -e SSH_AUTH_SOCK=/ssh-agent" +fi + +podman run -it \ + --security-opt label=disable \ + -e KUBECONFIG="${KUBECONFIG}" \ + ${SSH_SOCK_MOUNTS} \ + -e GIT_SSH_COMMAND="ssh -o IgnoreUnknown=pubkeyacceptedalgorithms" \ + -v ${HOME}:/home/runner \ + -v ${HOME}:${HOME} \ + -v ${HOME}:/root \ + -w $(pwd) \ + "$PATTERN_UTILITY_CONTAINER" \ + $@ diff --git a/scripts/test.sh b/scripts/test.sh new file mode 100755 index 00000000..a4077fb6 --- /dev/null +++ b/scripts/test.sh @@ -0,0 +1,122 @@ +#!/bin/bash + +# helm template (even with --dry-run) can interact with the cluster +# This won't protect us if a user has ~/.kube +# Also call helm template with a non existing --kubeconfig while we're at it +unset KUBECONFIG +target=$1 +name=$(echo $1 | sed -e s@/@-@g -e s@charts-@@) + +function doTest() { + TEST_VARIANT=$1 + CHART_OPTS="$2" + TESTDIR=tests + TEST=${name}-${TEST_VARIANT} + FILENAME=${TEST}.expected.yml + OUTPUT=${TESTDIR}/.${FILENAME} + REFERENCE=${TESTDIR}/${FILENAME} + + echo -e "\nTesting $name chart (${TEST_VARIANT}) with opts [$CHART_OPTS]" >&2 + helm template --kubeconfig /tmp/doesnotexistever $target --name-template $name ${CHART_OPTS} > ${OUTPUT} + rc=$? + if [ $rc -ne 0 ]; then + echo "FAIL on helm template $target --name-template $name ${CHART_OPTS}" >&2 + exit 1 + fi + if [ ! -e ${REFERENCE} ]; then + cp ${OUTPUT} ${REFERENCE} + echo -e "\n\n#### Created test output\007\n#### Now add ${REFERENCE} to Git\n\n\007" >&2 + exit 2 + fi + diff -u ${REFERENCE} ${OUTPUT} + rc=$? + if [ $rc = 0 ]; then + rm -f ${OUTPUT} + echo "PASS" >&2 + elif [ -z $GITHUB_ACTIONS ]; then + read -p "Are these changes expected? [y/N] " EXPECTED + case $EXPECTED in + y*|Y*) + echo "Updating ${REFERENCE}" + cp ${OUTPUT} ${REFERENCE} + rm -f ${OUTPUT} + rc=0 + ;; + *) ;; + esac + fi + if [ $rc != 0 ]; then + echo "FAIL" >&2 + exit $rc + fi +} + +function doTestCompare() { + TEST_VARIANT="differences" + TESTDIR=tests + TEST=${name} + FILENAME=${TEST}.expected.yml + OUTPUT=${TESTDIR}/.${FILENAME} + REFERENCE=${TESTDIR}/${FILENAME} + + echo -e "\nTesting $name chart (${TEST_VARIANT})" >&2 + # Another method of finding variables missing from values.yaml, eg. + # - name: -datacenter + # + name: pattern-name-datacenter + + TEST=${name} + FILENAME=${TEST}.expected.diff + OUTPUT=${TESTDIR}/.${FILENAME} + REFERENCE=${TESTDIR}/${FILENAME} + + # Drop the date from the diff output, it will not be stable + diff -u ${TESTDIR}/${name}-naked.expected.yml ${TESTDIR}/${name}-normal.expected.yml | sed 's/\.yml.*20[0-9][0-9].*/.yml/g' > ${OUTPUT} + + if [ ! -e ${REFERENCE} -a -z $GITHUB_ACTIONS ]; then + cp ${OUTPUT} ${REFERENCE} + git add ${REFERENCE} + echo -e "\n\n#### Created test output\007\n\n\007" >&2 + fi + + diff -u ${REFERENCE} ${OUTPUT} + rc=$? + + if [ $rc = 0 ]; then + rm -f ${OUTPUT} + echo "PASS" >&2 + elif [ -z $GITHUB_ACTIONS ]; then + read -p "Are these changes expected? [y/N] " EXPECTED + case $EXPECTED in + y*|Y*) + echo "Updating ${REFERENCE}" + cp ${OUTPUT} ${REFERENCE} + rm -f ${OUTPUT} + rc=0 + ;; + *) ;; + esac + fi + if [ $rc != 0 ]; then + echo "FAIL" >&2 + exit $rc + fi +} + +if [ $2 = "all" ]; then + echo -e "\n#####################" >&2 + echo "### ${name}" >&2 + echo "#####################" >&2 + + # Test that all values used by the chart are in values.yaml with the same defaults as the pattern + doTest naked + + # Test the charts as the pattern would drive them + doTest normal "$3" + + # Ensure the differences between the two results are also stable + doTestCompare +else + doTest $2 "$3" +fi + +exit 0 diff --git a/scripts/vault-utils.sh b/scripts/vault-utils.sh new file mode 100755 index 00000000..2f014a45 --- /dev/null +++ b/scripts/vault-utils.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -eu + +get_abs_filename() { + # $1 : relative filename + echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")" +} + +SCRIPT=$(get_abs_filename "$0") +SCRIPTPATH=$(dirname "$SCRIPT") +COMMONPATH=$(dirname "$SCRIPTPATH") +ANSIBLEPATH="$(dirname ${SCRIPTPATH})/ansible" +PLAYBOOKPATH="${ANSIBLEPATH}/playbooks" +export ANSIBLE_CONFIG="${ANSIBLEPATH}/ansible.cfg" + +# Parse arguments +if [ $# -lt 1 ]; then + echo "Specify at least the command ($#): $*" + exit 1 +fi + +TASK="${1}" +OUTFILE=${2:-"$COMMONPATH"/pattern-vault.init} + +if [ -z ${TASK} ]; then + echo "Task is unset" + exit 1 +fi + +ansible-playbook -t "${TASK}" -e output_file="${OUTFILE}" "${PLAYBOOKPATH}/vault/vault.yaml" diff --git a/tests/acm-naked.expected.yml b/tests/acm-naked.expected.yml new file mode 100644 index 00000000..e94c6a51 --- /dev/null +++ b/tests/acm-naked.expected.yml @@ -0,0 +1,93 @@ +--- +# Source: acm/templates/policies/application-policies.yaml +# TODO: Also create a GitOpsCluster.apps.open-cluster-management.io +--- +# Source: acm/templates/multiclusterhub.yaml +apiVersion: operator.open-cluster-management.io/v1 +kind: MultiClusterHub +metadata: + name: multiclusterhub + namespace: open-cluster-management + annotations: + argocd.argoproj.io/sync-wave: "-1" +spec: {} +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: openshift-gitops-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: openshift-gitops-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: openshift-gitops-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: openshift-gitops-placement +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: vendor + operator: In + values: + - OpenShift +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: openshift-gitops-policy + annotations: + policy.open-cluster-management.io/standards: NIST-CSF + policy.open-cluster-management.io/categories: PR.DS Data Security + policy.open-cluster-management.io/controls: PR.DS-1 Data-at-rest + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + argocd.argoproj.io/compare-options: IgnoreExtraneous +spec: + remediationAction: enforce + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: openshift-gitops-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + # This is an auto-generated file. DO NOT EDIT + apiVersion: operators.coreos.com/v1alpha1 + kind: Subscription + metadata: + name: openshift-gitops-operator + namespace: openshift-operators + labels: + operators.coreos.com/openshift-gitops-operator.openshift-operators: '' + spec: + channel: stable + installPlanApproval: Automatic + name: openshift-gitops-operator + source: redhat-operators + sourceNamespace: openshift-marketplace + config: + env: + - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES + value: "*" diff --git a/tests/acm-normal.expected.yml b/tests/acm-normal.expected.yml new file mode 100644 index 00000000..42b9452b --- /dev/null +++ b/tests/acm-normal.expected.yml @@ -0,0 +1,694 @@ +--- +# Source: acm/templates/provision/secrets-common.yaml +apiVersion: v1 +kind: Secret +metadata: + name: aws-ap-acm-provision-edge-install-config +data: + # Base64 encoding of install-config yaml + install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXdzLWFwJyAKYmFzZURvbWFpbjogYmx1ZXByaW50cy5yaGVjb2VuZy5jb20KY29udHJvbFBsYW5lOgogIGFyY2hpdGVjdHVyZTogYW1kNjQKICBoeXBlcnRocmVhZGluZzogRW5hYmxlZAogIG5hbWU6IGNvbnRyb2xQbGFuZQogIHJlcGxpY2FzOiAzCiAgcGxhdGZvcm06CiAgICBhd3M6CiAgICAgIHR5cGU6IG01LnhsYXJnZQpjb21wdXRlOgotIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIG5hbWU6ICd3b3JrZXInCiAgcmVwbGljYXM6IDMKICBwbGF0Zm9ybToKICAgIGF3czoKICAgICAgdHlwZTogbTUueGxhcmdlCm5ldHdvcmtpbmc6CiAgY2x1c3Rlck5ldHdvcms6CiAgLSBjaWRyOiAxMC4xMjguMC4wLzE0CiAgICBob3N0UHJlZml4OiAyMwogIG1hY2hpbmVOZXR3b3JrOgogIC0gY2lkcjogMTAuMC4wLjAvMTYKICBuZXR3b3JrVHlwZTogT3BlblNoaWZ0U0ROCiAgc2VydmljZU5ldHdvcms6CiAgLSAxNzIuMzAuMC4wLzE2CnBsYXRmb3JtOiB7CiAgImF3cyI6IHsKICAgICJyZWdpb24iOiAiYXAtc291dGhlYXN0LTIiCiAgfQp9CnB1bGxTZWNyZXQ6ICIiICMgc2tpcCwgaGl2ZSB3aWxsIGluamVjdCBiYXNlZCBvbiBpdCdzIHNlY3JldHMKc3NoS2V5OiAiIiAgICAgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cw== +type: Opaque +--- +# Source: acm/templates/provision/secrets-common.yaml +apiVersion: v1 +kind: Secret +metadata: + name: azure-us-acm-provision-edge-install-config +data: + # Base64 encoding of install-config yaml + install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXp1cmUtdXMnIApiYXNlRG9tYWluOiBibHVlcHJpbnRzLnJoZWNvZW5nLmNvbQpjb250cm9sUGxhbmU6CiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgbmFtZTogY29udHJvbFBsYW5lCiAgcmVwbGljYXM6IDMKICBwbGF0Zm9ybToKICAgIGF6dXJlOgogICAgICB0eXBlOiBTdGFuZGFyZF9EOHNfdjMKY29tcHV0ZToKLSBoeXBlcnRocmVhZGluZzogRW5hYmxlZAogIGFyY2hpdGVjdHVyZTogYW1kNjQKICBuYW1lOiAnd29ya2VyJwogIHJlcGxpY2FzOiAzCiAgcGxhdGZvcm06CiAgICBhenVyZToKICAgICAgdHlwZTogU3RhbmRhcmRfRDhzX3YzCm5ldHdvcmtpbmc6CiAgY2x1c3Rlck5ldHdvcms6CiAgLSBjaWRyOiAxMC4xMjguMC4wLzE0CiAgICBob3N0UHJlZml4OiAyMwogIG1hY2hpbmVOZXR3b3JrOgogIC0gY2lkcjogMTAuMC4wLjAvMTYKICBuZXR3b3JrVHlwZTogT3BlblNoaWZ0U0ROCiAgc2VydmljZU5ldHdvcms6CiAgLSAxNzIuMzAuMC4wLzE2CnBsYXRmb3JtOiB7CiAgImF6dXJlIjogewogICAgImJhc2VEb21haW5SZXNvdXJjZUdyb3VwTmFtZSI6ICJkb2pvLWRucy16b25lcyIsCiAgICAicmVnaW9uIjogImVhc3R1cyIKICB9Cn0KcHVsbFNlY3JldDogIiIgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cwpzc2hLZXk6ICIiICAgICAjIHNraXAsIGhpdmUgd2lsbCBpbmplY3QgYmFzZWQgb24gaXQncyBzZWNyZXRz +type: Opaque +--- +# Source: acm/templates/provision/clusterpool.yaml +apiVersion: hive.openshift.io/v1 +kind: ClusterClaim +metadata: + name: 'One-acm-provision-edge' + annotations: + argocd.argoproj.io/sync-wave: "20" + cluster.open-cluster-management.io/createmanagedcluster: "true" + labels: + clusterClaimName: One-acm-provision-edge + clusterGroup: region +spec: + clusterPoolName: aws-ap +--- +# Source: acm/templates/provision/clusterpool.yaml +apiVersion: hive.openshift.io/v1 +kind: ClusterClaim +metadata: + name: 'Two-acm-provision-edge' + annotations: + argocd.argoproj.io/sync-wave: "20" + cluster.open-cluster-management.io/createmanagedcluster: "true" + labels: + clusterClaimName: Two-acm-provision-edge + clusterGroup: region +spec: + clusterPoolName: azure-us +--- +# Source: acm/templates/provision/clusterpool.yaml +apiVersion: hive.openshift.io/v1 +kind: ClusterClaim +metadata: + name: 'Three-acm-provision-edge' + annotations: + argocd.argoproj.io/sync-wave: "20" + cluster.open-cluster-management.io/createmanagedcluster: "true" + labels: + clusterClaimName: Three-acm-provision-edge + clusterGroup: region +spec: + clusterPoolName: azure-us +--- +# Source: acm/templates/provision/clusterpool.yaml +apiVersion: hive.openshift.io/v1 +kind: ClusterPool +metadata: + name: "aws-ap-acm-provision-edge" + annotations: + argocd.argoproj.io/sync-wave: "10" + labels: + cloud: aws + region: 'ap-southeast-2' + vendor: OpenShift + cluster.open-cluster-management.io/clusterset: aws-ap +spec: + size: 3 + runningCount: 1 + baseDomain: blueprints.rhecoeng.com + installConfigSecretTemplateRef: + name: aws-ap-acm-provision-edge-install-config + imageSetRef: + name: img4.10.18-x86-64-appsub + pullSecretRef: + name: aws-ap-acm-provision-edge-pull-secret + skipMachinePools: true # Disable MachinePool as using custom install-config + platform: + aws: + credentialsSecretRef: + name: aws-ap-acm-provision-edge-creds + region: ap-southeast-2 +--- +# Source: acm/templates/provision/clusterpool.yaml +apiVersion: hive.openshift.io/v1 +kind: ClusterPool +metadata: + name: "azure-us-acm-provision-edge" + annotations: + argocd.argoproj.io/sync-wave: "10" + labels: + cloud: azure + region: 'eastus' + vendor: OpenShift + cluster.open-cluster-management.io/clusterset: azure-us +spec: + size: 2 + runningCount: 2 + baseDomain: blueprints.rhecoeng.com + installConfigSecretTemplateRef: + name: azure-us-acm-provision-edge-install-config + imageSetRef: + name: img4.10.18-x86-64-appsub + pullSecretRef: + name: azure-us-acm-provision-edge-pull-secret + skipMachinePools: true # Disable MachinePool as using custom install-config + platform: + azure: + credentialsSecretRef: + name: azure-us-acm-provision-edge-creds + region: eastus +--- +# Source: acm/templates/provision/secrets-aws.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: aws-ap-acm-provision-edge-creds +spec: + dataFrom: + - extract: + # Expects entries called: aws_access_key_id and aws_secret_access_key + key: secret/data/hub/aws + refreshInterval: 24h0m0s + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: aws-ap-acm-provision-edge-creds + creationPolicy: Owner + template: + type: Opaque +--- +# Source: acm/templates/provision/secrets-aws.yaml +# For use when manually creating clusters with ACM +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: aws-ap-acm-provision-edge-infra-creds +spec: + data: + - secretKey: openshiftPullSecret + remoteRef: + key: secret/data/hub/openshiftPullSecret + property: content + - secretKey: awsKeyId + remoteRef: + key: secret/data/hub/aws + property: aws_access_key_id + - secretKey: awsAccessKey + remoteRef: + key: secret/data/hub/aws + property: aws_secret_access_key + - secretKey: sshPublicKey + remoteRef: + key: secret/data/hub/publickey + property: content + - secretKey: sshPrivateKey + remoteRef: + key: secret/data/hub/privatekey + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: aws-ap-acm-provision-edge-infra-creds + creationPolicy: Owner + template: + type: Opaque + metadata: + labels: + cluster.open-cluster-management.io/credentials: "" + cluster.open-cluster-management.io/type: aws + data: + baseDomain: "blueprints.rhecoeng.com" + pullSecret: |- + {{ .openshiftPullSecret | toString }} + aws_access_key_id: |- + {{ .awsKeyId | toString }} + aws_secret_access_key: |- + {{ .awsAccessKey | toString }} + ssh-privatekey: |- + {{ .sshPrivateKey | toString }} + ssh-publickey: |- + {{ .sshPublicKey | toString }} + httpProxy: "" + httpsProxy: "" + noProxy: "" + additionalTrustBundle: "" +--- +# Source: acm/templates/provision/secrets-azure.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: azure-us-acm-provision-edge-creds +spec: + data: + - secretKey: azureOsServicePrincipal + remoteRef: + key: secret/data/hub/azureOsServicePrincipal + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: azure-us-acm-provision-edge-creds + creationPolicy: Owner + template: + type: Opaque + data: + osServicePrincipal.json: |- + {{ .azureOsServicePrincipal | toString }} +--- +# Source: acm/templates/provision/secrets-azure.yaml +# For use when manually creating clusters with ACM +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: azure-us-acm-provision-edge-infra-creds +spec: + data: + - secretKey: openshiftPullSecret + remoteRef: + key: secret/data/hub/openshiftPullSecret + property: content + - secretKey: sshPublicKey + remoteRef: + key: secret/data/hub/publickey + property: content + - secretKey: sshPrivateKey + remoteRef: + key: secret/data/hub/privatekey + property: content + - secretKey: azureOsServicePrincipal + remoteRef: + key: secret/data/hub/azureOsServicePrincipal + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: azure-us-acm-provision-edge-infra-creds + creationPolicy: Owner + template: + type: Opaque + metadata: + labels: + cluster.open-cluster-management.io/credentials: "" + cluster.open-cluster-management.io/type: aws + data: + cloudName: AzurePublicCloud + osServicePrincipal.json: |- + {{ .azureOsServicePrincipal | toString }} + baseDomain: "blueprints.rhecoeng.com" + baseDomainResourceGroupName: "dojo-dns-zones" + pullSecret: |- + {{ .openshiftPullSecret | toString }} + ssh-privatekey: |- + {{ .sshPrivateKey | toString }} + ssh-publickey: |- + {{ .sshPublicKey | toString }} + httpProxy: "" + httpsProxy: "" + noProxy: "" + additionalTrustBundle: "" +--- +# Source: acm/templates/provision/secrets-common.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: aws-ap-acm-provision-edge-pull-secret +spec: + data: + - secretKey: openshiftPullSecret + remoteRef: + key: secret/data/hub/openshiftPullSecret + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: aws-ap-acm-provision-edge-pull-secret + creationPolicy: Owner + template: + type: kubernetes.io/dockerconfigjson + data: + .dockerconfigjson: |- + {{ .openshiftPullSecret | toString }} +--- +# Source: acm/templates/provision/secrets-common.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: aws-ap-acm-provision-edge-ssh-private-key +spec: + data: + - secretKey: sshPrivateKey + remoteRef: + key: secret/data/hub/privatekey + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: aws-ap-acm-provision-edge-ssh-private-key + creationPolicy: Owner + template: + type: Opaque + data: + ssh-privatekey: |- + {{ .sshPrivateKey | toString }} +--- +# Source: acm/templates/provision/secrets-common.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: azure-us-acm-provision-edge-pull-secret +spec: + data: + - secretKey: openshiftPullSecret + remoteRef: + key: secret/data/hub/openshiftPullSecret + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: azure-us-acm-provision-edge-pull-secret + creationPolicy: Owner + template: + type: kubernetes.io/dockerconfigjson + data: + .dockerconfigjson: |- + {{ .openshiftPullSecret | toString }} +--- +# Source: acm/templates/provision/secrets-common.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: azure-us-acm-provision-edge-ssh-private-key +spec: + data: + - secretKey: sshPrivateKey + remoteRef: + key: secret/data/hub/privatekey + property: content + refreshInterval: 24h0m0s + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: azure-us-acm-provision-edge-ssh-private-key + creationPolicy: Owner + template: + type: Opaque + data: + ssh-privatekey: |- + {{ .sshPrivateKey | toString }} +--- +# Source: acm/templates/provision/clusterpool.yaml +apiVersion: cluster.open-cluster-management.io/v1beta1 +kind: ManagedClusterSet +metadata: + annotations: + cluster.open-cluster-management.io/submariner-broker-ns: acm-provision-edge-broker + name: acm-provision-edge +spec: + clusterSelector: + selectorType: LegacyClusterSetLabel +--- +# Source: acm/templates/multiclusterhub.yaml +apiVersion: operator.open-cluster-management.io/v1 +kind: MultiClusterHub +metadata: + name: multiclusterhub + namespace: open-cluster-management + annotations: + argocd.argoproj.io/sync-wave: "-1" +spec: {} +--- +# Source: acm/templates/policies/application-policies.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: acm-edge-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: acm-edge-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: acm-edge-clustergroup-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/application-policies.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: acm-provision-edge-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: acm-provision-edge-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: acm-provision-edge-clustergroup-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: openshift-gitops-placement-binding + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +placementRef: + name: openshift-gitops-placement + kind: PlacementRule + apiGroup: apps.open-cluster-management.io +subjects: + - name: openshift-gitops-policy + kind: Policy + apiGroup: policy.open-cluster-management.io +--- +# Source: acm/templates/policies/application-policies.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: acm-edge-placement +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchLabels: + clusterGroup: acm-region +--- +# Source: acm/templates/policies/application-policies.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: acm-provision-edge-placement +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchLabels: + clusterGroup: region +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: openshift-gitops-placement +spec: + clusterConditions: + - status: 'True' + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: vendor + operator: In + values: + - OpenShift +--- +# Source: acm/templates/policies/application-policies.yaml +# TODO: Also create a GitOpsCluster.apps.open-cluster-management.io +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: acm-edge-clustergroup-policy + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + argocd.argoproj.io/compare-options: IgnoreExtraneous +spec: + remediationAction: enforce + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: acm-edge-clustergroup-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + apiVersion: argoproj.io/v1alpha1 + kind: Application + metadata: + name: mypattern-acm-edge + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground + spec: + project: default + source: + repoURL: https://github.com/pattern-clone/mypattern + targetRevision: main + path: common/clustergroup + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-acm-edge.yaml" + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: mypattern + - name: global.hubClusterDomain + value: apps.hub.example.com + - name: global.localClusterDomain + value: '{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain }}' + # Requires ACM 2.6 or higher + - name: global.clusterDomain + value: '{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain | replace "apps." "" }}' + - name: clusterGroup.name + value: acm-edge + - name: clusterGroup.isHubCluster + value: "false" + destination: + server: https://kubernetes.default.svc + namespace: mypattern-acm-edge + syncPolicy: + automated: + prune: false + selfHeal: true + ignoreDifferences: + - group: apps + kind: Deployment + jsonPointers: + - /spec/replicas + - group: route.openshift.io + kind: Route + jsonPointers: + - /status +--- +# Source: acm/templates/policies/application-policies.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: acm-provision-edge-clustergroup-policy + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + argocd.argoproj.io/compare-options: IgnoreExtraneous +spec: + remediationAction: enforce + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: acm-provision-edge-clustergroup-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + apiVersion: argoproj.io/v1alpha1 + kind: Application + metadata: + name: mypattern-acm-provision-edge + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground + spec: + project: default + source: + repoURL: https://github.com/pattern-clone/mypattern + targetRevision: main + path: common/clustergroup + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-acm-provision-edge.yaml" + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: mypattern + - name: global.hubClusterDomain + value: apps.hub.example.com + - name: global.localClusterDomain + value: '{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain }}' + # Requires ACM 2.6 or higher + - name: global.clusterDomain + value: '{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain | replace "apps." "" }}' + - name: clusterGroup.name + value: acm-provision-edge + - name: clusterGroup.isHubCluster + value: "false" + destination: + server: https://kubernetes.default.svc + namespace: mypattern-acm-provision-edge + syncPolicy: + automated: + prune: false + selfHeal: true + ignoreDifferences: + - group: apps + kind: Deployment + jsonPointers: + - /spec/replicas + - group: route.openshift.io + kind: Route + jsonPointers: + - /status +--- +# Source: acm/templates/policies/ocp-gitops-policy.yaml +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: openshift-gitops-policy + annotations: + policy.open-cluster-management.io/standards: NIST-CSF + policy.open-cluster-management.io/categories: PR.DS Data Security + policy.open-cluster-management.io/controls: PR.DS-1 Data-at-rest + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + argocd.argoproj.io/compare-options: IgnoreExtraneous +spec: + remediationAction: enforce + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: openshift-gitops-config + spec: + remediationAction: enforce + severity: medium + namespaceSelector: + include: + - default + object-templates: + - complianceType: mustonlyhave + objectDefinition: + # This is an auto-generated file. DO NOT EDIT + apiVersion: operators.coreos.com/v1alpha1 + kind: Subscription + metadata: + name: openshift-gitops-operator + namespace: openshift-operators + labels: + operators.coreos.com/openshift-gitops-operator.openshift-operators: '' + spec: + channel: stable + installPlanApproval: Automatic + name: openshift-gitops-operator + source: redhat-operators + sourceNamespace: openshift-marketplace + config: + env: + - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES + value: "*" diff --git a/tests/acm.expected.diff b/tests/acm.expected.diff new file mode 100644 index 00000000..9cf23621 --- /dev/null +++ b/tests/acm.expected.diff @@ -0,0 +1,633 @@ +--- tests/acm-naked.expected.yml ++++ tests/acm-normal.expected.yml +@@ -1,6 +1,386 @@ + --- +-# Source: acm/templates/policies/application-policies.yaml +-# TODO: Also create a GitOpsCluster.apps.open-cluster-management.io ++# Source: acm/templates/provision/secrets-common.yaml ++apiVersion: v1 ++kind: Secret ++metadata: ++ name: aws-ap-acm-provision-edge-install-config ++data: ++ # Base64 encoding of install-config yaml ++ install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXdzLWFwJyAKYmFzZURvbWFpbjogYmx1ZXByaW50cy5yaGVjb2VuZy5jb20KY29udHJvbFBsYW5lOgogIGFyY2hpdGVjdHVyZTogYW1kNjQKICBoeXBlcnRocmVhZGluZzogRW5hYmxlZAogIG5hbWU6IGNvbnRyb2xQbGFuZQogIHJlcGxpY2FzOiAzCiAgcGxhdGZvcm06CiAgICBhd3M6CiAgICAgIHR5cGU6IG01LnhsYXJnZQpjb21wdXRlOgotIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIG5hbWU6ICd3b3JrZXInCiAgcmVwbGljYXM6IDMKICBwbGF0Zm9ybToKICAgIGF3czoKICAgICAgdHlwZTogbTUueGxhcmdlCm5ldHdvcmtpbmc6CiAgY2x1c3Rlck5ldHdvcms6CiAgLSBjaWRyOiAxMC4xMjguMC4wLzE0CiAgICBob3N0UHJlZml4OiAyMwogIG1hY2hpbmVOZXR3b3JrOgogIC0gY2lkcjogMTAuMC4wLjAvMTYKICBuZXR3b3JrVHlwZTogT3BlblNoaWZ0U0ROCiAgc2VydmljZU5ldHdvcms6CiAgLSAxNzIuMzAuMC4wLzE2CnBsYXRmb3JtOiB7CiAgImF3cyI6IHsKICAgICJyZWdpb24iOiAiYXAtc291dGhlYXN0LTIiCiAgfQp9CnB1bGxTZWNyZXQ6ICIiICMgc2tpcCwgaGl2ZSB3aWxsIGluamVjdCBiYXNlZCBvbiBpdCdzIHNlY3JldHMKc3NoS2V5OiAiIiAgICAgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cw== ++type: Opaque ++--- ++# Source: acm/templates/provision/secrets-common.yaml ++apiVersion: v1 ++kind: Secret ++metadata: ++ name: azure-us-acm-provision-edge-install-config ++data: ++ # Base64 encoding of install-config yaml ++ install-config.yaml: CgphcGlWZXJzaW9uOiB2MQptZXRhZGF0YToKICBuYW1lOiAnYXp1cmUtdXMnIApiYXNlRG9tYWluOiBibHVlcHJpbnRzLnJoZWNvZW5nLmNvbQpjb250cm9sUGxhbmU6CiAgYXJjaGl0ZWN0dXJlOiBhbWQ2NAogIGh5cGVydGhyZWFkaW5nOiBFbmFibGVkCiAgbmFtZTogY29udHJvbFBsYW5lCiAgcmVwbGljYXM6IDMKICBwbGF0Zm9ybToKICAgIGF6dXJlOgogICAgICB0eXBlOiBTdGFuZGFyZF9EOHNfdjMKY29tcHV0ZToKLSBoeXBlcnRocmVhZGluZzogRW5hYmxlZAogIGFyY2hpdGVjdHVyZTogYW1kNjQKICBuYW1lOiAnd29ya2VyJwogIHJlcGxpY2FzOiAzCiAgcGxhdGZvcm06CiAgICBhenVyZToKICAgICAgdHlwZTogU3RhbmRhcmRfRDhzX3YzCm5ldHdvcmtpbmc6CiAgY2x1c3Rlck5ldHdvcms6CiAgLSBjaWRyOiAxMC4xMjguMC4wLzE0CiAgICBob3N0UHJlZml4OiAyMwogIG1hY2hpbmVOZXR3b3JrOgogIC0gY2lkcjogMTAuMC4wLjAvMTYKICBuZXR3b3JrVHlwZTogT3BlblNoaWZ0U0ROCiAgc2VydmljZU5ldHdvcms6CiAgLSAxNzIuMzAuMC4wLzE2CnBsYXRmb3JtOiB7CiAgImF6dXJlIjogewogICAgImJhc2VEb21haW5SZXNvdXJjZUdyb3VwTmFtZSI6ICJkb2pvLWRucy16b25lcyIsCiAgICAicmVnaW9uIjogImVhc3R1cyIKICB9Cn0KcHVsbFNlY3JldDogIiIgIyBza2lwLCBoaXZlIHdpbGwgaW5qZWN0IGJhc2VkIG9uIGl0J3Mgc2VjcmV0cwpzc2hLZXk6ICIiICAgICAjIHNraXAsIGhpdmUgd2lsbCBpbmplY3QgYmFzZWQgb24gaXQncyBzZWNyZXRz ++type: Opaque ++--- ++# Source: acm/templates/provision/clusterpool.yaml ++apiVersion: hive.openshift.io/v1 ++kind: ClusterClaim ++metadata: ++ name: 'One-acm-provision-edge' ++ annotations: ++ argocd.argoproj.io/sync-wave: "20" ++ cluster.open-cluster-management.io/createmanagedcluster: "true" ++ labels: ++ clusterClaimName: One-acm-provision-edge ++ clusterGroup: region ++spec: ++ clusterPoolName: aws-ap ++--- ++# Source: acm/templates/provision/clusterpool.yaml ++apiVersion: hive.openshift.io/v1 ++kind: ClusterClaim ++metadata: ++ name: 'Two-acm-provision-edge' ++ annotations: ++ argocd.argoproj.io/sync-wave: "20" ++ cluster.open-cluster-management.io/createmanagedcluster: "true" ++ labels: ++ clusterClaimName: Two-acm-provision-edge ++ clusterGroup: region ++spec: ++ clusterPoolName: azure-us ++--- ++# Source: acm/templates/provision/clusterpool.yaml ++apiVersion: hive.openshift.io/v1 ++kind: ClusterClaim ++metadata: ++ name: 'Three-acm-provision-edge' ++ annotations: ++ argocd.argoproj.io/sync-wave: "20" ++ cluster.open-cluster-management.io/createmanagedcluster: "true" ++ labels: ++ clusterClaimName: Three-acm-provision-edge ++ clusterGroup: region ++spec: ++ clusterPoolName: azure-us ++--- ++# Source: acm/templates/provision/clusterpool.yaml ++apiVersion: hive.openshift.io/v1 ++kind: ClusterPool ++metadata: ++ name: "aws-ap-acm-provision-edge" ++ annotations: ++ argocd.argoproj.io/sync-wave: "10" ++ labels: ++ cloud: aws ++ region: 'ap-southeast-2' ++ vendor: OpenShift ++ cluster.open-cluster-management.io/clusterset: aws-ap ++spec: ++ size: 3 ++ runningCount: 1 ++ baseDomain: blueprints.rhecoeng.com ++ installConfigSecretTemplateRef: ++ name: aws-ap-acm-provision-edge-install-config ++ imageSetRef: ++ name: img4.10.18-x86-64-appsub ++ pullSecretRef: ++ name: aws-ap-acm-provision-edge-pull-secret ++ skipMachinePools: true # Disable MachinePool as using custom install-config ++ platform: ++ aws: ++ credentialsSecretRef: ++ name: aws-ap-acm-provision-edge-creds ++ region: ap-southeast-2 ++--- ++# Source: acm/templates/provision/clusterpool.yaml ++apiVersion: hive.openshift.io/v1 ++kind: ClusterPool ++metadata: ++ name: "azure-us-acm-provision-edge" ++ annotations: ++ argocd.argoproj.io/sync-wave: "10" ++ labels: ++ cloud: azure ++ region: 'eastus' ++ vendor: OpenShift ++ cluster.open-cluster-management.io/clusterset: azure-us ++spec: ++ size: 2 ++ runningCount: 2 ++ baseDomain: blueprints.rhecoeng.com ++ installConfigSecretTemplateRef: ++ name: azure-us-acm-provision-edge-install-config ++ imageSetRef: ++ name: img4.10.18-x86-64-appsub ++ pullSecretRef: ++ name: azure-us-acm-provision-edge-pull-secret ++ skipMachinePools: true # Disable MachinePool as using custom install-config ++ platform: ++ azure: ++ credentialsSecretRef: ++ name: azure-us-acm-provision-edge-creds ++ region: eastus ++--- ++# Source: acm/templates/provision/secrets-aws.yaml ++apiVersion: external-secrets.io/v1beta1 ++kind: ExternalSecret ++metadata: ++ name: aws-ap-acm-provision-edge-creds ++spec: ++ dataFrom: ++ - extract: ++ # Expects entries called: aws_access_key_id and aws_secret_access_key ++ key: secret/data/hub/aws ++ refreshInterval: 24h0m0s ++ secretStoreRef: ++ name: vault-backend ++ kind: ClusterSecretStore ++ target: ++ name: aws-ap-acm-provision-edge-creds ++ creationPolicy: Owner ++ template: ++ type: Opaque ++--- ++# Source: acm/templates/provision/secrets-aws.yaml ++# For use when manually creating clusters with ACM ++apiVersion: external-secrets.io/v1beta1 ++kind: ExternalSecret ++metadata: ++ name: aws-ap-acm-provision-edge-infra-creds ++spec: ++ data: ++ - secretKey: openshiftPullSecret ++ remoteRef: ++ key: secret/data/hub/openshiftPullSecret ++ property: content ++ - secretKey: awsKeyId ++ remoteRef: ++ key: secret/data/hub/aws ++ property: aws_access_key_id ++ - secretKey: awsAccessKey ++ remoteRef: ++ key: secret/data/hub/aws ++ property: aws_secret_access_key ++ - secretKey: sshPublicKey ++ remoteRef: ++ key: secret/data/hub/publickey ++ property: content ++ - secretKey: sshPrivateKey ++ remoteRef: ++ key: secret/data/hub/privatekey ++ property: content ++ refreshInterval: 24h0m0s ++ secretStoreRef: ++ name: vault-backend ++ kind: ClusterSecretStore ++ target: ++ name: aws-ap-acm-provision-edge-infra-creds ++ creationPolicy: Owner ++ template: ++ type: Opaque ++ metadata: ++ labels: ++ cluster.open-cluster-management.io/credentials: "" ++ cluster.open-cluster-management.io/type: aws ++ data: ++ baseDomain: "blueprints.rhecoeng.com" ++ pullSecret: |- ++ {{ .openshiftPullSecret | toString }} ++ aws_access_key_id: |- ++ {{ .awsKeyId | toString }} ++ aws_secret_access_key: |- ++ {{ .awsAccessKey | toString }} ++ ssh-privatekey: |- ++ {{ .sshPrivateKey | toString }} ++ ssh-publickey: |- ++ {{ .sshPublicKey | toString }} ++ httpProxy: "" ++ httpsProxy: "" ++ noProxy: "" ++ additionalTrustBundle: "" ++--- ++# Source: acm/templates/provision/secrets-azure.yaml ++apiVersion: external-secrets.io/v1beta1 ++kind: ExternalSecret ++metadata: ++ name: azure-us-acm-provision-edge-creds ++spec: ++ data: ++ - secretKey: azureOsServicePrincipal ++ remoteRef: ++ key: secret/data/hub/azureOsServicePrincipal ++ property: content ++ refreshInterval: 24h0m0s ++ secretStoreRef: ++ name: vault-backend ++ kind: ClusterSecretStore ++ target: ++ name: azure-us-acm-provision-edge-creds ++ creationPolicy: Owner ++ template: ++ type: Opaque ++ data: ++ osServicePrincipal.json: |- ++ {{ .azureOsServicePrincipal | toString }} ++--- ++# Source: acm/templates/provision/secrets-azure.yaml ++# For use when manually creating clusters with ACM ++apiVersion: external-secrets.io/v1beta1 ++kind: ExternalSecret ++metadata: ++ name: azure-us-acm-provision-edge-infra-creds ++spec: ++ data: ++ - secretKey: openshiftPullSecret ++ remoteRef: ++ key: secret/data/hub/openshiftPullSecret ++ property: content ++ - secretKey: sshPublicKey ++ remoteRef: ++ key: secret/data/hub/publickey ++ property: content ++ - secretKey: sshPrivateKey ++ remoteRef: ++ key: secret/data/hub/privatekey ++ property: content ++ - secretKey: azureOsServicePrincipal ++ remoteRef: ++ key: secret/data/hub/azureOsServicePrincipal ++ property: content ++ refreshInterval: 24h0m0s ++ secretStoreRef: ++ name: vault-backend ++ kind: ClusterSecretStore ++ target: ++ name: azure-us-acm-provision-edge-infra-creds ++ creationPolicy: Owner ++ template: ++ type: Opaque ++ metadata: ++ labels: ++ cluster.open-cluster-management.io/credentials: "" ++ cluster.open-cluster-management.io/type: aws ++ data: ++ cloudName: AzurePublicCloud ++ osServicePrincipal.json: |- ++ {{ .azureOsServicePrincipal | toString }} ++ baseDomain: "blueprints.rhecoeng.com" ++ baseDomainResourceGroupName: "dojo-dns-zones" ++ pullSecret: |- ++ {{ .openshiftPullSecret | toString }} ++ ssh-privatekey: |- ++ {{ .sshPrivateKey | toString }} ++ ssh-publickey: |- ++ {{ .sshPublicKey | toString }} ++ httpProxy: "" ++ httpsProxy: "" ++ noProxy: "" ++ additionalTrustBundle: "" ++--- ++# Source: acm/templates/provision/secrets-common.yaml ++apiVersion: external-secrets.io/v1beta1 ++kind: ExternalSecret ++metadata: ++ name: aws-ap-acm-provision-edge-pull-secret ++spec: ++ data: ++ - secretKey: openshiftPullSecret ++ remoteRef: ++ key: secret/data/hub/openshiftPullSecret ++ property: content ++ refreshInterval: 24h0m0s ++ secretStoreRef: ++ name: vault-backend ++ kind: ClusterSecretStore ++ target: ++ name: aws-ap-acm-provision-edge-pull-secret ++ creationPolicy: Owner ++ template: ++ type: kubernetes.io/dockerconfigjson ++ data: ++ .dockerconfigjson: |- ++ {{ .openshiftPullSecret | toString }} ++--- ++# Source: acm/templates/provision/secrets-common.yaml ++apiVersion: external-secrets.io/v1beta1 ++kind: ExternalSecret ++metadata: ++ name: aws-ap-acm-provision-edge-ssh-private-key ++spec: ++ data: ++ - secretKey: sshPrivateKey ++ remoteRef: ++ key: secret/data/hub/privatekey ++ property: content ++ refreshInterval: 24h0m0s ++ secretStoreRef: ++ name: vault-backend ++ kind: ClusterSecretStore ++ target: ++ name: aws-ap-acm-provision-edge-ssh-private-key ++ creationPolicy: Owner ++ template: ++ type: Opaque ++ data: ++ ssh-privatekey: |- ++ {{ .sshPrivateKey | toString }} ++--- ++# Source: acm/templates/provision/secrets-common.yaml ++apiVersion: external-secrets.io/v1beta1 ++kind: ExternalSecret ++metadata: ++ name: azure-us-acm-provision-edge-pull-secret ++spec: ++ data: ++ - secretKey: openshiftPullSecret ++ remoteRef: ++ key: secret/data/hub/openshiftPullSecret ++ property: content ++ refreshInterval: 24h0m0s ++ secretStoreRef: ++ name: vault-backend ++ kind: ClusterSecretStore ++ target: ++ name: azure-us-acm-provision-edge-pull-secret ++ creationPolicy: Owner ++ template: ++ type: kubernetes.io/dockerconfigjson ++ data: ++ .dockerconfigjson: |- ++ {{ .openshiftPullSecret | toString }} ++--- ++# Source: acm/templates/provision/secrets-common.yaml ++apiVersion: external-secrets.io/v1beta1 ++kind: ExternalSecret ++metadata: ++ name: azure-us-acm-provision-edge-ssh-private-key ++spec: ++ data: ++ - secretKey: sshPrivateKey ++ remoteRef: ++ key: secret/data/hub/privatekey ++ property: content ++ refreshInterval: 24h0m0s ++ secretStoreRef: ++ name: vault-backend ++ kind: ClusterSecretStore ++ target: ++ name: azure-us-acm-provision-edge-ssh-private-key ++ creationPolicy: Owner ++ template: ++ type: Opaque ++ data: ++ ssh-privatekey: |- ++ {{ .sshPrivateKey | toString }} ++--- ++# Source: acm/templates/provision/clusterpool.yaml ++apiVersion: cluster.open-cluster-management.io/v1beta1 ++kind: ManagedClusterSet ++metadata: ++ annotations: ++ cluster.open-cluster-management.io/submariner-broker-ns: acm-provision-edge-broker ++ name: acm-provision-edge ++spec: ++ clusterSelector: ++ selectorType: LegacyClusterSetLabel + --- + # Source: acm/templates/multiclusterhub.yaml + apiVersion: operator.open-cluster-management.io/v1 +@@ -12,6 +392,38 @@ + argocd.argoproj.io/sync-wave: "-1" + spec: {} + --- ++# Source: acm/templates/policies/application-policies.yaml ++apiVersion: policy.open-cluster-management.io/v1 ++kind: PlacementBinding ++metadata: ++ name: acm-edge-placement-binding ++ annotations: ++ argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true ++placementRef: ++ name: acm-edge-placement ++ kind: PlacementRule ++ apiGroup: apps.open-cluster-management.io ++subjects: ++ - name: acm-edge-clustergroup-policy ++ kind: Policy ++ apiGroup: policy.open-cluster-management.io ++--- ++# Source: acm/templates/policies/application-policies.yaml ++apiVersion: policy.open-cluster-management.io/v1 ++kind: PlacementBinding ++metadata: ++ name: acm-provision-edge-placement-binding ++ annotations: ++ argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true ++placementRef: ++ name: acm-provision-edge-placement ++ kind: PlacementRule ++ apiGroup: apps.open-cluster-management.io ++subjects: ++ - name: acm-provision-edge-clustergroup-policy ++ kind: Policy ++ apiGroup: policy.open-cluster-management.io ++--- + # Source: acm/templates/policies/ocp-gitops-policy.yaml + apiVersion: policy.open-cluster-management.io/v1 + kind: PlacementBinding +@@ -28,6 +440,32 @@ + kind: Policy + apiGroup: policy.open-cluster-management.io + --- ++# Source: acm/templates/policies/application-policies.yaml ++apiVersion: apps.open-cluster-management.io/v1 ++kind: PlacementRule ++metadata: ++ name: acm-edge-placement ++spec: ++ clusterConditions: ++ - status: 'True' ++ type: ManagedClusterConditionAvailable ++ clusterSelector: ++ matchLabels: ++ clusterGroup: acm-region ++--- ++# Source: acm/templates/policies/application-policies.yaml ++apiVersion: apps.open-cluster-management.io/v1 ++kind: PlacementRule ++metadata: ++ name: acm-provision-edge-placement ++spec: ++ clusterConditions: ++ - status: 'True' ++ type: ManagedClusterConditionAvailable ++ clusterSelector: ++ matchLabels: ++ clusterGroup: region ++--- + # Source: acm/templates/policies/ocp-gitops-policy.yaml + apiVersion: apps.open-cluster-management.io/v1 + kind: PlacementRule +@@ -44,6 +482,169 @@ + values: + - OpenShift + --- ++# Source: acm/templates/policies/application-policies.yaml ++# TODO: Also create a GitOpsCluster.apps.open-cluster-management.io ++apiVersion: policy.open-cluster-management.io/v1 ++kind: Policy ++metadata: ++ name: acm-edge-clustergroup-policy ++ annotations: ++ argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true ++ argocd.argoproj.io/compare-options: IgnoreExtraneous ++spec: ++ remediationAction: enforce ++ disabled: false ++ policy-templates: ++ - objectDefinition: ++ apiVersion: policy.open-cluster-management.io/v1 ++ kind: ConfigurationPolicy ++ metadata: ++ name: acm-edge-clustergroup-config ++ spec: ++ remediationAction: enforce ++ severity: medium ++ namespaceSelector: ++ include: ++ - default ++ object-templates: ++ - complianceType: mustonlyhave ++ objectDefinition: ++ apiVersion: argoproj.io/v1alpha1 ++ kind: Application ++ metadata: ++ name: mypattern-acm-edge ++ namespace: openshift-gitops ++ finalizers: ++ - resources-finalizer.argocd.argoproj.io/foreground ++ spec: ++ project: default ++ source: ++ repoURL: https://github.com/pattern-clone/mypattern ++ targetRevision: main ++ path: common/clustergroup ++ helm: ++ ignoreMissingValueFiles: true ++ valueFiles: ++ - "/values-global.yaml" ++ - "/values-acm-edge.yaml" ++ parameters: ++ - name: global.repoURL ++ value: $ARGOCD_APP_SOURCE_REPO_URL ++ - name: global.targetRevision ++ value: $ARGOCD_APP_SOURCE_TARGET_REVISION ++ - name: global.namespace ++ value: $ARGOCD_APP_NAMESPACE ++ - name: global.pattern ++ value: mypattern ++ - name: global.hubClusterDomain ++ value: apps.hub.example.com ++ - name: global.localClusterDomain ++ value: '{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain }}' ++ # Requires ACM 2.6 or higher ++ - name: global.clusterDomain ++ value: '{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain | replace "apps." "" }}' ++ - name: clusterGroup.name ++ value: acm-edge ++ - name: clusterGroup.isHubCluster ++ value: "false" ++ destination: ++ server: https://kubernetes.default.svc ++ namespace: mypattern-acm-edge ++ syncPolicy: ++ automated: ++ prune: false ++ selfHeal: true ++ ignoreDifferences: ++ - group: apps ++ kind: Deployment ++ jsonPointers: ++ - /spec/replicas ++ - group: route.openshift.io ++ kind: Route ++ jsonPointers: ++ - /status ++--- ++# Source: acm/templates/policies/application-policies.yaml ++apiVersion: policy.open-cluster-management.io/v1 ++kind: Policy ++metadata: ++ name: acm-provision-edge-clustergroup-policy ++ annotations: ++ argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true ++ argocd.argoproj.io/compare-options: IgnoreExtraneous ++spec: ++ remediationAction: enforce ++ disabled: false ++ policy-templates: ++ - objectDefinition: ++ apiVersion: policy.open-cluster-management.io/v1 ++ kind: ConfigurationPolicy ++ metadata: ++ name: acm-provision-edge-clustergroup-config ++ spec: ++ remediationAction: enforce ++ severity: medium ++ namespaceSelector: ++ include: ++ - default ++ object-templates: ++ - complianceType: mustonlyhave ++ objectDefinition: ++ apiVersion: argoproj.io/v1alpha1 ++ kind: Application ++ metadata: ++ name: mypattern-acm-provision-edge ++ namespace: openshift-gitops ++ finalizers: ++ - resources-finalizer.argocd.argoproj.io/foreground ++ spec: ++ project: default ++ source: ++ repoURL: https://github.com/pattern-clone/mypattern ++ targetRevision: main ++ path: common/clustergroup ++ helm: ++ ignoreMissingValueFiles: true ++ valueFiles: ++ - "/values-global.yaml" ++ - "/values-acm-provision-edge.yaml" ++ parameters: ++ - name: global.repoURL ++ value: $ARGOCD_APP_SOURCE_REPO_URL ++ - name: global.targetRevision ++ value: $ARGOCD_APP_SOURCE_TARGET_REVISION ++ - name: global.namespace ++ value: $ARGOCD_APP_NAMESPACE ++ - name: global.pattern ++ value: mypattern ++ - name: global.hubClusterDomain ++ value: apps.hub.example.com ++ - name: global.localClusterDomain ++ value: '{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain }}' ++ # Requires ACM 2.6 or higher ++ - name: global.clusterDomain ++ value: '{{ (lookup "config.openshift.io/v1" "Ingress" "" "cluster").spec.domain | replace "apps." "" }}' ++ - name: clusterGroup.name ++ value: acm-provision-edge ++ - name: clusterGroup.isHubCluster ++ value: "false" ++ destination: ++ server: https://kubernetes.default.svc ++ namespace: mypattern-acm-provision-edge ++ syncPolicy: ++ automated: ++ prune: false ++ selfHeal: true ++ ignoreDifferences: ++ - group: apps ++ kind: Deployment ++ jsonPointers: ++ - /spec/replicas ++ - group: route.openshift.io ++ kind: Route ++ jsonPointers: ++ - /status ++--- + # Source: acm/templates/policies/ocp-gitops-policy.yaml + apiVersion: policy.open-cluster-management.io/v1 + kind: Policy diff --git a/tests/clustergroup-naked.expected.yml b/tests/clustergroup-naked.expected.yml new file mode 100644 index 00000000..4d5c5eee --- /dev/null +++ b/tests/clustergroup-naked.expected.yml @@ -0,0 +1,184 @@ +--- +# Source: pattern-clustergroup/templates/plumbing/gitops-namespace.yaml +apiVersion: v1 +kind: Namespace +metadata: + labels: + name: common-example + # The name here needs to be consistent with + # - acm/templates/policies/application-policies.yaml + # - clustergroup/templates/applications.yaml + # - any references to secrets and route URLs in documentation + name: common-example +spec: {} +--- +# Source: pattern-clustergroup/templates/plumbing/argocd-super-role.yaml +# WARNING: ONLY USE THIS FOR MANAGING CLUSTERS NOT FOR REGULAR USERS +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: openshift-gitops-cluster-admin-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: + - kind: ServiceAccount + name: openshift-gitops-argocd-application-controller + namespace: openshift-gitops + # NOTE: THIS MUST BE FIXED FOR MULTITENANT SETUP + - kind: ServiceAccount + name: openshift-gitops-argocd-server + namespace: openshift-gitops +--- +# Source: pattern-clustergroup/templates/plumbing/argocd-super-role.yaml +# WARNING: ONLY USE THIS FOR MANAGING CLUSTERS NOT FOR REGULAR USERS +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: common-example-cluster-admin-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: + - kind: ServiceAccount + # This is the {ArgoCD.name}-argocd-application-controller + name: example-gitops-argocd-application-controller + namespace: common-example + # NOTE: THIS MUST BE FIXED FOR MULTITENANT SETUP + - kind: ServiceAccount + # This is the {ArgoCD.name}-argocd-server + name: example-gitops-argocd-server + namespace: common-example + # NOTE: This is needed starting with gitops-1.5.0 (see issue common#76) + - kind: ServiceAccount + name: example-gitops-argocd-dex-server + namespace: common-example +--- +# Source: pattern-clustergroup/templates/plumbing/argocd.yaml +apiVersion: argoproj.io/v1alpha1 +kind: ArgoCD +metadata: + finalizers: + - argoproj.io/finalizer + # Changing the name affects the ClusterRoleBinding, the generated secret, + # route URL, and argocd.argoproj.io/managed-by annotations + name: example-gitops + namespace: common-example + annotations: + argocd.argoproj.io/compare-options: IgnoreExtraneous +spec: + applicationInstanceLabelKey: argocd.argoproj.io/instance + # Not the greatest way to pass git/quay info to sub-applications, but it will do until + # we can support helmChart with kustomize + # The other option is to pass them in as environment variables eg. BLUEPRINT_VERSION + configManagementPlugins: | + - name: kustomize-version + generate: + command: ["sh", "-c"] + args: ["kustomize version 1>&2 && exit 1"] + - name: kustomize-with-helm + generate: + command: ["kustomize"] + args: ["build", "--enable-helm"] + - name: helm-with-kustomize + init: + command: ["/bin/sh", "-c"] + args: ["helm dependency build"] + generate: + command: ["/bin/bash", "-c"] + args: ["helm template . --name-template ${ARGOCD_APP_NAME:0:52} + -f $(git rev-parse --show-toplevel)/values-global.yaml + -f $(git rev-parse --show-toplevel)/values-example.yaml + --set global.repoURL=$ARGOCD_APP_SOURCE_REPO_URL + --set global.targetRevision=$ARGOCD_APP_SOURCE_TARGET_REVISION + --set global.namespace=$ARGOCD_APP_NAMESPACE + --set global.pattern=common + --set global.clusterDomain= + --set global.hubClusterDomain= + --set global.localClusterDomain= + --set clusterGroup.name=example + --post-renderer ./kustomize"] + applicationSet: + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: 250m + memory: 512Mi + controller: + processors: {} + resources: + limits: + cpu: "4" + memory: 4Gi + requests: + cpu: 500m + memory: 2Gi + dex: + openShiftOAuth: true + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + initialSSHKnownHosts: {} + rbac: + defaultPolicy: role:admin + repo: + resources: + limits: + cpu: "1" + memory: 512Mi + requests: + cpu: 250m + memory: 256Mi + resourceExclusions: | + - apiGroups: + - tekton.dev + kinds: + - TaskRun + - PipelineRun + server: + autoscale: + enabled: false + grpc: + ingress: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 125m + memory: 128Mi + route: + enabled: true + tls: + insecureEdgeTerminationPolicy: Redirect + termination: reencrypt + service: + type: "" + tls: + ca: {} +status: +--- +# Source: pattern-clustergroup/templates/plumbing/argocd.yaml +apiVersion: console.openshift.io/v1 +kind: ConsoleLink +metadata: + name: example-gitops-link + namespace: common-example +spec: + applicationMenu: + section: OpenShift GitOps + imageURL: data:image/png;base64,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 + href: 'https://example-gitops-server-common-example.' + location: ApplicationMenu + text: 'Example ArgoCD' diff --git a/tests/clustergroup-normal.expected.yml b/tests/clustergroup-normal.expected.yml new file mode 100644 index 00000000..50a8fb46 --- /dev/null +++ b/tests/clustergroup-normal.expected.yml @@ -0,0 +1,1025 @@ +--- +# Source: pattern-clustergroup/templates/core/namespaces.yaml +apiVersion: v1 +kind: Namespace +metadata: + labels: + name: pattern + argocd.argoproj.io/managed-by: mypattern-example + name: open-cluster-management +spec: +--- +# Source: pattern-clustergroup/templates/core/namespaces.yaml +apiVersion: v1 +kind: Namespace +metadata: + labels: + name: pattern + argocd.argoproj.io/managed-by: mypattern-example + name: application-ci +spec: +--- +# Source: pattern-clustergroup/templates/imperative/namespace.yaml +apiVersion: v1 +kind: Namespace +metadata: + labels: + name: imperative + argocd.argoproj.io/managed-by: mypattern-example + name: imperative +--- +# Source: pattern-clustergroup/templates/plumbing/gitops-namespace.yaml +apiVersion: v1 +kind: Namespace +metadata: + labels: + name: mypattern-example + # The name here needs to be consistent with + # - acm/templates/policies/application-policies.yaml + # - clustergroup/templates/applications.yaml + # - any references to secrets and route URLs in documentation + name: mypattern-example +spec: {} +--- +# Source: pattern-clustergroup/templates/imperative/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: imperative-sa + namespace: imperative +--- +# Source: pattern-clustergroup/templates/imperative/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: helm-values-configmap-example + namespace: imperative +data: + values.yaml: | + clusterGroup: + applications: + acm: + ignoreDifferences: + - group: internal.open-cluster-management.io + jsonPointers: + - /spec/loggingCA + kind: ManagedClusterInfo + name: acm + namespace: open-cluster-management + path: common/acm + project: datacenter + pipe: + name: pipelines + namespace: application-ci + path: charts/datacenter/pipelines + project: datacenter + imperative: + activeDeadlineSeconds: 3600 + clusterRoleName: imperative-cluster-role + clusterRoleYaml: "" + cronJobName: imperative-cronjob + image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest + imagePullPolicy: Always + insecureUnsealVaultInsideClusterSchedule: '*/5 * * * *' + jobName: imperative-job + jobs: + - name: test + playbook: ansible/test.yml + namespace: imperative + roleName: imperative-role + roleYaml: "" + schedule: '*/10 * * * *' + serviceAccountCreate: true + serviceAccountName: imperative-sa + valuesConfigMap: helm-values-configmap + verbosity: "" + insecureUnsealVaultInsideCluster: true + isHubCluster: true + managedClusterGroups: + - acmlabels: + - name: clusterGroup + value: acm-region + helmOverrides: + - name: clusterGroup.isHubCluster + value: "false" + name: acm-edge + targetRevision: main + - acmlabels: + - name: clusterGroup + value: region + clusterPools: + exampleAWSPool: + baseDomain: blueprints.rhecoeng.com + clusters: + - One + name: aws-ap + openshiftVersion: 4.10.18 + platform: + aws: + region: ap-southeast-2 + size: 3 + exampleAzurePool: + baseDomain: blueprints.rhecoeng.com + clusters: + - Two + - Three + name: azure-us + openshiftVersion: 4.10.18 + platform: + azure: + baseDomainResourceGroupName: dojo-dns-zones + region: eastus + helmOverrides: + - name: clusterGroup.isHubCluster + value: "false" + name: acm-provision-edge + targetRevision: main + - helmOverrides: + - name: clusterGroup.isHubCluster + value: "false" + hostedArgoSites: + - bearerKeyPath: secret/data/hub/cluster_perth + caKeyPath: secret/data/hub/cluster_perth_ca + domain: perth1.beekhof.net + name: perth + - domain: syd.beekhof.net + name: sydney + name: argo-edge + name: example + namespaces: + - open-cluster-management + - application-ci + projects: + - datacenter + subscriptions: + acm: + channel: release-2.4 + csv: advanced-cluster-management.v2.4.1 + name: advanced-cluster-management + namespace: open-cluster-management + odh: + csv: opendatahub-operator.v1.1.0 + disabled: true + name: opendatahub-operator + source: community-operators + pipelines: + csv: redhat-openshift-pipelines.v1.5.2 + name: openshift-pipelines-operator-rh + targetCluster: in-cluster + enabled: all + files: + cluster_example_ca: /path/to/ca.file + global: + clusterDomain: region.example.com + git: + account: hybrid-cloud-patterns + dev_revision: main + email: someone@somewhere.com + hostname: github.com + hubClusterDomain: apps.hub.example.com + localClusterDomain: apps.region.example.com + namespace: pattern-namespace + options: + installPlanApproval: Automatic + syncPolicy: Automatic + useCSV: false + pattern: mypattern + repoURL: https://github.com/pattern-clone/mypattern + targetRevision: main + main: + clusterGroupName: example + git: + repoURL: https://github.com/pattern-clone/mypattern + revision: main + secretStore: + kind: ClusterSecretStore + name: vault-backend + secrets: + aws: + s3Secret: test-secret + cluster_example: + bearerToken: + server: https://api.example.openshiftapps.com:6443 + git: + token: test-git-token + username: test-user + imageregistry: + account: test-account + token: test-quay-token + secretsBase: + key: secret/data/hub +--- +# Source: pattern-clustergroup/templates/imperative/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: imperative-cluster-role +rules: + - apiGroups: + - '*' + resources: + - '*' + verbs: + - get + - list + - watch +--- +# Source: pattern-clustergroup/templates/imperative/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: imperative-cluster-admin-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: imperative-cluster-role +subjects: + - kind: ServiceAccount + name: imperative-sa + namespace: imperative +--- +# Source: pattern-clustergroup/templates/plumbing/argocd-super-role.yaml +# WARNING: ONLY USE THIS FOR MANAGING CLUSTERS NOT FOR REGULAR USERS +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: openshift-gitops-cluster-admin-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: + - kind: ServiceAccount + name: openshift-gitops-argocd-application-controller + namespace: openshift-gitops + # NOTE: THIS MUST BE FIXED FOR MULTITENANT SETUP + - kind: ServiceAccount + name: openshift-gitops-argocd-server + namespace: openshift-gitops +--- +# Source: pattern-clustergroup/templates/plumbing/argocd-super-role.yaml +# WARNING: ONLY USE THIS FOR MANAGING CLUSTERS NOT FOR REGULAR USERS +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: mypattern-example-cluster-admin-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: + - kind: ServiceAccount + # This is the {ArgoCD.name}-argocd-application-controller + name: example-gitops-argocd-application-controller + namespace: mypattern-example + # NOTE: THIS MUST BE FIXED FOR MULTITENANT SETUP + - kind: ServiceAccount + # This is the {ArgoCD.name}-argocd-server + name: example-gitops-argocd-server + namespace: mypattern-example + # NOTE: This is needed starting with gitops-1.5.0 (see issue common#76) + - kind: ServiceAccount + name: example-gitops-argocd-dex-server + namespace: mypattern-example +--- +# Source: pattern-clustergroup/templates/imperative/role.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: imperative-role + namespace: imperative +rules: + - apiGroups: + - '*' + resources: + - '*' + verbs: + - '*' +--- +# Source: pattern-clustergroup/templates/imperative/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: imperative-admin-rolebinding + namespace: imperative +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: imperative-role +subjects: + - kind: ServiceAccount + name: imperative-sa + namespace: imperative +--- +# Source: pattern-clustergroup/templates/imperative/job.yaml +apiVersion: batch/v1 +kind: CronJob +metadata: + name: imperative-cronjob + namespace: imperative +spec: + schedule: "*/10 * * * *" + # if previous Job is still running, skip execution of a new Job + concurrencyPolicy: Forbid + jobTemplate: + spec: + activeDeadlineSeconds: 3600 + template: + metadata: + name: imperative-job + spec: + serviceAccountName: imperative-sa + initContainers: + # git init happens in /git/repo so that we can set the folder to 0770 permissions + # reason for that is ansible refuses to create temporary folders in there + - name: git-init + image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest + imagePullPolicy: Always + env: + - name: HOME + value: /git/home + command: + - 'sh' + - '-c' + - "mkdir /git/{repo,home};git clone --single-branch --branch main --depth 1 -- https://github.com/pattern-clone/mypattern /git/repo;chmod 0770 /git/{repo,home}" + volumeMounts: + - name: git + mountPath: "/git" + - name: test + image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest + imagePullPolicy: Always + env: + - name: HOME + value: /git/home + workingDir: /git/repo + # We have a default timeout of 600s for each playbook. Can be overridden + # on a per-job basis + command: + - timeout + - "600" + - ansible-playbook + - -e + - "@/values/values.yaml" + - ansible/test.yml + volumeMounts: + - name: git + mountPath: "/git" + - name: values-volume + mountPath: /values/values.yaml + subPath: values.yaml + containers: + - name: "done" + image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest + imagePullPolicy: Always + command: + - 'sh' + - '-c' + - 'echo' + - 'done' + - '\n' + volumes: + - name: git + emptyDir: {} + - name: values-volume + configMap: + name: helm-values-configmap-example + restartPolicy: Never +--- +# Source: pattern-clustergroup/templates/imperative/unsealjob.yaml +apiVersion: batch/v1 +kind: CronJob +metadata: + name: unsealvault-cronjob + namespace: imperative +spec: + schedule: "*/5 * * * *" + # if previous Job is still running, skip execution of a new Job + concurrencyPolicy: Forbid + jobTemplate: + spec: + activeDeadlineSeconds: 3600 + template: + metadata: + name: unsealvault-job + spec: + serviceAccountName: imperative-sa + initContainers: + # git init happens in /git/repo so that we can set the folder to 0770 permissions + # reason for that is ansible refuses to create temporary folders in there + - name: git-init + image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest + imagePullPolicy: Always + env: + - name: HOME + value: /git/home + command: + - 'sh' + - '-c' + - "mkdir /git/{repo,home};git clone --single-branch --branch main --depth 1 -- https://github.com/pattern-clone/mypattern /git/repo;chmod 0770 /git/{repo,home}" + volumeMounts: + - name: git + mountPath: "/git" + - name: unseal-playbook + image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest + imagePullPolicy: Always + env: + - name: HOME + value: /git/home + workingDir: /git/repo + # We have a default timeout of 600s for each playbook. Can be overridden + # on a per-job basis + command: + - timeout + - "600" + - ansible-playbook + - -e + - "@/values/values.yaml" + - -e + - '{"file_unseal": false}' + - -t + - 'vault_init,vault_unseal,vault_secrets_init' + - "common/ansible/playbooks/vault/vault.yaml" + volumeMounts: + - name: git + mountPath: "/git" + - name: values-volume + mountPath: /values/values.yaml + subPath: values.yaml + containers: + - name: "done" + image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest + imagePullPolicy: Always + command: + - 'sh' + - '-c' + - 'echo' + - 'done' + - '\n' + volumes: + - name: git + emptyDir: {} + - name: values-volume + configMap: + name: helm-values-configmap-example + restartPolicy: Never +--- +# Source: pattern-clustergroup/templates/core/subscriptions.yaml +--- +--- +# Source: pattern-clustergroup/templates/plumbing/hosted-sites.yaml +apiVersion: argoproj.io/v1alpha1 +kind: AppProject +metadata: + name: argo-edge + namespace: openshift-gitops +spec: + description: "Cluster Group argo-edge" + destinations: + - namespace: '*' + server: '*' + clusterResourceWhitelist: + - group: '*' + kind: '*' + namespaceResourceWhitelist: + - group: '*' + kind: '*' + sourceRepos: + - '*' +status: {} +--- +# Source: pattern-clustergroup/templates/plumbing/projects.yaml +apiVersion: argoproj.io/v1alpha1 +kind: AppProject +metadata: + name: datacenter + namespace: mypattern-example +spec: + description: "Pattern datacenter" + destinations: + - namespace: '*' + server: '*' + clusterResourceWhitelist: + - group: '*' + kind: '*' + namespaceResourceWhitelist: + - group: '*' + kind: '*' + sourceRepos: + - '*' +status: {} +--- +# Source: pattern-clustergroup/templates/plumbing/applications.yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: acm + namespace: mypattern-example + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground +spec: + destination: + name: in-cluster + namespace: open-cluster-management + project: datacenter + source: + repoURL: https://github.com/pattern-clone/mypattern + targetRevision: main + path: common/acm + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-example.yaml" + # Watch the progress of https://issues.redhat.com/browse/GITOPS-891 and update accordingly + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: mypattern + - name: global.clusterDomain + value: region.example.com + - name: global.hubClusterDomain + value: apps.hub.example.com + - name: global.localClusterDomain + value: apps.region.example.com + ignoreDifferences: [ + { + "group": "internal.open-cluster-management.io", + "jsonPointers": [ + "/spec/loggingCA" + ], + "kind": "ManagedClusterInfo" + } +] + syncPolicy: + automated: {} + # selfHeal: true +--- +# Source: pattern-clustergroup/templates/plumbing/applications.yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: pipelines + namespace: mypattern-example + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground +spec: + destination: + name: in-cluster + namespace: application-ci + project: datacenter + source: + repoURL: https://github.com/pattern-clone/mypattern + targetRevision: main + path: charts/datacenter/pipelines + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-example.yaml" + # Watch the progress of https://issues.redhat.com/browse/GITOPS-891 and update accordingly + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: mypattern + - name: global.clusterDomain + value: region.example.com + - name: global.hubClusterDomain + value: apps.hub.example.com + - name: global.localClusterDomain + value: apps.region.example.com + syncPolicy: + automated: {} + # selfHeal: true +--- +# Source: pattern-clustergroup/templates/plumbing/hosted-sites.yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: mypattern-argo-edge-perth + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground +spec: + project: argo-edge + source: + repoURL: https://github.com/pattern-clone/mypattern + targetRevision: main + path: common/clustergroup + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-argo-edge.yaml" + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: mypattern + - name: global.hubClusterDomain + value: apps.hub.example.com + - name: global.localClusterDomain + value: apps.perth1.beekhof.net + - name: global.clusterDomain + value: perth1.beekhof.net + - name: enabled + value: core + - name: clusterGroup.name + value: argo-edge + - name: clusterGroup.targetCluster + value: perth + - name: clusterGroup.hostedSite.bearerKeyPath + value: secret/data/hub/cluster_perth + - name: clusterGroup.hostedSite.caKeyPath + value: secret/data/hub/cluster_perth_ca + - name: clusterGroup.isHubCluster + value: "false" + destination: + name: perth + namespace: mypattern-argo-edge + syncPolicy: + automated: + selfHeal: true + ignoreDifferences: + - group: apps + kind: Deployment + jsonPointers: + - /spec/replicas + - group: route.openshift.io + kind: Route + jsonPointers: + - /status +--- +# Source: pattern-clustergroup/templates/plumbing/hosted-sites.yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: mypattern-argo-edge-perth-plumbing + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground +spec: + project: argo-edge + source: + repoURL: https://github.com/pattern-clone/mypattern + targetRevision: main + path: common/clustergroup + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-argo-edge.yaml" + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: mypattern + - name: global.hubClusterDomain + value: apps.hub.example.com + - name: global.localClusterDomain + value: apps.perth1.beekhof.net + - name: global.clusterDomain + value: perth1.beekhof.net + - name: enabled + value: plumbing + - name: clusterGroup.name + value: argo-edge + - name: clusterGroup.targetCluster + value: perth + - name: clusterGroup.hostedSite.bearerKeyPath + value: secret/data/hub/cluster_perth + - name: clusterGroup.hostedSite.caKeyPath + value: secret/data/hub/cluster_perth_ca + - name: clusterGroup.isHubCluster + value: "false" + destination: + name: in-cluster + namespace: openshift-gitops + syncPolicy: + automated: + selfHeal: true + ignoreDifferences: + - group: apps + kind: Deployment + jsonPointers: + - /spec/replicas + - group: route.openshift.io + kind: Route + jsonPointers: + - /status +--- +# Source: pattern-clustergroup/templates/plumbing/hosted-sites.yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: mypattern-argo-edge-sydney + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground +spec: + project: argo-edge + source: + repoURL: https://github.com/pattern-clone/mypattern + targetRevision: main + path: common/clustergroup + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-argo-edge.yaml" + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: mypattern + - name: global.hubClusterDomain + value: apps.hub.example.com + - name: global.localClusterDomain + value: apps.syd.beekhof.net + - name: global.clusterDomain + value: syd.beekhof.net + - name: enabled + value: core + - name: clusterGroup.name + value: argo-edge + - name: clusterGroup.targetCluster + value: sydney + - name: clusterGroup.hostedSite.bearerKeyPath + value: secret/data/hub/cluster_sydney + - name: clusterGroup.hostedSite.caKeyPath + value: secret/data/hub/cluster_sydney_ca + - name: clusterGroup.isHubCluster + value: "false" + destination: + name: sydney + namespace: mypattern-argo-edge + syncPolicy: + automated: + selfHeal: true + ignoreDifferences: + - group: apps + kind: Deployment + jsonPointers: + - /spec/replicas + - group: route.openshift.io + kind: Route + jsonPointers: + - /status +--- +# Source: pattern-clustergroup/templates/plumbing/hosted-sites.yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: mypattern-argo-edge-sydney-plumbing + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground +spec: + project: argo-edge + source: + repoURL: https://github.com/pattern-clone/mypattern + targetRevision: main + path: common/clustergroup + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-argo-edge.yaml" + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: mypattern + - name: global.hubClusterDomain + value: apps.hub.example.com + - name: global.localClusterDomain + value: apps.syd.beekhof.net + - name: global.clusterDomain + value: syd.beekhof.net + - name: enabled + value: plumbing + - name: clusterGroup.name + value: argo-edge + - name: clusterGroup.targetCluster + value: sydney + - name: clusterGroup.hostedSite.bearerKeyPath + value: secret/data/hub/cluster_sydney + - name: clusterGroup.hostedSite.caKeyPath + value: secret/data/hub/cluster_sydney_ca + - name: clusterGroup.isHubCluster + value: "false" + destination: + name: in-cluster + namespace: openshift-gitops + syncPolicy: + automated: + selfHeal: true + ignoreDifferences: + - group: apps + kind: Deployment + jsonPointers: + - /spec/replicas + - group: route.openshift.io + kind: Route + jsonPointers: + - /status +--- +# Source: pattern-clustergroup/templates/plumbing/argocd.yaml +apiVersion: argoproj.io/v1alpha1 +kind: ArgoCD +metadata: + finalizers: + - argoproj.io/finalizer + # Changing the name affects the ClusterRoleBinding, the generated secret, + # route URL, and argocd.argoproj.io/managed-by annotations + name: example-gitops + namespace: mypattern-example + annotations: + argocd.argoproj.io/compare-options: IgnoreExtraneous +spec: + applicationInstanceLabelKey: argocd.argoproj.io/instance + # Not the greatest way to pass git/quay info to sub-applications, but it will do until + # we can support helmChart with kustomize + # The other option is to pass them in as environment variables eg. BLUEPRINT_VERSION + configManagementPlugins: | + - name: kustomize-version + generate: + command: ["sh", "-c"] + args: ["kustomize version 1>&2 && exit 1"] + - name: kustomize-with-helm + generate: + command: ["kustomize"] + args: ["build", "--enable-helm"] + - name: helm-with-kustomize + init: + command: ["/bin/sh", "-c"] + args: ["helm dependency build"] + generate: + command: ["/bin/bash", "-c"] + args: ["helm template . --name-template ${ARGOCD_APP_NAME:0:52} + -f $(git rev-parse --show-toplevel)/values-global.yaml + -f $(git rev-parse --show-toplevel)/values-example.yaml + --set global.repoURL=$ARGOCD_APP_SOURCE_REPO_URL + --set global.targetRevision=$ARGOCD_APP_SOURCE_TARGET_REVISION + --set global.namespace=$ARGOCD_APP_NAMESPACE + --set global.pattern=mypattern + --set global.clusterDomain=region.example.com + --set global.hubClusterDomain=apps.hub.example.com + --set global.localClusterDomain=apps.region.example.com + --set clusterGroup.name=example + --post-renderer ./kustomize"] + applicationSet: + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: 250m + memory: 512Mi + controller: + processors: {} + resources: + limits: + cpu: "4" + memory: 4Gi + requests: + cpu: 500m + memory: 2Gi + dex: + openShiftOAuth: true + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 250m + memory: 128Mi + initialSSHKnownHosts: {} + rbac: + defaultPolicy: role:admin + repo: + resources: + limits: + cpu: "1" + memory: 512Mi + requests: + cpu: 250m + memory: 256Mi + resourceExclusions: | + - apiGroups: + - tekton.dev + kinds: + - TaskRun + - PipelineRun + server: + autoscale: + enabled: false + grpc: + ingress: + enabled: false + ingress: + enabled: false + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 125m + memory: 128Mi + route: + enabled: true + tls: + insecureEdgeTerminationPolicy: Redirect + termination: reencrypt + service: + type: "" + tls: + ca: {} +status: +--- +# Source: pattern-clustergroup/templates/plumbing/argocd.yaml +apiVersion: console.openshift.io/v1 +kind: ConsoleLink +metadata: + name: example-gitops-link + namespace: mypattern-example +spec: + applicationMenu: + section: OpenShift GitOps + imageURL: data:image/png;base64,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 + href: 'https://example-gitops-server-mypattern-example.apps.region.example.com' + location: ApplicationMenu + text: 'Example ArgoCD' +--- +# Source: pattern-clustergroup/templates/core/operatorgroup.yaml +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: open-cluster-management-operator-group + namespace: open-cluster-management +spec: + targetNamespaces: + - open-cluster-management +--- +# Source: pattern-clustergroup/templates/core/operatorgroup.yaml +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: application-ci-operator-group + namespace: application-ci +spec: + targetNamespaces: + - application-ci +--- +# Source: pattern-clustergroup/templates/core/subscriptions.yaml +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: advanced-cluster-management + namespace: open-cluster-management +spec: + name: advanced-cluster-management + source: redhat-operators + sourceNamespace: openshift-marketplace + channel: release-2.4 + installPlanApproval: Automatic + startingCSV: advanced-cluster-management.v2.4.1 +--- +# Source: pattern-clustergroup/templates/core/subscriptions.yaml +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: openshift-pipelines-operator-rh + namespace: openshift-operators +spec: + name: openshift-pipelines-operator-rh + source: redhat-operators + sourceNamespace: openshift-marketplace + channel: stable + installPlanApproval: Automatic + startingCSV: redhat-openshift-pipelines.v1.5.2 diff --git a/tests/clustergroup.expected.diff b/tests/clustergroup.expected.diff new file mode 100644 index 00000000..b1bb3239 --- /dev/null +++ b/tests/clustergroup.expected.diff @@ -0,0 +1,930 @@ +--- tests/clustergroup-naked.expected.yml ++++ tests/clustergroup-normal.expected.yml +@@ -1,17 +1,243 @@ + --- ++# Source: pattern-clustergroup/templates/core/namespaces.yaml ++apiVersion: v1 ++kind: Namespace ++metadata: ++ labels: ++ name: pattern ++ argocd.argoproj.io/managed-by: mypattern-example ++ name: open-cluster-management ++spec: ++--- ++# Source: pattern-clustergroup/templates/core/namespaces.yaml ++apiVersion: v1 ++kind: Namespace ++metadata: ++ labels: ++ name: pattern ++ argocd.argoproj.io/managed-by: mypattern-example ++ name: application-ci ++spec: ++--- ++# Source: pattern-clustergroup/templates/imperative/namespace.yaml ++apiVersion: v1 ++kind: Namespace ++metadata: ++ labels: ++ name: imperative ++ argocd.argoproj.io/managed-by: mypattern-example ++ name: imperative ++--- + # Source: pattern-clustergroup/templates/plumbing/gitops-namespace.yaml + apiVersion: v1 + kind: Namespace + metadata: + labels: +- name: common-example ++ name: mypattern-example + # The name here needs to be consistent with + # - acm/templates/policies/application-policies.yaml + # - clustergroup/templates/applications.yaml + # - any references to secrets and route URLs in documentation +- name: common-example ++ name: mypattern-example + spec: {} + --- ++# Source: pattern-clustergroup/templates/imperative/serviceaccount.yaml ++apiVersion: v1 ++kind: ServiceAccount ++metadata: ++ name: imperative-sa ++ namespace: imperative ++--- ++# Source: pattern-clustergroup/templates/imperative/configmap.yaml ++apiVersion: v1 ++kind: ConfigMap ++metadata: ++ name: helm-values-configmap-example ++ namespace: imperative ++data: ++ values.yaml: | ++ clusterGroup: ++ applications: ++ acm: ++ ignoreDifferences: ++ - group: internal.open-cluster-management.io ++ jsonPointers: ++ - /spec/loggingCA ++ kind: ManagedClusterInfo ++ name: acm ++ namespace: open-cluster-management ++ path: common/acm ++ project: datacenter ++ pipe: ++ name: pipelines ++ namespace: application-ci ++ path: charts/datacenter/pipelines ++ project: datacenter ++ imperative: ++ activeDeadlineSeconds: 3600 ++ clusterRoleName: imperative-cluster-role ++ clusterRoleYaml: "" ++ cronJobName: imperative-cronjob ++ image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest ++ imagePullPolicy: Always ++ insecureUnsealVaultInsideClusterSchedule: '*/5 * * * *' ++ jobName: imperative-job ++ jobs: ++ - name: test ++ playbook: ansible/test.yml ++ namespace: imperative ++ roleName: imperative-role ++ roleYaml: "" ++ schedule: '*/10 * * * *' ++ serviceAccountCreate: true ++ serviceAccountName: imperative-sa ++ valuesConfigMap: helm-values-configmap ++ verbosity: "" ++ insecureUnsealVaultInsideCluster: true ++ isHubCluster: true ++ managedClusterGroups: ++ - acmlabels: ++ - name: clusterGroup ++ value: acm-region ++ helmOverrides: ++ - name: clusterGroup.isHubCluster ++ value: "false" ++ name: acm-edge ++ targetRevision: main ++ - acmlabels: ++ - name: clusterGroup ++ value: region ++ clusterPools: ++ exampleAWSPool: ++ baseDomain: blueprints.rhecoeng.com ++ clusters: ++ - One ++ name: aws-ap ++ openshiftVersion: 4.10.18 ++ platform: ++ aws: ++ region: ap-southeast-2 ++ size: 3 ++ exampleAzurePool: ++ baseDomain: blueprints.rhecoeng.com ++ clusters: ++ - Two ++ - Three ++ name: azure-us ++ openshiftVersion: 4.10.18 ++ platform: ++ azure: ++ baseDomainResourceGroupName: dojo-dns-zones ++ region: eastus ++ helmOverrides: ++ - name: clusterGroup.isHubCluster ++ value: "false" ++ name: acm-provision-edge ++ targetRevision: main ++ - helmOverrides: ++ - name: clusterGroup.isHubCluster ++ value: "false" ++ hostedArgoSites: ++ - bearerKeyPath: secret/data/hub/cluster_perth ++ caKeyPath: secret/data/hub/cluster_perth_ca ++ domain: perth1.beekhof.net ++ name: perth ++ - domain: syd.beekhof.net ++ name: sydney ++ name: argo-edge ++ name: example ++ namespaces: ++ - open-cluster-management ++ - application-ci ++ projects: ++ - datacenter ++ subscriptions: ++ acm: ++ channel: release-2.4 ++ csv: advanced-cluster-management.v2.4.1 ++ name: advanced-cluster-management ++ namespace: open-cluster-management ++ odh: ++ csv: opendatahub-operator.v1.1.0 ++ disabled: true ++ name: opendatahub-operator ++ source: community-operators ++ pipelines: ++ csv: redhat-openshift-pipelines.v1.5.2 ++ name: openshift-pipelines-operator-rh ++ targetCluster: in-cluster ++ enabled: all ++ files: ++ cluster_example_ca: /path/to/ca.file ++ global: ++ clusterDomain: region.example.com ++ git: ++ account: hybrid-cloud-patterns ++ dev_revision: main ++ email: someone@somewhere.com ++ hostname: github.com ++ hubClusterDomain: apps.hub.example.com ++ localClusterDomain: apps.region.example.com ++ namespace: pattern-namespace ++ options: ++ installPlanApproval: Automatic ++ syncPolicy: Automatic ++ useCSV: false ++ pattern: mypattern ++ repoURL: https://github.com/pattern-clone/mypattern ++ targetRevision: main ++ main: ++ clusterGroupName: example ++ git: ++ repoURL: https://github.com/pattern-clone/mypattern ++ revision: main ++ secretStore: ++ kind: ClusterSecretStore ++ name: vault-backend ++ secrets: ++ aws: ++ s3Secret: test-secret ++ cluster_example: ++ bearerToken: ++ server: https://api.example.openshiftapps.com:6443 ++ git: ++ token: test-git-token ++ username: test-user ++ imageregistry: ++ account: test-account ++ token: test-quay-token ++ secretsBase: ++ key: secret/data/hub ++--- ++# Source: pattern-clustergroup/templates/imperative/clusterrole.yaml ++apiVersion: rbac.authorization.k8s.io/v1 ++kind: ClusterRole ++metadata: ++ name: imperative-cluster-role ++rules: ++ - apiGroups: ++ - '*' ++ resources: ++ - '*' ++ verbs: ++ - get ++ - list ++ - watch ++--- ++# Source: pattern-clustergroup/templates/imperative/rbac.yaml ++apiVersion: rbac.authorization.k8s.io/v1 ++kind: ClusterRoleBinding ++metadata: ++ name: imperative-cluster-admin-rolebinding ++roleRef: ++ apiGroup: rbac.authorization.k8s.io ++ kind: ClusterRole ++ name: imperative-cluster-role ++subjects: ++ - kind: ServiceAccount ++ name: imperative-sa ++ namespace: imperative ++--- + # Source: pattern-clustergroup/templates/plumbing/argocd-super-role.yaml + # WARNING: ONLY USE THIS FOR MANAGING CLUSTERS NOT FOR REGULAR USERS + apiVersion: rbac.authorization.k8s.io/v1 +@@ -36,7 +262,7 @@ + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: +- name: common-example-cluster-admin-rolebinding ++ name: mypattern-example-cluster-admin-rolebinding + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole +@@ -45,16 +271,583 @@ + - kind: ServiceAccount + # This is the {ArgoCD.name}-argocd-application-controller + name: example-gitops-argocd-application-controller +- namespace: common-example ++ namespace: mypattern-example + # NOTE: THIS MUST BE FIXED FOR MULTITENANT SETUP + - kind: ServiceAccount + # This is the {ArgoCD.name}-argocd-server + name: example-gitops-argocd-server +- namespace: common-example ++ namespace: mypattern-example + # NOTE: This is needed starting with gitops-1.5.0 (see issue common#76) + - kind: ServiceAccount + name: example-gitops-argocd-dex-server +- namespace: common-example ++ namespace: mypattern-example ++--- ++# Source: pattern-clustergroup/templates/imperative/role.yaml ++apiVersion: rbac.authorization.k8s.io/v1 ++kind: Role ++metadata: ++ name: imperative-role ++ namespace: imperative ++rules: ++ - apiGroups: ++ - '*' ++ resources: ++ - '*' ++ verbs: ++ - '*' ++--- ++# Source: pattern-clustergroup/templates/imperative/rbac.yaml ++apiVersion: rbac.authorization.k8s.io/v1 ++kind: RoleBinding ++metadata: ++ name: imperative-admin-rolebinding ++ namespace: imperative ++roleRef: ++ apiGroup: rbac.authorization.k8s.io ++ kind: Role ++ name: imperative-role ++subjects: ++ - kind: ServiceAccount ++ name: imperative-sa ++ namespace: imperative ++--- ++# Source: pattern-clustergroup/templates/imperative/job.yaml ++apiVersion: batch/v1 ++kind: CronJob ++metadata: ++ name: imperative-cronjob ++ namespace: imperative ++spec: ++ schedule: "*/10 * * * *" ++ # if previous Job is still running, skip execution of a new Job ++ concurrencyPolicy: Forbid ++ jobTemplate: ++ spec: ++ activeDeadlineSeconds: 3600 ++ template: ++ metadata: ++ name: imperative-job ++ spec: ++ serviceAccountName: imperative-sa ++ initContainers: ++ # git init happens in /git/repo so that we can set the folder to 0770 permissions ++ # reason for that is ansible refuses to create temporary folders in there ++ - name: git-init ++ image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest ++ imagePullPolicy: Always ++ env: ++ - name: HOME ++ value: /git/home ++ command: ++ - 'sh' ++ - '-c' ++ - "mkdir /git/{repo,home};git clone --single-branch --branch main --depth 1 -- https://github.com/pattern-clone/mypattern /git/repo;chmod 0770 /git/{repo,home}" ++ volumeMounts: ++ - name: git ++ mountPath: "/git" ++ - name: test ++ image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest ++ imagePullPolicy: Always ++ env: ++ - name: HOME ++ value: /git/home ++ workingDir: /git/repo ++ # We have a default timeout of 600s for each playbook. Can be overridden ++ # on a per-job basis ++ command: ++ - timeout ++ - "600" ++ - ansible-playbook ++ - -e ++ - "@/values/values.yaml" ++ - ansible/test.yml ++ volumeMounts: ++ - name: git ++ mountPath: "/git" ++ - name: values-volume ++ mountPath: /values/values.yaml ++ subPath: values.yaml ++ containers: ++ - name: "done" ++ image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest ++ imagePullPolicy: Always ++ command: ++ - 'sh' ++ - '-c' ++ - 'echo' ++ - 'done' ++ - '\n' ++ volumes: ++ - name: git ++ emptyDir: {} ++ - name: values-volume ++ configMap: ++ name: helm-values-configmap-example ++ restartPolicy: Never ++--- ++# Source: pattern-clustergroup/templates/imperative/unsealjob.yaml ++apiVersion: batch/v1 ++kind: CronJob ++metadata: ++ name: unsealvault-cronjob ++ namespace: imperative ++spec: ++ schedule: "*/5 * * * *" ++ # if previous Job is still running, skip execution of a new Job ++ concurrencyPolicy: Forbid ++ jobTemplate: ++ spec: ++ activeDeadlineSeconds: 3600 ++ template: ++ metadata: ++ name: unsealvault-job ++ spec: ++ serviceAccountName: imperative-sa ++ initContainers: ++ # git init happens in /git/repo so that we can set the folder to 0770 permissions ++ # reason for that is ansible refuses to create temporary folders in there ++ - name: git-init ++ image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest ++ imagePullPolicy: Always ++ env: ++ - name: HOME ++ value: /git/home ++ command: ++ - 'sh' ++ - '-c' ++ - "mkdir /git/{repo,home};git clone --single-branch --branch main --depth 1 -- https://github.com/pattern-clone/mypattern /git/repo;chmod 0770 /git/{repo,home}" ++ volumeMounts: ++ - name: git ++ mountPath: "/git" ++ - name: unseal-playbook ++ image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest ++ imagePullPolicy: Always ++ env: ++ - name: HOME ++ value: /git/home ++ workingDir: /git/repo ++ # We have a default timeout of 600s for each playbook. Can be overridden ++ # on a per-job basis ++ command: ++ - timeout ++ - "600" ++ - ansible-playbook ++ - -e ++ - "@/values/values.yaml" ++ - -e ++ - '{"file_unseal": false}' ++ - -t ++ - 'vault_init,vault_unseal,vault_secrets_init' ++ - "common/ansible/playbooks/vault/vault.yaml" ++ volumeMounts: ++ - name: git ++ mountPath: "/git" ++ - name: values-volume ++ mountPath: /values/values.yaml ++ subPath: values.yaml ++ containers: ++ - name: "done" ++ image: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest ++ imagePullPolicy: Always ++ command: ++ - 'sh' ++ - '-c' ++ - 'echo' ++ - 'done' ++ - '\n' ++ volumes: ++ - name: git ++ emptyDir: {} ++ - name: values-volume ++ configMap: ++ name: helm-values-configmap-example ++ restartPolicy: Never ++--- ++# Source: pattern-clustergroup/templates/core/subscriptions.yaml ++--- ++--- ++# Source: pattern-clustergroup/templates/plumbing/hosted-sites.yaml ++apiVersion: argoproj.io/v1alpha1 ++kind: AppProject ++metadata: ++ name: argo-edge ++ namespace: openshift-gitops ++spec: ++ description: "Cluster Group argo-edge" ++ destinations: ++ - namespace: '*' ++ server: '*' ++ clusterResourceWhitelist: ++ - group: '*' ++ kind: '*' ++ namespaceResourceWhitelist: ++ - group: '*' ++ kind: '*' ++ sourceRepos: ++ - '*' ++status: {} ++--- ++# Source: pattern-clustergroup/templates/plumbing/projects.yaml ++apiVersion: argoproj.io/v1alpha1 ++kind: AppProject ++metadata: ++ name: datacenter ++ namespace: mypattern-example ++spec: ++ description: "Pattern datacenter" ++ destinations: ++ - namespace: '*' ++ server: '*' ++ clusterResourceWhitelist: ++ - group: '*' ++ kind: '*' ++ namespaceResourceWhitelist: ++ - group: '*' ++ kind: '*' ++ sourceRepos: ++ - '*' ++status: {} ++--- ++# Source: pattern-clustergroup/templates/plumbing/applications.yaml ++apiVersion: argoproj.io/v1alpha1 ++kind: Application ++metadata: ++ name: acm ++ namespace: mypattern-example ++ finalizers: ++ - resources-finalizer.argocd.argoproj.io/foreground ++spec: ++ destination: ++ name: in-cluster ++ namespace: open-cluster-management ++ project: datacenter ++ source: ++ repoURL: https://github.com/pattern-clone/mypattern ++ targetRevision: main ++ path: common/acm ++ helm: ++ ignoreMissingValueFiles: true ++ valueFiles: ++ - "/values-global.yaml" ++ - "/values-example.yaml" ++ # Watch the progress of https://issues.redhat.com/browse/GITOPS-891 and update accordingly ++ parameters: ++ - name: global.repoURL ++ value: $ARGOCD_APP_SOURCE_REPO_URL ++ - name: global.targetRevision ++ value: $ARGOCD_APP_SOURCE_TARGET_REVISION ++ - name: global.namespace ++ value: $ARGOCD_APP_NAMESPACE ++ - name: global.pattern ++ value: mypattern ++ - name: global.clusterDomain ++ value: region.example.com ++ - name: global.hubClusterDomain ++ value: apps.hub.example.com ++ - name: global.localClusterDomain ++ value: apps.region.example.com ++ ignoreDifferences: [ ++ { ++ "group": "internal.open-cluster-management.io", ++ "jsonPointers": [ ++ "/spec/loggingCA" ++ ], ++ "kind": "ManagedClusterInfo" ++ } ++] ++ syncPolicy: ++ automated: {} ++ # selfHeal: true ++--- ++# Source: pattern-clustergroup/templates/plumbing/applications.yaml ++apiVersion: argoproj.io/v1alpha1 ++kind: Application ++metadata: ++ name: pipelines ++ namespace: mypattern-example ++ finalizers: ++ - resources-finalizer.argocd.argoproj.io/foreground ++spec: ++ destination: ++ name: in-cluster ++ namespace: application-ci ++ project: datacenter ++ source: ++ repoURL: https://github.com/pattern-clone/mypattern ++ targetRevision: main ++ path: charts/datacenter/pipelines ++ helm: ++ ignoreMissingValueFiles: true ++ valueFiles: ++ - "/values-global.yaml" ++ - "/values-example.yaml" ++ # Watch the progress of https://issues.redhat.com/browse/GITOPS-891 and update accordingly ++ parameters: ++ - name: global.repoURL ++ value: $ARGOCD_APP_SOURCE_REPO_URL ++ - name: global.targetRevision ++ value: $ARGOCD_APP_SOURCE_TARGET_REVISION ++ - name: global.namespace ++ value: $ARGOCD_APP_NAMESPACE ++ - name: global.pattern ++ value: mypattern ++ - name: global.clusterDomain ++ value: region.example.com ++ - name: global.hubClusterDomain ++ value: apps.hub.example.com ++ - name: global.localClusterDomain ++ value: apps.region.example.com ++ syncPolicy: ++ automated: {} ++ # selfHeal: true ++--- ++# Source: pattern-clustergroup/templates/plumbing/hosted-sites.yaml ++apiVersion: argoproj.io/v1alpha1 ++kind: Application ++metadata: ++ name: mypattern-argo-edge-perth ++ namespace: openshift-gitops ++ finalizers: ++ - resources-finalizer.argocd.argoproj.io/foreground ++spec: ++ project: argo-edge ++ source: ++ repoURL: https://github.com/pattern-clone/mypattern ++ targetRevision: main ++ path: common/clustergroup ++ helm: ++ ignoreMissingValueFiles: true ++ valueFiles: ++ - "/values-global.yaml" ++ - "/values-argo-edge.yaml" ++ parameters: ++ - name: global.repoURL ++ value: $ARGOCD_APP_SOURCE_REPO_URL ++ - name: global.targetRevision ++ value: $ARGOCD_APP_SOURCE_TARGET_REVISION ++ - name: global.namespace ++ value: $ARGOCD_APP_NAMESPACE ++ - name: global.pattern ++ value: mypattern ++ - name: global.hubClusterDomain ++ value: apps.hub.example.com ++ - name: global.localClusterDomain ++ value: apps.perth1.beekhof.net ++ - name: global.clusterDomain ++ value: perth1.beekhof.net ++ - name: enabled ++ value: core ++ - name: clusterGroup.name ++ value: argo-edge ++ - name: clusterGroup.targetCluster ++ value: perth ++ - name: clusterGroup.hostedSite.bearerKeyPath ++ value: secret/data/hub/cluster_perth ++ - name: clusterGroup.hostedSite.caKeyPath ++ value: secret/data/hub/cluster_perth_ca ++ - name: clusterGroup.isHubCluster ++ value: "false" ++ destination: ++ name: perth ++ namespace: mypattern-argo-edge ++ syncPolicy: ++ automated: ++ selfHeal: true ++ ignoreDifferences: ++ - group: apps ++ kind: Deployment ++ jsonPointers: ++ - /spec/replicas ++ - group: route.openshift.io ++ kind: Route ++ jsonPointers: ++ - /status ++--- ++# Source: pattern-clustergroup/templates/plumbing/hosted-sites.yaml ++apiVersion: argoproj.io/v1alpha1 ++kind: Application ++metadata: ++ name: mypattern-argo-edge-perth-plumbing ++ namespace: openshift-gitops ++ finalizers: ++ - resources-finalizer.argocd.argoproj.io/foreground ++spec: ++ project: argo-edge ++ source: ++ repoURL: https://github.com/pattern-clone/mypattern ++ targetRevision: main ++ path: common/clustergroup ++ helm: ++ ignoreMissingValueFiles: true ++ valueFiles: ++ - "/values-global.yaml" ++ - "/values-argo-edge.yaml" ++ parameters: ++ - name: global.repoURL ++ value: $ARGOCD_APP_SOURCE_REPO_URL ++ - name: global.targetRevision ++ value: $ARGOCD_APP_SOURCE_TARGET_REVISION ++ - name: global.namespace ++ value: $ARGOCD_APP_NAMESPACE ++ - name: global.pattern ++ value: mypattern ++ - name: global.hubClusterDomain ++ value: apps.hub.example.com ++ - name: global.localClusterDomain ++ value: apps.perth1.beekhof.net ++ - name: global.clusterDomain ++ value: perth1.beekhof.net ++ - name: enabled ++ value: plumbing ++ - name: clusterGroup.name ++ value: argo-edge ++ - name: clusterGroup.targetCluster ++ value: perth ++ - name: clusterGroup.hostedSite.bearerKeyPath ++ value: secret/data/hub/cluster_perth ++ - name: clusterGroup.hostedSite.caKeyPath ++ value: secret/data/hub/cluster_perth_ca ++ - name: clusterGroup.isHubCluster ++ value: "false" ++ destination: ++ name: in-cluster ++ namespace: openshift-gitops ++ syncPolicy: ++ automated: ++ selfHeal: true ++ ignoreDifferences: ++ - group: apps ++ kind: Deployment ++ jsonPointers: ++ - /spec/replicas ++ - group: route.openshift.io ++ kind: Route ++ jsonPointers: ++ - /status ++--- ++# Source: pattern-clustergroup/templates/plumbing/hosted-sites.yaml ++apiVersion: argoproj.io/v1alpha1 ++kind: Application ++metadata: ++ name: mypattern-argo-edge-sydney ++ namespace: openshift-gitops ++ finalizers: ++ - resources-finalizer.argocd.argoproj.io/foreground ++spec: ++ project: argo-edge ++ source: ++ repoURL: https://github.com/pattern-clone/mypattern ++ targetRevision: main ++ path: common/clustergroup ++ helm: ++ ignoreMissingValueFiles: true ++ valueFiles: ++ - "/values-global.yaml" ++ - "/values-argo-edge.yaml" ++ parameters: ++ - name: global.repoURL ++ value: $ARGOCD_APP_SOURCE_REPO_URL ++ - name: global.targetRevision ++ value: $ARGOCD_APP_SOURCE_TARGET_REVISION ++ - name: global.namespace ++ value: $ARGOCD_APP_NAMESPACE ++ - name: global.pattern ++ value: mypattern ++ - name: global.hubClusterDomain ++ value: apps.hub.example.com ++ - name: global.localClusterDomain ++ value: apps.syd.beekhof.net ++ - name: global.clusterDomain ++ value: syd.beekhof.net ++ - name: enabled ++ value: core ++ - name: clusterGroup.name ++ value: argo-edge ++ - name: clusterGroup.targetCluster ++ value: sydney ++ - name: clusterGroup.hostedSite.bearerKeyPath ++ value: secret/data/hub/cluster_sydney ++ - name: clusterGroup.hostedSite.caKeyPath ++ value: secret/data/hub/cluster_sydney_ca ++ - name: clusterGroup.isHubCluster ++ value: "false" ++ destination: ++ name: sydney ++ namespace: mypattern-argo-edge ++ syncPolicy: ++ automated: ++ selfHeal: true ++ ignoreDifferences: ++ - group: apps ++ kind: Deployment ++ jsonPointers: ++ - /spec/replicas ++ - group: route.openshift.io ++ kind: Route ++ jsonPointers: ++ - /status ++--- ++# Source: pattern-clustergroup/templates/plumbing/hosted-sites.yaml ++apiVersion: argoproj.io/v1alpha1 ++kind: Application ++metadata: ++ name: mypattern-argo-edge-sydney-plumbing ++ namespace: openshift-gitops ++ finalizers: ++ - resources-finalizer.argocd.argoproj.io/foreground ++spec: ++ project: argo-edge ++ source: ++ repoURL: https://github.com/pattern-clone/mypattern ++ targetRevision: main ++ path: common/clustergroup ++ helm: ++ ignoreMissingValueFiles: true ++ valueFiles: ++ - "/values-global.yaml" ++ - "/values-argo-edge.yaml" ++ parameters: ++ - name: global.repoURL ++ value: $ARGOCD_APP_SOURCE_REPO_URL ++ - name: global.targetRevision ++ value: $ARGOCD_APP_SOURCE_TARGET_REVISION ++ - name: global.namespace ++ value: $ARGOCD_APP_NAMESPACE ++ - name: global.pattern ++ value: mypattern ++ - name: global.hubClusterDomain ++ value: apps.hub.example.com ++ - name: global.localClusterDomain ++ value: apps.syd.beekhof.net ++ - name: global.clusterDomain ++ value: syd.beekhof.net ++ - name: enabled ++ value: plumbing ++ - name: clusterGroup.name ++ value: argo-edge ++ - name: clusterGroup.targetCluster ++ value: sydney ++ - name: clusterGroup.hostedSite.bearerKeyPath ++ value: secret/data/hub/cluster_sydney ++ - name: clusterGroup.hostedSite.caKeyPath ++ value: secret/data/hub/cluster_sydney_ca ++ - name: clusterGroup.isHubCluster ++ value: "false" ++ destination: ++ name: in-cluster ++ namespace: openshift-gitops ++ syncPolicy: ++ automated: ++ selfHeal: true ++ ignoreDifferences: ++ - group: apps ++ kind: Deployment ++ jsonPointers: ++ - /spec/replicas ++ - group: route.openshift.io ++ kind: Route ++ jsonPointers: ++ - /status + --- + # Source: pattern-clustergroup/templates/plumbing/argocd.yaml + apiVersion: argoproj.io/v1alpha1 +@@ -65,7 +858,7 @@ + # Changing the name affects the ClusterRoleBinding, the generated secret, + # route URL, and argocd.argoproj.io/managed-by annotations + name: example-gitops +- namespace: common-example ++ namespace: mypattern-example + annotations: + argocd.argoproj.io/compare-options: IgnoreExtraneous + spec: +@@ -94,10 +887,10 @@ + --set global.repoURL=$ARGOCD_APP_SOURCE_REPO_URL + --set global.targetRevision=$ARGOCD_APP_SOURCE_TARGET_REVISION + --set global.namespace=$ARGOCD_APP_NAMESPACE +- --set global.pattern=common +- --set global.clusterDomain= +- --set global.hubClusterDomain= +- --set global.localClusterDomain= ++ --set global.pattern=mypattern ++ --set global.clusterDomain=region.example.com ++ --set global.hubClusterDomain=apps.hub.example.com ++ --set global.localClusterDomain=apps.region.example.com + --set clusterGroup.name=example + --post-renderer ./kustomize"] + applicationSet: +@@ -174,11 +967,59 @@ + kind: ConsoleLink + metadata: + name: example-gitops-link +- namespace: common-example ++ namespace: mypattern-example + spec: + applicationMenu: + section: OpenShift GitOps + imageURL: data:image/png;base64,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 +- href: 'https://example-gitops-server-common-example.' ++ href: 'https://example-gitops-server-mypattern-example.apps.region.example.com' + location: ApplicationMenu + text: 'Example ArgoCD' ++--- ++# Source: pattern-clustergroup/templates/core/operatorgroup.yaml ++apiVersion: operators.coreos.com/v1 ++kind: OperatorGroup ++metadata: ++ name: open-cluster-management-operator-group ++ namespace: open-cluster-management ++spec: ++ targetNamespaces: ++ - open-cluster-management ++--- ++# Source: pattern-clustergroup/templates/core/operatorgroup.yaml ++apiVersion: operators.coreos.com/v1 ++kind: OperatorGroup ++metadata: ++ name: application-ci-operator-group ++ namespace: application-ci ++spec: ++ targetNamespaces: ++ - application-ci ++--- ++# Source: pattern-clustergroup/templates/core/subscriptions.yaml ++apiVersion: operators.coreos.com/v1alpha1 ++kind: Subscription ++metadata: ++ name: advanced-cluster-management ++ namespace: open-cluster-management ++spec: ++ name: advanced-cluster-management ++ source: redhat-operators ++ sourceNamespace: openshift-marketplace ++ channel: release-2.4 ++ installPlanApproval: Automatic ++ startingCSV: advanced-cluster-management.v2.4.1 ++--- ++# Source: pattern-clustergroup/templates/core/subscriptions.yaml ++apiVersion: operators.coreos.com/v1alpha1 ++kind: Subscription ++metadata: ++ name: openshift-pipelines-operator-rh ++ namespace: openshift-operators ++spec: ++ name: openshift-pipelines-operator-rh ++ source: redhat-operators ++ sourceNamespace: openshift-marketplace ++ channel: stable ++ installPlanApproval: Automatic ++ startingCSV: redhat-openshift-pipelines.v1.5.2 diff --git a/tests/examples-blank-naked.expected.yml b/tests/examples-blank-naked.expected.yml new file mode 100644 index 00000000..51a92e5d --- /dev/null +++ b/tests/examples-blank-naked.expected.yml @@ -0,0 +1,6 @@ +--- +# Source: blank/templates/manifest.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: example diff --git a/tests/examples-blank-normal.expected.yml b/tests/examples-blank-normal.expected.yml new file mode 100644 index 00000000..51a92e5d --- /dev/null +++ b/tests/examples-blank-normal.expected.yml @@ -0,0 +1,6 @@ +--- +# Source: blank/templates/manifest.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: example diff --git a/tests/examples-blank.expected.diff b/tests/examples-blank.expected.diff new file mode 100644 index 00000000..e69de29b diff --git a/tests/examples-kustomize-renderer-naked.expected.yml b/tests/examples-kustomize-renderer-naked.expected.yml new file mode 100644 index 00000000..0aa7ee5d --- /dev/null +++ b/tests/examples-kustomize-renderer-naked.expected.yml @@ -0,0 +1,36 @@ +--- +# Source: example/templates/environment.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: environment +data: + IMAGE_PROVIDER: + IMAGE_ACCOUNT: PLAINTEXT + GIT_EMAIL: SOMEWHERE@EXAMPLE.COM + GIT_DEV_REPO_URL: https:///PLAINTEXT/manuela-dev.git + GIT_DEV_REPO_REVISION: main + GIT_OPS_REPO_TEST_URL: + GIT_OPS_REPO_TEST_REVISION: + GIT_OPS_REPO_PROD_URL: + GIT_OPS_REPO_PROD_REVISION: + IOT_CONSUMER_IMAGE: iot-consumer + IOT_CONSUMER_YAML_PATH: images.(name==messaging).newTag + IOT_CONSUMER_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml + IOT_CONSUMER_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/messaging/kustomization.yaml + IOT_CONSUMER_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/messaging/messaging-is.yaml + IOT_FRONTEND_IMAGE: iot-frontend + IOT_FRONTEND_YAML_PATH: images.(name==line-dashboard).newTag + IOT_FRONTEND_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml + IOT_FRONTEND_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/line-dashboard/kustomization.yaml + IOT_FRONTEND_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/line-dashboard/line-dashboard-is.yaml + IOT_SWSENSOR_IMAGE: iot-software-sensor + IOT_SWSENSOR_YAML_PATH: images.(name==machine-sensor).newTag + IOT_SWSENSOR_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml + IOT_SWSENSOR_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/machine-sensor/kustomization.yaml + IOT_SWSENSOR_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/machine-sensor/machine-sensor-is.yaml + IOT_ANOMALY_IMAGE: iot-anomaly-detection + IOT_ANOMALY_YAML_PATH: images.(name==anomaly-detection).newTag + IOT_ANOMALY_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml + IOT_ANOMALY_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/anomaly-detection/kustomization.yaml + IOT_ANOMALY_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/anomaly-detection/anomaly-detection-is.yaml diff --git a/tests/examples-kustomize-renderer-normal.expected.yml b/tests/examples-kustomize-renderer-normal.expected.yml new file mode 100644 index 00000000..09e04b22 --- /dev/null +++ b/tests/examples-kustomize-renderer-normal.expected.yml @@ -0,0 +1,36 @@ +--- +# Source: example/templates/environment.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: environment +data: + IMAGE_PROVIDER: + IMAGE_ACCOUNT: PLAINTEXT + GIT_EMAIL: someone@somewhere.com + GIT_DEV_REPO_URL: https://github.com/hybrid-cloud-patterns/manuela-dev.git + GIT_DEV_REPO_REVISION: main + GIT_OPS_REPO_TEST_URL: https://github.com/pattern-clone/mypattern + GIT_OPS_REPO_TEST_REVISION: + GIT_OPS_REPO_PROD_URL: https://github.com/pattern-clone/mypattern + GIT_OPS_REPO_PROD_REVISION: + IOT_CONSUMER_IMAGE: iot-consumer + IOT_CONSUMER_YAML_PATH: images.(name==messaging).newTag + IOT_CONSUMER_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml + IOT_CONSUMER_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/messaging/kustomization.yaml + IOT_CONSUMER_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/messaging/messaging-is.yaml + IOT_FRONTEND_IMAGE: iot-frontend + IOT_FRONTEND_YAML_PATH: images.(name==line-dashboard).newTag + IOT_FRONTEND_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml + IOT_FRONTEND_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/line-dashboard/kustomization.yaml + IOT_FRONTEND_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/line-dashboard/line-dashboard-is.yaml + IOT_SWSENSOR_IMAGE: iot-software-sensor + IOT_SWSENSOR_YAML_PATH: images.(name==machine-sensor).newTag + IOT_SWSENSOR_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml + IOT_SWSENSOR_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/machine-sensor/kustomization.yaml + IOT_SWSENSOR_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/machine-sensor/machine-sensor-is.yaml + IOT_ANOMALY_IMAGE: iot-anomaly-detection + IOT_ANOMALY_YAML_PATH: images.(name==anomaly-detection).newTag + IOT_ANOMALY_TEST_KUSTOMIZATION_PATH: charts/datacenter/manuela-tst/kustomization.yaml + IOT_ANOMALY_PROD_KUSTOMIZATION_PATH: charts/factory/manuela-stormshift/anomaly-detection/kustomization.yaml + IOT_ANOMALY_PROD_IMAGESTREAM_PATH: charts/factory/manuela-stormshift/anomaly-detection/anomaly-detection-is.yaml diff --git a/tests/examples-kustomize-renderer.expected.diff b/tests/examples-kustomize-renderer.expected.diff new file mode 100644 index 00000000..cee20d02 --- /dev/null +++ b/tests/examples-kustomize-renderer.expected.diff @@ -0,0 +1,19 @@ +--- tests/examples-kustomize-renderer-naked.expected.yml ++++ tests/examples-kustomize-renderer-normal.expected.yml +@@ -7,12 +7,12 @@ + data: + IMAGE_PROVIDER: + IMAGE_ACCOUNT: PLAINTEXT +- GIT_EMAIL: SOMEWHERE@EXAMPLE.COM +- GIT_DEV_REPO_URL: https:///PLAINTEXT/manuela-dev.git ++ GIT_EMAIL: someone@somewhere.com ++ GIT_DEV_REPO_URL: https://github.com/hybrid-cloud-patterns/manuela-dev.git + GIT_DEV_REPO_REVISION: main +- GIT_OPS_REPO_TEST_URL: ++ GIT_OPS_REPO_TEST_URL: https://github.com/pattern-clone/mypattern + GIT_OPS_REPO_TEST_REVISION: +- GIT_OPS_REPO_PROD_URL: ++ GIT_OPS_REPO_PROD_URL: https://github.com/pattern-clone/mypattern + GIT_OPS_REPO_PROD_REVISION: + IOT_CONSUMER_IMAGE: iot-consumer + IOT_CONSUMER_YAML_PATH: images.(name==messaging).newTag diff --git a/tests/golang-external-secrets-naked.expected.yml b/tests/golang-external-secrets-naked.expected.yml new file mode 100644 index 00000000..7d9fa628 --- /dev/null +++ b/tests/golang-external-secrets-naked.expected.yml @@ -0,0 +1,5911 @@ +--- +# Source: golang-external-secrets/charts/external-secrets/templates/cert-controller-serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: external-secrets-cert-controller + namespace: "default" + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets-cert-controller + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +--- +# Source: golang-external-secrets/charts/external-secrets/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: golang-external-secrets + namespace: "default" + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +--- +# Source: golang-external-secrets/charts/external-secrets/templates/webhook-serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: external-secrets-webhook + namespace: "default" + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets-webhook + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +--- +# Source: golang-external-secrets/charts/external-secrets/templates/webhook-secret.yaml +apiVersion: v1 +kind: Secret +metadata: + name: golang-external-secrets-webhook + namespace: "default" + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets-webhook + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm + external-secrets.io/component : webhook +--- +# Source: golang-external-secrets/templates/golang-external-secrets-hub-clusterrolebinding.yaml +apiVersion: v1 +kind: Secret +metadata: + name: golang-external-secrets + namespace: golang-external-secrets + annotations: + kubernetes.io/service-account.name: golang-external-secrets +type: kubernetes.io/service-account-token +--- +# Source: golang-external-secrets/charts/external-secrets/templates/crds/clusterexternalsecret.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: clusterexternalsecrets.external-secrets.io +spec: + group: external-secrets.io + names: + categories: + - externalsecrets + kind: ClusterExternalSecret + listKind: ClusterExternalSecretList + plural: clusterexternalsecrets + shortNames: + - ces + singular: clusterexternalsecret + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .spec.secretStoreRef.name + name: Store + type: string + - jsonPath: .spec.refreshInterval + name: Refresh Interval + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: ClusterExternalSecret is the Schema for the clusterexternalsecrets 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: ClusterExternalSecretSpec defines the desired state of ClusterExternalSecret. + properties: + externalSecretName: + description: The name of the external secrets to be created defaults to the name of the ClusterExternalSecret + type: string + externalSecretSpec: + description: The spec for the ExternalSecrets to be created + properties: + data: + description: Data defines the connection between the Kubernetes Secret keys and the Provider data + items: + description: ExternalSecretData defines the connection between the Kubernetes Secret key (spec.data.) and the Provider data. + properties: + remoteRef: + description: ExternalSecretDataRemoteRef defines Provider data location. + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + type: string + decodingStrategy: + default: None + description: Used to define a decoding Strategy + type: string + key: + description: Key is the key used in the Provider, mandatory + type: string + metadataPolicy: + description: Policy for fetching tags/labels from provider secrets, possible options are Fetch, None. Defaults to None + type: string + property: + description: Used to select a specific property of the Provider value (if a map), if supported + type: string + version: + description: Used to select a specific version of the Provider value, if supported + type: string + required: + - key + type: object + secretKey: + type: string + required: + - remoteRef + - secretKey + type: object + type: array + dataFrom: + description: DataFrom is used to fetch all properties from a specific Provider data If multiple entries are specified, the Secret keys are merged in the specified order + items: + properties: + extract: + description: Used to extract multiple key/value pairs from one secret + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + type: string + decodingStrategy: + default: None + description: Used to define a decoding Strategy + type: string + key: + description: Key is the key used in the Provider, mandatory + type: string + metadataPolicy: + description: Policy for fetching tags/labels from provider secrets, possible options are Fetch, None. Defaults to None + type: string + property: + description: Used to select a specific property of the Provider value (if a map), if supported + type: string + version: + description: Used to select a specific version of the Provider value, if supported + type: string + required: + - key + type: object + find: + description: Used to find secrets based on tags or regular expressions + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + type: string + decodingStrategy: + default: None + description: Used to define a decoding Strategy + type: string + name: + description: Finds secrets based on the name. + properties: + regexp: + description: Finds secrets base + type: string + type: object + path: + description: A root path to start the find operations. + type: string + tags: + additionalProperties: + type: string + description: Find secrets based on tags. + type: object + type: object + rewrite: + description: Used to rewrite secret Keys after getting them from the secret Provider Multiple Rewrite operations can be provided. They are applied in a layered order (first to last) + items: + properties: + regexp: + description: Used to rewrite with regular expressions. The resulting key will be the output of a regexp.ReplaceAll operation. + properties: + source: + description: Used to define the regular expression of a re.Compiler. + type: string + target: + description: Used to define the target pattern of a ReplaceAll operation. + type: string + required: + - source + - target + type: object + type: object + type: array + type: object + type: array + refreshInterval: + default: 1h + description: RefreshInterval is the amount of time before the values are read again from the SecretStore provider Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h" May be set to zero to fetch and create it once. Defaults to 1h. + type: string + secretStoreRef: + description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret data. + properties: + kind: + description: Kind of the SecretStore resource (SecretStore or ClusterSecretStore) Defaults to `SecretStore` + type: string + name: + description: Name of the SecretStore resource + type: string + required: + - name + type: object + target: + description: ExternalSecretTarget defines the Kubernetes Secret to be created There can be only one target per ExternalSecret. + properties: + creationPolicy: + default: Owner + description: CreationPolicy defines rules on how to create the resulting Secret Defaults to 'Owner' + enum: + - Owner + - Orphan + - Merge + - None + type: string + deletionPolicy: + default: Retain + description: DeletionPolicy defines rules on how to delete the resulting Secret Defaults to 'Retain' + enum: + - Delete + - Merge + - Retain + type: string + immutable: + description: Immutable defines if the final secret will be immutable + type: boolean + name: + description: Name defines the name of the Secret resource to be managed This field is immutable Defaults to the .metadata.name of the ExternalSecret resource + type: string + template: + description: Template defines a blueprint for the created Secret resource. + properties: + data: + additionalProperties: + type: string + type: object + engineVersion: + default: v2 + type: string + metadata: + description: ExternalSecretTemplateMetadata defines metadata fields for the Secret blueprint. + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + templateFrom: + items: + maxProperties: 1 + minProperties: 1 + properties: + configMap: + properties: + items: + items: + properties: + key: + type: string + required: + - key + type: object + type: array + name: + type: string + required: + - items + - name + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + required: + - key + type: object + type: array + name: + type: string + required: + - items + - name + type: object + type: object + type: array + type: + type: string + type: object + type: object + required: + - secretStoreRef + type: object + namespaceSelector: + description: The labels to select by to find the Namespaces to create the ExternalSecrets in. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + refreshTime: + description: The time in which the controller should reconcile it's objects and recheck namespaces for labels. + type: string + required: + - externalSecretSpec + - namespaceSelector + type: object + status: + description: ClusterExternalSecretStatus defines the observed state of ClusterExternalSecret. + properties: + conditions: + items: + properties: + message: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + failedNamespaces: + description: Failed namespaces are the namespaces that failed to apply an ExternalSecret + items: + description: ClusterExternalSecretNamespaceFailure represents a failed namespace deployment and it's reason. + properties: + namespace: + description: Namespace is the namespace that failed when trying to apply an ExternalSecret + type: string + reason: + description: Reason is why the ExternalSecret failed to apply to the namespace + type: string + required: + - namespace + type: object + type: array + provisionedNamespaces: + description: ProvisionedNamespaces are the namespaces where the ClusterExternalSecret has secrets + items: + type: string + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: golang-external-secrets-webhook + namespace: "default" + path: /convert +--- +# Source: golang-external-secrets/charts/external-secrets/templates/crds/clustersecretstore.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: clustersecretstores.external-secrets.io +spec: + group: external-secrets.io + names: + categories: + - externalsecrets + kind: ClusterSecretStore + listKind: ClusterSecretStoreList + plural: clustersecretstores + shortNames: + - css + singular: clustersecretstore + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + deprecated: true + name: v1alpha1 + schema: + openAPIV3Schema: + description: ClusterSecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields. + 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: SecretStoreSpec defines the desired state of SecretStore. + properties: + controller: + description: 'Used to select the correct KES controller (think: ingress.ingressClassName) The KES controller is instantiated with a specific controller name and filters ES based on this property' + type: string + provider: + description: Used to configure the provider. Only one provider may be set + maxProperties: 1 + minProperties: 1 + properties: + akeyless: + description: Akeyless configures this store to sync secrets using Akeyless Vault provider + properties: + akeylessGWApiURL: + description: Akeyless GW API Url from which the secrets to be fetched from. + type: string + authSecretRef: + description: Auth configures how the operator authenticates with Akeyless. + properties: + secretRef: + description: 'AkeylessAuthSecretRef AKEYLESS_ACCESS_TYPE_PARAM: AZURE_OBJ_ID OR GCP_AUDIENCE OR ACCESS_KEY OR KUB_CONFIG_NAME.' + properties: + accessID: + description: The SecretAccessID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessType: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessTypeParam: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + required: + - akeylessGWApiURL + - authSecretRef + type: object + alibaba: + description: Alibaba configures this store to sync secrets using Alibaba Cloud provider + properties: + auth: + description: AlibabaAuth contains a secretRef for credentials. + properties: + secretRef: + description: AlibabaAuthSecretRef holds secret references for Alibaba credentials. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessKeySecretSecretRef: + description: The AccessKeySecret is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - accessKeyIDSecretRef + - accessKeySecretSecretRef + type: object + required: + - secretRef + type: object + endpoint: + type: string + regionID: + description: Alibaba Region to be used for the provider + type: string + required: + - auth + - regionID + type: object + aws: + description: AWS configures this store to sync secrets using AWS Secret Manager provider + properties: + auth: + description: 'Auth defines the information necessary to authenticate against AWS if not set aws sdk will infer credentials from your environment see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' + properties: + jwt: + description: Authenticate against AWS using service account tokens. + properties: + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + type: object + secretRef: + description: AWSAuthSecretRef holds secret references for AWS credentials both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + type: object + region: + description: AWS Region to be used for the provider + type: string + role: + description: Role is a Role ARN which the SecretManager provider will assume + type: string + service: + description: Service defines which service should be used to fetch the secrets + enum: + - SecretsManager + - ParameterStore + type: string + required: + - region + - service + type: object + azurekv: + description: AzureKV configures this store to sync secrets using Azure Key Vault provider + properties: + authSecretRef: + description: Auth configures how the operator authenticates with Azure. Required for ServicePrincipal auth type. + properties: + clientId: + description: The Azure clientId of the service principle used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + clientSecret: + description: The Azure ClientSecret of the service principle used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + authType: + default: ServicePrincipal + description: 'Auth type defines how to authenticate to the keyvault service. Valid values are: - "ServicePrincipal" (default): Using a service principal (tenantId, clientId, clientSecret) - "ManagedIdentity": Using Managed Identity assigned to the pod (see aad-pod-identity)' + enum: + - ServicePrincipal + - ManagedIdentity + - WorkloadIdentity + type: string + identityId: + description: If multiple Managed Identity is assigned to the pod, you can select the one to be used + type: string + serviceAccountRef: + description: ServiceAccountRef specified the service account that should be used when authenticating with WorkloadIdentity. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + tenantId: + description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. + type: string + vaultUrl: + description: Vault Url from which the secrets to be fetched from. + type: string + required: + - vaultUrl + type: object + fake: + description: Fake configures a store with static key/value pairs + properties: + data: + items: + properties: + key: + type: string + value: + type: string + valueMap: + additionalProperties: + type: string + type: object + version: + type: string + required: + - key + type: object + type: array + required: + - data + type: object + gcpsm: + description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider + properties: + auth: + description: Auth defines the information necessary to authenticate against GCP + properties: + secretRef: + properties: + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + workloadIdentity: + properties: + clusterLocation: + type: string + clusterName: + type: string + clusterProjectID: + type: string + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - clusterLocation + - clusterName + - serviceAccountRef + type: object + type: object + projectID: + description: ProjectID project where secret is located + type: string + type: object + gitlab: + description: Gitlab configures this store to sync secrets using Gitlab Variables provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a GitLab instance. + properties: + SecretRef: + properties: + accessToken: + description: AccessToken is used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - SecretRef + type: object + projectID: + description: ProjectID specifies a project where secrets are located. + type: string + url: + description: URL configures the GitLab instance URL. Defaults to https://gitlab.com/. + type: string + required: + - auth + type: object + ibm: + description: IBM configures this store to sync secrets using IBM Cloud provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the IBM secrets manager. + properties: + secretRef: + properties: + secretApiKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + serviceUrl: + description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance + type: string + required: + - auth + type: object + kubernetes: + description: Kubernetes configures this store to sync secrets using a Kubernetes cluster provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Kubernetes instance. + maxProperties: 1 + minProperties: 1 + properties: + cert: + description: has both clientCert and clientKey as secretKeySelector + properties: + clientCert: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + clientKey: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + serviceAccount: + description: points to a service account that should be used for authentication + properties: + serviceAccount: + description: A reference to a ServiceAccount resource. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + type: object + token: + description: use static token to authenticate with + properties: + bearerToken: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + type: object + remoteNamespace: + default: default + description: Remote namespace to fetch the secrets from + type: string + server: + description: configures the Kubernetes server Address. + properties: + caBundle: + description: CABundle is a base64-encoded CA certificate + format: byte + type: string + caProvider: + description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider' + properties: + key: + description: The key the value inside of the provider type to use, only used with "Secret" type + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + url: + default: kubernetes.default + description: configures the Kubernetes server Address. + type: string + type: object + required: + - auth + type: object + oracle: + description: Oracle configures this store to sync secrets using Oracle Vault provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the Oracle Vault. If empty, use the instance principal, otherwise the user credentials specified in Auth. + properties: + secretRef: + description: SecretRef to pass through sensitive information. + properties: + fingerprint: + description: Fingerprint is the fingerprint of the API private key. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + privatekey: + description: PrivateKey is the user's API Signing Key in PEM format, used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - fingerprint + - privatekey + type: object + tenancy: + description: Tenancy is the tenancy OCID where user is located. + type: string + user: + description: User is an access OCID specific to the account. + type: string + required: + - secretRef + - tenancy + - user + type: object + region: + description: Region is the region where vault is located. + type: string + vault: + description: Vault is the vault's OCID of the specific vault where secret is located. + type: string + required: + - region + - vault + type: object + vault: + description: Vault configures this store to sync secrets using Hashi provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the Vault server. + properties: + appRole: + description: AppRole authenticates with Vault using the App Role auth mechanism, with the role and secret stored in a Kubernetes Secret resource. + properties: + path: + default: approle + description: 'Path where the App Role authentication backend is mounted in Vault, e.g: "approle"' + type: string + roleId: + description: RoleID configured in the App Role authentication backend when setting up the authentication backend in Vault. + type: string + secretRef: + description: Reference to a key in a Secret that contains the App Role secret used to authenticate with Vault. The `key` field must be specified and denotes which entry within the Secret resource is used as the app role secret. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - path + - roleId + - secretRef + type: object + cert: + description: Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate Cert authentication method + properties: + clientCert: + description: ClientCert is a certificate to authenticate using the Cert Vault authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + secretRef: + description: SecretRef to a key in a Secret resource containing client private key to authenticate with Vault using the Cert authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + jwt: + description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method + properties: + kubernetesServiceAccountToken: + description: Optional ServiceAccountToken specifies the Kubernetes service account for which to request a token for with the `TokenRequest` API. + properties: + audiences: + description: Optional audiences field that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to a single audience `vault` it not specified. + items: + type: string + type: array + expirationSeconds: + description: Optional expiration time in seconds that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to 10 minutes. + format: int64 + type: integer + serviceAccountRef: + description: Service account field containing the name of a kubernetes ServiceAccount. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - serviceAccountRef + type: object + path: + default: jwt + description: 'Path where the JWT authentication backend is mounted in Vault, e.g: "jwt"' + type: string + role: + description: Role is a JWT role to authenticate using the JWT/OIDC Vault authentication method + type: string + secretRef: + description: Optional SecretRef that refers to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - path + type: object + kubernetes: + description: Kubernetes authenticates with Vault by passing the ServiceAccount token stored in the named Secret resource to the Vault server. + properties: + mountPath: + default: kubernetes + description: 'Path where the Kubernetes authentication backend is mounted in Vault, e.g: "kubernetes"' + type: string + role: + description: A required field containing the Vault Role to assume. A Role binds a Kubernetes ServiceAccount with a set of Vault policies. + type: string + secretRef: + description: Optional secret field containing a Kubernetes ServiceAccount JWT used for authenticating with Vault. If a name is specified without a key, `token` is the default. If one is not specified, the one bound to the controller will be used. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + serviceAccountRef: + description: Optional service account field containing the name of a kubernetes ServiceAccount. If the service account is specified, the service account secret token JWT will be used for authenticating with Vault. If the service account selector is not supplied, the secretRef will be used instead. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - mountPath + - role + type: object + ldap: + description: Ldap authenticates with Vault by passing username/password pair using the LDAP authentication method + properties: + path: + default: ldap + description: 'Path where the LDAP authentication backend is mounted in Vault, e.g: "ldap"' + type: string + secretRef: + description: SecretRef to a key in a Secret resource containing password for the LDAP user used to authenticate with Vault using the LDAP authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + username: + description: Username is a LDAP user name used to authenticate using the LDAP Vault authentication method + type: string + required: + - path + - username + type: object + tokenSecretRef: + description: TokenSecretRef authenticates with Vault by presenting a token. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + caBundle: + description: PEM encoded CA bundle used to validate Vault server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate Vault server certificate. + properties: + key: + description: The key the value inside of the provider type to use, only used with "Secret" type + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + forwardInconsistent: + description: ForwardInconsistent tells Vault to forward read-after-write requests to the Vault leader instead of simply retrying within a loop. This can increase performance if the option is enabled serverside. https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header + type: boolean + namespace: + description: 'Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1". More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces' + type: string + path: + description: 'Path is the mount path of the Vault KV backend endpoint, e.g: "secret". The v2 KV secret engine version specific "/data" path suffix for fetching secrets from Vault is optional and will be appended if not present in specified path.' + type: string + readYourWrites: + description: ReadYourWrites ensures isolated read-after-write semantics by providing discovered cluster replication states in each request. More information about eventual consistency in Vault can be found here https://www.vaultproject.io/docs/enterprise/consistency + type: boolean + server: + description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' + type: string + version: + default: v2 + description: Version is the Vault KV secret engine version. This can be either "v1" or "v2". Version defaults to "v2". + enum: + - v1 + - v2 + type: string + required: + - auth + - server + type: object + webhook: + description: Webhook configures this store to sync secrets using a generic templated webhook + properties: + body: + description: Body + type: string + caBundle: + description: PEM encoded CA bundle used to validate webhook server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate webhook server certificate. + properties: + key: + description: The key the value inside of the provider type to use, only used with "Secret" type + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + headers: + additionalProperties: + type: string + description: Headers + type: object + method: + description: Webhook Method + type: string + result: + description: Result formatting + properties: + jsonPath: + description: Json path of return value + type: string + type: object + secrets: + description: Secrets to fill in templates These secrets will be passed to the templating function as key value pairs under the given name + items: + properties: + name: + description: Name of this secret in templates + type: string + secretRef: + description: Secret ref to fill in credentials + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - name + - secretRef + type: object + type: array + timeout: + description: Timeout + type: string + url: + description: Webhook url to call + type: string + required: + - result + - url + type: object + yandexlockbox: + description: YandexLockbox configures this store to sync secrets using Yandex Lockbox provider + properties: + apiEndpoint: + description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') + type: string + auth: + description: Auth defines the information necessary to authenticate against Yandex Lockbox + properties: + authorizedKeySecretRef: + description: The authorized key used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + caProvider: + description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. + properties: + certSecretRef: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - auth + type: object + type: object + retrySettings: + description: Used to configure http retries if failed + properties: + maxRetries: + format: int32 + type: integer + retryInterval: + type: string + type: object + required: + - provider + type: object + status: + description: SecretStoreStatus defines the observed state of the SecretStore. + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: ClusterSecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields. + 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: SecretStoreSpec defines the desired state of SecretStore. + properties: + controller: + description: 'Used to select the correct KES controller (think: ingress.ingressClassName) The KES controller is instantiated with a specific controller name and filters ES based on this property' + type: string + provider: + description: Used to configure the provider. Only one provider may be set + maxProperties: 1 + minProperties: 1 + properties: + akeyless: + description: Akeyless configures this store to sync secrets using Akeyless Vault provider + properties: + akeylessGWApiURL: + description: Akeyless GW API Url from which the secrets to be fetched from. + type: string + authSecretRef: + description: Auth configures how the operator authenticates with Akeyless. + properties: + secretRef: + description: 'AkeylessAuthSecretRef AKEYLESS_ACCESS_TYPE_PARAM: AZURE_OBJ_ID OR GCP_AUDIENCE OR ACCESS_KEY OR KUB_CONFIG_NAME.' + properties: + accessID: + description: The SecretAccessID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessType: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessTypeParam: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + required: + - akeylessGWApiURL + - authSecretRef + type: object + alibaba: + description: Alibaba configures this store to sync secrets using Alibaba Cloud provider + properties: + auth: + description: AlibabaAuth contains a secretRef for credentials. + properties: + secretRef: + description: AlibabaAuthSecretRef holds secret references for Alibaba credentials. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessKeySecretSecretRef: + description: The AccessKeySecret is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - accessKeyIDSecretRef + - accessKeySecretSecretRef + type: object + required: + - secretRef + type: object + endpoint: + type: string + regionID: + description: Alibaba Region to be used for the provider + type: string + required: + - auth + - regionID + type: object + aws: + description: AWS configures this store to sync secrets using AWS Secret Manager provider + properties: + auth: + description: 'Auth defines the information necessary to authenticate against AWS if not set aws sdk will infer credentials from your environment see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' + properties: + jwt: + description: Authenticate against AWS using service account tokens. + properties: + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + type: object + secretRef: + description: AWSAuthSecretRef holds secret references for AWS credentials both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + type: object + region: + description: AWS Region to be used for the provider + type: string + role: + description: Role is a Role ARN which the SecretManager provider will assume + type: string + service: + description: Service defines which service should be used to fetch the secrets + enum: + - SecretsManager + - ParameterStore + type: string + required: + - region + - service + type: object + azurekv: + description: AzureKV configures this store to sync secrets using Azure Key Vault provider + properties: + authSecretRef: + description: Auth configures how the operator authenticates with Azure. Required for ServicePrincipal auth type. + properties: + clientId: + description: The Azure clientId of the service principle used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + clientSecret: + description: The Azure ClientSecret of the service principle used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + authType: + default: ServicePrincipal + description: 'Auth type defines how to authenticate to the keyvault service. Valid values are: - "ServicePrincipal" (default): Using a service principal (tenantId, clientId, clientSecret) - "ManagedIdentity": Using Managed Identity assigned to the pod (see aad-pod-identity)' + enum: + - ServicePrincipal + - ManagedIdentity + - WorkloadIdentity + type: string + identityId: + description: If multiple Managed Identity is assigned to the pod, you can select the one to be used + type: string + serviceAccountRef: + description: ServiceAccountRef specified the service account that should be used when authenticating with WorkloadIdentity. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + tenantId: + description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. + type: string + vaultUrl: + description: Vault Url from which the secrets to be fetched from. + type: string + required: + - vaultUrl + type: object + fake: + description: Fake configures a store with static key/value pairs + properties: + data: + items: + properties: + key: + type: string + value: + type: string + valueMap: + additionalProperties: + type: string + type: object + version: + type: string + required: + - key + type: object + type: array + required: + - data + type: object + gcpsm: + description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider + properties: + auth: + description: Auth defines the information necessary to authenticate against GCP + properties: + secretRef: + properties: + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + workloadIdentity: + properties: + clusterLocation: + type: string + clusterName: + type: string + clusterProjectID: + type: string + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - clusterLocation + - clusterName + - serviceAccountRef + type: object + type: object + projectID: + description: ProjectID project where secret is located + type: string + type: object + gitlab: + description: Gitlab configures this store to sync secrets using Gitlab Variables provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a GitLab instance. + properties: + SecretRef: + properties: + accessToken: + description: AccessToken is used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - SecretRef + type: object + projectID: + description: ProjectID specifies a project where secrets are located. + type: string + url: + description: URL configures the GitLab instance URL. Defaults to https://gitlab.com/. + type: string + required: + - auth + type: object + ibm: + description: IBM configures this store to sync secrets using IBM Cloud provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the IBM secrets manager. + maxProperties: 1 + minProperties: 1 + properties: + containerAuth: + description: IBM Container-based auth with IAM Trusted Profile. + properties: + iamEndpoint: + type: string + profile: + description: the IBM Trusted Profile + type: string + tokenLocation: + description: Location the token is mounted on the pod + type: string + required: + - profile + type: object + secretRef: + properties: + secretApiKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + type: object + serviceUrl: + description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance + type: string + required: + - auth + type: object + kubernetes: + description: Kubernetes configures this store to sync secrets using a Kubernetes cluster provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Kubernetes instance. + maxProperties: 1 + minProperties: 1 + properties: + cert: + description: has both clientCert and clientKey as secretKeySelector + properties: + clientCert: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + clientKey: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + serviceAccount: + description: points to a service account that should be used for authentication + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + token: + description: use static token to authenticate with + properties: + bearerToken: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + type: object + remoteNamespace: + default: default + description: Remote namespace to fetch the secrets from + type: string + server: + description: configures the Kubernetes server Address. + properties: + caBundle: + description: CABundle is a base64-encoded CA certificate + format: byte + type: string + caProvider: + description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider' + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. Can only be defined when used in a ClusterSecretStore. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + url: + default: kubernetes.default + description: configures the Kubernetes server Address. + type: string + type: object + required: + - auth + type: object + onepassword: + description: OnePassword configures this store to sync secrets using the 1Password Cloud provider + properties: + auth: + description: Auth defines the information necessary to authenticate against OnePassword Connect Server + properties: + secretRef: + description: OnePasswordAuthSecretRef holds secret references for 1Password credentials. + properties: + connectTokenSecretRef: + description: The ConnectToken is used for authentication to a 1Password Connect Server. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - connectTokenSecretRef + type: object + required: + - secretRef + type: object + connectHost: + description: ConnectHost defines the OnePassword Connect Server to connect to + type: string + vaults: + additionalProperties: + type: integer + description: Vaults defines which OnePassword vaults to search in which order + type: object + required: + - auth + - connectHost + - vaults + type: object + oracle: + description: Oracle configures this store to sync secrets using Oracle Vault provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the Oracle Vault. If empty, use the instance principal, otherwise the user credentials specified in Auth. + properties: + secretRef: + description: SecretRef to pass through sensitive information. + properties: + fingerprint: + description: Fingerprint is the fingerprint of the API private key. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + privatekey: + description: PrivateKey is the user's API Signing Key in PEM format, used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - fingerprint + - privatekey + type: object + tenancy: + description: Tenancy is the tenancy OCID where user is located. + type: string + user: + description: User is an access OCID specific to the account. + type: string + required: + - secretRef + - tenancy + - user + type: object + region: + description: Region is the region where vault is located. + type: string + vault: + description: Vault is the vault's OCID of the specific vault where secret is located. + type: string + required: + - region + - vault + type: object + senhasegura: + description: Senhasegura configures this store to sync secrets using senhasegura provider + properties: + auth: + description: Auth defines parameters to authenticate in senhasegura + properties: + clientId: + type: string + clientSecretSecretRef: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - clientId + - clientSecretSecretRef + type: object + ignoreSslCertificate: + default: false + description: IgnoreSslCertificate defines if SSL certificate must be ignored + type: boolean + module: + description: Module defines which senhasegura module should be used to get secrets + type: string + url: + description: URL of senhasegura + type: string + required: + - auth + - module + - url + type: object + vault: + description: Vault configures this store to sync secrets using Hashi provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the Vault server. + properties: + appRole: + description: AppRole authenticates with Vault using the App Role auth mechanism, with the role and secret stored in a Kubernetes Secret resource. + properties: + path: + default: approle + description: 'Path where the App Role authentication backend is mounted in Vault, e.g: "approle"' + type: string + roleId: + description: RoleID configured in the App Role authentication backend when setting up the authentication backend in Vault. + type: string + secretRef: + description: Reference to a key in a Secret that contains the App Role secret used to authenticate with Vault. The `key` field must be specified and denotes which entry within the Secret resource is used as the app role secret. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - path + - roleId + - secretRef + type: object + cert: + description: Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate Cert authentication method + properties: + clientCert: + description: ClientCert is a certificate to authenticate using the Cert Vault authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + secretRef: + description: SecretRef to a key in a Secret resource containing client private key to authenticate with Vault using the Cert authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + jwt: + description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method + properties: + kubernetesServiceAccountToken: + description: Optional ServiceAccountToken specifies the Kubernetes service account for which to request a token for with the `TokenRequest` API. + properties: + audiences: + description: Optional audiences field that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to a single audience `vault` it not specified. + items: + type: string + type: array + expirationSeconds: + description: Optional expiration time in seconds that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to 10 minutes. + format: int64 + type: integer + serviceAccountRef: + description: Service account field containing the name of a kubernetes ServiceAccount. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - serviceAccountRef + type: object + path: + default: jwt + description: 'Path where the JWT authentication backend is mounted in Vault, e.g: "jwt"' + type: string + role: + description: Role is a JWT role to authenticate using the JWT/OIDC Vault authentication method + type: string + secretRef: + description: Optional SecretRef that refers to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - path + type: object + kubernetes: + description: Kubernetes authenticates with Vault by passing the ServiceAccount token stored in the named Secret resource to the Vault server. + properties: + mountPath: + default: kubernetes + description: 'Path where the Kubernetes authentication backend is mounted in Vault, e.g: "kubernetes"' + type: string + role: + description: A required field containing the Vault Role to assume. A Role binds a Kubernetes ServiceAccount with a set of Vault policies. + type: string + secretRef: + description: Optional secret field containing a Kubernetes ServiceAccount JWT used for authenticating with Vault. If a name is specified without a key, `token` is the default. If one is not specified, the one bound to the controller will be used. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + serviceAccountRef: + description: Optional service account field containing the name of a kubernetes ServiceAccount. If the service account is specified, the service account secret token JWT will be used for authenticating with Vault. If the service account selector is not supplied, the secretRef will be used instead. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - mountPath + - role + type: object + ldap: + description: Ldap authenticates with Vault by passing username/password pair using the LDAP authentication method + properties: + path: + default: ldap + description: 'Path where the LDAP authentication backend is mounted in Vault, e.g: "ldap"' + type: string + secretRef: + description: SecretRef to a key in a Secret resource containing password for the LDAP user used to authenticate with Vault using the LDAP authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + username: + description: Username is a LDAP user name used to authenticate using the LDAP Vault authentication method + type: string + required: + - path + - username + type: object + tokenSecretRef: + description: TokenSecretRef authenticates with Vault by presenting a token. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + caBundle: + description: PEM encoded CA bundle used to validate Vault server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate Vault server certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. Can only be defined when used in a ClusterSecretStore. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + forwardInconsistent: + description: ForwardInconsistent tells Vault to forward read-after-write requests to the Vault leader instead of simply retrying within a loop. This can increase performance if the option is enabled serverside. https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header + type: boolean + namespace: + description: 'Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1". More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces' + type: string + path: + description: 'Path is the mount path of the Vault KV backend endpoint, e.g: "secret". The v2 KV secret engine version specific "/data" path suffix for fetching secrets from Vault is optional and will be appended if not present in specified path.' + type: string + readYourWrites: + description: ReadYourWrites ensures isolated read-after-write semantics by providing discovered cluster replication states in each request. More information about eventual consistency in Vault can be found here https://www.vaultproject.io/docs/enterprise/consistency + type: boolean + server: + description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' + type: string + version: + default: v2 + description: Version is the Vault KV secret engine version. This can be either "v1" or "v2". Version defaults to "v2". + enum: + - v1 + - v2 + type: string + required: + - auth + - server + type: object + webhook: + description: Webhook configures this store to sync secrets using a generic templated webhook + properties: + body: + description: Body + type: string + caBundle: + description: PEM encoded CA bundle used to validate webhook server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate webhook server certificate. + properties: + key: + description: The key the value inside of the provider type to use, only used with "Secret" type + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + headers: + additionalProperties: + type: string + description: Headers + type: object + method: + description: Webhook Method + type: string + result: + description: Result formatting + properties: + jsonPath: + description: Json path of return value + type: string + type: object + secrets: + description: Secrets to fill in templates These secrets will be passed to the templating function as key value pairs under the given name + items: + properties: + name: + description: Name of this secret in templates + type: string + secretRef: + description: Secret ref to fill in credentials + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - name + - secretRef + type: object + type: array + timeout: + description: Timeout + type: string + url: + description: Webhook url to call + type: string + required: + - result + - url + type: object + yandexcertificatemanager: + description: YandexCertificateManager configures this store to sync secrets using Yandex Certificate Manager provider + properties: + apiEndpoint: + description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') + type: string + auth: + description: Auth defines the information necessary to authenticate against Yandex Certificate Manager + properties: + authorizedKeySecretRef: + description: The authorized key used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + caProvider: + description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. + properties: + certSecretRef: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - auth + type: object + yandexlockbox: + description: YandexLockbox configures this store to sync secrets using Yandex Lockbox provider + properties: + apiEndpoint: + description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') + type: string + auth: + description: Auth defines the information necessary to authenticate against Yandex Lockbox + properties: + authorizedKeySecretRef: + description: The authorized key used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + caProvider: + description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. + properties: + certSecretRef: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - auth + type: object + type: object + refreshInterval: + description: Used to configure store refresh interval in seconds. Empty or 0 will default to the controller config. + type: integer + retrySettings: + description: Used to configure http retries if failed + properties: + maxRetries: + format: int32 + type: integer + retryInterval: + type: string + type: object + required: + - provider + type: object + status: + description: SecretStoreStatus defines the observed state of the SecretStore. + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: golang-external-secrets-webhook + namespace: "default" + path: /convert +--- +# Source: golang-external-secrets/charts/external-secrets/templates/crds/externalsecret.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: externalsecrets.external-secrets.io +spec: + group: external-secrets.io + names: + categories: + - externalsecrets + kind: ExternalSecret + listKind: ExternalSecretList + plural: externalsecrets + shortNames: + - es + singular: externalsecret + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.secretStoreRef.name + name: Store + type: string + - jsonPath: .spec.refreshInterval + name: Refresh Interval + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + deprecated: true + name: v1alpha1 + schema: + openAPIV3Schema: + description: ExternalSecret is the Schema for the external-secrets 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: ExternalSecretSpec defines the desired state of ExternalSecret. + properties: + data: + description: Data defines the connection between the Kubernetes Secret keys and the Provider data + items: + description: ExternalSecretData defines the connection between the Kubernetes Secret key (spec.data.) and the Provider data. + properties: + remoteRef: + description: ExternalSecretDataRemoteRef defines Provider data location. + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + type: string + key: + description: Key is the key used in the Provider, mandatory + type: string + property: + description: Used to select a specific property of the Provider value (if a map), if supported + type: string + version: + description: Used to select a specific version of the Provider value, if supported + type: string + required: + - key + type: object + secretKey: + type: string + required: + - remoteRef + - secretKey + type: object + type: array + dataFrom: + description: DataFrom is used to fetch all properties from a specific Provider data If multiple entries are specified, the Secret keys are merged in the specified order + items: + description: ExternalSecretDataRemoteRef defines Provider data location. + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + type: string + key: + description: Key is the key used in the Provider, mandatory + type: string + property: + description: Used to select a specific property of the Provider value (if a map), if supported + type: string + version: + description: Used to select a specific version of the Provider value, if supported + type: string + required: + - key + type: object + type: array + refreshInterval: + default: 1h + description: RefreshInterval is the amount of time before the values are read again from the SecretStore provider Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h" May be set to zero to fetch and create it once. Defaults to 1h. + type: string + secretStoreRef: + description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret data. + properties: + kind: + description: Kind of the SecretStore resource (SecretStore or ClusterSecretStore) Defaults to `SecretStore` + type: string + name: + description: Name of the SecretStore resource + type: string + required: + - name + type: object + target: + description: ExternalSecretTarget defines the Kubernetes Secret to be created There can be only one target per ExternalSecret. + properties: + creationPolicy: + default: Owner + description: CreationPolicy defines rules on how to create the resulting Secret Defaults to 'Owner' + type: string + immutable: + description: Immutable defines if the final secret will be immutable + type: boolean + name: + description: Name defines the name of the Secret resource to be managed This field is immutable Defaults to the .metadata.name of the ExternalSecret resource + type: string + template: + description: Template defines a blueprint for the created Secret resource. + properties: + data: + additionalProperties: + type: string + type: object + engineVersion: + default: v1 + description: EngineVersion specifies the template engine version that should be used to compile/execute the template specified in .data and .templateFrom[]. + type: string + metadata: + description: ExternalSecretTemplateMetadata defines metadata fields for the Secret blueprint. + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + templateFrom: + items: + maxProperties: 1 + minProperties: 1 + properties: + configMap: + properties: + items: + items: + properties: + key: + type: string + required: + - key + type: object + type: array + name: + type: string + required: + - items + - name + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + required: + - key + type: object + type: array + name: + type: string + required: + - items + - name + type: object + type: object + type: array + type: + type: string + type: object + type: object + required: + - secretStoreRef + - target + type: object + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + refreshTime: + description: refreshTime is the time and date the external secret was fetched and the target secret updated + format: date-time + nullable: true + type: string + syncedResourceVersion: + description: SyncedResourceVersion keeps track of the last synced version + type: string + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.secretStoreRef.name + name: Store + type: string + - jsonPath: .spec.refreshInterval + name: Refresh Interval + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: ExternalSecret is the Schema for the external-secrets 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: ExternalSecretSpec defines the desired state of ExternalSecret. + properties: + data: + description: Data defines the connection between the Kubernetes Secret keys and the Provider data + items: + description: ExternalSecretData defines the connection between the Kubernetes Secret key (spec.data.) and the Provider data. + properties: + remoteRef: + description: ExternalSecretDataRemoteRef defines Provider data location. + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + type: string + decodingStrategy: + default: None + description: Used to define a decoding Strategy + type: string + key: + description: Key is the key used in the Provider, mandatory + type: string + metadataPolicy: + description: Policy for fetching tags/labels from provider secrets, possible options are Fetch, None. Defaults to None + type: string + property: + description: Used to select a specific property of the Provider value (if a map), if supported + type: string + version: + description: Used to select a specific version of the Provider value, if supported + type: string + required: + - key + type: object + secretKey: + type: string + required: + - remoteRef + - secretKey + type: object + type: array + dataFrom: + description: DataFrom is used to fetch all properties from a specific Provider data If multiple entries are specified, the Secret keys are merged in the specified order + items: + properties: + extract: + description: Used to extract multiple key/value pairs from one secret + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + type: string + decodingStrategy: + default: None + description: Used to define a decoding Strategy + type: string + key: + description: Key is the key used in the Provider, mandatory + type: string + metadataPolicy: + description: Policy for fetching tags/labels from provider secrets, possible options are Fetch, None. Defaults to None + type: string + property: + description: Used to select a specific property of the Provider value (if a map), if supported + type: string + version: + description: Used to select a specific version of the Provider value, if supported + type: string + required: + - key + type: object + find: + description: Used to find secrets based on tags or regular expressions + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + type: string + decodingStrategy: + default: None + description: Used to define a decoding Strategy + type: string + name: + description: Finds secrets based on the name. + properties: + regexp: + description: Finds secrets base + type: string + type: object + path: + description: A root path to start the find operations. + type: string + tags: + additionalProperties: + type: string + description: Find secrets based on tags. + type: object + type: object + rewrite: + description: Used to rewrite secret Keys after getting them from the secret Provider Multiple Rewrite operations can be provided. They are applied in a layered order (first to last) + items: + properties: + regexp: + description: Used to rewrite with regular expressions. The resulting key will be the output of a regexp.ReplaceAll operation. + properties: + source: + description: Used to define the regular expression of a re.Compiler. + type: string + target: + description: Used to define the target pattern of a ReplaceAll operation. + type: string + required: + - source + - target + type: object + type: object + type: array + type: object + type: array + refreshInterval: + default: 1h + description: RefreshInterval is the amount of time before the values are read again from the SecretStore provider Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h" May be set to zero to fetch and create it once. Defaults to 1h. + type: string + secretStoreRef: + description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret data. + properties: + kind: + description: Kind of the SecretStore resource (SecretStore or ClusterSecretStore) Defaults to `SecretStore` + type: string + name: + description: Name of the SecretStore resource + type: string + required: + - name + type: object + target: + description: ExternalSecretTarget defines the Kubernetes Secret to be created There can be only one target per ExternalSecret. + properties: + creationPolicy: + default: Owner + description: CreationPolicy defines rules on how to create the resulting Secret Defaults to 'Owner' + enum: + - Owner + - Orphan + - Merge + - None + type: string + deletionPolicy: + default: Retain + description: DeletionPolicy defines rules on how to delete the resulting Secret Defaults to 'Retain' + enum: + - Delete + - Merge + - Retain + type: string + immutable: + description: Immutable defines if the final secret will be immutable + type: boolean + name: + description: Name defines the name of the Secret resource to be managed This field is immutable Defaults to the .metadata.name of the ExternalSecret resource + type: string + template: + description: Template defines a blueprint for the created Secret resource. + properties: + data: + additionalProperties: + type: string + type: object + engineVersion: + default: v2 + type: string + metadata: + description: ExternalSecretTemplateMetadata defines metadata fields for the Secret blueprint. + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + templateFrom: + items: + maxProperties: 1 + minProperties: 1 + properties: + configMap: + properties: + items: + items: + properties: + key: + type: string + required: + - key + type: object + type: array + name: + type: string + required: + - items + - name + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + required: + - key + type: object + type: array + name: + type: string + required: + - items + - name + type: object + type: object + type: array + type: + type: string + type: object + type: object + required: + - secretStoreRef + type: object + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + refreshTime: + description: refreshTime is the time and date the external secret was fetched and the target secret updated + format: date-time + nullable: true + type: string + syncedResourceVersion: + description: SyncedResourceVersion keeps track of the last synced version + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: golang-external-secrets-webhook + namespace: "default" + path: /convert +--- +# Source: golang-external-secrets/charts/external-secrets/templates/crds/secretstore.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: secretstores.external-secrets.io +spec: + group: external-secrets.io + names: + categories: + - externalsecrets + kind: SecretStore + listKind: SecretStoreList + plural: secretstores + shortNames: + - ss + singular: secretstore + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + deprecated: true + name: v1alpha1 + schema: + openAPIV3Schema: + description: SecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields. + 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: SecretStoreSpec defines the desired state of SecretStore. + properties: + controller: + description: 'Used to select the correct KES controller (think: ingress.ingressClassName) The KES controller is instantiated with a specific controller name and filters ES based on this property' + type: string + provider: + description: Used to configure the provider. Only one provider may be set + maxProperties: 1 + minProperties: 1 + properties: + akeyless: + description: Akeyless configures this store to sync secrets using Akeyless Vault provider + properties: + akeylessGWApiURL: + description: Akeyless GW API Url from which the secrets to be fetched from. + type: string + authSecretRef: + description: Auth configures how the operator authenticates with Akeyless. + properties: + secretRef: + description: 'AkeylessAuthSecretRef AKEYLESS_ACCESS_TYPE_PARAM: AZURE_OBJ_ID OR GCP_AUDIENCE OR ACCESS_KEY OR KUB_CONFIG_NAME.' + properties: + accessID: + description: The SecretAccessID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessType: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessTypeParam: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + required: + - akeylessGWApiURL + - authSecretRef + type: object + alibaba: + description: Alibaba configures this store to sync secrets using Alibaba Cloud provider + properties: + auth: + description: AlibabaAuth contains a secretRef for credentials. + properties: + secretRef: + description: AlibabaAuthSecretRef holds secret references for Alibaba credentials. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessKeySecretSecretRef: + description: The AccessKeySecret is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - accessKeyIDSecretRef + - accessKeySecretSecretRef + type: object + required: + - secretRef + type: object + endpoint: + type: string + regionID: + description: Alibaba Region to be used for the provider + type: string + required: + - auth + - regionID + type: object + aws: + description: AWS configures this store to sync secrets using AWS Secret Manager provider + properties: + auth: + description: 'Auth defines the information necessary to authenticate against AWS if not set aws sdk will infer credentials from your environment see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' + properties: + jwt: + description: Authenticate against AWS using service account tokens. + properties: + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + type: object + secretRef: + description: AWSAuthSecretRef holds secret references for AWS credentials both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + type: object + region: + description: AWS Region to be used for the provider + type: string + role: + description: Role is a Role ARN which the SecretManager provider will assume + type: string + service: + description: Service defines which service should be used to fetch the secrets + enum: + - SecretsManager + - ParameterStore + type: string + required: + - region + - service + type: object + azurekv: + description: AzureKV configures this store to sync secrets using Azure Key Vault provider + properties: + authSecretRef: + description: Auth configures how the operator authenticates with Azure. Required for ServicePrincipal auth type. + properties: + clientId: + description: The Azure clientId of the service principle used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + clientSecret: + description: The Azure ClientSecret of the service principle used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + authType: + default: ServicePrincipal + description: 'Auth type defines how to authenticate to the keyvault service. Valid values are: - "ServicePrincipal" (default): Using a service principal (tenantId, clientId, clientSecret) - "ManagedIdentity": Using Managed Identity assigned to the pod (see aad-pod-identity)' + enum: + - ServicePrincipal + - ManagedIdentity + - WorkloadIdentity + type: string + identityId: + description: If multiple Managed Identity is assigned to the pod, you can select the one to be used + type: string + serviceAccountRef: + description: ServiceAccountRef specified the service account that should be used when authenticating with WorkloadIdentity. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + tenantId: + description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. + type: string + vaultUrl: + description: Vault Url from which the secrets to be fetched from. + type: string + required: + - vaultUrl + type: object + fake: + description: Fake configures a store with static key/value pairs + properties: + data: + items: + properties: + key: + type: string + value: + type: string + valueMap: + additionalProperties: + type: string + type: object + version: + type: string + required: + - key + type: object + type: array + required: + - data + type: object + gcpsm: + description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider + properties: + auth: + description: Auth defines the information necessary to authenticate against GCP + properties: + secretRef: + properties: + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + workloadIdentity: + properties: + clusterLocation: + type: string + clusterName: + type: string + clusterProjectID: + type: string + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - clusterLocation + - clusterName + - serviceAccountRef + type: object + type: object + projectID: + description: ProjectID project where secret is located + type: string + type: object + gitlab: + description: Gitlab configures this store to sync secrets using Gitlab Variables provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a GitLab instance. + properties: + SecretRef: + properties: + accessToken: + description: AccessToken is used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - SecretRef + type: object + projectID: + description: ProjectID specifies a project where secrets are located. + type: string + url: + description: URL configures the GitLab instance URL. Defaults to https://gitlab.com/. + type: string + required: + - auth + type: object + ibm: + description: IBM configures this store to sync secrets using IBM Cloud provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the IBM secrets manager. + properties: + secretRef: + properties: + secretApiKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + serviceUrl: + description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance + type: string + required: + - auth + type: object + kubernetes: + description: Kubernetes configures this store to sync secrets using a Kubernetes cluster provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Kubernetes instance. + maxProperties: 1 + minProperties: 1 + properties: + cert: + description: has both clientCert and clientKey as secretKeySelector + properties: + clientCert: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + clientKey: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + serviceAccount: + description: points to a service account that should be used for authentication + properties: + serviceAccount: + description: A reference to a ServiceAccount resource. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + type: object + token: + description: use static token to authenticate with + properties: + bearerToken: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + type: object + remoteNamespace: + default: default + description: Remote namespace to fetch the secrets from + type: string + server: + description: configures the Kubernetes server Address. + properties: + caBundle: + description: CABundle is a base64-encoded CA certificate + format: byte + type: string + caProvider: + description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider' + properties: + key: + description: The key the value inside of the provider type to use, only used with "Secret" type + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + url: + default: kubernetes.default + description: configures the Kubernetes server Address. + type: string + type: object + required: + - auth + type: object + oracle: + description: Oracle configures this store to sync secrets using Oracle Vault provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the Oracle Vault. If empty, use the instance principal, otherwise the user credentials specified in Auth. + properties: + secretRef: + description: SecretRef to pass through sensitive information. + properties: + fingerprint: + description: Fingerprint is the fingerprint of the API private key. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + privatekey: + description: PrivateKey is the user's API Signing Key in PEM format, used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - fingerprint + - privatekey + type: object + tenancy: + description: Tenancy is the tenancy OCID where user is located. + type: string + user: + description: User is an access OCID specific to the account. + type: string + required: + - secretRef + - tenancy + - user + type: object + region: + description: Region is the region where vault is located. + type: string + vault: + description: Vault is the vault's OCID of the specific vault where secret is located. + type: string + required: + - region + - vault + type: object + vault: + description: Vault configures this store to sync secrets using Hashi provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the Vault server. + properties: + appRole: + description: AppRole authenticates with Vault using the App Role auth mechanism, with the role and secret stored in a Kubernetes Secret resource. + properties: + path: + default: approle + description: 'Path where the App Role authentication backend is mounted in Vault, e.g: "approle"' + type: string + roleId: + description: RoleID configured in the App Role authentication backend when setting up the authentication backend in Vault. + type: string + secretRef: + description: Reference to a key in a Secret that contains the App Role secret used to authenticate with Vault. The `key` field must be specified and denotes which entry within the Secret resource is used as the app role secret. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - path + - roleId + - secretRef + type: object + cert: + description: Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate Cert authentication method + properties: + clientCert: + description: ClientCert is a certificate to authenticate using the Cert Vault authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + secretRef: + description: SecretRef to a key in a Secret resource containing client private key to authenticate with Vault using the Cert authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + jwt: + description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method + properties: + kubernetesServiceAccountToken: + description: Optional ServiceAccountToken specifies the Kubernetes service account for which to request a token for with the `TokenRequest` API. + properties: + audiences: + description: Optional audiences field that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to a single audience `vault` it not specified. + items: + type: string + type: array + expirationSeconds: + description: Optional expiration time in seconds that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to 10 minutes. + format: int64 + type: integer + serviceAccountRef: + description: Service account field containing the name of a kubernetes ServiceAccount. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - serviceAccountRef + type: object + path: + default: jwt + description: 'Path where the JWT authentication backend is mounted in Vault, e.g: "jwt"' + type: string + role: + description: Role is a JWT role to authenticate using the JWT/OIDC Vault authentication method + type: string + secretRef: + description: Optional SecretRef that refers to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - path + type: object + kubernetes: + description: Kubernetes authenticates with Vault by passing the ServiceAccount token stored in the named Secret resource to the Vault server. + properties: + mountPath: + default: kubernetes + description: 'Path where the Kubernetes authentication backend is mounted in Vault, e.g: "kubernetes"' + type: string + role: + description: A required field containing the Vault Role to assume. A Role binds a Kubernetes ServiceAccount with a set of Vault policies. + type: string + secretRef: + description: Optional secret field containing a Kubernetes ServiceAccount JWT used for authenticating with Vault. If a name is specified without a key, `token` is the default. If one is not specified, the one bound to the controller will be used. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + serviceAccountRef: + description: Optional service account field containing the name of a kubernetes ServiceAccount. If the service account is specified, the service account secret token JWT will be used for authenticating with Vault. If the service account selector is not supplied, the secretRef will be used instead. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - mountPath + - role + type: object + ldap: + description: Ldap authenticates with Vault by passing username/password pair using the LDAP authentication method + properties: + path: + default: ldap + description: 'Path where the LDAP authentication backend is mounted in Vault, e.g: "ldap"' + type: string + secretRef: + description: SecretRef to a key in a Secret resource containing password for the LDAP user used to authenticate with Vault using the LDAP authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + username: + description: Username is a LDAP user name used to authenticate using the LDAP Vault authentication method + type: string + required: + - path + - username + type: object + tokenSecretRef: + description: TokenSecretRef authenticates with Vault by presenting a token. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + caBundle: + description: PEM encoded CA bundle used to validate Vault server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate Vault server certificate. + properties: + key: + description: The key the value inside of the provider type to use, only used with "Secret" type + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + forwardInconsistent: + description: ForwardInconsistent tells Vault to forward read-after-write requests to the Vault leader instead of simply retrying within a loop. This can increase performance if the option is enabled serverside. https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header + type: boolean + namespace: + description: 'Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1". More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces' + type: string + path: + description: 'Path is the mount path of the Vault KV backend endpoint, e.g: "secret". The v2 KV secret engine version specific "/data" path suffix for fetching secrets from Vault is optional and will be appended if not present in specified path.' + type: string + readYourWrites: + description: ReadYourWrites ensures isolated read-after-write semantics by providing discovered cluster replication states in each request. More information about eventual consistency in Vault can be found here https://www.vaultproject.io/docs/enterprise/consistency + type: boolean + server: + description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' + type: string + version: + default: v2 + description: Version is the Vault KV secret engine version. This can be either "v1" or "v2". Version defaults to "v2". + enum: + - v1 + - v2 + type: string + required: + - auth + - server + type: object + webhook: + description: Webhook configures this store to sync secrets using a generic templated webhook + properties: + body: + description: Body + type: string + caBundle: + description: PEM encoded CA bundle used to validate webhook server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate webhook server certificate. + properties: + key: + description: The key the value inside of the provider type to use, only used with "Secret" type + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + headers: + additionalProperties: + type: string + description: Headers + type: object + method: + description: Webhook Method + type: string + result: + description: Result formatting + properties: + jsonPath: + description: Json path of return value + type: string + type: object + secrets: + description: Secrets to fill in templates These secrets will be passed to the templating function as key value pairs under the given name + items: + properties: + name: + description: Name of this secret in templates + type: string + secretRef: + description: Secret ref to fill in credentials + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - name + - secretRef + type: object + type: array + timeout: + description: Timeout + type: string + url: + description: Webhook url to call + type: string + required: + - result + - url + type: object + yandexlockbox: + description: YandexLockbox configures this store to sync secrets using Yandex Lockbox provider + properties: + apiEndpoint: + description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') + type: string + auth: + description: Auth defines the information necessary to authenticate against Yandex Lockbox + properties: + authorizedKeySecretRef: + description: The authorized key used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + caProvider: + description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. + properties: + certSecretRef: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - auth + type: object + type: object + retrySettings: + description: Used to configure http retries if failed + properties: + maxRetries: + format: int32 + type: integer + retryInterval: + type: string + type: object + required: + - provider + type: object + status: + description: SecretStoreStatus defines the observed state of the SecretStore. + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: SecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields. + 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: SecretStoreSpec defines the desired state of SecretStore. + properties: + controller: + description: 'Used to select the correct KES controller (think: ingress.ingressClassName) The KES controller is instantiated with a specific controller name and filters ES based on this property' + type: string + provider: + description: Used to configure the provider. Only one provider may be set + maxProperties: 1 + minProperties: 1 + properties: + akeyless: + description: Akeyless configures this store to sync secrets using Akeyless Vault provider + properties: + akeylessGWApiURL: + description: Akeyless GW API Url from which the secrets to be fetched from. + type: string + authSecretRef: + description: Auth configures how the operator authenticates with Akeyless. + properties: + secretRef: + description: 'AkeylessAuthSecretRef AKEYLESS_ACCESS_TYPE_PARAM: AZURE_OBJ_ID OR GCP_AUDIENCE OR ACCESS_KEY OR KUB_CONFIG_NAME.' + properties: + accessID: + description: The SecretAccessID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessType: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessTypeParam: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + required: + - akeylessGWApiURL + - authSecretRef + type: object + alibaba: + description: Alibaba configures this store to sync secrets using Alibaba Cloud provider + properties: + auth: + description: AlibabaAuth contains a secretRef for credentials. + properties: + secretRef: + description: AlibabaAuthSecretRef holds secret references for Alibaba credentials. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessKeySecretSecretRef: + description: The AccessKeySecret is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - accessKeyIDSecretRef + - accessKeySecretSecretRef + type: object + required: + - secretRef + type: object + endpoint: + type: string + regionID: + description: Alibaba Region to be used for the provider + type: string + required: + - auth + - regionID + type: object + aws: + description: AWS configures this store to sync secrets using AWS Secret Manager provider + properties: + auth: + description: 'Auth defines the information necessary to authenticate against AWS if not set aws sdk will infer credentials from your environment see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' + properties: + jwt: + description: Authenticate against AWS using service account tokens. + properties: + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + type: object + secretRef: + description: AWSAuthSecretRef holds secret references for AWS credentials both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + type: object + region: + description: AWS Region to be used for the provider + type: string + role: + description: Role is a Role ARN which the SecretManager provider will assume + type: string + service: + description: Service defines which service should be used to fetch the secrets + enum: + - SecretsManager + - ParameterStore + type: string + required: + - region + - service + type: object + azurekv: + description: AzureKV configures this store to sync secrets using Azure Key Vault provider + properties: + authSecretRef: + description: Auth configures how the operator authenticates with Azure. Required for ServicePrincipal auth type. + properties: + clientId: + description: The Azure clientId of the service principle used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + clientSecret: + description: The Azure ClientSecret of the service principle used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + authType: + default: ServicePrincipal + description: 'Auth type defines how to authenticate to the keyvault service. Valid values are: - "ServicePrincipal" (default): Using a service principal (tenantId, clientId, clientSecret) - "ManagedIdentity": Using Managed Identity assigned to the pod (see aad-pod-identity)' + enum: + - ServicePrincipal + - ManagedIdentity + - WorkloadIdentity + type: string + identityId: + description: If multiple Managed Identity is assigned to the pod, you can select the one to be used + type: string + serviceAccountRef: + description: ServiceAccountRef specified the service account that should be used when authenticating with WorkloadIdentity. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + tenantId: + description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. + type: string + vaultUrl: + description: Vault Url from which the secrets to be fetched from. + type: string + required: + - vaultUrl + type: object + fake: + description: Fake configures a store with static key/value pairs + properties: + data: + items: + properties: + key: + type: string + value: + type: string + valueMap: + additionalProperties: + type: string + type: object + version: + type: string + required: + - key + type: object + type: array + required: + - data + type: object + gcpsm: + description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider + properties: + auth: + description: Auth defines the information necessary to authenticate against GCP + properties: + secretRef: + properties: + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + workloadIdentity: + properties: + clusterLocation: + type: string + clusterName: + type: string + clusterProjectID: + type: string + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - clusterLocation + - clusterName + - serviceAccountRef + type: object + type: object + projectID: + description: ProjectID project where secret is located + type: string + type: object + gitlab: + description: Gitlab configures this store to sync secrets using Gitlab Variables provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a GitLab instance. + properties: + SecretRef: + properties: + accessToken: + description: AccessToken is used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - SecretRef + type: object + projectID: + description: ProjectID specifies a project where secrets are located. + type: string + url: + description: URL configures the GitLab instance URL. Defaults to https://gitlab.com/. + type: string + required: + - auth + type: object + ibm: + description: IBM configures this store to sync secrets using IBM Cloud provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the IBM secrets manager. + maxProperties: 1 + minProperties: 1 + properties: + containerAuth: + description: IBM Container-based auth with IAM Trusted Profile. + properties: + iamEndpoint: + type: string + profile: + description: the IBM Trusted Profile + type: string + tokenLocation: + description: Location the token is mounted on the pod + type: string + required: + - profile + type: object + secretRef: + properties: + secretApiKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + type: object + serviceUrl: + description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance + type: string + required: + - auth + type: object + kubernetes: + description: Kubernetes configures this store to sync secrets using a Kubernetes cluster provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Kubernetes instance. + maxProperties: 1 + minProperties: 1 + properties: + cert: + description: has both clientCert and clientKey as secretKeySelector + properties: + clientCert: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + clientKey: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + serviceAccount: + description: points to a service account that should be used for authentication + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + token: + description: use static token to authenticate with + properties: + bearerToken: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + type: object + remoteNamespace: + default: default + description: Remote namespace to fetch the secrets from + type: string + server: + description: configures the Kubernetes server Address. + properties: + caBundle: + description: CABundle is a base64-encoded CA certificate + format: byte + type: string + caProvider: + description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider' + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. Can only be defined when used in a ClusterSecretStore. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + url: + default: kubernetes.default + description: configures the Kubernetes server Address. + type: string + type: object + required: + - auth + type: object + onepassword: + description: OnePassword configures this store to sync secrets using the 1Password Cloud provider + properties: + auth: + description: Auth defines the information necessary to authenticate against OnePassword Connect Server + properties: + secretRef: + description: OnePasswordAuthSecretRef holds secret references for 1Password credentials. + properties: + connectTokenSecretRef: + description: The ConnectToken is used for authentication to a 1Password Connect Server. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - connectTokenSecretRef + type: object + required: + - secretRef + type: object + connectHost: + description: ConnectHost defines the OnePassword Connect Server to connect to + type: string + vaults: + additionalProperties: + type: integer + description: Vaults defines which OnePassword vaults to search in which order + type: object + required: + - auth + - connectHost + - vaults + type: object + oracle: + description: Oracle configures this store to sync secrets using Oracle Vault provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the Oracle Vault. If empty, use the instance principal, otherwise the user credentials specified in Auth. + properties: + secretRef: + description: SecretRef to pass through sensitive information. + properties: + fingerprint: + description: Fingerprint is the fingerprint of the API private key. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + privatekey: + description: PrivateKey is the user's API Signing Key in PEM format, used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - fingerprint + - privatekey + type: object + tenancy: + description: Tenancy is the tenancy OCID where user is located. + type: string + user: + description: User is an access OCID specific to the account. + type: string + required: + - secretRef + - tenancy + - user + type: object + region: + description: Region is the region where vault is located. + type: string + vault: + description: Vault is the vault's OCID of the specific vault where secret is located. + type: string + required: + - region + - vault + type: object + senhasegura: + description: Senhasegura configures this store to sync secrets using senhasegura provider + properties: + auth: + description: Auth defines parameters to authenticate in senhasegura + properties: + clientId: + type: string + clientSecretSecretRef: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - clientId + - clientSecretSecretRef + type: object + ignoreSslCertificate: + default: false + description: IgnoreSslCertificate defines if SSL certificate must be ignored + type: boolean + module: + description: Module defines which senhasegura module should be used to get secrets + type: string + url: + description: URL of senhasegura + type: string + required: + - auth + - module + - url + type: object + vault: + description: Vault configures this store to sync secrets using Hashi provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the Vault server. + properties: + appRole: + description: AppRole authenticates with Vault using the App Role auth mechanism, with the role and secret stored in a Kubernetes Secret resource. + properties: + path: + default: approle + description: 'Path where the App Role authentication backend is mounted in Vault, e.g: "approle"' + type: string + roleId: + description: RoleID configured in the App Role authentication backend when setting up the authentication backend in Vault. + type: string + secretRef: + description: Reference to a key in a Secret that contains the App Role secret used to authenticate with Vault. The `key` field must be specified and denotes which entry within the Secret resource is used as the app role secret. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - path + - roleId + - secretRef + type: object + cert: + description: Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate Cert authentication method + properties: + clientCert: + description: ClientCert is a certificate to authenticate using the Cert Vault authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + secretRef: + description: SecretRef to a key in a Secret resource containing client private key to authenticate with Vault using the Cert authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + jwt: + description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method + properties: + kubernetesServiceAccountToken: + description: Optional ServiceAccountToken specifies the Kubernetes service account for which to request a token for with the `TokenRequest` API. + properties: + audiences: + description: Optional audiences field that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to a single audience `vault` it not specified. + items: + type: string + type: array + expirationSeconds: + description: Optional expiration time in seconds that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to 10 minutes. + format: int64 + type: integer + serviceAccountRef: + description: Service account field containing the name of a kubernetes ServiceAccount. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - serviceAccountRef + type: object + path: + default: jwt + description: 'Path where the JWT authentication backend is mounted in Vault, e.g: "jwt"' + type: string + role: + description: Role is a JWT role to authenticate using the JWT/OIDC Vault authentication method + type: string + secretRef: + description: Optional SecretRef that refers to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - path + type: object + kubernetes: + description: Kubernetes authenticates with Vault by passing the ServiceAccount token stored in the named Secret resource to the Vault server. + properties: + mountPath: + default: kubernetes + description: 'Path where the Kubernetes authentication backend is mounted in Vault, e.g: "kubernetes"' + type: string + role: + description: A required field containing the Vault Role to assume. A Role binds a Kubernetes ServiceAccount with a set of Vault policies. + type: string + secretRef: + description: Optional secret field containing a Kubernetes ServiceAccount JWT used for authenticating with Vault. If a name is specified without a key, `token` is the default. If one is not specified, the one bound to the controller will be used. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + serviceAccountRef: + description: Optional service account field containing the name of a kubernetes ServiceAccount. If the service account is specified, the service account secret token JWT will be used for authenticating with Vault. If the service account selector is not supplied, the secretRef will be used instead. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - mountPath + - role + type: object + ldap: + description: Ldap authenticates with Vault by passing username/password pair using the LDAP authentication method + properties: + path: + default: ldap + description: 'Path where the LDAP authentication backend is mounted in Vault, e.g: "ldap"' + type: string + secretRef: + description: SecretRef to a key in a Secret resource containing password for the LDAP user used to authenticate with Vault using the LDAP authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + username: + description: Username is a LDAP user name used to authenticate using the LDAP Vault authentication method + type: string + required: + - path + - username + type: object + tokenSecretRef: + description: TokenSecretRef authenticates with Vault by presenting a token. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + caBundle: + description: PEM encoded CA bundle used to validate Vault server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate Vault server certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. Can only be defined when used in a ClusterSecretStore. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + forwardInconsistent: + description: ForwardInconsistent tells Vault to forward read-after-write requests to the Vault leader instead of simply retrying within a loop. This can increase performance if the option is enabled serverside. https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header + type: boolean + namespace: + description: 'Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1". More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces' + type: string + path: + description: 'Path is the mount path of the Vault KV backend endpoint, e.g: "secret". The v2 KV secret engine version specific "/data" path suffix for fetching secrets from Vault is optional and will be appended if not present in specified path.' + type: string + readYourWrites: + description: ReadYourWrites ensures isolated read-after-write semantics by providing discovered cluster replication states in each request. More information about eventual consistency in Vault can be found here https://www.vaultproject.io/docs/enterprise/consistency + type: boolean + server: + description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' + type: string + version: + default: v2 + description: Version is the Vault KV secret engine version. This can be either "v1" or "v2". Version defaults to "v2". + enum: + - v1 + - v2 + type: string + required: + - auth + - server + type: object + webhook: + description: Webhook configures this store to sync secrets using a generic templated webhook + properties: + body: + description: Body + type: string + caBundle: + description: PEM encoded CA bundle used to validate webhook server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate webhook server certificate. + properties: + key: + description: The key the value inside of the provider type to use, only used with "Secret" type + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + headers: + additionalProperties: + type: string + description: Headers + type: object + method: + description: Webhook Method + type: string + result: + description: Result formatting + properties: + jsonPath: + description: Json path of return value + type: string + type: object + secrets: + description: Secrets to fill in templates These secrets will be passed to the templating function as key value pairs under the given name + items: + properties: + name: + description: Name of this secret in templates + type: string + secretRef: + description: Secret ref to fill in credentials + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - name + - secretRef + type: object + type: array + timeout: + description: Timeout + type: string + url: + description: Webhook url to call + type: string + required: + - result + - url + type: object + yandexcertificatemanager: + description: YandexCertificateManager configures this store to sync secrets using Yandex Certificate Manager provider + properties: + apiEndpoint: + description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') + type: string + auth: + description: Auth defines the information necessary to authenticate against Yandex Certificate Manager + properties: + authorizedKeySecretRef: + description: The authorized key used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + caProvider: + description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. + properties: + certSecretRef: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - auth + type: object + yandexlockbox: + description: YandexLockbox configures this store to sync secrets using Yandex Lockbox provider + properties: + apiEndpoint: + description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') + type: string + auth: + description: Auth defines the information necessary to authenticate against Yandex Lockbox + properties: + authorizedKeySecretRef: + description: The authorized key used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + caProvider: + description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. + properties: + certSecretRef: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - auth + type: object + type: object + refreshInterval: + description: Used to configure store refresh interval in seconds. Empty or 0 will default to the controller config. + type: integer + retrySettings: + description: Used to configure http retries if failed + properties: + maxRetries: + format: int32 + type: integer + retryInterval: + type: string + type: object + required: + - provider + type: object + status: + description: SecretStoreStatus defines the observed state of the SecretStore. + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: golang-external-secrets-webhook + namespace: "default" + path: /convert +--- +# Source: golang-external-secrets/charts/external-secrets/templates/cert-controller-rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: golang-external-secrets-cert-controller + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets-cert-controller + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +rules: + - apiGroups: + - "apiextensions.k8s.io" + resources: + - "customresourcedefinitions" + verbs: + - "get" + - "list" + - "watch" + - "update" + - "patch" + - apiGroups: + - "admissionregistration.k8s.io" + resources: + - "validatingwebhookconfigurations" + verbs: + - "get" + - "list" + - "watch" + - "update" + - "patch" + - apiGroups: + - "" + resources: + - "endpoints" + verbs: + - "list" + - "get" + - "watch" + - apiGroups: + - "" + resources: + - "events" + verbs: + - "create" + - "patch" + - apiGroups: + - "" + resources: + - "secrets" + verbs: + - "get" + - "list" + - "watch" + - "update" + - "patch" +--- +# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: golang-external-secrets-controller + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +rules: + - apiGroups: + - "external-secrets.io" + resources: + - "secretstores" + - "clustersecretstores" + - "externalsecrets" + - "clusterexternalsecrets" + verbs: + - "get" + - "list" + - "watch" + - apiGroups: + - "external-secrets.io" + resources: + - "externalsecrets" + - "externalsecrets/status" + - "externalsecrets/finalizers" + - "secretstores" + - "secretstores/status" + - "secretstores/finalizers" + - "clustersecretstores" + - "clustersecretstores/status" + - "clustersecretstores/finalizers" + - "clusterexternalsecrets" + - "clusterexternalsecrets/status" + - "clusterexternalsecrets/finalizers" + verbs: + - "update" + - "patch" + - apiGroups: + - "" + resources: + - "serviceaccounts" + - "namespaces" + verbs: + - "get" + - "list" + - "watch" + - apiGroups: + - "" + resources: + - "configmaps" + verbs: + - "get" + - "list" + - "watch" + - apiGroups: + - "" + resources: + - "secrets" + verbs: + - "get" + - "list" + - "watch" + - "create" + - "update" + - "delete" + - "patch" + - apiGroups: + - "" + resources: + - "serviceaccounts/token" + verbs: + - "create" + - apiGroups: + - "" + resources: + - "events" + verbs: + - "create" + - "patch" + - apiGroups: + - "external-secrets.io" + resources: + - "externalsecrets" + verbs: + - "create" + - "update" +--- +# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: golang-external-secrets-view + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm + rbac.authorization.k8s.io/aggregate-to-view: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" + rbac.authorization.k8s.io/aggregate-to-admin: "true" +rules: + - apiGroups: + - "external-secrets.io" + resources: + - "externalsecrets" + - "secretstores" + - "clustersecretstores" + verbs: + - "get" + - "watch" + - "list" +--- +# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: golang-external-secrets-edit + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm + rbac.authorization.k8s.io/aggregate-to-edit: "true" + rbac.authorization.k8s.io/aggregate-to-admin: "true" +rules: + - apiGroups: + - "external-secrets.io" + resources: + - "externalsecrets" + - "secretstores" + - "clustersecretstores" + verbs: + - "create" + - "delete" + - "deletecollection" + - "patch" + - "update" +--- +# Source: golang-external-secrets/charts/external-secrets/templates/cert-controller-rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: golang-external-secrets-cert-controller + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets-cert-controller + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: golang-external-secrets-cert-controller +subjects: + - name: external-secrets-cert-controller + namespace: "default" + kind: ServiceAccount +--- +# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: golang-external-secrets-controller + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: golang-external-secrets-controller +subjects: + - name: golang-external-secrets + namespace: "default" + kind: ServiceAccount +--- +# Source: golang-external-secrets/templates/golang-external-secrets-hub-clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: role-tokenreview-binding + namespace: default +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator +subjects: +- kind: ServiceAccount + name: golang-external-secrets + namespace: golang-external-secrets +--- +# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: golang-external-secrets-leaderelection + namespace: "default" + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +rules: + - apiGroups: + - "" + resources: + - "configmaps" + resourceNames: + - "external-secrets-controller" + verbs: + - "get" + - "update" + - "patch" + - apiGroups: + - "" + resources: + - "configmaps" + verbs: + - "create" + - apiGroups: + - "coordination.k8s.io" + resources: + - "leases" + verbs: + - "get" + - "create" + - "update" + - "patch" +--- +# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: golang-external-secrets-leaderelection + namespace: "default" + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: golang-external-secrets-leaderelection +subjects: + - kind: ServiceAccount + name: golang-external-secrets + namespace: "default" +--- +# Source: golang-external-secrets/charts/external-secrets/templates/webhook-service.yaml +apiVersion: v1 +kind: Service +metadata: + name: golang-external-secrets-webhook + namespace: "default" + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets-webhook + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm + external-secrets.io/component : webhook +spec: + type: ClusterIP + ports: + - port: 443 + targetPort: 10250 + protocol: TCP + name: webhook + selector: + app.kubernetes.io/name: external-secrets-webhook + app.kubernetes.io/instance: golang-external-secrets +--- +# Source: golang-external-secrets/charts/external-secrets/templates/cert-controller-deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: golang-external-secrets-cert-controller + namespace: "default" + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets-cert-controller + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: external-secrets-cert-controller + app.kubernetes.io/instance: golang-external-secrets + template: + metadata: + labels: + app.kubernetes.io/name: external-secrets-cert-controller + app.kubernetes.io/instance: golang-external-secrets + spec: + serviceAccountName: external-secrets-cert-controller + containers: + - name: cert-controller + image: "ghcr.io/external-secrets/external-secrets:v0.5.9" + imagePullPolicy: IfNotPresent + args: + - certcontroller + - --crd-requeue-interval=5m + - --service-name=golang-external-secrets-webhook + - --service-namespace=default + - --secret-name=golang-external-secrets-webhook + - --secret-namespace=default + ports: + - containerPort: 8080 + protocol: TCP + name: metrics + readinessProbe: + httpGet: + port: 8081 + path: /readyz + initialDelaySeconds: 20 + periodSeconds: 5 +--- +# Source: golang-external-secrets/charts/external-secrets/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: golang-external-secrets + namespace: "default" + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: external-secrets + app.kubernetes.io/instance: golang-external-secrets + template: + metadata: + labels: + app.kubernetes.io/name: external-secrets + app.kubernetes.io/instance: golang-external-secrets + spec: + serviceAccountName: golang-external-secrets + containers: + - name: external-secrets + image: "ghcr.io/external-secrets/external-secrets:v0.5.9" + imagePullPolicy: IfNotPresent + args: + - --concurrent=1 + ports: + - containerPort: 8080 + protocol: TCP + name: metrics +--- +# Source: golang-external-secrets/charts/external-secrets/templates/webhook-deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: golang-external-secrets-webhook + namespace: "default" + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets-webhook + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: external-secrets-webhook + app.kubernetes.io/instance: golang-external-secrets + template: + metadata: + labels: + app.kubernetes.io/name: external-secrets-webhook + app.kubernetes.io/instance: golang-external-secrets + spec: + hostNetwork: false + serviceAccountName: external-secrets-webhook + containers: + - name: webhook + image: "ghcr.io/external-secrets/external-secrets:v0.5.9" + imagePullPolicy: IfNotPresent + args: + - webhook + - --port=10250 + - --dns-name=golang-external-secrets-webhook.default.svc + - --cert-dir=/tmp/certs + - --check-interval=5m + ports: + - containerPort: 8080 + protocol: TCP + name: metrics + - containerPort: 10250 + protocol: TCP + name: webhook + readinessProbe: + httpGet: + port: 8081 + path: /readyz + initialDelaySeconds: 20 + periodSeconds: 5 + volumeMounts: + - name: certs + mountPath: /tmp/certs + readOnly: true + volumes: + - name: certs + secret: + secretName: golang-external-secrets-webhook +--- +# Source: golang-external-secrets/templates/golang-external-secrets-hub-secretstore.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ClusterSecretStore +metadata: + name: vault-backend + namespace: golang-external-secrets +spec: + provider: + vault: + server: https://vault-vault.hub.example.com + path: secret + # Version of KV backend + version: v2 + caProvider: + type: ConfigMap + name: kube-root-ca.crt + key: ca.crt + namespace: golang-external-secrets + auth: + kubernetes: + mountPath: hub + role: hub-role + secretRef: + name: golang-external-secrets + namespace: golang-external-secrets + key: "token" +--- +# Source: golang-external-secrets/charts/external-secrets/templates/validatingwebhook.yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: secretstore-validate + labels: + external-secrets.io/component: webhook +webhooks: +- name: "validate.secretstore.external-secrets.io" + rules: + - apiGroups: ["external-secrets.io"] + apiVersions: ["v1beta1"] + operations: ["CREATE", "UPDATE", "DELETE"] + resources: ["secretstores"] + scope: "Namespaced" + clientConfig: + service: + namespace: "default" + name: golang-external-secrets-webhook + path: /validate-external-secrets-io-v1beta1-secretstore + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + +- name: "validate.clustersecretstore.external-secrets.io" + rules: + - apiGroups: ["external-secrets.io"] + apiVersions: ["v1beta1"] + operations: ["CREATE", "UPDATE", "DELETE"] + resources: ["clustersecretstores"] + scope: "Cluster" + clientConfig: + service: + namespace: "default" + name: golang-external-secrets-webhook + path: /validate-external-secrets-io-v1beta1-clustersecretstore + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 +--- +# Source: golang-external-secrets/charts/external-secrets/templates/validatingwebhook.yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: externalsecret-validate + labels: + external-secrets.io/component: webhook +webhooks: +- name: "validate.externalsecret.external-secrets.io" + rules: + - apiGroups: ["external-secrets.io"] + apiVersions: ["v1beta1"] + operations: ["CREATE", "UPDATE", "DELETE"] + resources: ["externalsecrets"] + scope: "Namespaced" + clientConfig: + service: + namespace: "default" + name: golang-external-secrets-webhook + path: /validate-external-secrets-io-v1beta1-externalsecret + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + failurePolicy: Fail diff --git a/tests/golang-external-secrets-normal.expected.yml b/tests/golang-external-secrets-normal.expected.yml new file mode 100644 index 00000000..872b07de --- /dev/null +++ b/tests/golang-external-secrets-normal.expected.yml @@ -0,0 +1,5911 @@ +--- +# Source: golang-external-secrets/charts/external-secrets/templates/cert-controller-serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: external-secrets-cert-controller + namespace: "default" + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets-cert-controller + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +--- +# Source: golang-external-secrets/charts/external-secrets/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: golang-external-secrets + namespace: "default" + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +--- +# Source: golang-external-secrets/charts/external-secrets/templates/webhook-serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: external-secrets-webhook + namespace: "default" + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets-webhook + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +--- +# Source: golang-external-secrets/charts/external-secrets/templates/webhook-secret.yaml +apiVersion: v1 +kind: Secret +metadata: + name: golang-external-secrets-webhook + namespace: "default" + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets-webhook + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm + external-secrets.io/component : webhook +--- +# Source: golang-external-secrets/templates/golang-external-secrets-hub-clusterrolebinding.yaml +apiVersion: v1 +kind: Secret +metadata: + name: golang-external-secrets + namespace: golang-external-secrets + annotations: + kubernetes.io/service-account.name: golang-external-secrets +type: kubernetes.io/service-account-token +--- +# Source: golang-external-secrets/charts/external-secrets/templates/crds/clusterexternalsecret.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: clusterexternalsecrets.external-secrets.io +spec: + group: external-secrets.io + names: + categories: + - externalsecrets + kind: ClusterExternalSecret + listKind: ClusterExternalSecretList + plural: clusterexternalsecrets + shortNames: + - ces + singular: clusterexternalsecret + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .spec.secretStoreRef.name + name: Store + type: string + - jsonPath: .spec.refreshInterval + name: Refresh Interval + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: ClusterExternalSecret is the Schema for the clusterexternalsecrets 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: ClusterExternalSecretSpec defines the desired state of ClusterExternalSecret. + properties: + externalSecretName: + description: The name of the external secrets to be created defaults to the name of the ClusterExternalSecret + type: string + externalSecretSpec: + description: The spec for the ExternalSecrets to be created + properties: + data: + description: Data defines the connection between the Kubernetes Secret keys and the Provider data + items: + description: ExternalSecretData defines the connection between the Kubernetes Secret key (spec.data.) and the Provider data. + properties: + remoteRef: + description: ExternalSecretDataRemoteRef defines Provider data location. + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + type: string + decodingStrategy: + default: None + description: Used to define a decoding Strategy + type: string + key: + description: Key is the key used in the Provider, mandatory + type: string + metadataPolicy: + description: Policy for fetching tags/labels from provider secrets, possible options are Fetch, None. Defaults to None + type: string + property: + description: Used to select a specific property of the Provider value (if a map), if supported + type: string + version: + description: Used to select a specific version of the Provider value, if supported + type: string + required: + - key + type: object + secretKey: + type: string + required: + - remoteRef + - secretKey + type: object + type: array + dataFrom: + description: DataFrom is used to fetch all properties from a specific Provider data If multiple entries are specified, the Secret keys are merged in the specified order + items: + properties: + extract: + description: Used to extract multiple key/value pairs from one secret + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + type: string + decodingStrategy: + default: None + description: Used to define a decoding Strategy + type: string + key: + description: Key is the key used in the Provider, mandatory + type: string + metadataPolicy: + description: Policy for fetching tags/labels from provider secrets, possible options are Fetch, None. Defaults to None + type: string + property: + description: Used to select a specific property of the Provider value (if a map), if supported + type: string + version: + description: Used to select a specific version of the Provider value, if supported + type: string + required: + - key + type: object + find: + description: Used to find secrets based on tags or regular expressions + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + type: string + decodingStrategy: + default: None + description: Used to define a decoding Strategy + type: string + name: + description: Finds secrets based on the name. + properties: + regexp: + description: Finds secrets base + type: string + type: object + path: + description: A root path to start the find operations. + type: string + tags: + additionalProperties: + type: string + description: Find secrets based on tags. + type: object + type: object + rewrite: + description: Used to rewrite secret Keys after getting them from the secret Provider Multiple Rewrite operations can be provided. They are applied in a layered order (first to last) + items: + properties: + regexp: + description: Used to rewrite with regular expressions. The resulting key will be the output of a regexp.ReplaceAll operation. + properties: + source: + description: Used to define the regular expression of a re.Compiler. + type: string + target: + description: Used to define the target pattern of a ReplaceAll operation. + type: string + required: + - source + - target + type: object + type: object + type: array + type: object + type: array + refreshInterval: + default: 1h + description: RefreshInterval is the amount of time before the values are read again from the SecretStore provider Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h" May be set to zero to fetch and create it once. Defaults to 1h. + type: string + secretStoreRef: + description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret data. + properties: + kind: + description: Kind of the SecretStore resource (SecretStore or ClusterSecretStore) Defaults to `SecretStore` + type: string + name: + description: Name of the SecretStore resource + type: string + required: + - name + type: object + target: + description: ExternalSecretTarget defines the Kubernetes Secret to be created There can be only one target per ExternalSecret. + properties: + creationPolicy: + default: Owner + description: CreationPolicy defines rules on how to create the resulting Secret Defaults to 'Owner' + enum: + - Owner + - Orphan + - Merge + - None + type: string + deletionPolicy: + default: Retain + description: DeletionPolicy defines rules on how to delete the resulting Secret Defaults to 'Retain' + enum: + - Delete + - Merge + - Retain + type: string + immutable: + description: Immutable defines if the final secret will be immutable + type: boolean + name: + description: Name defines the name of the Secret resource to be managed This field is immutable Defaults to the .metadata.name of the ExternalSecret resource + type: string + template: + description: Template defines a blueprint for the created Secret resource. + properties: + data: + additionalProperties: + type: string + type: object + engineVersion: + default: v2 + type: string + metadata: + description: ExternalSecretTemplateMetadata defines metadata fields for the Secret blueprint. + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + templateFrom: + items: + maxProperties: 1 + minProperties: 1 + properties: + configMap: + properties: + items: + items: + properties: + key: + type: string + required: + - key + type: object + type: array + name: + type: string + required: + - items + - name + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + required: + - key + type: object + type: array + name: + type: string + required: + - items + - name + type: object + type: object + type: array + type: + type: string + type: object + type: object + required: + - secretStoreRef + type: object + namespaceSelector: + description: The labels to select by to find the Namespaces to create the ExternalSecrets in. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + refreshTime: + description: The time in which the controller should reconcile it's objects and recheck namespaces for labels. + type: string + required: + - externalSecretSpec + - namespaceSelector + type: object + status: + description: ClusterExternalSecretStatus defines the observed state of ClusterExternalSecret. + properties: + conditions: + items: + properties: + message: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + failedNamespaces: + description: Failed namespaces are the namespaces that failed to apply an ExternalSecret + items: + description: ClusterExternalSecretNamespaceFailure represents a failed namespace deployment and it's reason. + properties: + namespace: + description: Namespace is the namespace that failed when trying to apply an ExternalSecret + type: string + reason: + description: Reason is why the ExternalSecret failed to apply to the namespace + type: string + required: + - namespace + type: object + type: array + provisionedNamespaces: + description: ProvisionedNamespaces are the namespaces where the ClusterExternalSecret has secrets + items: + type: string + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: golang-external-secrets-webhook + namespace: "default" + path: /convert +--- +# Source: golang-external-secrets/charts/external-secrets/templates/crds/clustersecretstore.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: clustersecretstores.external-secrets.io +spec: + group: external-secrets.io + names: + categories: + - externalsecrets + kind: ClusterSecretStore + listKind: ClusterSecretStoreList + plural: clustersecretstores + shortNames: + - css + singular: clustersecretstore + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + deprecated: true + name: v1alpha1 + schema: + openAPIV3Schema: + description: ClusterSecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields. + 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: SecretStoreSpec defines the desired state of SecretStore. + properties: + controller: + description: 'Used to select the correct KES controller (think: ingress.ingressClassName) The KES controller is instantiated with a specific controller name and filters ES based on this property' + type: string + provider: + description: Used to configure the provider. Only one provider may be set + maxProperties: 1 + minProperties: 1 + properties: + akeyless: + description: Akeyless configures this store to sync secrets using Akeyless Vault provider + properties: + akeylessGWApiURL: + description: Akeyless GW API Url from which the secrets to be fetched from. + type: string + authSecretRef: + description: Auth configures how the operator authenticates with Akeyless. + properties: + secretRef: + description: 'AkeylessAuthSecretRef AKEYLESS_ACCESS_TYPE_PARAM: AZURE_OBJ_ID OR GCP_AUDIENCE OR ACCESS_KEY OR KUB_CONFIG_NAME.' + properties: + accessID: + description: The SecretAccessID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessType: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessTypeParam: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + required: + - akeylessGWApiURL + - authSecretRef + type: object + alibaba: + description: Alibaba configures this store to sync secrets using Alibaba Cloud provider + properties: + auth: + description: AlibabaAuth contains a secretRef for credentials. + properties: + secretRef: + description: AlibabaAuthSecretRef holds secret references for Alibaba credentials. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessKeySecretSecretRef: + description: The AccessKeySecret is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - accessKeyIDSecretRef + - accessKeySecretSecretRef + type: object + required: + - secretRef + type: object + endpoint: + type: string + regionID: + description: Alibaba Region to be used for the provider + type: string + required: + - auth + - regionID + type: object + aws: + description: AWS configures this store to sync secrets using AWS Secret Manager provider + properties: + auth: + description: 'Auth defines the information necessary to authenticate against AWS if not set aws sdk will infer credentials from your environment see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' + properties: + jwt: + description: Authenticate against AWS using service account tokens. + properties: + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + type: object + secretRef: + description: AWSAuthSecretRef holds secret references for AWS credentials both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + type: object + region: + description: AWS Region to be used for the provider + type: string + role: + description: Role is a Role ARN which the SecretManager provider will assume + type: string + service: + description: Service defines which service should be used to fetch the secrets + enum: + - SecretsManager + - ParameterStore + type: string + required: + - region + - service + type: object + azurekv: + description: AzureKV configures this store to sync secrets using Azure Key Vault provider + properties: + authSecretRef: + description: Auth configures how the operator authenticates with Azure. Required for ServicePrincipal auth type. + properties: + clientId: + description: The Azure clientId of the service principle used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + clientSecret: + description: The Azure ClientSecret of the service principle used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + authType: + default: ServicePrincipal + description: 'Auth type defines how to authenticate to the keyvault service. Valid values are: - "ServicePrincipal" (default): Using a service principal (tenantId, clientId, clientSecret) - "ManagedIdentity": Using Managed Identity assigned to the pod (see aad-pod-identity)' + enum: + - ServicePrincipal + - ManagedIdentity + - WorkloadIdentity + type: string + identityId: + description: If multiple Managed Identity is assigned to the pod, you can select the one to be used + type: string + serviceAccountRef: + description: ServiceAccountRef specified the service account that should be used when authenticating with WorkloadIdentity. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + tenantId: + description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. + type: string + vaultUrl: + description: Vault Url from which the secrets to be fetched from. + type: string + required: + - vaultUrl + type: object + fake: + description: Fake configures a store with static key/value pairs + properties: + data: + items: + properties: + key: + type: string + value: + type: string + valueMap: + additionalProperties: + type: string + type: object + version: + type: string + required: + - key + type: object + type: array + required: + - data + type: object + gcpsm: + description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider + properties: + auth: + description: Auth defines the information necessary to authenticate against GCP + properties: + secretRef: + properties: + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + workloadIdentity: + properties: + clusterLocation: + type: string + clusterName: + type: string + clusterProjectID: + type: string + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - clusterLocation + - clusterName + - serviceAccountRef + type: object + type: object + projectID: + description: ProjectID project where secret is located + type: string + type: object + gitlab: + description: Gitlab configures this store to sync secrets using Gitlab Variables provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a GitLab instance. + properties: + SecretRef: + properties: + accessToken: + description: AccessToken is used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - SecretRef + type: object + projectID: + description: ProjectID specifies a project where secrets are located. + type: string + url: + description: URL configures the GitLab instance URL. Defaults to https://gitlab.com/. + type: string + required: + - auth + type: object + ibm: + description: IBM configures this store to sync secrets using IBM Cloud provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the IBM secrets manager. + properties: + secretRef: + properties: + secretApiKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + serviceUrl: + description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance + type: string + required: + - auth + type: object + kubernetes: + description: Kubernetes configures this store to sync secrets using a Kubernetes cluster provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Kubernetes instance. + maxProperties: 1 + minProperties: 1 + properties: + cert: + description: has both clientCert and clientKey as secretKeySelector + properties: + clientCert: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + clientKey: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + serviceAccount: + description: points to a service account that should be used for authentication + properties: + serviceAccount: + description: A reference to a ServiceAccount resource. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + type: object + token: + description: use static token to authenticate with + properties: + bearerToken: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + type: object + remoteNamespace: + default: default + description: Remote namespace to fetch the secrets from + type: string + server: + description: configures the Kubernetes server Address. + properties: + caBundle: + description: CABundle is a base64-encoded CA certificate + format: byte + type: string + caProvider: + description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider' + properties: + key: + description: The key the value inside of the provider type to use, only used with "Secret" type + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + url: + default: kubernetes.default + description: configures the Kubernetes server Address. + type: string + type: object + required: + - auth + type: object + oracle: + description: Oracle configures this store to sync secrets using Oracle Vault provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the Oracle Vault. If empty, use the instance principal, otherwise the user credentials specified in Auth. + properties: + secretRef: + description: SecretRef to pass through sensitive information. + properties: + fingerprint: + description: Fingerprint is the fingerprint of the API private key. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + privatekey: + description: PrivateKey is the user's API Signing Key in PEM format, used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - fingerprint + - privatekey + type: object + tenancy: + description: Tenancy is the tenancy OCID where user is located. + type: string + user: + description: User is an access OCID specific to the account. + type: string + required: + - secretRef + - tenancy + - user + type: object + region: + description: Region is the region where vault is located. + type: string + vault: + description: Vault is the vault's OCID of the specific vault where secret is located. + type: string + required: + - region + - vault + type: object + vault: + description: Vault configures this store to sync secrets using Hashi provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the Vault server. + properties: + appRole: + description: AppRole authenticates with Vault using the App Role auth mechanism, with the role and secret stored in a Kubernetes Secret resource. + properties: + path: + default: approle + description: 'Path where the App Role authentication backend is mounted in Vault, e.g: "approle"' + type: string + roleId: + description: RoleID configured in the App Role authentication backend when setting up the authentication backend in Vault. + type: string + secretRef: + description: Reference to a key in a Secret that contains the App Role secret used to authenticate with Vault. The `key` field must be specified and denotes which entry within the Secret resource is used as the app role secret. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - path + - roleId + - secretRef + type: object + cert: + description: Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate Cert authentication method + properties: + clientCert: + description: ClientCert is a certificate to authenticate using the Cert Vault authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + secretRef: + description: SecretRef to a key in a Secret resource containing client private key to authenticate with Vault using the Cert authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + jwt: + description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method + properties: + kubernetesServiceAccountToken: + description: Optional ServiceAccountToken specifies the Kubernetes service account for which to request a token for with the `TokenRequest` API. + properties: + audiences: + description: Optional audiences field that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to a single audience `vault` it not specified. + items: + type: string + type: array + expirationSeconds: + description: Optional expiration time in seconds that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to 10 minutes. + format: int64 + type: integer + serviceAccountRef: + description: Service account field containing the name of a kubernetes ServiceAccount. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - serviceAccountRef + type: object + path: + default: jwt + description: 'Path where the JWT authentication backend is mounted in Vault, e.g: "jwt"' + type: string + role: + description: Role is a JWT role to authenticate using the JWT/OIDC Vault authentication method + type: string + secretRef: + description: Optional SecretRef that refers to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - path + type: object + kubernetes: + description: Kubernetes authenticates with Vault by passing the ServiceAccount token stored in the named Secret resource to the Vault server. + properties: + mountPath: + default: kubernetes + description: 'Path where the Kubernetes authentication backend is mounted in Vault, e.g: "kubernetes"' + type: string + role: + description: A required field containing the Vault Role to assume. A Role binds a Kubernetes ServiceAccount with a set of Vault policies. + type: string + secretRef: + description: Optional secret field containing a Kubernetes ServiceAccount JWT used for authenticating with Vault. If a name is specified without a key, `token` is the default. If one is not specified, the one bound to the controller will be used. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + serviceAccountRef: + description: Optional service account field containing the name of a kubernetes ServiceAccount. If the service account is specified, the service account secret token JWT will be used for authenticating with Vault. If the service account selector is not supplied, the secretRef will be used instead. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - mountPath + - role + type: object + ldap: + description: Ldap authenticates with Vault by passing username/password pair using the LDAP authentication method + properties: + path: + default: ldap + description: 'Path where the LDAP authentication backend is mounted in Vault, e.g: "ldap"' + type: string + secretRef: + description: SecretRef to a key in a Secret resource containing password for the LDAP user used to authenticate with Vault using the LDAP authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + username: + description: Username is a LDAP user name used to authenticate using the LDAP Vault authentication method + type: string + required: + - path + - username + type: object + tokenSecretRef: + description: TokenSecretRef authenticates with Vault by presenting a token. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + caBundle: + description: PEM encoded CA bundle used to validate Vault server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate Vault server certificate. + properties: + key: + description: The key the value inside of the provider type to use, only used with "Secret" type + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + forwardInconsistent: + description: ForwardInconsistent tells Vault to forward read-after-write requests to the Vault leader instead of simply retrying within a loop. This can increase performance if the option is enabled serverside. https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header + type: boolean + namespace: + description: 'Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1". More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces' + type: string + path: + description: 'Path is the mount path of the Vault KV backend endpoint, e.g: "secret". The v2 KV secret engine version specific "/data" path suffix for fetching secrets from Vault is optional and will be appended if not present in specified path.' + type: string + readYourWrites: + description: ReadYourWrites ensures isolated read-after-write semantics by providing discovered cluster replication states in each request. More information about eventual consistency in Vault can be found here https://www.vaultproject.io/docs/enterprise/consistency + type: boolean + server: + description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' + type: string + version: + default: v2 + description: Version is the Vault KV secret engine version. This can be either "v1" or "v2". Version defaults to "v2". + enum: + - v1 + - v2 + type: string + required: + - auth + - server + type: object + webhook: + description: Webhook configures this store to sync secrets using a generic templated webhook + properties: + body: + description: Body + type: string + caBundle: + description: PEM encoded CA bundle used to validate webhook server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate webhook server certificate. + properties: + key: + description: The key the value inside of the provider type to use, only used with "Secret" type + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + headers: + additionalProperties: + type: string + description: Headers + type: object + method: + description: Webhook Method + type: string + result: + description: Result formatting + properties: + jsonPath: + description: Json path of return value + type: string + type: object + secrets: + description: Secrets to fill in templates These secrets will be passed to the templating function as key value pairs under the given name + items: + properties: + name: + description: Name of this secret in templates + type: string + secretRef: + description: Secret ref to fill in credentials + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - name + - secretRef + type: object + type: array + timeout: + description: Timeout + type: string + url: + description: Webhook url to call + type: string + required: + - result + - url + type: object + yandexlockbox: + description: YandexLockbox configures this store to sync secrets using Yandex Lockbox provider + properties: + apiEndpoint: + description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') + type: string + auth: + description: Auth defines the information necessary to authenticate against Yandex Lockbox + properties: + authorizedKeySecretRef: + description: The authorized key used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + caProvider: + description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. + properties: + certSecretRef: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - auth + type: object + type: object + retrySettings: + description: Used to configure http retries if failed + properties: + maxRetries: + format: int32 + type: integer + retryInterval: + type: string + type: object + required: + - provider + type: object + status: + description: SecretStoreStatus defines the observed state of the SecretStore. + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: ClusterSecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields. + 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: SecretStoreSpec defines the desired state of SecretStore. + properties: + controller: + description: 'Used to select the correct KES controller (think: ingress.ingressClassName) The KES controller is instantiated with a specific controller name and filters ES based on this property' + type: string + provider: + description: Used to configure the provider. Only one provider may be set + maxProperties: 1 + minProperties: 1 + properties: + akeyless: + description: Akeyless configures this store to sync secrets using Akeyless Vault provider + properties: + akeylessGWApiURL: + description: Akeyless GW API Url from which the secrets to be fetched from. + type: string + authSecretRef: + description: Auth configures how the operator authenticates with Akeyless. + properties: + secretRef: + description: 'AkeylessAuthSecretRef AKEYLESS_ACCESS_TYPE_PARAM: AZURE_OBJ_ID OR GCP_AUDIENCE OR ACCESS_KEY OR KUB_CONFIG_NAME.' + properties: + accessID: + description: The SecretAccessID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessType: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessTypeParam: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + required: + - akeylessGWApiURL + - authSecretRef + type: object + alibaba: + description: Alibaba configures this store to sync secrets using Alibaba Cloud provider + properties: + auth: + description: AlibabaAuth contains a secretRef for credentials. + properties: + secretRef: + description: AlibabaAuthSecretRef holds secret references for Alibaba credentials. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessKeySecretSecretRef: + description: The AccessKeySecret is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - accessKeyIDSecretRef + - accessKeySecretSecretRef + type: object + required: + - secretRef + type: object + endpoint: + type: string + regionID: + description: Alibaba Region to be used for the provider + type: string + required: + - auth + - regionID + type: object + aws: + description: AWS configures this store to sync secrets using AWS Secret Manager provider + properties: + auth: + description: 'Auth defines the information necessary to authenticate against AWS if not set aws sdk will infer credentials from your environment see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' + properties: + jwt: + description: Authenticate against AWS using service account tokens. + properties: + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + type: object + secretRef: + description: AWSAuthSecretRef holds secret references for AWS credentials both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + type: object + region: + description: AWS Region to be used for the provider + type: string + role: + description: Role is a Role ARN which the SecretManager provider will assume + type: string + service: + description: Service defines which service should be used to fetch the secrets + enum: + - SecretsManager + - ParameterStore + type: string + required: + - region + - service + type: object + azurekv: + description: AzureKV configures this store to sync secrets using Azure Key Vault provider + properties: + authSecretRef: + description: Auth configures how the operator authenticates with Azure. Required for ServicePrincipal auth type. + properties: + clientId: + description: The Azure clientId of the service principle used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + clientSecret: + description: The Azure ClientSecret of the service principle used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + authType: + default: ServicePrincipal + description: 'Auth type defines how to authenticate to the keyvault service. Valid values are: - "ServicePrincipal" (default): Using a service principal (tenantId, clientId, clientSecret) - "ManagedIdentity": Using Managed Identity assigned to the pod (see aad-pod-identity)' + enum: + - ServicePrincipal + - ManagedIdentity + - WorkloadIdentity + type: string + identityId: + description: If multiple Managed Identity is assigned to the pod, you can select the one to be used + type: string + serviceAccountRef: + description: ServiceAccountRef specified the service account that should be used when authenticating with WorkloadIdentity. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + tenantId: + description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. + type: string + vaultUrl: + description: Vault Url from which the secrets to be fetched from. + type: string + required: + - vaultUrl + type: object + fake: + description: Fake configures a store with static key/value pairs + properties: + data: + items: + properties: + key: + type: string + value: + type: string + valueMap: + additionalProperties: + type: string + type: object + version: + type: string + required: + - key + type: object + type: array + required: + - data + type: object + gcpsm: + description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider + properties: + auth: + description: Auth defines the information necessary to authenticate against GCP + properties: + secretRef: + properties: + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + workloadIdentity: + properties: + clusterLocation: + type: string + clusterName: + type: string + clusterProjectID: + type: string + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - clusterLocation + - clusterName + - serviceAccountRef + type: object + type: object + projectID: + description: ProjectID project where secret is located + type: string + type: object + gitlab: + description: Gitlab configures this store to sync secrets using Gitlab Variables provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a GitLab instance. + properties: + SecretRef: + properties: + accessToken: + description: AccessToken is used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - SecretRef + type: object + projectID: + description: ProjectID specifies a project where secrets are located. + type: string + url: + description: URL configures the GitLab instance URL. Defaults to https://gitlab.com/. + type: string + required: + - auth + type: object + ibm: + description: IBM configures this store to sync secrets using IBM Cloud provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the IBM secrets manager. + maxProperties: 1 + minProperties: 1 + properties: + containerAuth: + description: IBM Container-based auth with IAM Trusted Profile. + properties: + iamEndpoint: + type: string + profile: + description: the IBM Trusted Profile + type: string + tokenLocation: + description: Location the token is mounted on the pod + type: string + required: + - profile + type: object + secretRef: + properties: + secretApiKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + type: object + serviceUrl: + description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance + type: string + required: + - auth + type: object + kubernetes: + description: Kubernetes configures this store to sync secrets using a Kubernetes cluster provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Kubernetes instance. + maxProperties: 1 + minProperties: 1 + properties: + cert: + description: has both clientCert and clientKey as secretKeySelector + properties: + clientCert: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + clientKey: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + serviceAccount: + description: points to a service account that should be used for authentication + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + token: + description: use static token to authenticate with + properties: + bearerToken: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + type: object + remoteNamespace: + default: default + description: Remote namespace to fetch the secrets from + type: string + server: + description: configures the Kubernetes server Address. + properties: + caBundle: + description: CABundle is a base64-encoded CA certificate + format: byte + type: string + caProvider: + description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider' + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. Can only be defined when used in a ClusterSecretStore. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + url: + default: kubernetes.default + description: configures the Kubernetes server Address. + type: string + type: object + required: + - auth + type: object + onepassword: + description: OnePassword configures this store to sync secrets using the 1Password Cloud provider + properties: + auth: + description: Auth defines the information necessary to authenticate against OnePassword Connect Server + properties: + secretRef: + description: OnePasswordAuthSecretRef holds secret references for 1Password credentials. + properties: + connectTokenSecretRef: + description: The ConnectToken is used for authentication to a 1Password Connect Server. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - connectTokenSecretRef + type: object + required: + - secretRef + type: object + connectHost: + description: ConnectHost defines the OnePassword Connect Server to connect to + type: string + vaults: + additionalProperties: + type: integer + description: Vaults defines which OnePassword vaults to search in which order + type: object + required: + - auth + - connectHost + - vaults + type: object + oracle: + description: Oracle configures this store to sync secrets using Oracle Vault provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the Oracle Vault. If empty, use the instance principal, otherwise the user credentials specified in Auth. + properties: + secretRef: + description: SecretRef to pass through sensitive information. + properties: + fingerprint: + description: Fingerprint is the fingerprint of the API private key. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + privatekey: + description: PrivateKey is the user's API Signing Key in PEM format, used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - fingerprint + - privatekey + type: object + tenancy: + description: Tenancy is the tenancy OCID where user is located. + type: string + user: + description: User is an access OCID specific to the account. + type: string + required: + - secretRef + - tenancy + - user + type: object + region: + description: Region is the region where vault is located. + type: string + vault: + description: Vault is the vault's OCID of the specific vault where secret is located. + type: string + required: + - region + - vault + type: object + senhasegura: + description: Senhasegura configures this store to sync secrets using senhasegura provider + properties: + auth: + description: Auth defines parameters to authenticate in senhasegura + properties: + clientId: + type: string + clientSecretSecretRef: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - clientId + - clientSecretSecretRef + type: object + ignoreSslCertificate: + default: false + description: IgnoreSslCertificate defines if SSL certificate must be ignored + type: boolean + module: + description: Module defines which senhasegura module should be used to get secrets + type: string + url: + description: URL of senhasegura + type: string + required: + - auth + - module + - url + type: object + vault: + description: Vault configures this store to sync secrets using Hashi provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the Vault server. + properties: + appRole: + description: AppRole authenticates with Vault using the App Role auth mechanism, with the role and secret stored in a Kubernetes Secret resource. + properties: + path: + default: approle + description: 'Path where the App Role authentication backend is mounted in Vault, e.g: "approle"' + type: string + roleId: + description: RoleID configured in the App Role authentication backend when setting up the authentication backend in Vault. + type: string + secretRef: + description: Reference to a key in a Secret that contains the App Role secret used to authenticate with Vault. The `key` field must be specified and denotes which entry within the Secret resource is used as the app role secret. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - path + - roleId + - secretRef + type: object + cert: + description: Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate Cert authentication method + properties: + clientCert: + description: ClientCert is a certificate to authenticate using the Cert Vault authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + secretRef: + description: SecretRef to a key in a Secret resource containing client private key to authenticate with Vault using the Cert authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + jwt: + description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method + properties: + kubernetesServiceAccountToken: + description: Optional ServiceAccountToken specifies the Kubernetes service account for which to request a token for with the `TokenRequest` API. + properties: + audiences: + description: Optional audiences field that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to a single audience `vault` it not specified. + items: + type: string + type: array + expirationSeconds: + description: Optional expiration time in seconds that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to 10 minutes. + format: int64 + type: integer + serviceAccountRef: + description: Service account field containing the name of a kubernetes ServiceAccount. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - serviceAccountRef + type: object + path: + default: jwt + description: 'Path where the JWT authentication backend is mounted in Vault, e.g: "jwt"' + type: string + role: + description: Role is a JWT role to authenticate using the JWT/OIDC Vault authentication method + type: string + secretRef: + description: Optional SecretRef that refers to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - path + type: object + kubernetes: + description: Kubernetes authenticates with Vault by passing the ServiceAccount token stored in the named Secret resource to the Vault server. + properties: + mountPath: + default: kubernetes + description: 'Path where the Kubernetes authentication backend is mounted in Vault, e.g: "kubernetes"' + type: string + role: + description: A required field containing the Vault Role to assume. A Role binds a Kubernetes ServiceAccount with a set of Vault policies. + type: string + secretRef: + description: Optional secret field containing a Kubernetes ServiceAccount JWT used for authenticating with Vault. If a name is specified without a key, `token` is the default. If one is not specified, the one bound to the controller will be used. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + serviceAccountRef: + description: Optional service account field containing the name of a kubernetes ServiceAccount. If the service account is specified, the service account secret token JWT will be used for authenticating with Vault. If the service account selector is not supplied, the secretRef will be used instead. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - mountPath + - role + type: object + ldap: + description: Ldap authenticates with Vault by passing username/password pair using the LDAP authentication method + properties: + path: + default: ldap + description: 'Path where the LDAP authentication backend is mounted in Vault, e.g: "ldap"' + type: string + secretRef: + description: SecretRef to a key in a Secret resource containing password for the LDAP user used to authenticate with Vault using the LDAP authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + username: + description: Username is a LDAP user name used to authenticate using the LDAP Vault authentication method + type: string + required: + - path + - username + type: object + tokenSecretRef: + description: TokenSecretRef authenticates with Vault by presenting a token. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + caBundle: + description: PEM encoded CA bundle used to validate Vault server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate Vault server certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. Can only be defined when used in a ClusterSecretStore. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + forwardInconsistent: + description: ForwardInconsistent tells Vault to forward read-after-write requests to the Vault leader instead of simply retrying within a loop. This can increase performance if the option is enabled serverside. https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header + type: boolean + namespace: + description: 'Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1". More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces' + type: string + path: + description: 'Path is the mount path of the Vault KV backend endpoint, e.g: "secret". The v2 KV secret engine version specific "/data" path suffix for fetching secrets from Vault is optional and will be appended if not present in specified path.' + type: string + readYourWrites: + description: ReadYourWrites ensures isolated read-after-write semantics by providing discovered cluster replication states in each request. More information about eventual consistency in Vault can be found here https://www.vaultproject.io/docs/enterprise/consistency + type: boolean + server: + description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' + type: string + version: + default: v2 + description: Version is the Vault KV secret engine version. This can be either "v1" or "v2". Version defaults to "v2". + enum: + - v1 + - v2 + type: string + required: + - auth + - server + type: object + webhook: + description: Webhook configures this store to sync secrets using a generic templated webhook + properties: + body: + description: Body + type: string + caBundle: + description: PEM encoded CA bundle used to validate webhook server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate webhook server certificate. + properties: + key: + description: The key the value inside of the provider type to use, only used with "Secret" type + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + headers: + additionalProperties: + type: string + description: Headers + type: object + method: + description: Webhook Method + type: string + result: + description: Result formatting + properties: + jsonPath: + description: Json path of return value + type: string + type: object + secrets: + description: Secrets to fill in templates These secrets will be passed to the templating function as key value pairs under the given name + items: + properties: + name: + description: Name of this secret in templates + type: string + secretRef: + description: Secret ref to fill in credentials + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - name + - secretRef + type: object + type: array + timeout: + description: Timeout + type: string + url: + description: Webhook url to call + type: string + required: + - result + - url + type: object + yandexcertificatemanager: + description: YandexCertificateManager configures this store to sync secrets using Yandex Certificate Manager provider + properties: + apiEndpoint: + description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') + type: string + auth: + description: Auth defines the information necessary to authenticate against Yandex Certificate Manager + properties: + authorizedKeySecretRef: + description: The authorized key used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + caProvider: + description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. + properties: + certSecretRef: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - auth + type: object + yandexlockbox: + description: YandexLockbox configures this store to sync secrets using Yandex Lockbox provider + properties: + apiEndpoint: + description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') + type: string + auth: + description: Auth defines the information necessary to authenticate against Yandex Lockbox + properties: + authorizedKeySecretRef: + description: The authorized key used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + caProvider: + description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. + properties: + certSecretRef: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - auth + type: object + type: object + refreshInterval: + description: Used to configure store refresh interval in seconds. Empty or 0 will default to the controller config. + type: integer + retrySettings: + description: Used to configure http retries if failed + properties: + maxRetries: + format: int32 + type: integer + retryInterval: + type: string + type: object + required: + - provider + type: object + status: + description: SecretStoreStatus defines the observed state of the SecretStore. + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: golang-external-secrets-webhook + namespace: "default" + path: /convert +--- +# Source: golang-external-secrets/charts/external-secrets/templates/crds/externalsecret.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: externalsecrets.external-secrets.io +spec: + group: external-secrets.io + names: + categories: + - externalsecrets + kind: ExternalSecret + listKind: ExternalSecretList + plural: externalsecrets + shortNames: + - es + singular: externalsecret + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.secretStoreRef.name + name: Store + type: string + - jsonPath: .spec.refreshInterval + name: Refresh Interval + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + deprecated: true + name: v1alpha1 + schema: + openAPIV3Schema: + description: ExternalSecret is the Schema for the external-secrets 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: ExternalSecretSpec defines the desired state of ExternalSecret. + properties: + data: + description: Data defines the connection between the Kubernetes Secret keys and the Provider data + items: + description: ExternalSecretData defines the connection between the Kubernetes Secret key (spec.data.) and the Provider data. + properties: + remoteRef: + description: ExternalSecretDataRemoteRef defines Provider data location. + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + type: string + key: + description: Key is the key used in the Provider, mandatory + type: string + property: + description: Used to select a specific property of the Provider value (if a map), if supported + type: string + version: + description: Used to select a specific version of the Provider value, if supported + type: string + required: + - key + type: object + secretKey: + type: string + required: + - remoteRef + - secretKey + type: object + type: array + dataFrom: + description: DataFrom is used to fetch all properties from a specific Provider data If multiple entries are specified, the Secret keys are merged in the specified order + items: + description: ExternalSecretDataRemoteRef defines Provider data location. + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + type: string + key: + description: Key is the key used in the Provider, mandatory + type: string + property: + description: Used to select a specific property of the Provider value (if a map), if supported + type: string + version: + description: Used to select a specific version of the Provider value, if supported + type: string + required: + - key + type: object + type: array + refreshInterval: + default: 1h + description: RefreshInterval is the amount of time before the values are read again from the SecretStore provider Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h" May be set to zero to fetch and create it once. Defaults to 1h. + type: string + secretStoreRef: + description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret data. + properties: + kind: + description: Kind of the SecretStore resource (SecretStore or ClusterSecretStore) Defaults to `SecretStore` + type: string + name: + description: Name of the SecretStore resource + type: string + required: + - name + type: object + target: + description: ExternalSecretTarget defines the Kubernetes Secret to be created There can be only one target per ExternalSecret. + properties: + creationPolicy: + default: Owner + description: CreationPolicy defines rules on how to create the resulting Secret Defaults to 'Owner' + type: string + immutable: + description: Immutable defines if the final secret will be immutable + type: boolean + name: + description: Name defines the name of the Secret resource to be managed This field is immutable Defaults to the .metadata.name of the ExternalSecret resource + type: string + template: + description: Template defines a blueprint for the created Secret resource. + properties: + data: + additionalProperties: + type: string + type: object + engineVersion: + default: v1 + description: EngineVersion specifies the template engine version that should be used to compile/execute the template specified in .data and .templateFrom[]. + type: string + metadata: + description: ExternalSecretTemplateMetadata defines metadata fields for the Secret blueprint. + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + templateFrom: + items: + maxProperties: 1 + minProperties: 1 + properties: + configMap: + properties: + items: + items: + properties: + key: + type: string + required: + - key + type: object + type: array + name: + type: string + required: + - items + - name + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + required: + - key + type: object + type: array + name: + type: string + required: + - items + - name + type: object + type: object + type: array + type: + type: string + type: object + type: object + required: + - secretStoreRef + - target + type: object + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + refreshTime: + description: refreshTime is the time and date the external secret was fetched and the target secret updated + format: date-time + nullable: true + type: string + syncedResourceVersion: + description: SyncedResourceVersion keeps track of the last synced version + type: string + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.secretStoreRef.name + name: Store + type: string + - jsonPath: .spec.refreshInterval + name: Refresh Interval + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: ExternalSecret is the Schema for the external-secrets 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: ExternalSecretSpec defines the desired state of ExternalSecret. + properties: + data: + description: Data defines the connection between the Kubernetes Secret keys and the Provider data + items: + description: ExternalSecretData defines the connection between the Kubernetes Secret key (spec.data.) and the Provider data. + properties: + remoteRef: + description: ExternalSecretDataRemoteRef defines Provider data location. + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + type: string + decodingStrategy: + default: None + description: Used to define a decoding Strategy + type: string + key: + description: Key is the key used in the Provider, mandatory + type: string + metadataPolicy: + description: Policy for fetching tags/labels from provider secrets, possible options are Fetch, None. Defaults to None + type: string + property: + description: Used to select a specific property of the Provider value (if a map), if supported + type: string + version: + description: Used to select a specific version of the Provider value, if supported + type: string + required: + - key + type: object + secretKey: + type: string + required: + - remoteRef + - secretKey + type: object + type: array + dataFrom: + description: DataFrom is used to fetch all properties from a specific Provider data If multiple entries are specified, the Secret keys are merged in the specified order + items: + properties: + extract: + description: Used to extract multiple key/value pairs from one secret + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + type: string + decodingStrategy: + default: None + description: Used to define a decoding Strategy + type: string + key: + description: Key is the key used in the Provider, mandatory + type: string + metadataPolicy: + description: Policy for fetching tags/labels from provider secrets, possible options are Fetch, None. Defaults to None + type: string + property: + description: Used to select a specific property of the Provider value (if a map), if supported + type: string + version: + description: Used to select a specific version of the Provider value, if supported + type: string + required: + - key + type: object + find: + description: Used to find secrets based on tags or regular expressions + properties: + conversionStrategy: + default: Default + description: Used to define a conversion Strategy + type: string + decodingStrategy: + default: None + description: Used to define a decoding Strategy + type: string + name: + description: Finds secrets based on the name. + properties: + regexp: + description: Finds secrets base + type: string + type: object + path: + description: A root path to start the find operations. + type: string + tags: + additionalProperties: + type: string + description: Find secrets based on tags. + type: object + type: object + rewrite: + description: Used to rewrite secret Keys after getting them from the secret Provider Multiple Rewrite operations can be provided. They are applied in a layered order (first to last) + items: + properties: + regexp: + description: Used to rewrite with regular expressions. The resulting key will be the output of a regexp.ReplaceAll operation. + properties: + source: + description: Used to define the regular expression of a re.Compiler. + type: string + target: + description: Used to define the target pattern of a ReplaceAll operation. + type: string + required: + - source + - target + type: object + type: object + type: array + type: object + type: array + refreshInterval: + default: 1h + description: RefreshInterval is the amount of time before the values are read again from the SecretStore provider Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h" May be set to zero to fetch and create it once. Defaults to 1h. + type: string + secretStoreRef: + description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret data. + properties: + kind: + description: Kind of the SecretStore resource (SecretStore or ClusterSecretStore) Defaults to `SecretStore` + type: string + name: + description: Name of the SecretStore resource + type: string + required: + - name + type: object + target: + description: ExternalSecretTarget defines the Kubernetes Secret to be created There can be only one target per ExternalSecret. + properties: + creationPolicy: + default: Owner + description: CreationPolicy defines rules on how to create the resulting Secret Defaults to 'Owner' + enum: + - Owner + - Orphan + - Merge + - None + type: string + deletionPolicy: + default: Retain + description: DeletionPolicy defines rules on how to delete the resulting Secret Defaults to 'Retain' + enum: + - Delete + - Merge + - Retain + type: string + immutable: + description: Immutable defines if the final secret will be immutable + type: boolean + name: + description: Name defines the name of the Secret resource to be managed This field is immutable Defaults to the .metadata.name of the ExternalSecret resource + type: string + template: + description: Template defines a blueprint for the created Secret resource. + properties: + data: + additionalProperties: + type: string + type: object + engineVersion: + default: v2 + type: string + metadata: + description: ExternalSecretTemplateMetadata defines metadata fields for the Secret blueprint. + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + templateFrom: + items: + maxProperties: 1 + minProperties: 1 + properties: + configMap: + properties: + items: + items: + properties: + key: + type: string + required: + - key + type: object + type: array + name: + type: string + required: + - items + - name + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + required: + - key + type: object + type: array + name: + type: string + required: + - items + - name + type: object + type: object + type: array + type: + type: string + type: object + type: object + required: + - secretStoreRef + type: object + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + refreshTime: + description: refreshTime is the time and date the external secret was fetched and the target secret updated + format: date-time + nullable: true + type: string + syncedResourceVersion: + description: SyncedResourceVersion keeps track of the last synced version + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: golang-external-secrets-webhook + namespace: "default" + path: /convert +--- +# Source: golang-external-secrets/charts/external-secrets/templates/crds/secretstore.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: secretstores.external-secrets.io +spec: + group: external-secrets.io + names: + categories: + - externalsecrets + kind: SecretStore + listKind: SecretStoreList + plural: secretstores + shortNames: + - ss + singular: secretstore + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + deprecated: true + name: v1alpha1 + schema: + openAPIV3Schema: + description: SecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields. + 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: SecretStoreSpec defines the desired state of SecretStore. + properties: + controller: + description: 'Used to select the correct KES controller (think: ingress.ingressClassName) The KES controller is instantiated with a specific controller name and filters ES based on this property' + type: string + provider: + description: Used to configure the provider. Only one provider may be set + maxProperties: 1 + minProperties: 1 + properties: + akeyless: + description: Akeyless configures this store to sync secrets using Akeyless Vault provider + properties: + akeylessGWApiURL: + description: Akeyless GW API Url from which the secrets to be fetched from. + type: string + authSecretRef: + description: Auth configures how the operator authenticates with Akeyless. + properties: + secretRef: + description: 'AkeylessAuthSecretRef AKEYLESS_ACCESS_TYPE_PARAM: AZURE_OBJ_ID OR GCP_AUDIENCE OR ACCESS_KEY OR KUB_CONFIG_NAME.' + properties: + accessID: + description: The SecretAccessID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessType: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessTypeParam: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + required: + - akeylessGWApiURL + - authSecretRef + type: object + alibaba: + description: Alibaba configures this store to sync secrets using Alibaba Cloud provider + properties: + auth: + description: AlibabaAuth contains a secretRef for credentials. + properties: + secretRef: + description: AlibabaAuthSecretRef holds secret references for Alibaba credentials. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessKeySecretSecretRef: + description: The AccessKeySecret is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - accessKeyIDSecretRef + - accessKeySecretSecretRef + type: object + required: + - secretRef + type: object + endpoint: + type: string + regionID: + description: Alibaba Region to be used for the provider + type: string + required: + - auth + - regionID + type: object + aws: + description: AWS configures this store to sync secrets using AWS Secret Manager provider + properties: + auth: + description: 'Auth defines the information necessary to authenticate against AWS if not set aws sdk will infer credentials from your environment see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' + properties: + jwt: + description: Authenticate against AWS using service account tokens. + properties: + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + type: object + secretRef: + description: AWSAuthSecretRef holds secret references for AWS credentials both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + type: object + region: + description: AWS Region to be used for the provider + type: string + role: + description: Role is a Role ARN which the SecretManager provider will assume + type: string + service: + description: Service defines which service should be used to fetch the secrets + enum: + - SecretsManager + - ParameterStore + type: string + required: + - region + - service + type: object + azurekv: + description: AzureKV configures this store to sync secrets using Azure Key Vault provider + properties: + authSecretRef: + description: Auth configures how the operator authenticates with Azure. Required for ServicePrincipal auth type. + properties: + clientId: + description: The Azure clientId of the service principle used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + clientSecret: + description: The Azure ClientSecret of the service principle used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + authType: + default: ServicePrincipal + description: 'Auth type defines how to authenticate to the keyvault service. Valid values are: - "ServicePrincipal" (default): Using a service principal (tenantId, clientId, clientSecret) - "ManagedIdentity": Using Managed Identity assigned to the pod (see aad-pod-identity)' + enum: + - ServicePrincipal + - ManagedIdentity + - WorkloadIdentity + type: string + identityId: + description: If multiple Managed Identity is assigned to the pod, you can select the one to be used + type: string + serviceAccountRef: + description: ServiceAccountRef specified the service account that should be used when authenticating with WorkloadIdentity. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + tenantId: + description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. + type: string + vaultUrl: + description: Vault Url from which the secrets to be fetched from. + type: string + required: + - vaultUrl + type: object + fake: + description: Fake configures a store with static key/value pairs + properties: + data: + items: + properties: + key: + type: string + value: + type: string + valueMap: + additionalProperties: + type: string + type: object + version: + type: string + required: + - key + type: object + type: array + required: + - data + type: object + gcpsm: + description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider + properties: + auth: + description: Auth defines the information necessary to authenticate against GCP + properties: + secretRef: + properties: + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + workloadIdentity: + properties: + clusterLocation: + type: string + clusterName: + type: string + clusterProjectID: + type: string + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - clusterLocation + - clusterName + - serviceAccountRef + type: object + type: object + projectID: + description: ProjectID project where secret is located + type: string + type: object + gitlab: + description: Gitlab configures this store to sync secrets using Gitlab Variables provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a GitLab instance. + properties: + SecretRef: + properties: + accessToken: + description: AccessToken is used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - SecretRef + type: object + projectID: + description: ProjectID specifies a project where secrets are located. + type: string + url: + description: URL configures the GitLab instance URL. Defaults to https://gitlab.com/. + type: string + required: + - auth + type: object + ibm: + description: IBM configures this store to sync secrets using IBM Cloud provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the IBM secrets manager. + properties: + secretRef: + properties: + secretApiKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + serviceUrl: + description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance + type: string + required: + - auth + type: object + kubernetes: + description: Kubernetes configures this store to sync secrets using a Kubernetes cluster provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Kubernetes instance. + maxProperties: 1 + minProperties: 1 + properties: + cert: + description: has both clientCert and clientKey as secretKeySelector + properties: + clientCert: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + clientKey: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + serviceAccount: + description: points to a service account that should be used for authentication + properties: + serviceAccount: + description: A reference to a ServiceAccount resource. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + type: object + token: + description: use static token to authenticate with + properties: + bearerToken: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + type: object + remoteNamespace: + default: default + description: Remote namespace to fetch the secrets from + type: string + server: + description: configures the Kubernetes server Address. + properties: + caBundle: + description: CABundle is a base64-encoded CA certificate + format: byte + type: string + caProvider: + description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider' + properties: + key: + description: The key the value inside of the provider type to use, only used with "Secret" type + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + url: + default: kubernetes.default + description: configures the Kubernetes server Address. + type: string + type: object + required: + - auth + type: object + oracle: + description: Oracle configures this store to sync secrets using Oracle Vault provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the Oracle Vault. If empty, use the instance principal, otherwise the user credentials specified in Auth. + properties: + secretRef: + description: SecretRef to pass through sensitive information. + properties: + fingerprint: + description: Fingerprint is the fingerprint of the API private key. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + privatekey: + description: PrivateKey is the user's API Signing Key in PEM format, used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - fingerprint + - privatekey + type: object + tenancy: + description: Tenancy is the tenancy OCID where user is located. + type: string + user: + description: User is an access OCID specific to the account. + type: string + required: + - secretRef + - tenancy + - user + type: object + region: + description: Region is the region where vault is located. + type: string + vault: + description: Vault is the vault's OCID of the specific vault where secret is located. + type: string + required: + - region + - vault + type: object + vault: + description: Vault configures this store to sync secrets using Hashi provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the Vault server. + properties: + appRole: + description: AppRole authenticates with Vault using the App Role auth mechanism, with the role and secret stored in a Kubernetes Secret resource. + properties: + path: + default: approle + description: 'Path where the App Role authentication backend is mounted in Vault, e.g: "approle"' + type: string + roleId: + description: RoleID configured in the App Role authentication backend when setting up the authentication backend in Vault. + type: string + secretRef: + description: Reference to a key in a Secret that contains the App Role secret used to authenticate with Vault. The `key` field must be specified and denotes which entry within the Secret resource is used as the app role secret. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - path + - roleId + - secretRef + type: object + cert: + description: Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate Cert authentication method + properties: + clientCert: + description: ClientCert is a certificate to authenticate using the Cert Vault authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + secretRef: + description: SecretRef to a key in a Secret resource containing client private key to authenticate with Vault using the Cert authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + jwt: + description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method + properties: + kubernetesServiceAccountToken: + description: Optional ServiceAccountToken specifies the Kubernetes service account for which to request a token for with the `TokenRequest` API. + properties: + audiences: + description: Optional audiences field that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to a single audience `vault` it not specified. + items: + type: string + type: array + expirationSeconds: + description: Optional expiration time in seconds that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to 10 minutes. + format: int64 + type: integer + serviceAccountRef: + description: Service account field containing the name of a kubernetes ServiceAccount. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - serviceAccountRef + type: object + path: + default: jwt + description: 'Path where the JWT authentication backend is mounted in Vault, e.g: "jwt"' + type: string + role: + description: Role is a JWT role to authenticate using the JWT/OIDC Vault authentication method + type: string + secretRef: + description: Optional SecretRef that refers to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - path + type: object + kubernetes: + description: Kubernetes authenticates with Vault by passing the ServiceAccount token stored in the named Secret resource to the Vault server. + properties: + mountPath: + default: kubernetes + description: 'Path where the Kubernetes authentication backend is mounted in Vault, e.g: "kubernetes"' + type: string + role: + description: A required field containing the Vault Role to assume. A Role binds a Kubernetes ServiceAccount with a set of Vault policies. + type: string + secretRef: + description: Optional secret field containing a Kubernetes ServiceAccount JWT used for authenticating with Vault. If a name is specified without a key, `token` is the default. If one is not specified, the one bound to the controller will be used. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + serviceAccountRef: + description: Optional service account field containing the name of a kubernetes ServiceAccount. If the service account is specified, the service account secret token JWT will be used for authenticating with Vault. If the service account selector is not supplied, the secretRef will be used instead. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - mountPath + - role + type: object + ldap: + description: Ldap authenticates with Vault by passing username/password pair using the LDAP authentication method + properties: + path: + default: ldap + description: 'Path where the LDAP authentication backend is mounted in Vault, e.g: "ldap"' + type: string + secretRef: + description: SecretRef to a key in a Secret resource containing password for the LDAP user used to authenticate with Vault using the LDAP authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + username: + description: Username is a LDAP user name used to authenticate using the LDAP Vault authentication method + type: string + required: + - path + - username + type: object + tokenSecretRef: + description: TokenSecretRef authenticates with Vault by presenting a token. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + caBundle: + description: PEM encoded CA bundle used to validate Vault server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate Vault server certificate. + properties: + key: + description: The key the value inside of the provider type to use, only used with "Secret" type + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + forwardInconsistent: + description: ForwardInconsistent tells Vault to forward read-after-write requests to the Vault leader instead of simply retrying within a loop. This can increase performance if the option is enabled serverside. https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header + type: boolean + namespace: + description: 'Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1". More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces' + type: string + path: + description: 'Path is the mount path of the Vault KV backend endpoint, e.g: "secret". The v2 KV secret engine version specific "/data" path suffix for fetching secrets from Vault is optional and will be appended if not present in specified path.' + type: string + readYourWrites: + description: ReadYourWrites ensures isolated read-after-write semantics by providing discovered cluster replication states in each request. More information about eventual consistency in Vault can be found here https://www.vaultproject.io/docs/enterprise/consistency + type: boolean + server: + description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' + type: string + version: + default: v2 + description: Version is the Vault KV secret engine version. This can be either "v1" or "v2". Version defaults to "v2". + enum: + - v1 + - v2 + type: string + required: + - auth + - server + type: object + webhook: + description: Webhook configures this store to sync secrets using a generic templated webhook + properties: + body: + description: Body + type: string + caBundle: + description: PEM encoded CA bundle used to validate webhook server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate webhook server certificate. + properties: + key: + description: The key the value inside of the provider type to use, only used with "Secret" type + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + headers: + additionalProperties: + type: string + description: Headers + type: object + method: + description: Webhook Method + type: string + result: + description: Result formatting + properties: + jsonPath: + description: Json path of return value + type: string + type: object + secrets: + description: Secrets to fill in templates These secrets will be passed to the templating function as key value pairs under the given name + items: + properties: + name: + description: Name of this secret in templates + type: string + secretRef: + description: Secret ref to fill in credentials + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - name + - secretRef + type: object + type: array + timeout: + description: Timeout + type: string + url: + description: Webhook url to call + type: string + required: + - result + - url + type: object + yandexlockbox: + description: YandexLockbox configures this store to sync secrets using Yandex Lockbox provider + properties: + apiEndpoint: + description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') + type: string + auth: + description: Auth defines the information necessary to authenticate against Yandex Lockbox + properties: + authorizedKeySecretRef: + description: The authorized key used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + caProvider: + description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. + properties: + certSecretRef: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - auth + type: object + type: object + retrySettings: + description: Used to configure http retries if failed + properties: + maxRetries: + format: int32 + type: integer + retryInterval: + type: string + type: object + required: + - provider + type: object + status: + description: SecretStoreStatus defines the observed state of the SecretStore. + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].reason + name: Status + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: SecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields. + 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: SecretStoreSpec defines the desired state of SecretStore. + properties: + controller: + description: 'Used to select the correct KES controller (think: ingress.ingressClassName) The KES controller is instantiated with a specific controller name and filters ES based on this property' + type: string + provider: + description: Used to configure the provider. Only one provider may be set + maxProperties: 1 + minProperties: 1 + properties: + akeyless: + description: Akeyless configures this store to sync secrets using Akeyless Vault provider + properties: + akeylessGWApiURL: + description: Akeyless GW API Url from which the secrets to be fetched from. + type: string + authSecretRef: + description: Auth configures how the operator authenticates with Akeyless. + properties: + secretRef: + description: 'AkeylessAuthSecretRef AKEYLESS_ACCESS_TYPE_PARAM: AZURE_OBJ_ID OR GCP_AUDIENCE OR ACCESS_KEY OR KUB_CONFIG_NAME.' + properties: + accessID: + description: The SecretAccessID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessType: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessTypeParam: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - secretRef + type: object + required: + - akeylessGWApiURL + - authSecretRef + type: object + alibaba: + description: Alibaba configures this store to sync secrets using Alibaba Cloud provider + properties: + auth: + description: AlibabaAuth contains a secretRef for credentials. + properties: + secretRef: + description: AlibabaAuthSecretRef holds secret references for Alibaba credentials. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + accessKeySecretSecretRef: + description: The AccessKeySecret is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - accessKeyIDSecretRef + - accessKeySecretSecretRef + type: object + required: + - secretRef + type: object + endpoint: + type: string + regionID: + description: Alibaba Region to be used for the provider + type: string + required: + - auth + - regionID + type: object + aws: + description: AWS configures this store to sync secrets using AWS Secret Manager provider + properties: + auth: + description: 'Auth defines the information necessary to authenticate against AWS if not set aws sdk will infer credentials from your environment see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' + properties: + jwt: + description: Authenticate against AWS using service account tokens. + properties: + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + type: object + secretRef: + description: AWSAuthSecretRef holds secret references for AWS credentials both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate. + properties: + accessKeyIDSecretRef: + description: The AccessKeyID is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + type: object + region: + description: AWS Region to be used for the provider + type: string + role: + description: Role is a Role ARN which the SecretManager provider will assume + type: string + service: + description: Service defines which service should be used to fetch the secrets + enum: + - SecretsManager + - ParameterStore + type: string + required: + - region + - service + type: object + azurekv: + description: AzureKV configures this store to sync secrets using Azure Key Vault provider + properties: + authSecretRef: + description: Auth configures how the operator authenticates with Azure. Required for ServicePrincipal auth type. + properties: + clientId: + description: The Azure clientId of the service principle used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + clientSecret: + description: The Azure ClientSecret of the service principle used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + authType: + default: ServicePrincipal + description: 'Auth type defines how to authenticate to the keyvault service. Valid values are: - "ServicePrincipal" (default): Using a service principal (tenantId, clientId, clientSecret) - "ManagedIdentity": Using Managed Identity assigned to the pod (see aad-pod-identity)' + enum: + - ServicePrincipal + - ManagedIdentity + - WorkloadIdentity + type: string + identityId: + description: If multiple Managed Identity is assigned to the pod, you can select the one to be used + type: string + serviceAccountRef: + description: ServiceAccountRef specified the service account that should be used when authenticating with WorkloadIdentity. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + tenantId: + description: TenantID configures the Azure Tenant to send requests to. Required for ServicePrincipal auth type. + type: string + vaultUrl: + description: Vault Url from which the secrets to be fetched from. + type: string + required: + - vaultUrl + type: object + fake: + description: Fake configures a store with static key/value pairs + properties: + data: + items: + properties: + key: + type: string + value: + type: string + valueMap: + additionalProperties: + type: string + type: object + version: + type: string + required: + - key + type: object + type: array + required: + - data + type: object + gcpsm: + description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider + properties: + auth: + description: Auth defines the information necessary to authenticate against GCP + properties: + secretRef: + properties: + secretAccessKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + workloadIdentity: + properties: + clusterLocation: + type: string + clusterName: + type: string + clusterProjectID: + type: string + serviceAccountRef: + description: A reference to a ServiceAccount resource. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - clusterLocation + - clusterName + - serviceAccountRef + type: object + type: object + projectID: + description: ProjectID project where secret is located + type: string + type: object + gitlab: + description: Gitlab configures this store to sync secrets using Gitlab Variables provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a GitLab instance. + properties: + SecretRef: + properties: + accessToken: + description: AccessToken is used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - SecretRef + type: object + projectID: + description: ProjectID specifies a project where secrets are located. + type: string + url: + description: URL configures the GitLab instance URL. Defaults to https://gitlab.com/. + type: string + required: + - auth + type: object + ibm: + description: IBM configures this store to sync secrets using IBM Cloud provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the IBM secrets manager. + maxProperties: 1 + minProperties: 1 + properties: + containerAuth: + description: IBM Container-based auth with IAM Trusted Profile. + properties: + iamEndpoint: + type: string + profile: + description: the IBM Trusted Profile + type: string + tokenLocation: + description: Location the token is mounted on the pod + type: string + required: + - profile + type: object + secretRef: + properties: + secretApiKeySecretRef: + description: The SecretAccessKey is used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + type: object + serviceUrl: + description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance + type: string + required: + - auth + type: object + kubernetes: + description: Kubernetes configures this store to sync secrets using a Kubernetes cluster provider + properties: + auth: + description: Auth configures how secret-manager authenticates with a Kubernetes instance. + maxProperties: 1 + minProperties: 1 + properties: + cert: + description: has both clientCert and clientKey as secretKeySelector + properties: + clientCert: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + clientKey: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + serviceAccount: + description: points to a service account that should be used for authentication + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + token: + description: use static token to authenticate with + properties: + bearerToken: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + type: object + remoteNamespace: + default: default + description: Remote namespace to fetch the secrets from + type: string + server: + description: configures the Kubernetes server Address. + properties: + caBundle: + description: CABundle is a base64-encoded CA certificate + format: byte + type: string + caProvider: + description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider' + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. Can only be defined when used in a ClusterSecretStore. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + url: + default: kubernetes.default + description: configures the Kubernetes server Address. + type: string + type: object + required: + - auth + type: object + onepassword: + description: OnePassword configures this store to sync secrets using the 1Password Cloud provider + properties: + auth: + description: Auth defines the information necessary to authenticate against OnePassword Connect Server + properties: + secretRef: + description: OnePasswordAuthSecretRef holds secret references for 1Password credentials. + properties: + connectTokenSecretRef: + description: The ConnectToken is used for authentication to a 1Password Connect Server. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - connectTokenSecretRef + type: object + required: + - secretRef + type: object + connectHost: + description: ConnectHost defines the OnePassword Connect Server to connect to + type: string + vaults: + additionalProperties: + type: integer + description: Vaults defines which OnePassword vaults to search in which order + type: object + required: + - auth + - connectHost + - vaults + type: object + oracle: + description: Oracle configures this store to sync secrets using Oracle Vault provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the Oracle Vault. If empty, use the instance principal, otherwise the user credentials specified in Auth. + properties: + secretRef: + description: SecretRef to pass through sensitive information. + properties: + fingerprint: + description: Fingerprint is the fingerprint of the API private key. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + privatekey: + description: PrivateKey is the user's API Signing Key in PEM format, used for authentication. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - fingerprint + - privatekey + type: object + tenancy: + description: Tenancy is the tenancy OCID where user is located. + type: string + user: + description: User is an access OCID specific to the account. + type: string + required: + - secretRef + - tenancy + - user + type: object + region: + description: Region is the region where vault is located. + type: string + vault: + description: Vault is the vault's OCID of the specific vault where secret is located. + type: string + required: + - region + - vault + type: object + senhasegura: + description: Senhasegura configures this store to sync secrets using senhasegura provider + properties: + auth: + description: Auth defines parameters to authenticate in senhasegura + properties: + clientId: + type: string + clientSecretSecretRef: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - clientId + - clientSecretSecretRef + type: object + ignoreSslCertificate: + default: false + description: IgnoreSslCertificate defines if SSL certificate must be ignored + type: boolean + module: + description: Module defines which senhasegura module should be used to get secrets + type: string + url: + description: URL of senhasegura + type: string + required: + - auth + - module + - url + type: object + vault: + description: Vault configures this store to sync secrets using Hashi provider + properties: + auth: + description: Auth configures how secret-manager authenticates with the Vault server. + properties: + appRole: + description: AppRole authenticates with Vault using the App Role auth mechanism, with the role and secret stored in a Kubernetes Secret resource. + properties: + path: + default: approle + description: 'Path where the App Role authentication backend is mounted in Vault, e.g: "approle"' + type: string + roleId: + description: RoleID configured in the App Role authentication backend when setting up the authentication backend in Vault. + type: string + secretRef: + description: Reference to a key in a Secret that contains the App Role secret used to authenticate with Vault. The `key` field must be specified and denotes which entry within the Secret resource is used as the app role secret. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - path + - roleId + - secretRef + type: object + cert: + description: Cert authenticates with TLS Certificates by passing client certificate, private key and ca certificate Cert authentication method + properties: + clientCert: + description: ClientCert is a certificate to authenticate using the Cert Vault authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + secretRef: + description: SecretRef to a key in a Secret resource containing client private key to authenticate with Vault using the Cert authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + jwt: + description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method + properties: + kubernetesServiceAccountToken: + description: Optional ServiceAccountToken specifies the Kubernetes service account for which to request a token for with the `TokenRequest` API. + properties: + audiences: + description: Optional audiences field that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to a single audience `vault` it not specified. + items: + type: string + type: array + expirationSeconds: + description: Optional expiration time in seconds that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to 10 minutes. + format: int64 + type: integer + serviceAccountRef: + description: Service account field containing the name of a kubernetes ServiceAccount. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - serviceAccountRef + type: object + path: + default: jwt + description: 'Path where the JWT authentication backend is mounted in Vault, e.g: "jwt"' + type: string + role: + description: Role is a JWT role to authenticate using the JWT/OIDC Vault authentication method + type: string + secretRef: + description: Optional SecretRef that refers to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - path + type: object + kubernetes: + description: Kubernetes authenticates with Vault by passing the ServiceAccount token stored in the named Secret resource to the Vault server. + properties: + mountPath: + default: kubernetes + description: 'Path where the Kubernetes authentication backend is mounted in Vault, e.g: "kubernetes"' + type: string + role: + description: A required field containing the Vault Role to assume. A Role binds a Kubernetes ServiceAccount with a set of Vault policies. + type: string + secretRef: + description: Optional secret field containing a Kubernetes ServiceAccount JWT used for authenticating with Vault. If a name is specified without a key, `token` is the default. If one is not specified, the one bound to the controller will be used. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + serviceAccountRef: + description: Optional service account field containing the name of a kubernetes ServiceAccount. If the service account is specified, the service account secret token JWT will be used for authenticating with Vault. If the service account selector is not supplied, the secretRef will be used instead. + properties: + name: + description: The name of the ServiceAccount resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + required: + - name + type: object + required: + - mountPath + - role + type: object + ldap: + description: Ldap authenticates with Vault by passing username/password pair using the LDAP authentication method + properties: + path: + default: ldap + description: 'Path where the LDAP authentication backend is mounted in Vault, e.g: "ldap"' + type: string + secretRef: + description: SecretRef to a key in a Secret resource containing password for the LDAP user used to authenticate with Vault using the LDAP authentication method + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + username: + description: Username is a LDAP user name used to authenticate using the LDAP Vault authentication method + type: string + required: + - path + - username + type: object + tokenSecretRef: + description: TokenSecretRef authenticates with Vault by presenting a token. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + caBundle: + description: PEM encoded CA bundle used to validate Vault server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate Vault server certificate. + properties: + key: + description: The key where the CA certificate can be found in the Secret or ConfigMap. + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. Can only be defined when used in a ClusterSecretStore. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + forwardInconsistent: + description: ForwardInconsistent tells Vault to forward read-after-write requests to the Vault leader instead of simply retrying within a loop. This can increase performance if the option is enabled serverside. https://www.vaultproject.io/docs/configuration/replication#allow_forwarding_via_header + type: boolean + namespace: + description: 'Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1". More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces' + type: string + path: + description: 'Path is the mount path of the Vault KV backend endpoint, e.g: "secret". The v2 KV secret engine version specific "/data" path suffix for fetching secrets from Vault is optional and will be appended if not present in specified path.' + type: string + readYourWrites: + description: ReadYourWrites ensures isolated read-after-write semantics by providing discovered cluster replication states in each request. More information about eventual consistency in Vault can be found here https://www.vaultproject.io/docs/enterprise/consistency + type: boolean + server: + description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' + type: string + version: + default: v2 + description: Version is the Vault KV secret engine version. This can be either "v1" or "v2". Version defaults to "v2". + enum: + - v1 + - v2 + type: string + required: + - auth + - server + type: object + webhook: + description: Webhook configures this store to sync secrets using a generic templated webhook + properties: + body: + description: Body + type: string + caBundle: + description: PEM encoded CA bundle used to validate webhook server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. + format: byte + type: string + caProvider: + description: The provider for the CA bundle to use to validate webhook server certificate. + properties: + key: + description: The key the value inside of the provider type to use, only used with "Secret" type + type: string + name: + description: The name of the object located at the provider type. + type: string + namespace: + description: The namespace the Provider type is in. + type: string + type: + description: The type of provider to use such as "Secret", or "ConfigMap". + enum: + - Secret + - ConfigMap + type: string + required: + - name + - type + type: object + headers: + additionalProperties: + type: string + description: Headers + type: object + method: + description: Webhook Method + type: string + result: + description: Result formatting + properties: + jsonPath: + description: Json path of return value + type: string + type: object + secrets: + description: Secrets to fill in templates These secrets will be passed to the templating function as key value pairs under the given name + items: + properties: + name: + description: Name of this secret in templates + type: string + secretRef: + description: Secret ref to fill in credentials + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + required: + - name + - secretRef + type: object + type: array + timeout: + description: Timeout + type: string + url: + description: Webhook url to call + type: string + required: + - result + - url + type: object + yandexcertificatemanager: + description: YandexCertificateManager configures this store to sync secrets using Yandex Certificate Manager provider + properties: + apiEndpoint: + description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') + type: string + auth: + description: Auth defines the information necessary to authenticate against Yandex Certificate Manager + properties: + authorizedKeySecretRef: + description: The authorized key used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + caProvider: + description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. + properties: + certSecretRef: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - auth + type: object + yandexlockbox: + description: YandexLockbox configures this store to sync secrets using Yandex Lockbox provider + properties: + apiEndpoint: + description: Yandex.Cloud API endpoint (e.g. 'api.cloud.yandex.net:443') + type: string + auth: + description: Auth defines the information necessary to authenticate against Yandex Lockbox + properties: + authorizedKeySecretRef: + description: The authorized key used for authentication + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + caProvider: + description: The provider for the CA bundle to use to validate Yandex.Cloud server certificate. + properties: + certSecretRef: + description: A reference to a specific 'key' within a Secret resource, In some instances, `key` is a required field. + properties: + key: + description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. + type: string + name: + description: The name of the Secret resource being referred to. + type: string + namespace: + description: Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults to the namespace of the referent. + type: string + type: object + type: object + required: + - auth + type: object + type: object + refreshInterval: + description: Used to configure store refresh interval in seconds. Empty or 0 will default to the controller config. + type: integer + retrySettings: + description: Used to configure http retries if failed + properties: + maxRetries: + format: int32 + type: integer + retryInterval: + type: string + type: object + required: + - provider + type: object + status: + description: SecretStoreStatus defines the observed state of the SecretStore. + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: + - v1 + clientConfig: + service: + name: golang-external-secrets-webhook + namespace: "default" + path: /convert +--- +# Source: golang-external-secrets/charts/external-secrets/templates/cert-controller-rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: golang-external-secrets-cert-controller + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets-cert-controller + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +rules: + - apiGroups: + - "apiextensions.k8s.io" + resources: + - "customresourcedefinitions" + verbs: + - "get" + - "list" + - "watch" + - "update" + - "patch" + - apiGroups: + - "admissionregistration.k8s.io" + resources: + - "validatingwebhookconfigurations" + verbs: + - "get" + - "list" + - "watch" + - "update" + - "patch" + - apiGroups: + - "" + resources: + - "endpoints" + verbs: + - "list" + - "get" + - "watch" + - apiGroups: + - "" + resources: + - "events" + verbs: + - "create" + - "patch" + - apiGroups: + - "" + resources: + - "secrets" + verbs: + - "get" + - "list" + - "watch" + - "update" + - "patch" +--- +# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: golang-external-secrets-controller + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +rules: + - apiGroups: + - "external-secrets.io" + resources: + - "secretstores" + - "clustersecretstores" + - "externalsecrets" + - "clusterexternalsecrets" + verbs: + - "get" + - "list" + - "watch" + - apiGroups: + - "external-secrets.io" + resources: + - "externalsecrets" + - "externalsecrets/status" + - "externalsecrets/finalizers" + - "secretstores" + - "secretstores/status" + - "secretstores/finalizers" + - "clustersecretstores" + - "clustersecretstores/status" + - "clustersecretstores/finalizers" + - "clusterexternalsecrets" + - "clusterexternalsecrets/status" + - "clusterexternalsecrets/finalizers" + verbs: + - "update" + - "patch" + - apiGroups: + - "" + resources: + - "serviceaccounts" + - "namespaces" + verbs: + - "get" + - "list" + - "watch" + - apiGroups: + - "" + resources: + - "configmaps" + verbs: + - "get" + - "list" + - "watch" + - apiGroups: + - "" + resources: + - "secrets" + verbs: + - "get" + - "list" + - "watch" + - "create" + - "update" + - "delete" + - "patch" + - apiGroups: + - "" + resources: + - "serviceaccounts/token" + verbs: + - "create" + - apiGroups: + - "" + resources: + - "events" + verbs: + - "create" + - "patch" + - apiGroups: + - "external-secrets.io" + resources: + - "externalsecrets" + verbs: + - "create" + - "update" +--- +# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: golang-external-secrets-view + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm + rbac.authorization.k8s.io/aggregate-to-view: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" + rbac.authorization.k8s.io/aggregate-to-admin: "true" +rules: + - apiGroups: + - "external-secrets.io" + resources: + - "externalsecrets" + - "secretstores" + - "clustersecretstores" + verbs: + - "get" + - "watch" + - "list" +--- +# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: golang-external-secrets-edit + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm + rbac.authorization.k8s.io/aggregate-to-edit: "true" + rbac.authorization.k8s.io/aggregate-to-admin: "true" +rules: + - apiGroups: + - "external-secrets.io" + resources: + - "externalsecrets" + - "secretstores" + - "clustersecretstores" + verbs: + - "create" + - "delete" + - "deletecollection" + - "patch" + - "update" +--- +# Source: golang-external-secrets/charts/external-secrets/templates/cert-controller-rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: golang-external-secrets-cert-controller + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets-cert-controller + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: golang-external-secrets-cert-controller +subjects: + - name: external-secrets-cert-controller + namespace: "default" + kind: ServiceAccount +--- +# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: golang-external-secrets-controller + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: golang-external-secrets-controller +subjects: + - name: golang-external-secrets + namespace: "default" + kind: ServiceAccount +--- +# Source: golang-external-secrets/templates/golang-external-secrets-hub-clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: role-tokenreview-binding + namespace: default +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator +subjects: +- kind: ServiceAccount + name: golang-external-secrets + namespace: golang-external-secrets +--- +# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: golang-external-secrets-leaderelection + namespace: "default" + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +rules: + - apiGroups: + - "" + resources: + - "configmaps" + resourceNames: + - "external-secrets-controller" + verbs: + - "get" + - "update" + - "patch" + - apiGroups: + - "" + resources: + - "configmaps" + verbs: + - "create" + - apiGroups: + - "coordination.k8s.io" + resources: + - "leases" + verbs: + - "get" + - "create" + - "update" + - "patch" +--- +# Source: golang-external-secrets/charts/external-secrets/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: golang-external-secrets-leaderelection + namespace: "default" + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: golang-external-secrets-leaderelection +subjects: + - kind: ServiceAccount + name: golang-external-secrets + namespace: "default" +--- +# Source: golang-external-secrets/charts/external-secrets/templates/webhook-service.yaml +apiVersion: v1 +kind: Service +metadata: + name: golang-external-secrets-webhook + namespace: "default" + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets-webhook + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm + external-secrets.io/component : webhook +spec: + type: ClusterIP + ports: + - port: 443 + targetPort: 10250 + protocol: TCP + name: webhook + selector: + app.kubernetes.io/name: external-secrets-webhook + app.kubernetes.io/instance: golang-external-secrets +--- +# Source: golang-external-secrets/charts/external-secrets/templates/cert-controller-deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: golang-external-secrets-cert-controller + namespace: "default" + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets-cert-controller + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: external-secrets-cert-controller + app.kubernetes.io/instance: golang-external-secrets + template: + metadata: + labels: + app.kubernetes.io/name: external-secrets-cert-controller + app.kubernetes.io/instance: golang-external-secrets + spec: + serviceAccountName: external-secrets-cert-controller + containers: + - name: cert-controller + image: "ghcr.io/external-secrets/external-secrets:v0.5.9" + imagePullPolicy: IfNotPresent + args: + - certcontroller + - --crd-requeue-interval=5m + - --service-name=golang-external-secrets-webhook + - --service-namespace=default + - --secret-name=golang-external-secrets-webhook + - --secret-namespace=default + ports: + - containerPort: 8080 + protocol: TCP + name: metrics + readinessProbe: + httpGet: + port: 8081 + path: /readyz + initialDelaySeconds: 20 + periodSeconds: 5 +--- +# Source: golang-external-secrets/charts/external-secrets/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: golang-external-secrets + namespace: "default" + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: external-secrets + app.kubernetes.io/instance: golang-external-secrets + template: + metadata: + labels: + app.kubernetes.io/name: external-secrets + app.kubernetes.io/instance: golang-external-secrets + spec: + serviceAccountName: golang-external-secrets + containers: + - name: external-secrets + image: "ghcr.io/external-secrets/external-secrets:v0.5.9" + imagePullPolicy: IfNotPresent + args: + - --concurrent=1 + ports: + - containerPort: 8080 + protocol: TCP + name: metrics +--- +# Source: golang-external-secrets/charts/external-secrets/templates/webhook-deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: golang-external-secrets-webhook + namespace: "default" + labels: + helm.sh/chart: external-secrets-0.5.9 + app.kubernetes.io/name: external-secrets-webhook + app.kubernetes.io/instance: golang-external-secrets + app.kubernetes.io/version: "v0.5.9" + app.kubernetes.io/managed-by: Helm +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: external-secrets-webhook + app.kubernetes.io/instance: golang-external-secrets + template: + metadata: + labels: + app.kubernetes.io/name: external-secrets-webhook + app.kubernetes.io/instance: golang-external-secrets + spec: + hostNetwork: false + serviceAccountName: external-secrets-webhook + containers: + - name: webhook + image: "ghcr.io/external-secrets/external-secrets:v0.5.9" + imagePullPolicy: IfNotPresent + args: + - webhook + - --port=10250 + - --dns-name=golang-external-secrets-webhook.default.svc + - --cert-dir=/tmp/certs + - --check-interval=5m + ports: + - containerPort: 8080 + protocol: TCP + name: metrics + - containerPort: 10250 + protocol: TCP + name: webhook + readinessProbe: + httpGet: + port: 8081 + path: /readyz + initialDelaySeconds: 20 + periodSeconds: 5 + volumeMounts: + - name: certs + mountPath: /tmp/certs + readOnly: true + volumes: + - name: certs + secret: + secretName: golang-external-secrets-webhook +--- +# Source: golang-external-secrets/templates/golang-external-secrets-hub-secretstore.yaml +apiVersion: external-secrets.io/v1beta1 +kind: ClusterSecretStore +metadata: + name: vault-backend + namespace: golang-external-secrets +spec: + provider: + vault: + server: https://vault-vault.apps.hub.example.com + path: secret + # Version of KV backend + version: v2 + caProvider: + type: ConfigMap + name: kube-root-ca.crt + key: ca.crt + namespace: golang-external-secrets + auth: + kubernetes: + mountPath: hub + role: hub-role + secretRef: + name: golang-external-secrets + namespace: golang-external-secrets + key: "token" +--- +# Source: golang-external-secrets/charts/external-secrets/templates/validatingwebhook.yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: secretstore-validate + labels: + external-secrets.io/component: webhook +webhooks: +- name: "validate.secretstore.external-secrets.io" + rules: + - apiGroups: ["external-secrets.io"] + apiVersions: ["v1beta1"] + operations: ["CREATE", "UPDATE", "DELETE"] + resources: ["secretstores"] + scope: "Namespaced" + clientConfig: + service: + namespace: "default" + name: golang-external-secrets-webhook + path: /validate-external-secrets-io-v1beta1-secretstore + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + +- name: "validate.clustersecretstore.external-secrets.io" + rules: + - apiGroups: ["external-secrets.io"] + apiVersions: ["v1beta1"] + operations: ["CREATE", "UPDATE", "DELETE"] + resources: ["clustersecretstores"] + scope: "Cluster" + clientConfig: + service: + namespace: "default" + name: golang-external-secrets-webhook + path: /validate-external-secrets-io-v1beta1-clustersecretstore + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 +--- +# Source: golang-external-secrets/charts/external-secrets/templates/validatingwebhook.yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: externalsecret-validate + labels: + external-secrets.io/component: webhook +webhooks: +- name: "validate.externalsecret.external-secrets.io" + rules: + - apiGroups: ["external-secrets.io"] + apiVersions: ["v1beta1"] + operations: ["CREATE", "UPDATE", "DELETE"] + resources: ["externalsecrets"] + scope: "Namespaced" + clientConfig: + service: + namespace: "default" + name: golang-external-secrets-webhook + path: /validate-external-secrets-io-v1beta1-externalsecret + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 + failurePolicy: Fail diff --git a/tests/golang-external-secrets.expected.diff b/tests/golang-external-secrets.expected.diff new file mode 100644 index 00000000..299cd616 --- /dev/null +++ b/tests/golang-external-secrets.expected.diff @@ -0,0 +1,11 @@ +--- tests/golang-external-secrets-naked.expected.yml ++++ tests/golang-external-secrets-normal.expected.yml +@@ -5827,7 +5827,7 @@ + spec: + provider: + vault: +- server: https://vault-vault.hub.example.com ++ server: https://vault-vault.apps.hub.example.com + path: secret + # Version of KV backend + version: v2 diff --git a/tests/hashicorp-vault-naked.expected.yml b/tests/hashicorp-vault-naked.expected.yml new file mode 100644 index 00000000..51800147 --- /dev/null +++ b/tests/hashicorp-vault-naked.expected.yml @@ -0,0 +1,409 @@ +--- +# Source: hashicorp-vault/charts/vault/templates/server-serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: hashicorp-vault + namespace: default + labels: + helm.sh/chart: vault-0.22.0 + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + app.kubernetes.io/managed-by: Helm +--- +# Source: hashicorp-vault/charts/vault/templates/server-config-configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: hashicorp-vault-config + namespace: default + labels: + helm.sh/chart: vault-0.22.0 + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + app.kubernetes.io/managed-by: Helm +data: + extraconfig-from-values.hcl: |- + disable_mlock = true + ui = true + + listener "tcp" { + tls_disable = 1 + address = "[::]:8200" + cluster_address = "[::]:8201" + # Enable unauthenticated metrics access (necessary for Prometheus Operator) + #telemetry { + # unauthenticated_metrics_access = "true" + #} + } + storage "file" { + path = "/vault/data" + } + + # Example configuration for using auto-unseal, using Google Cloud KMS. The + # GKMS keys must already exist, and the cluster must have a service account + # that is authorized to access GCP KMS. + #seal "gcpckms" { + # project = "vault-helm-dev" + # region = "global" + # key_ring = "vault-helm-unseal-kr" + # crypto_key = "vault-helm-unseal-key" + #} + + # Example configuration for enabling Prometheus metrics in your config. + #telemetry { + # prometheus_retention_time = "30s", + # disable_hostname = true + #} +--- +# Source: hashicorp-vault/charts/vault/templates/server-clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: hashicorp-vault-server-binding + labels: + helm.sh/chart: vault-0.22.0 + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + app.kubernetes.io/managed-by: Helm +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator +subjects: +- kind: ServiceAccount + name: hashicorp-vault + namespace: default +--- +# Source: hashicorp-vault/charts/vault/templates/server-headless-service.yaml +# Service for Vault cluster +apiVersion: v1 +kind: Service +metadata: + name: hashicorp-vault-internal + namespace: default + labels: + helm.sh/chart: vault-0.22.0 + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + app.kubernetes.io/managed-by: Helm + vault-internal: "true" + annotations: + +spec: + clusterIP: None + publishNotReadyAddresses: true + ports: + - name: "http" + port: 8200 + targetPort: 8200 + - name: https-internal + port: 8201 + targetPort: 8201 + selector: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + component: server +--- +# Source: hashicorp-vault/charts/vault/templates/server-service.yaml +# Service for Vault cluster +apiVersion: v1 +kind: Service +metadata: + name: hashicorp-vault + namespace: default + labels: + helm.sh/chart: vault-0.22.0 + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + app.kubernetes.io/managed-by: Helm + annotations: + +spec: + # We want the servers to become available even if they're not ready + # since this DNS is also used for join operations. + publishNotReadyAddresses: true + ports: + - name: http + port: 8200 + targetPort: 8200 + - name: https-internal + port: 8201 + targetPort: 8201 + selector: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + component: server +--- +# Source: hashicorp-vault/charts/vault/templates/ui-service.yaml +apiVersion: v1 +kind: Service +metadata: + name: hashicorp-vault-ui + namespace: default + labels: + helm.sh/chart: vault-0.22.0 + app.kubernetes.io/name: vault-ui + app.kubernetes.io/instance: hashicorp-vault + app.kubernetes.io/managed-by: Helm +spec: + selector: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + component: server + publishNotReadyAddresses: true + ports: + - name: http + port: 8200 + targetPort: 8200 + type: LoadBalancer + externalTrafficPolicy: Cluster +--- +# Source: hashicorp-vault/charts/vault/templates/server-statefulset.yaml +# StatefulSet to run the actual vault server cluster. +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: hashicorp-vault + namespace: default + labels: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + app.kubernetes.io/managed-by: Helm +spec: + serviceName: hashicorp-vault-internal + podManagementPolicy: Parallel + replicas: 1 + updateStrategy: + type: OnDelete + selector: + matchLabels: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + component: server + template: + metadata: + labels: + helm.sh/chart: vault-0.22.0 + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + component: server + spec: + + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: "hashicorp-vault" + component: server + topologyKey: kubernetes.io/hostname + + + + + terminationGracePeriodSeconds: 10 + serviceAccountName: hashicorp-vault + + volumes: + + - name: config + configMap: + name: hashicorp-vault-config + + - name: home + emptyDir: {} + containers: + - name: vault + + image: registry.connect.redhat.com/hashicorp/vault:1.11.3-ubi + imagePullPolicy: IfNotPresent + command: + - "/bin/sh" + - "-ec" + args: + - | + cp /vault/config/extraconfig-from-values.hcl /tmp/storageconfig.hcl; + [ -n "${HOST_IP}" ] && sed -Ei "s|HOST_IP|${HOST_IP?}|g" /tmp/storageconfig.hcl; + [ -n "${POD_IP}" ] && sed -Ei "s|POD_IP|${POD_IP?}|g" /tmp/storageconfig.hcl; + [ -n "${HOSTNAME}" ] && sed -Ei "s|HOSTNAME|${HOSTNAME?}|g" /tmp/storageconfig.hcl; + [ -n "${API_ADDR}" ] && sed -Ei "s|API_ADDR|${API_ADDR?}|g" /tmp/storageconfig.hcl; + [ -n "${TRANSIT_ADDR}" ] && sed -Ei "s|TRANSIT_ADDR|${TRANSIT_ADDR?}|g" /tmp/storageconfig.hcl; + [ -n "${RAFT_ADDR}" ] && sed -Ei "s|RAFT_ADDR|${RAFT_ADDR?}|g" /tmp/storageconfig.hcl; + /usr/local/bin/docker-entrypoint.sh vault server -config=/tmp/storageconfig.hcl + + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: VAULT_K8S_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: VAULT_K8S_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: VAULT_ADDR + value: "http://127.0.0.1:8200" + - name: VAULT_API_ADDR + value: "http://$(POD_IP):8200" + - name: SKIP_CHOWN + value: "true" + - name: SKIP_SETCAP + value: "true" + - name: HOSTNAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: VAULT_CLUSTER_ADDR + value: "https://$(HOSTNAME).hashicorp-vault-internal:8201" + - name: HOME + value: "/home/vault" + + + + volumeMounts: + + + + - name: data + mountPath: /vault/data + + + + - name: config + mountPath: /vault/config + + - name: home + mountPath: /home/vault + ports: + - containerPort: 8200 + name: http + - containerPort: 8201 + name: https-internal + - containerPort: 8202 + name: http-rep + readinessProbe: + # Check status; unsealed vault servers return 0 + # The exit code reflects the seal status: + # 0 - unsealed + # 1 - error + # 2 - sealed + exec: + command: ["/bin/sh", "-ec", "vault status -tls-skip-verify"] + failureThreshold: 2 + initialDelaySeconds: 5 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 3 + lifecycle: + # Vault container doesn't receive SIGTERM from Kubernetes + # and after the grace period ends, Kube sends SIGKILL. This + # causes issues with graceful shutdowns such as deregistering itself + # from Consul (zombie services). + preStop: + exec: + command: [ + "/bin/sh", "-c", + # Adding a sleep here to give the pod eviction a + # chance to propagate, so requests will not be made + # to this pod while it's terminating + "sleep 5 && kill -SIGTERM $(pidof vault)", + ] + + + volumeClaimTemplates: + - metadata: + name: data + + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi +--- +# Source: hashicorp-vault/templates/vault-app.yaml +apiVersion: console.openshift.io/v1 +kind: ConsoleLink +metadata: + name: vault-link + namespace: vault +spec: + applicationMenu: + section: HashiCorp Vault + imageURL: data:image/png;base64,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 + href: 'https://vault-vault.apps.foo.cluster.com' + location: ApplicationMenu + text: 'Vault' +--- +# Source: hashicorp-vault/charts/vault/templates/server-route.yaml +kind: Route +apiVersion: route.openshift.io/v1 +metadata: + name: hashicorp-vault + namespace: default + labels: + helm.sh/chart: vault-0.22.0 + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + app.kubernetes.io/managed-by: Helm +spec: + host: + to: + kind: Service + name: hashicorp-vault + weight: 100 + port: + targetPort: 8200 + tls: + termination: edge +--- +# Source: hashicorp-vault/charts/vault/templates/tests/server-test.yaml +apiVersion: v1 +kind: Pod +metadata: + name: "hashicorp-vault-server-test" + namespace: default + annotations: + "helm.sh/hook": test +spec: + + containers: + - name: hashicorp-vault-server-test + image: registry.connect.redhat.com/hashicorp/vault:1.11.3-ubi + imagePullPolicy: IfNotPresent + env: + - name: VAULT_ADDR + value: http://hashicorp-vault.default.svc:8200 + + command: + - /bin/sh + - -c + - | + echo "Checking for sealed info in 'vault status' output" + ATTEMPTS=10 + n=0 + until [ "$n" -ge $ATTEMPTS ] + do + echo "Attempt" $n... + vault status -format yaml | grep -E '^sealed: (true|false)' && break + n=$((n+1)) + sleep 5 + done + if [ $n -ge $ATTEMPTS ]; then + echo "timed out looking for sealed info in 'vault status' output" + exit 1 + fi + + exit 0 + volumeMounts: + volumes: + restartPolicy: Never diff --git a/tests/hashicorp-vault-normal.expected.yml b/tests/hashicorp-vault-normal.expected.yml new file mode 100644 index 00000000..9d707c16 --- /dev/null +++ b/tests/hashicorp-vault-normal.expected.yml @@ -0,0 +1,409 @@ +--- +# Source: hashicorp-vault/charts/vault/templates/server-serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: hashicorp-vault + namespace: default + labels: + helm.sh/chart: vault-0.22.0 + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + app.kubernetes.io/managed-by: Helm +--- +# Source: hashicorp-vault/charts/vault/templates/server-config-configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: hashicorp-vault-config + namespace: default + labels: + helm.sh/chart: vault-0.22.0 + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + app.kubernetes.io/managed-by: Helm +data: + extraconfig-from-values.hcl: |- + disable_mlock = true + ui = true + + listener "tcp" { + tls_disable = 1 + address = "[::]:8200" + cluster_address = "[::]:8201" + # Enable unauthenticated metrics access (necessary for Prometheus Operator) + #telemetry { + # unauthenticated_metrics_access = "true" + #} + } + storage "file" { + path = "/vault/data" + } + + # Example configuration for using auto-unseal, using Google Cloud KMS. The + # GKMS keys must already exist, and the cluster must have a service account + # that is authorized to access GCP KMS. + #seal "gcpckms" { + # project = "vault-helm-dev" + # region = "global" + # key_ring = "vault-helm-unseal-kr" + # crypto_key = "vault-helm-unseal-key" + #} + + # Example configuration for enabling Prometheus metrics in your config. + #telemetry { + # prometheus_retention_time = "30s", + # disable_hostname = true + #} +--- +# Source: hashicorp-vault/charts/vault/templates/server-clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: hashicorp-vault-server-binding + labels: + helm.sh/chart: vault-0.22.0 + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + app.kubernetes.io/managed-by: Helm +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator +subjects: +- kind: ServiceAccount + name: hashicorp-vault + namespace: default +--- +# Source: hashicorp-vault/charts/vault/templates/server-headless-service.yaml +# Service for Vault cluster +apiVersion: v1 +kind: Service +metadata: + name: hashicorp-vault-internal + namespace: default + labels: + helm.sh/chart: vault-0.22.0 + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + app.kubernetes.io/managed-by: Helm + vault-internal: "true" + annotations: + +spec: + clusterIP: None + publishNotReadyAddresses: true + ports: + - name: "http" + port: 8200 + targetPort: 8200 + - name: https-internal + port: 8201 + targetPort: 8201 + selector: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + component: server +--- +# Source: hashicorp-vault/charts/vault/templates/server-service.yaml +# Service for Vault cluster +apiVersion: v1 +kind: Service +metadata: + name: hashicorp-vault + namespace: default + labels: + helm.sh/chart: vault-0.22.0 + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + app.kubernetes.io/managed-by: Helm + annotations: + +spec: + # We want the servers to become available even if they're not ready + # since this DNS is also used for join operations. + publishNotReadyAddresses: true + ports: + - name: http + port: 8200 + targetPort: 8200 + - name: https-internal + port: 8201 + targetPort: 8201 + selector: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + component: server +--- +# Source: hashicorp-vault/charts/vault/templates/ui-service.yaml +apiVersion: v1 +kind: Service +metadata: + name: hashicorp-vault-ui + namespace: default + labels: + helm.sh/chart: vault-0.22.0 + app.kubernetes.io/name: vault-ui + app.kubernetes.io/instance: hashicorp-vault + app.kubernetes.io/managed-by: Helm +spec: + selector: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + component: server + publishNotReadyAddresses: true + ports: + - name: http + port: 8200 + targetPort: 8200 + type: LoadBalancer + externalTrafficPolicy: Cluster +--- +# Source: hashicorp-vault/charts/vault/templates/server-statefulset.yaml +# StatefulSet to run the actual vault server cluster. +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: hashicorp-vault + namespace: default + labels: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + app.kubernetes.io/managed-by: Helm +spec: + serviceName: hashicorp-vault-internal + podManagementPolicy: Parallel + replicas: 1 + updateStrategy: + type: OnDelete + selector: + matchLabels: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + component: server + template: + metadata: + labels: + helm.sh/chart: vault-0.22.0 + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + component: server + spec: + + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: "hashicorp-vault" + component: server + topologyKey: kubernetes.io/hostname + + + + + terminationGracePeriodSeconds: 10 + serviceAccountName: hashicorp-vault + + volumes: + + - name: config + configMap: + name: hashicorp-vault-config + + - name: home + emptyDir: {} + containers: + - name: vault + + image: registry.connect.redhat.com/hashicorp/vault:1.11.3-ubi + imagePullPolicy: IfNotPresent + command: + - "/bin/sh" + - "-ec" + args: + - | + cp /vault/config/extraconfig-from-values.hcl /tmp/storageconfig.hcl; + [ -n "${HOST_IP}" ] && sed -Ei "s|HOST_IP|${HOST_IP?}|g" /tmp/storageconfig.hcl; + [ -n "${POD_IP}" ] && sed -Ei "s|POD_IP|${POD_IP?}|g" /tmp/storageconfig.hcl; + [ -n "${HOSTNAME}" ] && sed -Ei "s|HOSTNAME|${HOSTNAME?}|g" /tmp/storageconfig.hcl; + [ -n "${API_ADDR}" ] && sed -Ei "s|API_ADDR|${API_ADDR?}|g" /tmp/storageconfig.hcl; + [ -n "${TRANSIT_ADDR}" ] && sed -Ei "s|TRANSIT_ADDR|${TRANSIT_ADDR?}|g" /tmp/storageconfig.hcl; + [ -n "${RAFT_ADDR}" ] && sed -Ei "s|RAFT_ADDR|${RAFT_ADDR?}|g" /tmp/storageconfig.hcl; + /usr/local/bin/docker-entrypoint.sh vault server -config=/tmp/storageconfig.hcl + + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: VAULT_K8S_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: VAULT_K8S_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: VAULT_ADDR + value: "http://127.0.0.1:8200" + - name: VAULT_API_ADDR + value: "http://$(POD_IP):8200" + - name: SKIP_CHOWN + value: "true" + - name: SKIP_SETCAP + value: "true" + - name: HOSTNAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: VAULT_CLUSTER_ADDR + value: "https://$(HOSTNAME).hashicorp-vault-internal:8201" + - name: HOME + value: "/home/vault" + + + + volumeMounts: + + + + - name: data + mountPath: /vault/data + + + + - name: config + mountPath: /vault/config + + - name: home + mountPath: /home/vault + ports: + - containerPort: 8200 + name: http + - containerPort: 8201 + name: https-internal + - containerPort: 8202 + name: http-rep + readinessProbe: + # Check status; unsealed vault servers return 0 + # The exit code reflects the seal status: + # 0 - unsealed + # 1 - error + # 2 - sealed + exec: + command: ["/bin/sh", "-ec", "vault status -tls-skip-verify"] + failureThreshold: 2 + initialDelaySeconds: 5 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 3 + lifecycle: + # Vault container doesn't receive SIGTERM from Kubernetes + # and after the grace period ends, Kube sends SIGKILL. This + # causes issues with graceful shutdowns such as deregistering itself + # from Consul (zombie services). + preStop: + exec: + command: [ + "/bin/sh", "-c", + # Adding a sleep here to give the pod eviction a + # chance to propagate, so requests will not be made + # to this pod while it's terminating + "sleep 5 && kill -SIGTERM $(pidof vault)", + ] + + + volumeClaimTemplates: + - metadata: + name: data + + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi +--- +# Source: hashicorp-vault/templates/vault-app.yaml +apiVersion: console.openshift.io/v1 +kind: ConsoleLink +metadata: + name: vault-link + namespace: vault +spec: + applicationMenu: + section: HashiCorp Vault + imageURL: data:image/png;base64,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 + href: 'https://vault-vault.apps.region.example.com' + location: ApplicationMenu + text: 'Vault' +--- +# Source: hashicorp-vault/charts/vault/templates/server-route.yaml +kind: Route +apiVersion: route.openshift.io/v1 +metadata: + name: hashicorp-vault + namespace: default + labels: + helm.sh/chart: vault-0.22.0 + app.kubernetes.io/name: vault + app.kubernetes.io/instance: hashicorp-vault + app.kubernetes.io/managed-by: Helm +spec: + host: + to: + kind: Service + name: hashicorp-vault + weight: 100 + port: + targetPort: 8200 + tls: + termination: edge +--- +# Source: hashicorp-vault/charts/vault/templates/tests/server-test.yaml +apiVersion: v1 +kind: Pod +metadata: + name: "hashicorp-vault-server-test" + namespace: default + annotations: + "helm.sh/hook": test +spec: + + containers: + - name: hashicorp-vault-server-test + image: registry.connect.redhat.com/hashicorp/vault:1.11.3-ubi + imagePullPolicy: IfNotPresent + env: + - name: VAULT_ADDR + value: http://hashicorp-vault.default.svc:8200 + + command: + - /bin/sh + - -c + - | + echo "Checking for sealed info in 'vault status' output" + ATTEMPTS=10 + n=0 + until [ "$n" -ge $ATTEMPTS ] + do + echo "Attempt" $n... + vault status -format yaml | grep -E '^sealed: (true|false)' && break + n=$((n+1)) + sleep 5 + done + if [ $n -ge $ATTEMPTS ]; then + echo "timed out looking for sealed info in 'vault status' output" + exit 1 + fi + + exit 0 + volumeMounts: + volumes: + restartPolicy: Never diff --git a/tests/hashicorp-vault.expected.diff b/tests/hashicorp-vault.expected.diff new file mode 100644 index 00000000..dbc3442f --- /dev/null +++ b/tests/hashicorp-vault.expected.diff @@ -0,0 +1,11 @@ +--- tests/hashicorp-vault-naked.expected.yml ++++ tests/hashicorp-vault-normal.expected.yml +@@ -340,7 +340,7 @@ + applicationMenu: + section: HashiCorp Vault + imageURL: data:image/png;base64,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 +- href: 'https://vault-vault.apps.foo.cluster.com' ++ href: 'https://vault-vault.apps.region.example.com' + location: ApplicationMenu + text: 'Vault' + --- diff --git a/tests/install-naked.expected.yml b/tests/install-naked.expected.yml new file mode 100644 index 00000000..7272f0eb --- /dev/null +++ b/tests/install-naked.expected.yml @@ -0,0 +1,64 @@ +--- +# Source: pattern-install/templates/argocd/namespace.yaml +# Pre-create so we can create our argo app for keeping subscriptions in sync +# Do it here so that we don't try to sync it in the future +apiVersion: v1 +kind: Namespace +metadata: + name: openshift-gitops +--- +# Source: pattern-install/templates/argocd/application.yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: install-default + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground +spec: + destination: + name: in-cluster + namespace: install-default + project: default + source: + repoURL: https://github.com/pattern-clone/mypattern + targetRevision: main + path: common/clustergroup + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-default.yaml" + # Track the progress of https://github.com/argoproj/argo-cd/pull/6280 + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: install + - name: global.hubClusterDomain + value: + syncPolicy: + automated: {} +--- +# Source: pattern-install/templates/argocd/subscription.yaml +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: openshift-gitops-operator + namespace: openshift-operators + labels: + operators.coreos.com/openshift-gitops-operator.openshift-operators: "" +spec: + channel: stable + installPlanApproval: Automatic + name: openshift-gitops-operator + source: redhat-operators + sourceNamespace: openshift-marketplace + config: + env: + - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES + value: install-default,openshift-gitops diff --git a/tests/install-normal.expected.yml b/tests/install-normal.expected.yml new file mode 100644 index 00000000..faaef3cc --- /dev/null +++ b/tests/install-normal.expected.yml @@ -0,0 +1,64 @@ +--- +# Source: pattern-install/templates/argocd/namespace.yaml +# Pre-create so we can create our argo app for keeping subscriptions in sync +# Do it here so that we don't try to sync it in the future +apiVersion: v1 +kind: Namespace +metadata: + name: openshift-gitops +--- +# Source: pattern-install/templates/argocd/application.yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: install-example + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground +spec: + destination: + name: in-cluster + namespace: install-example + project: default + source: + repoURL: https://github.com/pattern-clone/mypattern + targetRevision: main + path: common/clustergroup + helm: + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" + - "/values-example.yaml" + # Track the progress of https://github.com/argoproj/argo-cd/pull/6280 + parameters: + - name: global.repoURL + value: $ARGOCD_APP_SOURCE_REPO_URL + - name: global.targetRevision + value: $ARGOCD_APP_SOURCE_TARGET_REVISION + - name: global.namespace + value: $ARGOCD_APP_NAMESPACE + - name: global.pattern + value: install + - name: global.hubClusterDomain + value: apps.hub.example.com + syncPolicy: + automated: {} +--- +# Source: pattern-install/templates/argocd/subscription.yaml +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: openshift-gitops-operator + namespace: openshift-operators + labels: + operators.coreos.com/openshift-gitops-operator.openshift-operators: "" +spec: + channel: stable + installPlanApproval: Automatic + name: openshift-gitops-operator + source: redhat-operators + sourceNamespace: openshift-marketplace + config: + env: + - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES + value: install-example,openshift-gitops diff --git a/tests/install.expected.diff b/tests/install.expected.diff new file mode 100644 index 00000000..563de641 --- /dev/null +++ b/tests/install.expected.diff @@ -0,0 +1,43 @@ +--- tests/install-naked.expected.yml ++++ tests/install-normal.expected.yml +@@ -11,14 +11,14 @@ + apiVersion: argoproj.io/v1alpha1 + kind: Application + metadata: +- name: install-default ++ name: install-example + namespace: openshift-gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground + spec: + destination: + name: in-cluster +- namespace: install-default ++ namespace: install-example + project: default + source: + repoURL: https://github.com/pattern-clone/mypattern +@@ -28,7 +28,7 @@ + ignoreMissingValueFiles: true + valueFiles: + - "/values-global.yaml" +- - "/values-default.yaml" ++ - "/values-example.yaml" + # Track the progress of https://github.com/argoproj/argo-cd/pull/6280 + parameters: + - name: global.repoURL +@@ -40,7 +40,7 @@ + - name: global.pattern + value: install + - name: global.hubClusterDomain +- value: ++ value: apps.hub.example.com + syncPolicy: + automated: {} + --- +@@ -61,4 +61,4 @@ + config: + env: + - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES +- value: install-default,openshift-gitops ++ value: install-example,openshift-gitops diff --git a/tests/operator-install-naked.expected.yml b/tests/operator-install-naked.expected.yml new file mode 100644 index 00000000..6b4cddc7 --- /dev/null +++ b/tests/operator-install-naked.expected.yml @@ -0,0 +1,29 @@ +--- +# Source: pattern-install/templates/pattern.yaml +apiVersion: gitops.hybrid-cloud-patterns.io/v1alpha1 +kind: Pattern +metadata: + name: operator-install + namespace: openshift-operators +spec: + clusterGroupName: default + gitSpec: + targetRepo: https://github.com/pattern-clone/mypattern + targetRevision: main + gitOpsSpec: + operatorChannel: stable +--- +# Source: pattern-install/templates/subscription.yaml +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: patterns-operator + namespace: openshift-operators + labels: + operators.coreos.com/patterns-operator.openshift-operators: "" +spec: + channel: fast + installPlanApproval: Automatic + name: patterns-operator + source: community-operators + sourceNamespace: openshift-marketplace diff --git a/tests/operator-install-normal.expected.yml b/tests/operator-install-normal.expected.yml new file mode 100644 index 00000000..dc07be36 --- /dev/null +++ b/tests/operator-install-normal.expected.yml @@ -0,0 +1,29 @@ +--- +# Source: pattern-install/templates/pattern.yaml +apiVersion: gitops.hybrid-cloud-patterns.io/v1alpha1 +kind: Pattern +metadata: + name: operator-install + namespace: openshift-operators +spec: + clusterGroupName: example + gitSpec: + targetRepo: https://github.com/pattern-clone/mypattern + targetRevision: main + gitOpsSpec: + operatorChannel: stable +--- +# Source: pattern-install/templates/subscription.yaml +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: patterns-operator + namespace: openshift-operators + labels: + operators.coreos.com/patterns-operator.openshift-operators: "" +spec: + channel: fast + installPlanApproval: Automatic + name: patterns-operator + source: community-operators + sourceNamespace: openshift-marketplace diff --git a/tests/operator-install.expected.diff b/tests/operator-install.expected.diff new file mode 100644 index 00000000..9f5bdedc --- /dev/null +++ b/tests/operator-install.expected.diff @@ -0,0 +1,11 @@ +--- tests/operator-install-naked.expected.yml ++++ tests/operator-install-normal.expected.yml +@@ -6,7 +6,7 @@ + name: operator-install + namespace: openshift-operators + spec: +- clusterGroupName: default ++ clusterGroupName: example + gitSpec: + targetRepo: https://github.com/pattern-clone/mypattern + targetRevision: main diff --git a/values-global.yaml b/values-global.yaml new file mode 100644 index 00000000..8a890f3d --- /dev/null +++ b/values-global.yaml @@ -0,0 +1,16 @@ +global: + options: + useCSV: True + syncPolicy: Manual + installPlanApproval: Automatic + + git: + hostname: github.com + # Account is the user or organization under which the pattern repos lives + account: hybrid-cloud-patterns + email: someone@somewhere.com + dev_revision: main + +main: + clusterGroupName: example + From 71f39ffc47fcc1181155231e2b8c812873d73db0 Mon Sep 17 00:00:00 2001 From: ruromero Date: Mon, 3 Oct 2022 10:24:28 +0200 Subject: [PATCH 3/4] adapt tests to new common Signed-off-by: ruromero --- ...d.yaml => all-bookinfo-naked.expected.yml} | 0 ....yaml => all-bookinfo-normal.expected.yml} | 0 tests/all-bookinfo.expected.diff | 136 +++++++++++++++ ...yaml => all-clustering-naked.expected.yml} | 0 ...aml => all-clustering-normal.expected.yml} | 0 tests/all-clustering.expected.diff | 164 ++++++++++++++++++ ...ected.yaml => all-kong-naked.expected.yml} | 0 ...cted.yaml => all-kong-normal.expected.yml} | 0 tests/all-kong.expected.diff | 158 +++++++++++++++++ 9 files changed, 458 insertions(+) rename tests/{all-bookinfo-naked.expected.yaml => all-bookinfo-naked.expected.yml} (100%) rename tests/{all-bookinfo-normal.expected.yaml => all-bookinfo-normal.expected.yml} (100%) create mode 100644 tests/all-bookinfo.expected.diff rename tests/{all-clustering-naked.expected.yaml => all-clustering-naked.expected.yml} (100%) rename tests/{all-clustering-normal.expected.yaml => all-clustering-normal.expected.yml} (100%) create mode 100644 tests/all-clustering.expected.diff rename tests/{all-kong-naked.expected.yaml => all-kong-naked.expected.yml} (100%) rename tests/{all-kong-normal.expected.yaml => all-kong-normal.expected.yml} (100%) create mode 100644 tests/all-kong.expected.diff diff --git a/tests/all-bookinfo-naked.expected.yaml b/tests/all-bookinfo-naked.expected.yml similarity index 100% rename from tests/all-bookinfo-naked.expected.yaml rename to tests/all-bookinfo-naked.expected.yml diff --git a/tests/all-bookinfo-normal.expected.yaml b/tests/all-bookinfo-normal.expected.yml similarity index 100% rename from tests/all-bookinfo-normal.expected.yaml rename to tests/all-bookinfo-normal.expected.yml diff --git a/tests/all-bookinfo.expected.diff b/tests/all-bookinfo.expected.diff new file mode 100644 index 00000000..69e547d1 --- /dev/null +++ b/tests/all-bookinfo.expected.diff @@ -0,0 +1,136 @@ +--- tests/all-bookinfo-naked.expected.yml ++++ tests/all-bookinfo-normal.expected.yml +@@ -3,14 +3,14 @@ + apiVersion: v1 + kind: Namespace + metadata: +- name: bookinfo ++ name: pattern-namespace + --- + # Source: bookinfo/charts/details/templates/serviceaccount.yaml + apiVersion: v1 + kind: ServiceAccount + metadata: + name: bookinfo-details +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + account: details + --- +@@ -19,7 +19,7 @@ + kind: ServiceAccount + metadata: + name: bookinfo-productpage +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + account: productpage + --- +@@ -28,7 +28,7 @@ + kind: ServiceAccount + metadata: + name: bookinfo-ratings +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + account: ratings + --- +@@ -37,7 +37,7 @@ + kind: ServiceAccount + metadata: + name: bookinfo-reviews +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + account: reviews + --- +@@ -75,7 +75,7 @@ + kind: Service + metadata: + name: details +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + app: details + service: details +@@ -91,7 +91,7 @@ + kind: Service + metadata: + name: productpage +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + app: productpage + service: productpage +@@ -110,7 +110,7 @@ + kind: Service + metadata: + name: ratings +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + app: ratings + service: ratings +@@ -126,7 +126,7 @@ + kind: Service + metadata: + name: reviews +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + app: reviews + service: reviews +@@ -142,7 +142,7 @@ + kind: Deployment + metadata: + name: details-v1 +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + helm.sh/chart: details-0.1.0 + app: details +@@ -176,7 +176,7 @@ + kind: Deployment + metadata: + name: productpage-v1 +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + helm.sh/chart: productpage-0.1.0 + app: productpage +@@ -216,7 +216,7 @@ + kind: Deployment + metadata: + name: ratings-v1 +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + helm.sh/chart: ratings-0.1.0 + app: ratings +@@ -250,7 +250,7 @@ + kind: Deployment + metadata: + name: reviews-v1 +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + helm.sh/chart: reviews-0.1.0 + app: reviews +@@ -297,7 +297,7 @@ + kind: Deployment + metadata: + name: reviews-v2 +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + helm.sh/chart: reviews-0.1.0 + app: reviews +@@ -344,7 +344,7 @@ + kind: Deployment + metadata: + name: reviews-v3 +- namespace: bookinfo ++ namespace: pattern-namespace + labels: + helm.sh/chart: reviews-0.1.0 + app: reviews diff --git a/tests/all-clustering-naked.expected.yaml b/tests/all-clustering-naked.expected.yml similarity index 100% rename from tests/all-clustering-naked.expected.yaml rename to tests/all-clustering-naked.expected.yml diff --git a/tests/all-clustering-normal.expected.yaml b/tests/all-clustering-normal.expected.yml similarity index 100% rename from tests/all-clustering-normal.expected.yaml rename to tests/all-clustering-normal.expected.yml diff --git a/tests/all-clustering.expected.diff b/tests/all-clustering.expected.diff new file mode 100644 index 00000000..983ca8a2 --- /dev/null +++ b/tests/all-clustering.expected.diff @@ -0,0 +1,164 @@ +--- tests/all-clustering-naked.expected.yml ++++ tests/all-clustering-normal.expected.yml +@@ -3,22 +3,22 @@ + apiVersion: v1 + kind: ServiceAccount + metadata: +- name: kong-clustering-gitops +- namespace: test ++ name: kong-gitops ++ namespace: pattern-namespace + --- + # Source: kong-clustering/templates/post-deploy-cp.yaml + apiVersion: v1 + kind: ConfigMap + metadata: +- namespace: test +- name: kong-clustering-cp-post-deploy ++ namespace: pattern-namespace ++ name: kong-cp-post-deploy + data: + post-deploy.sh: | + #!/bin/bash + set -eu + argocd login --username admin \ +- $(oc get routes -n unmanaged- -gitops-server -otemplate='{{ .spec.host }}') \ +- --password $(oc get secret -n unmanaged- -gitops-cluster -ojsonpath='{.data.admin\.password}' | base64 -d) \ ++ $(oc get routes -n mypattern-unmanaged unmanaged-gitops-server -otemplate='{{ .spec.host }}') \ ++ --password $(oc get secret -n mypattern-unmanaged unmanaged-gitops-cluster -ojsonpath='{.data.admin\.password}' | base64 -d) \ + --insecure \ + --grpc-web + argocd app patch-resource kong-cp \ +@@ -31,22 +31,22 @@ + apiVersion: v1 + kind: ConfigMap + metadata: +- namespace: test +- name: kong-clustering-dp-post-deploy ++ namespace: pattern-namespace ++ name: kong-dp-post-deploy + data: + post-deploy.sh: | + #!/bin/bash + set -eu + argocd login --username admin \ +- $(oc get routes -n unmanaged- -gitops-server -otemplate='{{ .spec.host }}') \ +- --password $(oc get secret -n unmanaged- -gitops-cluster -ojsonpath='{.data.admin\.password}' | base64 -d) \ ++ $(oc get routes -n mypattern-unmanaged unmanaged-gitops-server -otemplate='{{ .spec.host }}') \ ++ --password $(oc get secret -n mypattern-unmanaged unmanaged-gitops-cluster -ojsonpath='{.data.admin\.password}' | base64 -d) \ + --insecure \ + --grpc-web + if ! oc get cm -n kong cluster-urls; then + echo "config map cluster-urls not found" + exit 1 + fi +- if ! oc get appprojects -n unmanaged- dataplane; then ++ if ! oc get appprojects -n mypattern-unmanaged dataplane; then + echo "dataplane project cannot be retrieved" + exit 1 + fi +@@ -64,7 +64,7 @@ + kind: ClusterRole + apiVersion: rbac.authorization.k8s.io/v1 + metadata: +- name: kong-clustering-jobs ++ name: kong-jobs + rules: + - verbs: + - get +@@ -92,22 +92,22 @@ + kind: ClusterRoleBinding + apiVersion: rbac.authorization.k8s.io/v1 + metadata: +- name: kong-clustering-jobs-cluster-binding ++ name: kong-jobs-cluster-binding + subjects: + - kind: ServiceAccount +- namespace: test +- name: kong-clustering-gitops ++ namespace: pattern-namespace ++ name: kong-gitops + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole +- name: kong-clustering-jobs ++ name: kong-jobs + --- + # Source: kong-clustering/templates/post-deploy-roles.yaml + kind: Role + apiVersion: rbac.authorization.k8s.io/v1 + metadata: +- name: kong-clustering-role +- namespace: test ++ name: kong-role ++ namespace: pattern-namespace + rules: + - apiGroups: + - security.openshift.io +@@ -122,33 +122,33 @@ + kind: RoleBinding + apiVersion: rbac.authorization.k8s.io/v1 + metadata: +- name: kong-clustering-jobs-binding +- namespace: test ++ name: kong-jobs-binding ++ namespace: pattern-namespace + subjects: + - kind: ServiceAccount +- name: kong-clustering-gitops +- namespace: test ++ name: kong-gitops ++ namespace: pattern-namespace + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role +- name: kong-clustering-role ++ name: kong-role + --- + # Source: kong-clustering/templates/post-deploy-cp.yaml + apiVersion: batch/v1 + kind: Job + metadata: +- namespace: test +- name: kong-clustering-cp-post-deploy ++ namespace: pattern-namespace ++ name: kong-cp-post-deploy + spec: + backoffLimit: 20 + template: + spec: + restartPolicy: OnFailure +- serviceAccountName: kong-clustering-gitops ++ serviceAccountName: kong-gitops + volumes: + - name: post-deploy + configMap: +- name: kong-clustering-cp-post-deploy ++ name: kong-cp-post-deploy + defaultMode: 0711 + containers: + - image: quay.io/ecosystem-appeng/argocd-helper:1.0 +@@ -165,19 +165,19 @@ + apiVersion: batch/v1 + kind: Job + metadata: +- namespace: test +- name: kong-clustering-dp-post-deploy ++ namespace: pattern-namespace ++ name: kong-dp-post-deploy + generateName: path-kong-clustering + spec: + backoffLimit: 20 + template: + spec: + restartPolicy: OnFailure +- serviceAccountName: kong-clustering-gitops ++ serviceAccountName: kong-gitops + volumes: + - name: post-deploy + configMap: +- name: kong-clustering-dp-post-deploy ++ name: kong-dp-post-deploy + defaultMode: 0711 + containers: + - image: quay.io/ecosystem-appeng/argocd-helper:1.0 diff --git a/tests/all-kong-naked.expected.yaml b/tests/all-kong-naked.expected.yml similarity index 100% rename from tests/all-kong-naked.expected.yaml rename to tests/all-kong-naked.expected.yml diff --git a/tests/all-kong-normal.expected.yaml b/tests/all-kong-normal.expected.yml similarity index 100% rename from tests/all-kong-normal.expected.yaml rename to tests/all-kong-normal.expected.yml diff --git a/tests/all-kong.expected.diff b/tests/all-kong.expected.diff new file mode 100644 index 00000000..f495f45b --- /dev/null +++ b/tests/all-kong.expected.diff @@ -0,0 +1,158 @@ +--- tests/all-kong-naked.expected.yml ++++ tests/all-kong-normal.expected.yml +@@ -3,14 +3,14 @@ + apiVersion: v1 + kind: Namespace + metadata: +- name: test ++ name: pattern-namespace + --- + # Source: kong/templates/service-account.yaml + apiVersion: v1 + kind: ServiceAccount + metadata: + name: kong +- namespace: test ++ namespace: pattern-namespace + --- + # Source: kong/charts/kong/templates/secret-sa-token.yaml + apiVersion: v1 +@@ -27,7 +27,7 @@ + kind: Secret + metadata: + name: postgresql +- namespace: test ++ namespace: pattern-namespace + stringData: + database-name: kong + database-password: kong123 +@@ -38,7 +38,7 @@ + kind: Secret + metadata: + name: kong-enterprise-license +- namespace: test ++ namespace: pattern-namespace + annotations: + avp.kubernetes.io/path: "secret/data/hub/kong" + type: Opaque +@@ -87,14 +87,14 @@ + kind: ConfigMap + metadata: + name: cm-generator +- namespace: test ++ namespace: pattern-namespace + --- + # Source: kong/charts/postgresql/templates/pvc.yaml + apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: postgresql +- namespace: test ++ namespace: pattern-namespace + spec: + accessModes: + - ReadWriteOnce +@@ -429,7 +429,7 @@ + apiVersion: rbac.authorization.k8s.io/v1 + metadata: + name: kong-role +- namespace: test ++ namespace: pattern-namespace + rules: + - apiGroups: + - security.openshift.io +@@ -481,11 +481,11 @@ + apiVersion: rbac.authorization.k8s.io/v1 + metadata: + name: kong-role-binding +- namespace: test ++ namespace: pattern-namespace + subjects: + - kind: ServiceAccount + name: kong +- namespace: test ++ namespace: pattern-namespace + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role +@@ -697,7 +697,7 @@ + kind: Service + metadata: + name: postgresql +- namespace: test ++ namespace: pattern-namespace + spec: + ports: + - name: postgresql +@@ -1357,7 +1357,7 @@ + kind: Job + metadata: + name: cert-secret +- namespace: test ++ namespace: pattern-namespace + spec: + backoffLimit: 1 + template: +@@ -1371,7 +1371,7 @@ + command: + - "/bin/bash" + - "-c" +- - "oc create secret tls kong-cluster-cert --cert=./cluster.crt --key=./cluster.key -n test && echo 'kong certificate secret created'" ++ - "oc create secret tls kong-cluster-cert --cert=./cluster.crt --key=./cluster.key -n pattern-namespace && echo 'kong certificate secret created'" + restartPolicy: Never + --- + # Source: kong/templates/cm-generator-job.yaml +@@ -1379,7 +1379,7 @@ + kind: Job + metadata: + name: cm-generator +- namespace: test ++ namespace: pattern-namespace + spec: + template: + spec: +@@ -1406,7 +1406,7 @@ + kind: DeploymentConfig + metadata: + name: postgresql +- namespace: test ++ namespace: pattern-namespace + spec: + replicas: 1 + selector: +@@ -1497,7 +1497,7 @@ + kind: Route + metadata: + name: kong-cp-kong-admin +- namespace: test ++ namespace: pattern-namespace + spec: + port: + targetPort: kong-admin +@@ -1510,7 +1510,7 @@ + kind: Route + metadata: + name: kong-cp-kong-manager +- namespace: test ++ namespace: pattern-namespace + spec: + port: + targetPort: kong-manager +@@ -1523,7 +1523,7 @@ + kind: Route + metadata: + name: kong-cp-kong-manager-tls +- namespace: test ++ namespace: pattern-namespace + spec: + port: + targetPort: kong-manager-tls +@@ -1538,7 +1538,7 @@ + kind: Route + metadata: + name: kong-cp-kong-admin-tls +- namespace: test ++ namespace: pattern-namespace + spec: + port: + targetPort: kong-admin-tls From 5e05d39a6d76d7524344bf9e45a22fb7471056d7 Mon Sep 17 00:00:00 2001 From: ruromero Date: Mon, 3 Oct 2022 10:35:57 +0200 Subject: [PATCH 4/4] fix linter issues Signed-off-by: ruromero --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6605388d..35e64e3f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Start Here -If you've followed a link to this repo, but are not really sure what it contains +If you've followed a link to this repository, but are not really sure what it contains or how to use it, head over to [Multicloud GitOps](http://hybrid-cloud-patterns.io/multicloud-gitops/) for additional context and installation instructions