From 40f7ca00d67d89651e97b5a305011a65a4a18162 Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Thu, 14 Nov 2024 13:03:40 +0530 Subject: [PATCH 01/40] init commit --- README.md | 577 +++++++++++++++--- cra-config.yaml | 14 +- cra-tf-validate-ignore-rules.json | 39 +- examples/advanced/README.md | 4 - examples/advanced/outputs.tf | 23 - examples/advanced/provider.tf | 8 - examples/advanced/variables.tf | 29 - examples/advanced/version.tf | 12 - examples/basic/README.md | 31 +- examples/basic/main.tf | 323 +++++++++- examples/basic/outputs.tf | 21 +- examples/basic/provider.tf | 25 +- examples/basic/variables.tf | 49 +- examples/basic/version.tf | 17 +- main.tf | 339 +++++++++- modules/eso-clusterstore/README.md | 54 ++ modules/eso-clusterstore/main.tf | 108 ++++ modules/eso-clusterstore/outputs.tf | 8 + modules/eso-clusterstore/variables.tf | 74 +++ modules/eso-clusterstore/version.tf | 14 + modules/eso-external-secret/README.md | 62 ++ modules/eso-external-secret/main.tf | 368 +++++++++++ .../eso-external-secret/outputs.tf | 2 +- modules/eso-external-secret/variables.tf | 139 +++++ modules/eso-external-secret/version.tf | 10 + modules/eso-secretstore/README.md | 54 ++ modules/eso-secretstore/main.tf | 99 +++ modules/eso-secretstore/outputs.tf | 8 + modules/eso-secretstore/variables.tf | 72 +++ modules/eso-secretstore/version.tf | 14 + modules/eso-trusted-profile/README.md | 45 ++ modules/eso-trusted-profile/main.tf | 83 +++ modules/eso-trusted-profile/outputs.tf | 13 + modules/eso-trusted-profile/variables.tf | 35 ++ modules/eso-trusted-profile/version.tf | 9 + tests/go.mod | 72 ++- tests/go.sum | 152 ++++- tests/other_test.go | 120 +++- tests/pr_test.go | 393 +++++++++++- tests/samples/README.md | 4 + tests/samples/sample.yaml | 53 ++ tests/samples/updated_secret.yaml | 10 + variables.tf | 161 ++++- version.tf | 20 +- 44 files changed, 3471 insertions(+), 296 deletions(-) delete mode 100644 examples/advanced/README.md delete mode 100644 examples/advanced/outputs.tf delete mode 100644 examples/advanced/provider.tf delete mode 100644 examples/advanced/variables.tf delete mode 100644 examples/advanced/version.tf create mode 100644 modules/eso-clusterstore/README.md create mode 100644 modules/eso-clusterstore/main.tf create mode 100644 modules/eso-clusterstore/outputs.tf create mode 100644 modules/eso-clusterstore/variables.tf create mode 100644 modules/eso-clusterstore/version.tf create mode 100644 modules/eso-external-secret/README.md create mode 100644 modules/eso-external-secret/main.tf rename examples/advanced/main.tf => modules/eso-external-secret/outputs.tf (89%) create mode 100644 modules/eso-external-secret/variables.tf create mode 100644 modules/eso-external-secret/version.tf create mode 100644 modules/eso-secretstore/README.md create mode 100644 modules/eso-secretstore/main.tf create mode 100644 modules/eso-secretstore/outputs.tf create mode 100644 modules/eso-secretstore/variables.tf create mode 100644 modules/eso-secretstore/version.tf create mode 100644 modules/eso-trusted-profile/README.md create mode 100644 modules/eso-trusted-profile/main.tf create mode 100644 modules/eso-trusted-profile/outputs.tf create mode 100644 modules/eso-trusted-profile/variables.tf create mode 100644 modules/eso-trusted-profile/version.tf create mode 100644 tests/samples/README.md create mode 100644 tests/samples/sample.yaml create mode 100644 tests/samples/updated_secret.yaml diff --git a/README.md b/README.md index 83e2d757..117f2c14 100644 --- a/README.md +++ b/README.md @@ -1,122 +1,557 @@ - -# Terraform modules template project - - -[![Incubating (Not yet consumable)](https://img.shields.io/badge/status-Incubating%20(Not%20yet%20consumable)-red)](https://terraform-ibm-modules.github.io/documentation/#/badge-status) -[![latest release](https://img.shields.io/github/v/release/terraform-ibm-modules/terraform-ibm-external-secrets-operator?logo=GitHub&sort=semver)](https://github.com/terraform-ibm-modules/terraform-ibm-external-secrets-operator/releases/latest) -[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) -[![Renovate enabled](https://img.shields.io/badge/renovate-enabled-brightgreen.svg)](https://renovatebot.com/) -[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) - - +## External Secrets Operator module -TODO: Replace this with a description of the modules in this repo. +[![Certified]()](https://github.ibm.com/GoldenEye/documentation/blob/master/status.md) +[![CI](https://img.shields.io/badge/CI-Toolchain%20Tekton%20Pipeline-3662FF?logo=ibm)](https://cloud.ibm.com/devops/toolchains/c3916535-165a-4275-9b1f-c58575839951?env_id=ibm:yp:us-south) +[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) +[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) +[![latest release](https://shields-server.m03l6u0cqkx.eu-de.codeengine.appdomain.cloud/github/v/release/GoldenEye/external-secrets-operator-module?logo=GitHub)](https://github.ibm.com/GoldenEye/external-secrets-operator-module/releases/latest) +This module automates the installation and configuration of the [External Secrets Operator](https://external-secrets.io/) in a cluster. - + ## Overview * [terraform-ibm-external-secrets-operator](#terraform-ibm-external-secrets-operator) * [Examples](./examples) - * [Advanced example](./examples/advanced) - * [Basic example](./examples/basic) + * [Basic Example](./examples/basic) + * [Example that uses trusted profiles (container authentication)](./examples/trusted-profiles-authentication) + * [Example to deploy the External Secret Operator and to create a different set of resources in terms of secrets, secret groups, stores and auth configurations](./examples/all-combined) + * [Example to deploy the External Secret Operator enrolled into RedHat Service Mesh](./examples/eso-enroll-into-servicemesh) * [Contributing](#contributing) +## Compliance and security + +NIST controls do not apply to this module. + + +## external-secrets-operator-module + +External Secrets Operator synchronizes secrets in the Kubernetes cluster with secrets that are mapped in [Secrets Manager](https://cloud.ibm.com/docs/secrets-manager). + +The module provides the following features: +- Install and configure External Secrets Operator (ESO). +- Customise External Secret Operator deployment on specific cluster workers by configuration approriate NodeSelector and Tolerations in the ESO helm release [More details below](#customise-eso-deployment-on-specific-cluster-nodes) + +The submodules automate the configuration of an operator, providing the following features: +- Deploy and configure [ClusterSecretStore](https://external-secrets.io/latest/api/clustersecretstore/) resources for cluster scope secrets store [eso-clusterstore](./eso-clusterstore/README.md) +- Deploy and configure [SecretStore](https://external-secrets.io/latest/api/secretstore/) resources for namespace scope secrets store [eso-secretstore](./eso-secretstore/README.md) +- Leverage on two authentication methods to be configured on the single stores instances: + - IAM apikey standard authentication + - IAM Trusted profile: in conjunction with [`eso-trusted-profile`](./eso-trusted-profile/README.md) submodule, which allows to create one or more trusted profiles to use with the ESO module for trusted profile authentication. +- Configure the [ExternalSecret](https://external-secrets.io/latest/api/externalsecret/) resources to be bound to the expected secrets store (according to the visibility you need) and to configure the target secret details + - The following secret types of [Kubernetes Secrets](https://kubernetes.io/docs/concepts/configuration/secret/#secret-types) are currently supported: + - `Opaque` (`opaque` in this module) + - `kubernetes.io/dockerconfigjson` (`dockerconfigjson` in this module) + +The current version of the module supports multitenants configuration by setting up "ESO as a service" (ref. https://cloud.redhat.com/blog/how-to-setup-external-secrets-operator-eso-as-a-service) for both authentication methods [More details below](#example-of-multitenancy-configuration-example-in-namespaced-externalsecrets-stores) + +The following combinations of Kubernetes Secrets and Secrets Manager secrets are used with given [External-Secret type](https://external-secrets.io/latest/provider/ibm-secrets-manager/). - - +| es_kubernetes_secret_type[^1] | sm_secret_type[^2] | external_secret_type[^3] | +|-------------------------------|--------------------|--------------------------| +| dockerconfigjson | arbitrary | arbitrary | +| dockerconfigjson | iam_credentials | iam_credentials | +| dockerconfigjson | username_password | username_password | +| opaque | arbitrary | arbitrary | +| opaque | iam_credentials | iam_credentials | +| opaque | username_password | username_password | +| opaque | kv | kv | +| tls | imported_cert | imported_cert | +| tls | public_cert | public_cert | +| tls | private_cert | private_cert | +[^1]: [es_kubernetes_secret_type](#input_es_kubernetes_secret_type): The Kubernetes Secrets type or format that ESO installs in the cluster. - -## terraform-ibm-external-secrets-operator +[^2]: [sm_secret_type](#input_sm_secret_type): IBM Cloud Secrets Manager secret type that is used as source data by ESO. -### Usage +[^3]: [external_secret_type](https://external-secrets.io/latest/provider/ibm-secrets-manager/#secret-types): The secret type that is used by ESO. - +In order to customise the NodeSelector and the tolerations to make the External Secret Operator deployed on specific cluster nodes it is possible to configure the following input variable with the appropriate values: ```hcl +variable "eso_cluster_nodes_configuration" { + description = "Configuration to use to customise ESO deployment on specific cluster nodes. Setting appropriate values will result in customising ESO helm release. Default value is null to keep ESO standard deployment." + type = object({ + nodeSelector = object({ + label = string + value = string + }) + tolerations = object({ + key = string + operator = string + value = string + effect = string + }) + }) + default = null +} +``` + +For example: + +```hcl +module "external_secrets_operator" { + (...) + eso_cluster_nodes_configuration = { + nodeSelector = { + label = "dedicated" + value = "edge" + } + tolerations = { + key = "dedicated" + operator = "Equal" + value = "edge" + effect = "NoExecute" + } + } + (...) +``` + +will make the External Secret Operator to run on clusters nodes labeled with `dedicated: edge`. + +The resulting helm release configuration, according to the `terraform plan` output would be like + +```bash + +(...) +# module.external_secrets_operator.helm_release.external_secrets_operator[0] will be created + + resource "helm_release" "external_secrets_operator" { + + atomic = false + + chart = "oci://icr.io/goldeneye_images/external-secrets" + + cleanup_on_fail = false + + create_namespace = false + + dependency_update = false + + disable_crd_hooks = false + + disable_openapi_validation = false + + disable_webhooks = false + + force_update = false + + id = (known after apply) + + lint = false + + manifest = (known after apply) + + max_history = 0 + + metadata = (known after apply) + + name = "external-secrets" + + namespace = "es-operator" + + pass_credentials = false + + recreate_pods = false + + render_subchart_notes = true + + replace = false + + reset_values = false + + reuse_values = false + + skip_crds = false + + status = "deployed" + + timeout = 300 + + values = [ + + <<-EOT + installCRDs: true + extraVolumes: + - name: sa-token + projected: + defaultMode: 0644 + sources: + - serviceAccountToken: + path: sa-token + expirationSeconds: 3600 + audience: iam + extraVolumeMounts: + - mountPath: /var/run/secrets/tokens + name: sa-token + webhook: + extraVolumes: + - name: sa-token + projected: + defaultMode: 0644 + sources: + - serviceAccountToken: + path: sa-token + expirationSeconds: 3600 + audience: iam + extraVolumeMounts: + - mountPath: /var/run/secrets/tokens + name: sa-token + EOT, + + <<-EOT + nodeSelector: { dedicated: edge } + tolerations: + - key: dedicated + operator: Equal + value: edge + effect: NoExecute + webhook: + nodeSelector: { dedicated: edge } + tolerations: + - key: dedicated + operator: Equal + value: edge + effect: NoExecute + certController: + nodeSelector: { dedicated: edge } + tolerations: + - key: dedicated + operator: Equal + value: edge + effect: NoExecute + EOT, + ] + + verify = false + + version = "0.9.7" + + wait = true + + wait_for_jobs = false + } +(...) ``` -### Required access policies +Similarly exporting this environment variable + +```bash +export TF_VAR_eso_cluster_nodes_configuration="{\"nodeSelector\": {\"label\": \"dedicated\", \"value\": \"transit\"}, \"tolerations\": {\"key\": \"dedicated\", \"operator\": \"Equal\", \"value\": \"transit\", \"effect\": \"NoExecute\"}}" +``` + +will make the External Secret Operator to run on clusters nodes labeled with `dedicated: transit`. + +The default `null` value keeps the default ESO behaviour. + +### Example of Multitenancy configuration example in namespaced externalsecrets stores + +To configure a set of tenants to be configured in their proper namespace (to achieve tenant isolation) you need simply to follow these steps: + +- deploy ESO in the cluster + +```hcl +module "external_secrets_operator" { + source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git?ref=" + eso_namespace = var.eso_namespace # namespace to deploy ESO + service_endpoints = var.service_endpoints # use public or private endpoints for IAM and Secrets Manager + eso_cluster_nodes_configuration = <> +} +``` + +- create multiple `SecretStore`(s) in the proper namespaces + +With `api_key` authentication mode + +```hcl + +module "eso_namespace_secretstore_1" { + depends_on = [ + module.external_secrets_operator + ] + source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git//modules/eso-secretstore?ref=master" + eso_authentication = "api_key" + region = local.sm_region # SM region + sstore_namespace = var.es_kubernetes_namespaces[2] # namespace to create the secret store + sstore_secrets_manager_guid = local.sm_guid # the guid of the secrets manager instance to use + sstore_store_name = "${var.es_kubernetes_namespaces[2]}-store" # store name + # to pull the secrets from SM + sstore_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key # pragma: allowlist secret + service_endpoints = var.service_endpoints + sstore_helm_rls_name = "es-store" # helm release name suffix to use for the store + sstore_secret_name = "generic-cluster-api-key" #checkov:skip=CKV_SECRET_6 +} + +``` + +With `trusted_profile` authentication mode + +```hcl +module "eso_namespace_secretstores" { + depends_on = [ + module.external_secrets_operator + ] + source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git//modules/eso-secretstore?ref=master" + eso_authentication = "trusted_profile" + region = local.sm_region # SM region + sstore_namespace = kubernetes_namespace.examples[count.index].metadata[0].name # namespace to create the secret store + sstore_secrets_manager_guid = local.sm_guid # the guid of the secrets manager instance to use + sstore_store_name = "${kubernetes_namespace.examples[count.index].metadata[0].name}-store" # store name + sstore_trusted_profile_name = module.external_secrets_trusted_profiles[count.index].trusted_profile_name # trusted profile name to use into this secret store + service_endpoints = var.service_endpoints + sstore_helm_rls_name = "es-store-${count.index}" # helm release name suffix to use for the store + sstore_secret_name = "secretstore-api-key" #checkov:skip=CKV_SECRET_6 +} + +``` + +More details can be found in the examples linked below. + +### More information links + +For more information about IAM Trusted profiles and ESO Multitenancy configuration please refer to +- [IBM IAM Trusted profiles article](https://www.ibm.com/cloud/blog/announcements/use-trusted-profiles-to-simplify-user-and-access-management) +- [Setup of ESO as a Service from RedHat](https://cloud.redhat.com/blog/how-to-setup-external-secrets-operator-eso-as-a-service) +- [ESO Multitenancy configuration from ESO Docs](https://external-secrets.io/latest/guides/multi-tenancy/) + +### _Important current limitation of ESO deployment_ + +The current ESO version doesn't allow to customise the default IAM endpoint (https://iam.cloud.ibm.com) it uses when authenticating through apikey (`api_key` authentication) for both ClusterSecretStore and SecretStore APIs. + +As a direct effect of this limitation, for a standard OCP cluster topology as defined by GoldenEye design (3 workers zones `edge` `private` and `transit`), an ESO deployment with `api_key` authentication configuration needs to be performed on the workers pool with access to the public network (`dedicated: edge` label in GE usual topology) to work fine. If the ESO deployment is performed on a workers pool without access to public network (i.e. to https://iam.cloud.ibm.com) the apikey authentication is expected to fail. + + +### Pod Reloader - +When secrets are updated, depending on you configuration pods may need to be restarted to pick up the new secrets. To do this you can use the [Stakater Reloader](https://github.com/stakater/Reloader). +By default, the module deploys this to watch for changes in secrets and configmaps and trigger a rolling update of the related pods. +To have Reloader watch a secret or configMap add the annotation `reloader.stakater.com/auto: "true"` to the secret or configMap, the same annotation can be added to deployments to have them restarted when the secret or configMap changes. +When using the [eso-external-secret](modules/eso-external-secret) submodule, use the `reloader_watching` variable to have the annotation added to the secret. - +### Troubleshooting - +In the case of problems with secrets synchronization a good start point to the investigation is to list the externalsecrets resources in the cluster: - +```bash +oc get externalsecrets -A +NAMESPACE NAME AGE STATUS CAPABILITIES READY +apikeynspace3 secretstore.external-secrets.io/apikeynspace3-store 32m Valid ReadOnly True +apikeynspace4 secretstore.external-secrets.io/apikeynspace4-store 32m Valid ReadOnly True +tpnspace1 secretstore.external-secrets.io/tpnspace1-store 32m Valid ReadOnly True +tpnspace2 secretstore.external-secrets.io/tpnspace2-store 32m Valid ReadOnly True +NAMESPACE NAME AGE STATUS CAPABILITIES READY + clustersecretstore.external-secrets.io/cluster-store 32m Valid ReadOnly True + +NAMESPACE NAME STORE REFRESH INTERVAL STATUS READY +apikeynspace1 externalsecret.external-secrets.io/dockerconfigjson-uc cluster-store 1m SecretSyncedError False +apikeynspace2 externalsecret.external-secrets.io/cloudant-opaque-arb cluster-store 5m SecretSyncedError False +apikeynspace3 externalsecret.external-secrets.io/dockerconfigjson-arb apikeynspace3-store 1h SecretSyncedError False +apikeynspace4 externalsecret.external-secrets.io/dockerconfigjson-iam apikeynspace4-store 1h SecretSyncedError False +tpnspace1 externalsecret.external-secrets.io/geretain-tesoall-arbitrary-arb-tp-0 tpnspace1-store 5m SecretSynced True +tpnspace2 externalsecret.external-secrets.io/geretain-tesoall-arbitrary-arb-tp-1 tpnspace2-store 5m SecretSynced True +``` + +In the example above some of the externalsecrets are experiencing secrets synchronization errors. +By describing them you should be able to identify the error: + +```bash +oc describe externalsecret dockerconfigjson-uc -n apikeynspace1 +Name: dockerconfigjson-uc +Namespace: apikeynspace1 +Labels: app=raw + app.kubernetes.io/managed-by=Helm + chart=raw-v0.2.5 + heritage=Helm + release=apikeynspace1-es-docker-uc +Annotations: meta.helm.sh/release-name: apikeynspace1-es-docker-uc + meta.helm.sh/release-namespace: apikeynspace1 +API Version: external-secrets.io/v1beta1 +Kind: ExternalSecret +Metadata: + (...) +Status: + Conditions: + Last Transition Time: 2023-06-27T15:18:31Z + Message: could not get secret data from provider + Reason: SecretSyncedError + Status: False + Type: Ready + Refresh Time: +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + (...) + Warning UpdateFailed 119s (x13 over 28m) external-secrets An error occurred while performing the 'authenticate' step: Post "https://iam.cloud.ibm.com/identity/token": context deadline exceeded (Client.Timeout exceeded while awaiting headers) +``` + +In the output above there is a problem with reaching IAM endpoint (as the ESO pods were deployed on private network and it was trying to reach IAM on public endpoint) + +### _Important note_ + +If you taint or destroy or simply make a change that needs the helm_release resource of the ESO operator to be deleted and recreated, this would make terraform to destroy the operator itself, including all the CRDs, which would destroy all the secrets synched through ESO, even if the helm_release resource of these CRDs aren't directly touched and terraform wouldn't be able to identify such a change. +So in the case you plan to make changes to the operator helm_release once deployed, run preliminary a `terraform plan` to be sure that the release isn't destroyed and recreated. + +### Examples of the secrets format and layout + +
dockerconfigjson from arbitrary or iam_credentials + +Secret Body > + +``` +apiVersion: v1 +kind: Secret +metadata: + name: dockerconfigjson-iam + namespace: test-ns +data: + .dockerconfigjson: [BASE64ENCODED] +type: kubernetes.io/dockerconfigjson +``` + +Base64 Decoded `.dockerconfigson` > + +``` +{ + "auths": { + "us.icr.io": { + "username": "iamapikey", + "password": "APIKEYVALUE", # pragma: allowlist secret + "email": "terraform@ibm.com" + } + } +} +``` + +
+ +
dockerconfigjson from username_password + +Secret Body > +``` +apiVersion: v1 +kind: Secret +metadata: + name: dockerconfigjson-uc + namespace: test-ns +data: + .dockerconfigjson: [BASE64ENCODED] +type: kubernetes.io/dockerconfigjson +``` + +Base64 Decoded `.dockerconfigson` > + +``` +{ + "auths": { + "xx.artifactory.swg-devops.com": { + "username": "artifactoryuser@ibm.com", + "password": "APIKEYVALUE" # pragma: allowlist secret + } + } +} +``` + +
+ +
opaque from arbitrary or iam_credentials + +Secret Body > +``` +apiVersion: v1 +kind: Secret +metadata: + name: opaque-arb + namespace: test-ns +type: Opaque +data: + apikey: APIKEYVALUE # pragma: allowlist secret + +``` + +
+ +
opaque from username_password + +Secret Body > +``` +apiVersion: v1 +kind: Secret +metadata: + name: opaque-uc + namespace: test-ns +type: Opaque +data: + username: test-user + password: PASSWORDVALUE # pragma: allowlist secret + +``` + +
+ + +NIST controls do not apply to this module. + +## Usage + +```hcl +# Replace "master" with a GIT release version to lock into a specific release +module "es_kubernetes_secret" { + source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git//modules/eso-external-secret?ref=master" + es_kubernetes_secret_type = "dockerconfigjson" + sm_secret_type = "iam_credentials" + sm_secret_id = module.docker_config.serviceid_apikey_secret_id + eso_setup = true + es_kubernetes_namespaces = var.es_kubernetes_namespaces + es_docker_email = "terraform@ibm.com" + eso_generic_secret_apikey = data.ibm_secrets_manager_secret.secret_puller_secret.api_key # pragma: allowlist secret + secrets_manager_guid = module.secrets_manager_iam_configuration.secrets_manager_guid + region = "us-south" + es_kubernetes_secret_name = "dockerconfigjson-iam" + depends_on = [ + kubernetes_namespace.cluster_namespaces + ] + es_kubernetes_secret_data_key = "apiKey" + es_helm_rls_name = "es-docker-iam" +} +``` + + +## Examples + +- [ Example to deploy the External Secret Operator and to create a different set of resources in terms of secrets, secret groups, stores and auth configurations](examples/all-combined) +- [ Basic Example](examples/basic) +- [ Example to deploy the External Secret Operator enrolled into RedHat Service Mesh](examples/eso-enroll-into-servicemesh) +- [ Example that uses trusted profiles (container authentication)](examples/trusted-profiles-authentication) + - ### Requirements | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3.0 | +| [helm](#requirement\_helm) | >= 2.11.0, < 3.0.0 | +| [kubernetes](#requirement\_kubernetes) | >= 2.16.1, < 3.0.0 | ### Modules -No modules. +| Name | Source | Version | +|------|--------|---------| +| [eso\_namespace](#module\_eso\_namespace) | terraform-ibm-modules/namespace/ibm | 1.0.2 | ### Resources -No resources. +| Name | Type | +|------|------| +| [helm_release.external_secrets_operator](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | +| [helm_release.pod_reloader](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | +| [kubernetes_namespace.existing_eso_namespace](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/data-sources/namespace) | data source | ### Inputs -No inputs. +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [eso\_cluster\_nodes\_configuration](#input\_eso\_cluster\_nodes\_configuration) | Configuration to use to customise ESO deployment on specific cluster nodes. Setting appropriate values will result in customising ESO helm release. Default value is null to keep ESO standard deployment. |
object({
nodeSelector = object({
label = string
value = string
})
tolerations = object({
key = string
operator = string
value = string
effect = string
})
})
| `null` | no | +| [eso\_enroll\_in\_servicemesh](#input\_eso\_enroll\_in\_servicemesh) | Flag to enroll ESO into istio servicemesh | `bool` | `false` | no | +| [eso\_namespace](#input\_eso\_namespace) | Namespace to create and be used to install ESO components including helm releases. If eso\_store\_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster\_store in it | `string` | `null` | no | +| [eso\_pod\_configuration](#input\_eso\_pod\_configuration) | Configuration to use to customise ESO deployment on specific pods. Setting appropriate values will result in customising ESO helm release. Default value is {} to keep ESO standard deployment. Ignore the key if not required. |
object({
annotations = optional(object({
# The annotations for external secret controller pods.
external_secrets = optional(map(string), {})
# The annotations for external secret cert controller pods.
external_secrets_cert_controller = optional(map(string), {})
# The annotations for external secret controller pods.
external_secrets_webhook = optional(map(string), {})
}), {})

labels = optional(object({
# The labels for external secret controller pods.
external_secrets = optional(map(string), {})
# The labels for external secret cert controller pods.
external_secrets_cert_controller = optional(map(string), {})
# The labels for external secret controller pods.
external_secrets_webhook = optional(map(string), {})
}), {})
})
| `{}` | no | +| [existing\_eso\_namespace](#input\_existing\_eso\_namespace) | Existing Namespace to be used to install ESO components including helm releases. If eso\_store\_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster\_store in it | `string` | `null` | no | +| [reloader\_custom\_values](#input\_reloader\_custom\_values) | String containing custom values to be used for reloader helm chart. See https://github.com/stakater/Reloader/blob/master/deployments/kubernetes/chart/reloader/values.yaml | `string` | `null` | no | +| [reloader\_deployed](#input\_reloader\_deployed) | Whether to deploy reloader or not https://github.com/stakater/Reloader | `bool` | `true` | no | +| [reloader\_ignore\_configmaps](#input\_reloader\_ignore\_configmaps) | Whether to ignore configmap changes or not | `bool` | `false` | no | +| [reloader\_ignore\_secrets](#input\_reloader\_ignore\_secrets) | Whether to ignore secret changes or not | `bool` | `false` | no | +| [reloader\_is\_argo\_rollouts](#input\_reloader\_is\_argo\_rollouts) | Enable Argo Rollouts | `bool` | `false` | no | +| [reloader\_is\_openshift](#input\_reloader\_is\_openshift) | Enable OpenShift DeploymentConfigs | `bool` | `true` | no | +| [reloader\_log\_format](#input\_reloader\_log\_format) | The log format to use for reloader. Possible values are `json` or `text`. Default value is `json` | `string` | `"text"` | no | +| [reloader\_namespaces\_selector](#input\_reloader\_namespaces\_selector) | List of comma separated label selectors, if multiple are provided they are combined with the AND operator | `string` | `null` | no | +| [reloader\_namespaces\_to\_ignore](#input\_reloader\_namespaces\_to\_ignore) | List of comma separated namespaces to ignore for reloader. If multiple are provided they are combined with the AND operator | `string` | `null` | no | +| [reloader\_pod\_monitor\_metrics](#input\_reloader\_pod\_monitor\_metrics) | Enable to scrape Reloader's Prometheus metrics | `bool` | `false` | no | +| [reloader\_reload\_on\_create](#input\_reloader\_reload\_on\_create) | Enable reload on create events | `bool` | `true` | no | +| [reloader\_reload\_strategy](#input\_reloader\_reload\_strategy) | The reload strategy to use for reloader. Possible values are `env-vars` or `annotations`. Default value is `annotations` | `string` | `"annotations"` | no | +| [reloader\_resource\_label\_selector](#input\_reloader\_resource\_label\_selector) | List of comma separated label selectors, if multiple are provided they are combined with the AND operator | `string` | `null` | no | +| [reloader\_resources\_to\_ignore](#input\_reloader\_resources\_to\_ignore) | List of comma separated resources to ignore for reloader. If multiple are provided they are combined with the AND operator | `string` | `null` | no | +| [reloader\_sync\_after\_restart](#input\_reloader\_sync\_after\_restart) | Enable sync after Reloader restarts for Add events, works only when reloadOnCreate is true | `bool` | `true` | no | ### Outputs No outputs. - - + ## Contributing You can report issues and request features for this module in GitHub issues in the module repo. See [Report an issue or request a feature](https://github.com/terraform-ibm-modules/.github/blob/main/.github/SUPPORT.md). diff --git a/cra-config.yaml b/cra-config.yaml index 02d79f03..ba837c7c 100644 --- a/cra-config.yaml +++ b/cra-config.yaml @@ -1,11 +1,9 @@ # More info about this file at https://github.com/terraform-ibm-modules/common-pipeline-assets/blob/main/.github/workflows/terraform-test-pipeline.md#cra-config-yaml version: "v1" CRA_TARGETS: - - CRA_TARGET: "examples/advanced" # Target directory for CRA scan. If not provided, the CRA Scan will not be run. - CRA_IGNORE_RULES_FILE: "cra-tf-validate-ignore-rules.json" # CRA Ignore file to use. If not provided, it checks the repo root directory for `cra-tf-validate-ignore-rules.json` - PROFILE_ID: "0e6e7b5a-817d-4344-ab6f-e5d7a9c49520" # SCC profile ID (currently set to the FSCloud 1.4.0 profile). - # SCC_INSTANCE_ID: "" # The SCC instance ID to use to download profile for CRA scan. If not provided, a default global value will be used. - # SCC_REGION: "" # The IBM Cloud region that the SCC instance is in. If not provided, a default global value will be used. - # CRA_ENVIRONMENT_VARIABLES: # An optional map of environment variables for CRA, where the key is the variable name and value is the value. Useful for providing TF_VARs. - # TF_VAR_sample: "sample value" - # TF_VAR_other: "another value" + - CRA_TARGET: "examples/all-combined" + CRA_IGNORE_RULES_FILE: "cra-tf-validate-ignore-rules.json" + CRA_ENVIRONMENT_VARIABLES: # An optional map of environment variables for CRA, where the key is the variable name and value is the value. Useful for providing TF_VARs. + TF_VAR_existing_cis_instance_name: "test_value_for_cis_instance_name" + TF_VAR_existing_cis_instance_resource_group_id: "test_value_for_cis_instance_rg_id" + TF_VAR_existing_sdnlb_serviceid_name: "test_value_for_existing_sdnlb_serviceid_name" diff --git a/cra-tf-validate-ignore-rules.json b/cra-tf-validate-ignore-rules.json index adbff6e0..e963b906 100644 --- a/cra-tf-validate-ignore-rules.json +++ b/cra-tf-validate-ignore-rules.json @@ -1,3 +1,40 @@ { - "scc_rules": [] + "scc_rules": [ + { + "scc_rule_id": "rule-216e2449-27d7-4afc-929a-b66e196a9cf9", + "description": "Check whether Flow Logs for VPC are enabled", + "ignore_reason": "This rule is not relevant to the module itself, just the VPC resource that is used in the example that is scanned", + "is_valid": false + }, + { + "scc_rule_id": "rule-64c0bea0-8760-4a6b-a56c-ee375a48961e", + "description": "Check whether Virtual Private Cloud (VPC) has no public gateways attached", + "ignore_reason": "This rule is not relevant to the module itself, just the VPC resource that is used in the example that is scanned", + "is_valid": false + }, + { + "scc_rule_id": "rule-2325054a-c338-474a-9740-0b7034487e40", + "description": "Check whether OpenShift clusters are accessible only by using private endpoints", + "ignore_reason": "This rule is not relevant to the module itself, just the OCP cluster resource that is used in the example that is scanned", + "is_valid": false + }, + { + "scc_rule_id": "rule-4d86c074-097e-4ff3-a763-ccff128388e2", + "description": "Check whether multifactor authentication (MFA) is enabled at the account level", + "ignore_reason": "This is an account based rule, so unrelated to this module itself", + "is_valid": false + }, + { + "scc_rule_id": "rule-0704e840-e443-4781-b9be-ec57469d09c1", + "description": "Check whether permissions for API key creation are limited and configured in IAM settings for the account owner", + "ignore_reason": "This is an account based rule, so unrelated to this module itself", + "is_valid": false + }, + { + "scc_rule_id": "rule-0244c010-fde6-4db3-95aa-8952bd292ac3", + "description": "Check whether permissions for service ID creation are limited and configured in IAM settings for the account owner", + "ignore_reason": "This is an account based rule, so unrelated to this module itself", + "is_valid": false + } + ] } diff --git a/examples/advanced/README.md b/examples/advanced/README.md deleted file mode 100644 index d52511a3..00000000 --- a/examples/advanced/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Advanced example - - - diff --git a/examples/advanced/outputs.tf b/examples/advanced/outputs.tf deleted file mode 100644 index addadea6..00000000 --- a/examples/advanced/outputs.tf +++ /dev/null @@ -1,23 +0,0 @@ -############################################################################## -# Outputs -############################################################################## - -output "region" { - description = "The region all resources were provisioned in" - value = var.region -} - -output "prefix" { - description = "The prefix used to name all provisioned resources" - value = var.prefix -} - -output "resource_group_name" { - description = "The name of the resource group used" - value = var.resource_group -} - -output "resource_tags" { - description = "List of resource tags" - value = var.resource_tags -} diff --git a/examples/advanced/provider.tf b/examples/advanced/provider.tf deleted file mode 100644 index 2080946b..00000000 --- a/examples/advanced/provider.tf +++ /dev/null @@ -1,8 +0,0 @@ -############################################################################## -# Provider config -############################################################################## - -provider "ibm" { - ibmcloud_api_key = var.ibmcloud_api_key - region = var.region -} diff --git a/examples/advanced/variables.tf b/examples/advanced/variables.tf deleted file mode 100644 index 170a5abc..00000000 --- a/examples/advanced/variables.tf +++ /dev/null @@ -1,29 +0,0 @@ -variable "ibmcloud_api_key" { - type = string - description = "The IBM Cloud API Key" - sensitive = true -} - -variable "region" { - type = string - description = "Region to provision all resources created by this example" - default = "us-south" -} - -variable "prefix" { - type = string - description = "Prefix to append to all resources created by this example" - default = "complete" -} - -variable "resource_group" { - type = string - description = "An existing resource group name to use for this example, if unset a new resource group will be created" - default = null -} - -variable "resource_tags" { - type = list(string) - description = "Optional list of tags to be added to created resources" - default = [] -} diff --git a/examples/advanced/version.tf b/examples/advanced/version.tf deleted file mode 100644 index 398bd442..00000000 --- a/examples/advanced/version.tf +++ /dev/null @@ -1,12 +0,0 @@ -terraform { - required_version = ">= 1.3.0" - - # Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main - # module's version.tf (usually a basic example), and 1 example that will always use the latest provider version. - required_providers { - ibm = { - source = "IBM-Cloud/ibm" - version = ">= 1.49.0, < 2.0.0" - } - } -} diff --git a/examples/basic/README.md b/examples/basic/README.md index 86eab8eb..504f852c 100644 --- a/examples/basic/README.md +++ b/examples/basic/README.md @@ -1,11 +1,24 @@ -# Basic example +# Basic Example - +This module provides a basic example to deploy the External Secrets Operator along with a simple username-password type secret in an IBM Cloud environment. It showcases a comprehensive implementation for managing secrets within a Kubernetes cluster, leveraging IBM Cloud's capabilities for a secure and efficient secret management system. -An end-to-end basic example that will provision the following: -- A new resource group if one is not passed in. -- A new Cloud Object Storage instance. +## Actions Performed + +- **Resource Group Handling**: Loads an existing resource group or creates a new one based on the provided variables. + +- **VPC and Subnet Configuration**: Establishes a Virtual Private Cloud (VPC) with associated subnets, setting up network segmentation and ACL rules. + +- **OpenShift Cluster Provisioning**: Deploys an OpenShift (OCP) cluster, tailored for a cloud-native architecture with worker pools for private, transit, and edge network segments. + +- **Secrets Manager Integration**: + - Either utilizes an existing Secrets Manager instance or creates a new one. + - Configures IAM engine, policies, and secret groups to manage access and operations on secrets. + +- **External Secrets Operator Configuration**: + - Deploys the External Secrets Operator in the Kubernetes cluster. + - Includes configurations for the External Secrets Operator to interact with the Secrets Manager and manage secrets at cluster and namespace levels. + +- **Secret Management**: + - Sets up a service ID (secret-puller) with IAM policies for accessing secrets from the Secrets Manager. + - Configures various types of secrets, including IAM service ID API keys and username-password combinations. + - Demonstrates the deployment of external secrets within Kubernetes, utilizing the configured `ClusterSecretStore` and `SecretStore` instances. diff --git a/examples/basic/main.tf b/examples/basic/main.tf index 95cc2a68..cef27c90 100644 --- a/examples/basic/main.tf +++ b/examples/basic/main.tf @@ -1,6 +1,31 @@ -######################################################################################################################## -# Resource group -######################################################################################################################## +############################################################################## +# Locals +############################################################################## + +locals { + + # general + validate_sm_region_cnd = var.existing_sm_instance_guid != null && var.existing_sm_instance_region == null + validate_sm_region_msg = "existing_sm_instance_region must also be set when value given for existing_sm_instance_guid." + # tflint-ignore: terraform_unused_declarations + validate_sm_region_chk = regex( + "^${local.validate_sm_region_msg}$", + (!local.validate_sm_region_cnd + ? local.validate_sm_region_msg + : "")) + + sm_guid = var.existing_sm_instance_guid == null ? ibm_resource_instance.secrets_manager[0].guid : var.existing_sm_instance_guid + + + sm_region = var.existing_sm_instance_region == null ? var.region : var.existing_sm_instance_region + sm_acct_id = var.existing_sm_instance_guid == null ? module.iam_secrets_engine[0].acct_secret_group_id : module.secrets_manager_group_acct[0].secret_group_id + es_namespace_apikey = "es-operator" # pragma: allowlist secret + eso_namespace = "apikeynspace1" +} + +################################################################## +# Resource Group +################################################################## module "resource_group" { source = "terraform-ibm-modules/resource-group/ibm" @@ -10,15 +35,291 @@ module "resource_group" { existing_resource_group_name = var.resource_group } -######################################################################################################################## -# COS instance -######################################################################################################################## +################################################################## +# Create VPC, public gateway and subnets +################################################################## + +locals { + + # OCP Configuration + ocp_worker_pools = [ + { + subnet_prefix = "private" + pool_name = "default" + machine_type = "bx2.4x16" + workers_per_zone = 1 + labels = { "dedicated" : "private" } + operating_system = "REDHAT_8_64" + }, + { + subnet_prefix = "edge" + pool_name = "edge" + machine_type = "bx2.4x16" + workers_per_zone = 1 + labels = { "dedicated" : "edge" } + operating_system = "REDHAT_8_64" + }, + { + subnet_prefix = "transit" + pool_name = "transit" + machine_type = "bx2.4x16" + workers_per_zone = 1 + labels = { "dedicated" : "transit" } + operating_system = "REDHAT_8_64" + } + ] +} + +# VPC creation +module "vpc" { + source = "terraform-ibm-modules/vpc/ibm" + version = "1.2.0" + vpc_name = "${var.prefix}-vpc" + resource_group_id = module.resource_group.resource_group_id + vpc_tags = [] +} + +# OCP CLUSTER creation +module "ocp_base" { + source = "terraform-ibm-modules/base-ocp-vpc/ibm" + version = "3.34.0" + cluster_name = "${var.prefix}-vpc" + resource_group_id = module.resource_group.resource_group_id + region = var.region + force_delete_storage = true + vpc_id = module.vpc.vpc_id + vpc_subnets = module.vpc.subnets + worker_pools = local.ocp_worker_pools + tags = [] + use_existing_cos = false + # outbound required by cluster proxy + disable_outbound_traffic_protection = true +} + +############################################################################## +# Init cluster config for helm and kubernetes providers +############################################################################## -resource "ibm_resource_instance" "cos_instance" { - name = "${var.prefix}-cos" +data "ibm_container_cluster_config" "cluster_config" { + cluster_name_id = module.ocp_base.cluster_id resource_group_id = module.resource_group.resource_group_id - service = "cloud-object-storage" - plan = "standard" - location = "global" +} + +# Wait time to allow cluster refreshes components after provisioning +resource "time_sleep" "wait_45_seconds" { + depends_on = [data.ibm_container_cluster_config.cluster_config] + create_duration = "45s" +} + +# Create namespace for apikey auth +resource "kubernetes_namespace" "apikey_namespace" { + + metadata { + name = local.es_namespace_apikey + } + lifecycle { + ignore_changes = [ + metadata[0].annotations, + metadata[0].labels + ] + } + depends_on = [ + time_sleep.wait_45_seconds + ] +} + +######################################## +# Secrets-Manager and IAM configuration +######################################## + +# IAM user policy, Secret Manager instance, Service ID for IAM engine, IAM service ID policies, associated Service ID API key stored in a secret object in account level secret-group and IAM engine configuration +resource "ibm_resource_instance" "secrets_manager" { + count = var.existing_sm_instance_guid == null ? 1 : 0 + name = "${var.prefix}-sm" + service = "secrets-manager" + plan = var.sm_service_plan + location = local.sm_region tags = var.resource_tags + resource_group_id = module.resource_group.resource_group_id + timeouts { + create = "30m" # Extending provisioning time to 30 minutes + } + provider = ibm.ibm-sm +} + +# Additional Secrets-Manager Secret-Group for SERVICE level secrets +module "secrets_manager_group_acct" { + source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" + version = "1.2.2" + count = var.existing_sm_instance_guid == null ? 0 : 1 + region = local.sm_region + secrets_manager_guid = local.sm_guid + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_group_name = "${var.prefix}-account-secret-group" #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + secret_group_description = "Secret-Group for storing account credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure + depends_on = [module.iam_secrets_engine] + providers = { + ibm = ibm.ibm-sm + } +} + +# Configure instance with IAM engine +module "iam_secrets_engine" { + count = var.existing_sm_instance_guid == null ? 1 : 0 + source = "terraform-ibm-modules/secrets-manager-iam-engine/ibm" + version = "1.2.3" + region = local.sm_region + secrets_manager_guid = ibm_resource_instance.secrets_manager[0].guid + iam_secret_generator_service_id_name = "${var.prefix}-sid:0.0.1:${ibm_resource_instance.secrets_manager[0].name}-iam-secret-generator:automated:simple-service:secret-manager:" + iam_secret_generator_apikey_name = "${var.prefix}-iam-secret-generator-apikey" + new_secret_group_name = "${var.prefix}-account-secret-group" + iam_secret_generator_apikey_secret_name = "${var.prefix}-iam-secret-generator-apikey-secret" + iam_engine_name = "iam-engine" + providers = { + ibm = ibm.ibm-sm + } +} + +################################################################## +# Create service-id, policy to pull secrets from secret manager +################################################################## + +# Create service-id +resource "ibm_iam_service_id" "secret_puller" { + name = "sid:0.0.1:${var.prefix}-secret-puller:automated:simple-service:secret-manager:" + description = "ServiceID that can pull secrets from Secret Manager" +} + +# Create policy to allow new service id to pull secrets from secrets manager +resource "ibm_iam_service_policy" "secret_puller_policy" { + iam_service_id = ibm_iam_service_id.secret_puller.id + roles = ["Viewer", "SecretsReader"] + + resources { + service = "secrets-manager" + resource_instance_id = local.sm_guid + resource_type = "secret-group" + resource = local.sm_acct_id + } +} + +################################################################## +# ESO deployment +################################################################## + +module "external_secrets_operator" { + source = "../../" + eso_namespace = local.eso_namespace + + eso_cluster_nodes_configuration = { + nodeSelector = { + label = "dedicated" + value = "edge" + } + tolerations = { + key = "dedicated" + operator = "Equal" + value = "edge" + effect = "NoExecute" + } + } + + depends_on = [ + kubernetes_namespace.apikey_namespace + ] +} +# +## Create dynamic Service ID API key and add to secret manager +module "dynamic_serviceid_apikey1" { + source = "terraform-ibm-modules/iam-serviceid-apikey-secrets-manager/ibm" + version = "1.1.0" + region = local.sm_region + #tfsec:ignore:general-secrets-no-plaintext-exposure + sm_iam_secret_name = "${var.prefix}-${var.sm_iam_secret_name}" + sm_iam_secret_description = "Example of dynamic IAM secret / apikey" #tfsec:ignore:general-secrets-no-plaintext-exposure + serviceid_id = ibm_iam_service_id.secret_puller.id + secrets_manager_guid = local.sm_guid + secret_group_id = local.sm_acct_id + depends_on = [module.iam_secrets_engine, ibm_iam_service_policy.secret_puller_policy, ibm_iam_service_id.secret_puller] + providers = { + ibm = ibm.ibm-sm + } +} + +## Data source to get API Key from secret manager secret-puller-secret +data "ibm_sm_iam_credentials_secret" "secret_puller_secret" { + instance_id = local.sm_guid + #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static type + secret_id = module.dynamic_serviceid_apikey1.secret_id + provider = ibm.ibm-sm +} + +################################################################## +# ESO ClusterStore creation with apikey authentication +################################################################## +module "eso_clusterstore" { + source = "../../modules/eso-clusterstore" + eso_authentication = "api_key" + clusterstore_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key + region = local.sm_region + clusterstore_helm_rls_name = "cluster-store" + clusterstore_secret_name = "generic-cluster-api-key" #checkov:skip=CKV_SECRET_6 + clusterstore_name = "cluster-store" + clusterstore_secrets_manager_guid = local.sm_guid + eso_namespace = local.eso_namespace + service_endpoints = "public" + depends_on = [ + module.external_secrets_operator, + ] +} + +################################################################## +# creation of generic username/password secret +# (for example to store artifactory username and API key) +################################################################## + +locals { + # secret value for sm_userpass_secret + userpass_apikey = sensitive("password-payload-example") +} + +# Create username_password secret and store in secret manager +module "sm_userpass_secret" { + source = "terraform-ibm-modules/secrets-manager-secret/ibm" + version = "1.3.2" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_id = local.sm_acct_id + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_name = "${var.prefix}-usernamepassword-secret" # checkov:skip=CKV_SECRET_6 + secret_description = "example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure # checkov:skip=CKV_SECRET_6 + secret_payload_password = local.userpass_apikey + secret_type = "username_password" #checkov:skip=CKV_SECRET_6 + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_username = "artifactory-user" # checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + secret_auto_rotation = false + secret_auto_rotation_interval = 0 + secret_auto_rotation_unit = null + providers = { + ibm = ibm.ibm-sm + } +} + +################################################################## +# ESO externalsecrets with cluster scope and apikey authentication +################################################################## + +# ESO externalsecret with cluster scope creating a dockerconfigjson type secret +module "external_secret_usr_pass" { + depends_on = [module.external_secrets_operator] + source = "../../modules/eso-external-secret" + es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "username_password" #checkov:skip=CKV_SECRET_6 + sm_secret_id = module.sm_userpass_secret.secret_id + es_kubernetes_namespace = kubernetes_namespace.apikey_namespace.metadata[0].name + eso_store_name = "cluster-store" + es_container_registry = "wcp-my-team-docker-local.artifactory.swg-devops.com" + es_kubernetes_secret_name = "dockerconfigjson-uc" #checkov:skip=CKV_SECRET_6 + es_helm_rls_name = "es-docker-uc" + reloader_watching = true } diff --git a/examples/basic/outputs.tf b/examples/basic/outputs.tf index 04b196e9..e124314b 100644 --- a/examples/basic/outputs.tf +++ b/examples/basic/outputs.tf @@ -1,18 +1,7 @@ -######################################################################################################################## +############################################################################## # Outputs -######################################################################################################################## - -output "cos_instance_id" { - description = "COS instance id" - value = ibm_resource_instance.cos_instance.id -} - -output "resource_group_name" { - description = "Resource group name" - value = module.resource_group.resource_group_name -} - -output "resource_group_id" { - description = "Resource group ID" - value = module.resource_group.resource_group_id +############################################################################## +output "cluster_id" { + description = "ID of the cluster deployed" + value = module.ocp_base.cluster_id } diff --git a/examples/basic/provider.tf b/examples/basic/provider.tf index 84b69850..8d6884a3 100644 --- a/examples/basic/provider.tf +++ b/examples/basic/provider.tf @@ -1,8 +1,25 @@ -######################################################################################################################## -# Provider config -######################################################################################################################## - provider "ibm" { ibmcloud_api_key = var.ibmcloud_api_key region = var.region } + +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.existing_sm_instance_region == null ? var.region : var.existing_sm_instance_region + alias = "ibm-sm" +} + +provider "kubernetes" { + host = data.ibm_container_cluster_config.cluster_config.host + token = data.ibm_container_cluster_config.cluster_config.token + cluster_ca_certificate = data.ibm_container_cluster_config.cluster_config.ca_certificate +} + + +provider "helm" { + kubernetes { + host = data.ibm_container_cluster_config.cluster_config.host + token = data.ibm_container_cluster_config.cluster_config.token + cluster_ca_certificate = data.ibm_container_cluster_config.cluster_config.ca_certificate + } +} diff --git a/examples/basic/variables.tf b/examples/basic/variables.tf index dd0d0af9..b7006743 100644 --- a/examples/basic/variables.tf +++ b/examples/basic/variables.tf @@ -1,33 +1,60 @@ -######################################################################################################################## -# Input variables -######################################################################################################################## +####################################################################### +# Generic +####################################################################### -variable "ibmcloud_api_key" { +variable "prefix" { + description = "Prefix for name of all resource created by this example" type = string - description = "The IBM Cloud API Key" - sensitive = true + default = "eso-example-basic" } variable "region" { type = string - description = "Region to provision all resources created by this example" + description = "Region where resources will be created." default = "us-south" } -variable "prefix" { +variable "ibmcloud_api_key" { type = string - description = "Prefix to append to all resources created by this example" - default = "basic" + description = "APIkey that's associated with the account to use, set via environment variable TF_VAR_ibmcloud_api_key or .tfvars file." + sensitive = true } variable "resource_group" { type = string - description = "The name of an existing resource group to provision resources in to. If not set a new resource group will be created using the prefix variable" + description = "An existing resource group name to use for this example, if unset a new resource group will be created" default = null } +# tflint-ignore: terraform_unused_declarations variable "resource_tags" { type = list(string) description = "Optional list of tags to be added to created resources" default = [] } + +## Image-pull module +variable "sm_iam_secret_name" { + type = string + description = "Name of SM IAM secret (dynamic ServiceID API Key) to be created" + default = "sm-iam-secret-puller" #tfsec:ignore:general-secrets-no-plaintext-exposure +} + +variable "sm_service_plan" { + type = string + description = "Secrets-Manager trial plan" + default = "trial" +} + +## ESO Module +variable "existing_sm_instance_guid" { + type = string + description = "Existing Secrets Manager GUID. If not provided a new instance will be provisioned" + default = null +} + +variable "existing_sm_instance_region" { + type = string + description = "Existing Secrets Manager Region. Required if value is passed into var.existing_instance_guid." + default = null +} diff --git a/examples/basic/version.tf b/examples/basic/version.tf index 2b99b89d..8ec2e629 100644 --- a/examples/basic/version.tf +++ b/examples/basic/version.tf @@ -1,12 +1,21 @@ terraform { required_version = ">= 1.3.0" - - # Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main - # module's version.tf (usually a basic example), and 1 example that will always use the latest provider version. required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = "= 2.16.1" + } + helm = { + source = "hashicorp/helm" + version = "= 2.11.0" + } + time = { + source = "hashicorp/time" + version = "= 0.9.1" + } ibm = { source = "IBM-Cloud/ibm" - version = "1.49.0" + version = "= 1.68.0" } } } diff --git a/main.tf b/main.tf index 0b919ea2..b39cc714 100644 --- a/main.tf +++ b/main.tf @@ -1,3 +1,336 @@ -/******************************************************************** -This file is used to implement the ROOT module. -*********************************************************************/ +############################################################################## +# External Secrets Sync Module +# +# Module for deploying External Secret Operator (ESO) and use it to create and synchronize Kubernetes secrets into clusters based on Secrets-Manager secrets. +############################################################################## + +## Install ESO + +locals { + eso_image_tag_digest = "v0.10.5-ubi@sha256:2d4583ff06dd9e186076cc11f2c4782f17e32da28fe18b1144d89806213d17cd" # datasource: icr.io/ibm-iac/external-secrets + eso_image_repo = "icr.io/ibm-iac/external-secrets" + + reloader_image_tag_digest = "v1.1.0-ubi@sha256:d2adccbac4da35a8b31aa21bfbc44da47d8676a41b91fd8f3b192f386f72aa20" # datasource: icr.io/ibm-iac/reloader + reloader_image_repo = "icr.io/ibm-iac/reloader" +} + +# creating namespace to deploy ESO into RedHat ServiceMesh +module "eso_namespace" { + count = var.eso_namespace != null ? 1 : 0 + source = "terraform-ibm-modules/namespace/ibm" + version = "1.0.2" + namespaces = [ + { + name = var.eso_namespace + metadata = { + name = var.eso_namespace + labels = { + } + annotations = { + "istio-injection" = var.eso_enroll_in_servicemesh == true ? "enabled" : null + } + } + } + ] +} + +# loading existing eso namespace +data "kubernetes_namespace" "existing_eso_namespace" { + count = var.existing_eso_namespace != null ? 1 : 0 + metadata { + name = var.existing_eso_namespace + } +} + +locals { + # namespace to use for eso. If both eso_namespace and existing_eso_namespace are not null, eso_namespace takes the precedence + eso_namespace = var.eso_namespace != null ? var.eso_namespace : data.kubernetes_namespace.existing_eso_namespace[0].metadata[0].name +} + +locals { + eso_helm_release_values_cri = <<-EOF +installCRDs: true +securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - "ALL" + enabled: true + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + seccompProfile: + type: "RuntimeDefault" +podAnnotations: +%{for key, value in var.eso_pod_configuration.annotations.external_secrets} "${key}": "${value}" %{endfor} +%{if var.eso_enroll_in_servicemesh == true} + sidecar.istio.io/inject: "true" + sidecar.istio.io/rewriteAppHTTPProbers: "true" +%{endif} +podLabels: +%{if var.eso_enroll_in_servicemesh == true} app: external-secrets-operator %{endif} +%{for key, value in var.eso_pod_configuration.labels.external_secrets} "${key}": "${value}" %{endfor} +%{if var.eso_enroll_in_servicemesh == true} +extraEnv: +- name: KUBERNETES_SERVICE_HOST + value: kubernetes.default.svc.cluster.local +%{endif} +extraVolumes: +- name: sa-token + projected: + defaultMode: 0644 + sources: + - serviceAccountToken: + path: sa-token + expirationSeconds: 3600 + audience: iam +extraVolumeMounts: +- mountPath: /var/run/secrets/tokens + name: sa-token +webhook: + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - "ALL" + enabled: true + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + seccompProfile: + type: "RuntimeDefault" + podAnnotations: + %{for key, value in var.eso_pod_configuration.annotations.external_secrets_webhook} "${key}": "${value}" %{endfor} + %{if var.eso_enroll_in_servicemesh == true} + sidecar.istio.io/inject: "true" + sidecar.istio.io/rewriteAppHTTPProbers: "true" + %{endif} + podLabels: + %{if var.eso_enroll_in_servicemesh == true} app: external-secrets-operator %{endif} + %{for key, value in var.eso_pod_configuration.labels.external_secrets_webhook} "${key}": "${value}" %{endfor} + %{if var.eso_enroll_in_servicemesh == true} + extraEnv: + - name: KUBERNETES_SERVICE_HOST + value: kubernetes.default.svc.cluster.local + %{endif} + extraVolumes: + - name: sa-token + projected: + defaultMode: 0644 + sources: + - serviceAccountToken: + path: sa-token + expirationSeconds: 3600 + audience: iam + extraVolumeMounts: + - mountPath: /var/run/secrets/tokens + name: sa-token +certController: + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - "ALL" + enabled: true + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + seccompProfile: + type: "RuntimeDefault" + podAnnotations: + %{for key, value in var.eso_pod_configuration.annotations.external_secrets_cert_controller} "${key}": "${value}" %{endfor} + %{if var.eso_enroll_in_servicemesh == true} + sidecar.istio.io/inject: "true" + sidecar.istio.io/rewriteAppHTTPProbers: "true" + %{endif} + podLabels: + %{if var.eso_enroll_in_servicemesh == true} app: external-secrets-operator %{endif} + %{for key, value in var.eso_pod_configuration.labels.external_secrets_cert_controller} "${key}": "${value}" %{endfor} + %{if var.eso_enroll_in_servicemesh == true} + extraEnv: + - name: KUBERNETES_SERVICE_HOST + value: kubernetes.default.svc.cluster.local + %{endif} +EOF + + eso_helm_release_values_workerselector = var.eso_cluster_nodes_configuration == null ? "" : <<-EOF +nodeSelector: { ${var.eso_cluster_nodes_configuration.nodeSelector.label}: ${var.eso_cluster_nodes_configuration.nodeSelector.value} } +tolerations: +- key: ${var.eso_cluster_nodes_configuration.tolerations.key} + operator: ${var.eso_cluster_nodes_configuration.tolerations.operator} + value: ${var.eso_cluster_nodes_configuration.tolerations.value} + effect: ${var.eso_cluster_nodes_configuration.tolerations.effect} +webhook: + nodeSelector: { ${var.eso_cluster_nodes_configuration.nodeSelector.label}: ${var.eso_cluster_nodes_configuration.nodeSelector.value} } + tolerations: + - key: ${var.eso_cluster_nodes_configuration.tolerations.key} + operator: ${var.eso_cluster_nodes_configuration.tolerations.operator} + value: ${var.eso_cluster_nodes_configuration.tolerations.value} + effect: ${var.eso_cluster_nodes_configuration.tolerations.effect} +certController: + nodeSelector: { ${var.eso_cluster_nodes_configuration.nodeSelector.label}: ${var.eso_cluster_nodes_configuration.nodeSelector.value} } + tolerations: + - key: ${var.eso_cluster_nodes_configuration.tolerations.key} + operator: ${var.eso_cluster_nodes_configuration.tolerations.operator} + value: ${var.eso_cluster_nodes_configuration.tolerations.value} + effect: ${var.eso_cluster_nodes_configuration.tolerations.effect} +EOF +} + +resource "helm_release" "external_secrets_operator" { + depends_on = [module.eso_namespace, data.kubernetes_namespace.existing_eso_namespace] + + name = "external-secrets" + namespace = local.eso_namespace + chart = "oci://icr.io/ibm-iac-charts/external-secrets" + version = "0.10.5" + wait = true + + set { + name = "image.repository" + type = "string" + value = local.eso_image_repo + } + + set { + name = "image.tag" + type = "string" + value = local.eso_image_tag_digest + } + + set { + name = "webhook.image.repository" + type = "string" + value = local.eso_image_repo + } + + set { + name = "webhook.image.tag" + type = "string" + value = local.eso_image_tag_digest + } + + set { + name = "certController.image.repository" + type = "string" + value = local.eso_image_repo + } + + set { + name = "certController.image.tag" + type = "string" + value = local.eso_image_tag_digest + } + + # The following mounts are needed for the CRI based authentication with Trusted Profiles + values = [local.eso_helm_release_values_cri, local.eso_helm_release_values_workerselector] +} + +resource "helm_release" "pod_reloader" { + depends_on = [module.eso_namespace, data.kubernetes_namespace.existing_eso_namespace] + count = var.reloader_deployed == true ? 1 : 0 + name = "reloader" + namespace = local.eso_namespace + chart = "oci://icr.io/ibm-iac-charts/reloader" + version = "1.1.0" + wait = true + + # Set the deployment image name and tag + set { + name = "reloader.deployment.image.name" + type = "string" + value = local.reloader_image_repo + } + + set { + name = "reloader.deployment.image.tag" + type = "string" + value = local.reloader_image_tag_digest + } + + # Set reload strategy + set { + name = "reloader.reloadStrategy" + type = "string" + value = var.reloader_reload_strategy + } + + # Set namespaces to ignore + dynamic "set" { + for_each = var.reloader_namespaces_to_ignore != null ? [1] : [] + content { + name = "reloader.namespacesToIgnore" + value = var.reloader_namespaces_to_ignore + } + } + + # Set resources to ignore + dynamic "set" { + for_each = var.reloader_resources_to_ignore != null ? [1] : [] + content { + name = "reloader.resourcesToIgnore" + value = var.reloader_resources_to_ignore + } + } + + # Set watchGlobally based on conditions + set { + name = "reloader.watchGlobally" + value = var.reloader_namespaces_selector == null && var.reloader_resource_label_selector == null ? true : false + } + + # Set ignoreSecrets and ignoreConfigMaps + set { + name = "reloader.ignoreSecrets" + value = var.reloader_ignore_secrets + } + + set { + name = "reloader.ignoreConfigMaps" + value = var.reloader_ignore_configmaps + } + + # Set OpenShift and Argo Rollouts options + set { + name = "reloader.isOpenshift" + value = var.reloader_is_openshift + } + # Set runAsUser to null if isOpenShift is true + dynamic "set" { + for_each = var.reloader_is_openshift ? [1] : [] + content { + name = "reloader.deployment.securityContext.runAsUser" + value = "null" + } + } + + set { + name = "reloader.podMonitor.enabled" + value = var.reloader_pod_monitor_metrics + } + dynamic "set" { + for_each = var.reloader_log_format == "json" ? [1] : [] + content { + name = "reloader.logFormat" + value = var.reloader_log_format + } + } + set { + name = "reloader.isArgoRollouts" + value = var.reloader_is_argo_rollouts + } + + # Set reloadOnCreate and syncAfterRestart options + set { + name = "reloader.reloadOnCreate" + value = var.reloader_reload_on_create + } + + set { + name = "reloader.syncAfterRestart" + value = var.reloader_sync_after_restart + } + + # Set the values attribute conditionally + values = var.reloader_custom_values != null ? yamldecode(var.reloader_custom_values) : [] +} diff --git a/modules/eso-clusterstore/README.md b/modules/eso-clusterstore/README.md new file mode 100644 index 00000000..615bb03d --- /dev/null +++ b/modules/eso-clusterstore/README.md @@ -0,0 +1,54 @@ +# ESO Cluster Store Module + +This module allows to configure an [ClusterSecretStore](https://external-secrets.io/latest/api/clustersecretstore/) resource for an ESO secret store with cluster scope, in the desired namespace (the same of the ESO deploymet is a requirement of ESO and it is up to the consumer) and with the desired configurations. + +For more information about ClusterSecretStore resource and about ESO please refer to the ESO documentation available [here](https://external-secrets.io/v0.8.3/guides/introduction/) + +This module supports ClusterSecretStore two authentication configurations to pull/push secrets with the configured Secrets Manager instance: +- apikey authentication +- trusted profile authentication + +For more information about Trusted Profiles refer to the IBM Cloud documentation available [here](https://cloud.ibm.com/docs/account?topic=account-create-trusted-profile&interface=ui) + + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.0.0 | +| [helm](#requirement\_helm) | >= 2.8.0 | +| [kubernetes](#requirement\_kubernetes) | >= 2.16.1, <3.0.0 | + +### Modules + +No modules. + +### Resources + +| Name | Type | +|------|------| +| [helm_release.cluster_secret_store_apikey](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | +| [helm_release.cluster_secret_store_tp](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | +| [kubernetes_secret.eso_clusterstore_secret](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret) | resource | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [clusterstore\_helm\_rls\_name](#input\_clusterstore\_helm\_rls\_name) | Name of helm release for clusterstore | `string` | `"cluster-secret-store"` | no | +| [clusterstore\_name](#input\_clusterstore\_name) | Name of the ESO secret store to be used/created for cluster scope. | `string` | `"clustersecret-store"` | no | +| [clusterstore\_secret\_apikey](#input\_clusterstore\_secret\_apikey) | APIkey to be configured in the clusterstore\_secret\_name secret in the ESO clusterstore. One between clusterstore\_secret\_apikey and clusterstore\_trusted\_profile\_name must be filled | `string` | `null` | no | +| [clusterstore\_secret\_name](#input\_clusterstore\_secret\_name) | Secret name to be used/referenced in the ESO clusterstore to pull from Secrets Manager | `string` | `"ibm-secret"` | no | +| [clusterstore\_secrets\_manager\_guid](#input\_clusterstore\_secrets\_manager\_guid) | Secrets manager instance GUID for clusterstore where secrets will be stored or fetched from | `string` | n/a | yes | +| [clusterstore\_trusted\_profile\_name](#input\_clusterstore\_trusted\_profile\_name) | The name of the trusted profile to use for clusterstore scope. This allows ESO to use CRI based authentication to access secrets manager. The trusted profile must be created in advance | `string` | `null` | no | +| [eso\_authentication](#input\_eso\_authentication) | Authentication method, Possible values are api\_key or/and trusted\_profile. | `string` | `"trusted_profile"` | no | +| [eso\_namespace](#input\_eso\_namespace) | Namespace where the ESO is deployed. It will be used to deploy the ClusterStore | `string` | n/a | yes | +| [region](#input\_region) | Region where Secrets Manager is deployed. It will be used to build the regional URL to the service | `string` | n/a | yes | +| [service\_endpoints](#input\_service\_endpoints) | The service endpoint type to communicate with the provided secrets manager instance. Possible values are `public` or `private`. This also will set the iam endpoint for containerAuth when enabling Trusted Profile/CR based authentication. | `string` | `"public"` | no | + +### Outputs + +| Name | Description | +|------|-------------| +| [helm\_release\_cluster\_store](#output\_helm\_release\_cluster\_store) | ClusterSecretStore helm release. Returning the helm release for trusted profile or apikey authentication according to the authentication type | + diff --git a/modules/eso-clusterstore/main.tf b/modules/eso-clusterstore/main.tf new file mode 100644 index 00000000..987c4e19 --- /dev/null +++ b/modules/eso-clusterstore/main.tf @@ -0,0 +1,108 @@ +locals { + # preliminary authentication validation - one of clusterstore_secret_apikey and clusterstore_trusted_profile_name must be valid + auth_validate_condition = var.clusterstore_secret_apikey == null && var.clusterstore_trusted_profile_name == null + auth_clusterstore_msg = "One of the variables clusterstore_secret_apikey and clusterstore_trusted_profile_name must be provided, cannot be both set to null" + # tflint-ignore: terraform_unused_declarations + auth_validate_check = regex("^${local.auth_clusterstore_msg}$", (!local.auth_validate_condition ? local.auth_clusterstore_msg : "")) + + # auth is apikey so the variable clusterstore_secret_apikey cannot be null + api_key_clusterstore_validate_condition = var.eso_authentication == "api_key" && var.clusterstore_secret_apikey == null + api_key_clusterstore_msg = "API Key authentication is enabled and scope for store is cluster, therefore clusterstore_secret_apikey must be provided." + # tflint-ignore: terraform_unused_declarations + api_key_clusterstore_validate_check = regex("^${local.api_key_clusterstore_msg}$", (!local.api_key_clusterstore_validate_condition ? local.api_key_clusterstore_msg : "")) + + # auth is trustedprofile so the variable clusterstore_trusted_profile_name cannot be null + tp_clusterstore_validate_condition = var.eso_authentication == "trusted_profile" && var.clusterstore_trusted_profile_name == null + tp_clusterstore_msg = "Trusted profile authentication is enabled, therefore clusterstore_trusted_profile_name must be provided." + # tflint-ignore: terraform_unused_declarations + tp_clusterstore_validate_check = regex("^${local.tp_clusterstore_msg}$", (!local.tp_clusterstore_validate_condition ? local.tp_clusterstore_msg : "")) +} + +locals { + helm_raw_chart_name = "raw" + helm_raw_chart_version = "0.2.5" + + # endpoints definition according to endpoints to use are private or public (var.service_endpoints) + iam_endpoint = "${var.service_endpoints == "private" ? "private." : ""}iam.cloud.ibm.com" + regional_endpoint = var.service_endpoints == "private" ? "private.${var.region}" : var.region + cluster_store_secrets_manager_endpoint = "${var.clusterstore_secrets_manager_guid}.${local.regional_endpoint}.secrets-manager.appdomain.cloud" +} + +### creating secret to store apikey to authenticate on secretsmanager for apikey authentication +resource "kubernetes_secret" "eso_clusterstore_secret" { + count = var.eso_authentication == "api_key" ? 1 : 0 + metadata { + name = var.clusterstore_secret_name + namespace = var.eso_namespace #checkov:skip=CKV_K8S_21 + } + + data = { + apiKey = var.clusterstore_secret_apikey + } + type = "opaque" +} + + +### ClusterSecretStore used to connect with SM instance for clusterstore and authentication is through apikey + +# define cluster secret store for cluster scope and apikey auth +resource "helm_release" "cluster_secret_store_apikey" { + count = var.eso_authentication == "api_key" ? 1 : 0 + name = "${var.clusterstore_helm_rls_name}-apikey" + namespace = var.eso_namespace + chart = "${path.module}/../../chart/${local.helm_raw_chart_name}" + version = local.helm_raw_chart_version + timeout = 600 + values = [ + <<-EOF + resources: + - apiVersion: external-secrets.io/v1beta1 + kind: ClusterSecretStore + metadata: + name: "${var.clusterstore_name}" + spec: + provider: + ibm: + serviceUrl: "https://${local.cluster_store_secrets_manager_endpoint}" + auth: + secretRef: + secretApiKeySecretRef: + name: "${var.clusterstore_secret_name}" + key: apiKey + namespace: "${var.eso_namespace}" + EOF + ] + + depends_on = [ + kubernetes_secret.eso_clusterstore_secret + ] +} + +# define cluster secret store for cluster scope and trusted store auth +# ContainerAuth with CRI based authentication +resource "helm_release" "cluster_secret_store_tp" { + count = var.eso_authentication == "trusted_profile" ? 1 : 0 + name = "${var.clusterstore_helm_rls_name}-tp" + namespace = var.eso_namespace + chart = "${path.module}/../../chart/${local.helm_raw_chart_name}" + version = local.helm_raw_chart_version + timeout = 600 + values = [ + <<-EOF + resources: + - apiVersion: external-secrets.io/v1beta1 + kind: ClusterSecretStore + metadata: + name: "${var.clusterstore_name}" + spec: + provider: + ibm: + serviceUrl: "https://${local.cluster_store_secrets_manager_endpoint}" + auth: + containerAuth: + profile: "${var.clusterstore_trusted_profile_name}" + iamEndpoint: "https://${local.iam_endpoint}" + tokenLocation: /var/run/secrets/tokens/sa-token + EOF + ] +} diff --git a/modules/eso-clusterstore/outputs.tf b/modules/eso-clusterstore/outputs.tf new file mode 100644 index 00000000..8c91317c --- /dev/null +++ b/modules/eso-clusterstore/outputs.tf @@ -0,0 +1,8 @@ +############################################################################## +# Outputs +############################################################################## + +output "helm_release_cluster_store" { + value = var.eso_authentication == "trusted_profile" ? helm_release.cluster_secret_store_tp : helm_release.cluster_secret_store_apikey + description = "ClusterSecretStore helm release. Returning the helm release for trusted profile or apikey authentication according to the authentication type" +} diff --git a/modules/eso-clusterstore/variables.tf b/modules/eso-clusterstore/variables.tf new file mode 100644 index 00000000..3d821825 --- /dev/null +++ b/modules/eso-clusterstore/variables.tf @@ -0,0 +1,74 @@ +######## eso clusterstore configuration + +variable "eso_namespace" { + description = "Namespace where the ESO is deployed. It will be used to deploy the ClusterStore" + type = string +} + +variable "region" { + description = "Region where Secrets Manager is deployed. It will be used to build the regional URL to the service" + type = string +} + +variable "service_endpoints" { + type = string + description = "The service endpoint type to communicate with the provided secrets manager instance. Possible values are `public` or `private`. This also will set the iam endpoint for containerAuth when enabling Trusted Profile/CR based authentication." + default = "public" + validation { + condition = contains(["public", "private"], var.service_endpoints) + error_message = "The specified service_endpoints is not a valid selection!" + } +} + +variable "clusterstore_name" { + description = "Name of the ESO secret store to be used/created for cluster scope." + default = "clustersecret-store" + type = string +} + +variable "clusterstore_helm_rls_name" { + description = "Name of helm release for clusterstore" + type = string + default = "cluster-secret-store" +} + +############################################################################## +# Authentication configuration for clusterstore that can be one of api_key or trusted_profile +############################################################################## +variable "eso_authentication" { + type = string + description = "Authentication method, Possible values are api_key or/and trusted_profile." + default = "trusted_profile" + validation { + condition = contains(["api_key", "trusted_profile"], var.eso_authentication) + error_message = "Authentication mode allowed are api_key or/and trusted_profile." + } +} + +variable "clusterstore_secret_name" { + description = "Secret name to be used/referenced in the ESO clusterstore to pull from Secrets Manager" + default = "ibm-secret" + type = string +} + +variable "clusterstore_secret_apikey" { + type = string + description = "APIkey to be configured in the clusterstore_secret_name secret in the ESO clusterstore. One between clusterstore_secret_apikey and clusterstore_trusted_profile_name must be filled" + sensitive = true + default = null +} + +####### trusted profile + +variable "clusterstore_trusted_profile_name" { + type = string + description = "The name of the trusted profile to use for clusterstore scope. This allows ESO to use CRI based authentication to access secrets manager. The trusted profile must be created in advance" + default = null +} + +####### Secrets Manager instance + +variable "clusterstore_secrets_manager_guid" { + type = string + description = "Secrets manager instance GUID for clusterstore where secrets will be stored or fetched from" +} diff --git a/modules/eso-clusterstore/version.tf b/modules/eso-clusterstore/version.tf new file mode 100644 index 00000000..168b3dc2 --- /dev/null +++ b/modules/eso-clusterstore/version.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">= 1.0.0" + required_providers { + # Use "greater than or equal to" range in modules + kubernetes = { + source = "hashicorp/kubernetes" + version = ">= 2.16.1, <3.0.0" + } + helm = { + source = "hashicorp/helm" + version = ">= 2.8.0" + } + } +} diff --git a/modules/eso-external-secret/README.md b/modules/eso-external-secret/README.md new file mode 100644 index 00000000..19a9b5fa --- /dev/null +++ b/modules/eso-external-secret/README.md @@ -0,0 +1,62 @@ +# ESO External Secrets Module + +This module allows to configure an [ExternalSecrets](https://external-secrets.io/latest/api/externalsecret/) resource in the desired namespace and with the desired configurations. + +It if possible to create ExternalSecret resource referencing either: +- a `ClusterSecretStore` for store with cluster scope +- a `SecretStore` for 'namespace' for regular namespaced scope +by correctly setting the related input variable `eso_store_scope` + +For more information about ExternalSecrets on ESO please refer to the ESO documentation available [here](https://external-secrets.io/v0.8.3/guides/introduction/) + + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.0.0 | +| [helm](#requirement\_helm) | >= 2.8.0 | + +### Modules + +No modules. + +### Resources + +| Name | Type | +|------|------| +| [helm_release.kubernetes_secret](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | +| [helm_release.kubernetes_secret_certificate](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | +| [helm_release.kubernetes_secret_chain_list](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | +| [helm_release.kubernetes_secret_kv_all](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | +| [helm_release.kubernetes_secret_kv_key](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | +| [helm_release.kubernetes_secret_user_pw](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [es\_container\_registry](#input\_es\_container\_registry) | The registry URL to be used in dockerconfigjson | `string` | `"us.icr.io"` | no | +| [es\_container\_registry\_email](#input\_es\_container\_registry\_email) | Optional - Email to be used in dockerconfigjson | `string` | `null` | no | +| [es\_container\_registry\_secrets\_chain](#input\_es\_container\_registry\_secrets\_chain) | Structure to generate a chain of secrets into a single dockerjsonconfig secret for multiple registries authentication. |
list(object({
es_container_registry = string
sm_secret_id = string # id of the secret storing the apikey that will be used for the secrets chain
es_container_registry_email = optional(string, null)
}))
| `[]` | no | +| [es\_helm\_rls\_name](#input\_es\_helm\_rls\_name) | Name to use for the helm release for externalsecrets resource. Must be unique in the namespace | `string` | n/a | yes | +| [es\_helm\_rls\_namespace](#input\_es\_helm\_rls\_namespace) | Namespace to deploy the helm release for the externalsecret. Default if null is the externalsecret namespace | `string` | `null` | no | +| [es\_kubernetes\_namespace](#input\_es\_kubernetes\_namespace) | Namespace to use to generate the externalsecret | `string` | n/a | yes | +| [es\_kubernetes\_secret\_data\_key](#input\_es\_kubernetes\_secret\_data\_key) | Data key to be used in Kubernetes Opaque secret. Only needed when 'es\_kubernetes\_secret\_type' is configured as `opaque` and sm\_secret\_type is set to either 'arbitrary' or 'iam\_credentials' | `string` | `null` | no | +| [es\_kubernetes\_secret\_name](#input\_es\_kubernetes\_secret\_name) | Name of the secret to use for the kubernetes secret object | `string` | n/a | yes | +| [es\_kubernetes\_secret\_type](#input\_es\_kubernetes\_secret\_type) | Secret type/format to be installed in the Kubernetes/Openshift cluster by ESO. Valid inputs are `opaque` `dockerconfigjson` and `tls` | `string` | n/a | yes | +| [es\_refresh\_interval](#input\_es\_refresh\_interval) | Specify interval for es secret synchronization. See recommendations for specifying/customizing refresh interval in this IBM Cloud article > https://cloud.ibm.com/docs/secrets-manager?topic=secrets-manager-tutorial-kubernetes-secrets#kubernetes-secrets-best-practices | `string` | `"1h"` | no | +| [eso\_store\_name](#input\_eso\_store\_name) | ESO store name to use when creating the externalsecret. Cannot be null and it is mandatory | `string` | n/a | yes | +| [eso\_store\_scope](#input\_eso\_store\_scope) | Set to 'cluster' to configure ESO store as with cluster scope (ClusterSecretStore) or 'namespace' for regular namespaced scope (SecretStore). This value is used to configure the externalsecret reference | `string` | `"cluster"` | no | +| [reloader\_watching](#input\_reloader\_watching) | Flag to enable/disable the reloader watching. If enabled the reloader will watch for changes in the secret and reload the associated annotated pods if needed | `bool` | `false` | no | +| [sm\_certificate\_bundle](#input\_sm\_certificate\_bundle) | Flag to enable if the public/intermediate certificate is bundled. If enabled public key is managed as bundled with intermediate and private key, otherwise the template considers the public key not bundled with intermediate certificate and private key | `bool` | `true` | no | +| [sm\_certificate\_has\_intermediate](#input\_sm\_certificate\_has\_intermediate) | The secret manager certificate is provided with intermediate certificate. By enabling this flag the certificate body on kube will contain certificate and intermediate content, otherwise only certificate will be added. Valid only for public and imported certificate | `bool` | `true` | no | +| [sm\_kv\_keyid](#input\_sm\_kv\_keyid) | Secrets-Manager key value (kv) keyid | `string` | `null` | no | +| [sm\_kv\_keypath](#input\_sm\_kv\_keypath) | Secrets-Manager key value (kv) keypath | `string` | `null` | no | +| [sm\_secret\_id](#input\_sm\_secret\_id) | Secrets-Manager secret ID where source data will be synchronized with Kubernetes secret. It can be null only in the case of a dockerjsonconfig secrets chain | `string` | n/a | yes | +| [sm\_secret\_type](#input\_sm\_secret\_type) | Secrets-manager secret type to be used as source data by ESO. Valid input types are 'arbitrary', 'username\_password' and 'iam\_credentials' | `string` | n/a | yes | + +### Outputs + +No outputs. + diff --git a/modules/eso-external-secret/main.tf b/modules/eso-external-secret/main.tf new file mode 100644 index 00000000..46c8cabc --- /dev/null +++ b/modules/eso-external-secret/main.tf @@ -0,0 +1,368 @@ +locals { + # Validation approach based on https://stackoverflow.com/a/66682419 + validate_condition_secret = var.es_kubernetes_secret_data_key == null && (var.es_kubernetes_secret_type == "opaque" && (var.sm_secret_type == "arbitrary" || var.sm_secret_type == "iam_credentials")) # checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + validate_msg_secret = "A value for 'es_kubernetes_secret_data_key' must be passed when 'es_kubernetes_secret_type = opaque' and 'sm_secret_type' is either 'arbitrary' or 'iam_credentials'" + # tflint-ignore: terraform_unused_declarations + validate_check_secret = regex("^${local.validate_msg_secret}$", (!local.validate_condition_secret ? local.validate_msg_secret : "")) + + # reloader annotation + reloader_annotation = var.reloader_watching ? "'reloader.stakater.com/auto': 'true'" : "{}" +} + +# secrets formatting +locals { + # certificate secret templates and management + is_certificate = can(regex("^imported_cert$|^public_cert$|^private_cert$", var.sm_secret_type)) + + # dockerjsonconfig secrets chain flag + is_dockerjsonconfig_chain = length(var.es_container_registry_secrets_chain) > 0 ? true : false + + # validation for dockerjsonconfig secrets chain -> if it is a chain the kube secret type must be dockerconfigjson and sm secret type iam_credentials + validate_condition_chain = local.is_dockerjsonconfig_chain == true && (var.es_kubernetes_secret_type != "dockerconfigjson" || var.sm_secret_type != "iam_credentials") # checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + validate_msg_chain = "If the externalsecret is expected to generate a dockerjsonconfig secrets chain the only supported value for es_kubernetes_secret_type is dockerconfigjson and for sm_secret_type is iam_credentials" + # tflint-ignore: terraform_unused_declarations + validate_check_chain = regex("^${local.validate_msg_chain}$", (!local.validate_condition_chain ? local.validate_msg_chain : "")) + + # validation of sm_secret_id => it can be null only in the case of a dockerjsonconfig chain (secret_ids will be stored ) + validate_condition_sm_secret_id = var.sm_secret_id == null && local.is_dockerjsonconfig_chain == false + validate_msg_sm_secret_id = "The input variable sm_secret_id can be null only a dockerjsonconfig secrets chain is going to be created" + # tflint-ignore: terraform_unused_declarations + validate_check_sm_secret_id = regex("^${local.validate_msg_sm_secret_id}$", (!local.validate_condition_sm_secret_id ? local.validate_msg_sm_secret_id : "")) + + # for certificate secrets public_cert and private_cert the id is the last part of the sm_secret_sm + cert_remoteref_key = local.is_certificate ? "${var.sm_secret_type}/${var.sm_secret_id}" : "" + # defining the template data structure according to the type of certificate + # public and imported certificate template will contain intermediate field only if sm_certificate_has_intermediate flag is true and the certificate bundle flag is disabled + public_cert_tls_template_data = (var.sm_certificate_has_intermediate == true && var.sm_certificate_bundle == false) ? "tls.crt: \"{{ .certificate }}\\n{{ .intermediate }}\"\n tls.key: '{{ .private_key }}'" : "tls.crt: '{{ .certificate}}'\n tls.key: '{{ .private_key }}'" + imported_cert_tls_template_data = (var.sm_certificate_has_intermediate == true && var.sm_certificate_bundle == false) ? "tls.crt: \"{{ .certificate }}\\n{{ .intermediate }}\"\n tls.key: '{{ .private_key }}'" : "tls.crt: '{{ .certificate}}'\n tls.key: '{{ .private_key }}'" + private_cert_tls_template_data = "tls.crt: '{{ .certificate}}'\n tls.key: '{{ .private_key }}'" + # defining the spec data structure according to the type of certificate + # public and imported certificate template will contain intermediate field only if sm_certificate_has_intermediate flag is true + public_certificate_spec_data = (var.sm_certificate_has_intermediate == true && var.sm_certificate_bundle == false) ? "- secretKey: certificate\n remoteRef:\n key: ${local.cert_remoteref_key}\n property: certificate\n - secretKey: intermediate\n remoteRef:\n key: ${local.cert_remoteref_key}\n property: intermediate\n - secretKey: private_key\n remoteRef:\n key: ${local.cert_remoteref_key}\n property: private_key" : "- secretKey: certificate\n remoteRef:\n key: ${local.cert_remoteref_key}\n property: certificate\n - secretKey: private_key\n remoteRef:\n key: ${local.cert_remoteref_key}\n property: private_key" + imported_certificate_spec_data = (var.sm_certificate_has_intermediate == true && var.sm_certificate_bundle == false) ? "- secretKey: certificate\n remoteRef:\n key: ${local.cert_remoteref_key}\n property: certificate\n - secretKey: intermediate\n remoteRef:\n key: ${local.cert_remoteref_key}\n property: intermediate\n - secretKey: private_key\n remoteRef:\n key: ${local.cert_remoteref_key}\n property: private_key" : "- secretKey: certificate\n remoteRef:\n key: ${local.cert_remoteref_key}\n property: certificate\n - secretKey: private_key\n remoteRef:\n key: ${local.cert_remoteref_key}\n property: private_key" + private_certificate_spec_data = "- secretKey: certificate\n remoteRef:\n key: ${local.cert_remoteref_key}\n property: certificate\n - secretKey: private_key\n remoteRef:\n key: ${local.cert_remoteref_key}\n property: private_key" + # definining the right structure to use according to the certificate type + certificate_template = local.is_certificate ? (var.sm_secret_type == "public_cert" ? local.public_cert_tls_template_data : (var.sm_secret_type == "imported_cert" ? local.imported_cert_tls_template_data : (var.sm_secret_type == "private_cert" ? local.private_cert_tls_template_data : ""))) : "" # checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + certificate_spec_data = local.is_certificate ? (var.sm_secret_type == "public_cert" ? local.public_certificate_spec_data : (var.sm_secret_type == "imported_cert" ? local.imported_certificate_spec_data : (var.sm_secret_type == "private_cert" ? local.private_certificate_spec_data : ""))) : "" # checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + + # dockerjson format + docker_user = var.sm_secret_type == "username_password" ? "{{ .username }}" : "iamapikey" # checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + docker_password = var.sm_secret_type == "username_password" ? "{{ .password }}" : "{{ .secretid }}" + + # setting data_type according to the kube secret and the SM secret types + # if kube secret type is opaque && SM secret type arbitrary or iam_credentials -> var.es_kubernetes_secret_data_key + # if kube secret type is opaque && SM secret type username_password -> data_type = .dockerconfigjson + # if kube secret type is opaque && SM secret type != username_password arbitrary and iam_credentials (so kv or the certificate types) -> not setting anything here but handled in related sections + # if kube secret type is not opaque && kube secret type is dockerconfigjson -> data_type = .dockerconfigjson + # if kube secret type is not opaque && if kube secret type is not dockerconfigjson -> not setting here + data_type = var.es_kubernetes_secret_type == "opaque" ? ((var.sm_secret_type == "arbitrary" || var.sm_secret_type == "iam_credentials") ? var.es_kubernetes_secret_data_key : (var.sm_secret_type == "username_password") ? ".dockerconfigjson" : "") : (var.es_kubernetes_secret_type == "dockerconfigjson" ? ".dockerconfigjson" : "") + + # setting data_payload for dockerconfigjson according to the value of var.es_container_registry_email + # if es_kubernetes_secret_type = dockerconfigjson -> setting payload according to the fields available + # if es_kubernetes_secret_type != dockerconfigjson -> data_payload = {{ .secretid }} + data_payload = var.es_kubernetes_secret_type == "dockerconfigjson" && var.es_container_registry_email != null ? jsonencode({ "auths" : { (var.es_container_registry) : { "email" : (var.es_container_registry_email), "username" : (local.docker_user), "password" : (local.docker_password) } } }) : (var.es_kubernetes_secret_type == "dockerconfigjson" && var.es_container_registry_email == null ? jsonencode({ "auths" : { (var.es_container_registry) : { "username" : (local.docker_user), "password" : (local.docker_password) } } }) : "{{ .secretid }}") # checkov:skip=CKV_SECRET_6:does not require high entropy string as is static value + + # final data field format according to the secret type + # only in the case sm_secret_type is username_password and kube secret type is opaque -> data = username : '{{ .username }}'\n password : '{{ .password }} + # in all the other cases data is the resulting data_type : data_payload + username_password_opaque_data = "username : '{{ .username }}'\n password : '{{ .password }}'" + data = var.sm_secret_type == "username_password" && var.es_kubernetes_secret_type == "opaque" ? local.username_password_opaque_data : "${local.data_type} : '${local.data_payload}'" # checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + + # setting value for template type field according to the var.es_kubernetes_secret_type value + es_kubernetes_secret_type = var.es_kubernetes_secret_type == "dockerconfigjson" ? "kubernetes.io/dockerconfigjson" : (var.es_kubernetes_secret_type == "tls" ? "kubernetes.io/tls" : "Opaque") + + # setting remote_ref field value according to the secret type + # for sm secrets types iam_credentials and kv the remoteref is sm_secret_type/sm_secret_id, for arbitrary is only sm_secret_id + # if is_dockerjsonconfig_chain is true it is set to empty as not used + es_remoteref_key = local.is_dockerjsonconfig_chain == false ? (var.sm_secret_type == "iam_credentials" || var.sm_secret_type == "kv" ? "${var.sm_secret_type}/${var.sm_secret_id}" : var.sm_secret_id) : "" # checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + + # dockerconfigjson config for chain of secrets - building a map for all the registries + data_payload_chain_map = local.is_dockerjsonconfig_chain == true ? { + "auths" : { + for index, element in var.es_container_registry_secrets_chain : + element.es_container_registry => (element.es_container_registry_email != null && element.es_container_registry_email != "") ? + { + "username" : "iamapikey", "password" : "{{ .secretid_${index} }}", "email" : (element.es_container_registry_email) + } + : + { + "username" : "iamapikey", "password" : "{{ .secretid_${index} }}" + } + } + } : {} + + # in order to have the content correctly mapped it needs to apply jsonencode twice + encodedchain = jsonencode(jsonencode(local.data_payload_chain_map)) + data_chain = ".dockerconfigjson : ${local.encodedchain}" + + # helm chart details + helm_raw_chart_name = "raw" + helm_raw_chart_version = "0.2.5" + + # if the scope is namespace the secret store kind is SecretStore while is ClusterSecretStore in all the other cases + secret_store_ref_kind = var.eso_store_scope != "namespace" ? "ClusterSecretStore" : "SecretStore" + + # if var.es_helm_rls_namespace is not set the namespace is set to es_kubernetes_namespace (default logic) + es_helm_rls_namespace = var.es_helm_rls_namespace != null ? var.es_helm_rls_namespace : var.es_kubernetes_namespace + + # key-value secret management + is_kv = can(regex("^kv$", var.sm_secret_type)) + + # validation for key-value secret type + validate_condition_kv_secret = local.is_kv && var.sm_kv_keyid != null && var.sm_kv_keypath != null + validate_msg_kv_secret = "For key-value secrets only one of input variables 'sm_kv_keyid' or 'sm_kv_keypath' can be set." + # tflint-ignore: terraform_unused_declarations + validate_check_kv_secret = regex("^${local.validate_msg_kv_secret}$", (!local.validate_condition_kv_secret ? local.validate_msg_kv_secret : "")) + + # second validation for key-value secret type - allowing only opaque for es_kubernetes_secret_type if sm_secret_type is kv + validate_condition_kv_kube_type = local.is_kv && var.es_kubernetes_secret_type != "opaque" + validate_msg_kv_kube_type = "For key-value secrets-manager secrets types es_kubernetes_secret_type cannot be different than opaque - found ${var.es_kubernetes_secret_type}" + # tflint-ignore: terraform_unused_declarations + validate_check_kv_kube_type = regex("^${local.validate_msg_kv_kube_type}$", (!local.validate_condition_kv_kube_type ? local.validate_msg_kv_kube_type : "")) + + # setting up the remoteref property for kv + kv_remoteref_property = var.sm_kv_keyid != null ? var.sm_kv_keyid : (var.sm_kv_keypath != null ? var.sm_kv_keypath : "") + + # kube secret name + helm_secret_name = substr(join("-", [var.es_kubernetes_namespace, var.es_helm_rls_name]), 0, 52) +} + +### Define kubernetes secret to be installed in cluster for sm_secret_type iam_credentials or arbitrary +resource "helm_release" "kubernetes_secret" { + count = (var.sm_secret_type == "iam_credentials" || var.sm_secret_type == "arbitrary") && local.is_dockerjsonconfig_chain == false ? 1 : 0 + name = local.helm_secret_name + namespace = local.es_helm_rls_namespace + chart = "${path.module}/../../chart/${local.helm_raw_chart_name}" + version = local.helm_raw_chart_version + timeout = 600 + values = [ + <<-EOF + resources: + - apiVersion: external-secrets.io/v1beta1 + kind: ExternalSecret + metadata: + name: "${var.es_kubernetes_secret_name}" + namespace: "${var.es_kubernetes_namespace}" + spec: + refreshInterval: ${var.es_refresh_interval} + secretStoreRef: + name: "${var.eso_store_name}" + kind: "${local.secret_store_ref_kind}" + target: + name: "${var.es_kubernetes_secret_name}" + template: + engineVersion: v2 + type: "${local.es_kubernetes_secret_type}" + metadata: + annotations: + ${local.reloader_annotation} + data: + ${local.data} + data: + - secretKey: secretid + remoteRef: + key: "${local.es_remoteref_key}" + EOF + ] +} + +### Define kubernetes secret to be installed in cluster for sm_secret_type iam_credentials and kubernetes secret type dockerjsonconfig and configured with a chain of secrets +resource "helm_release" "kubernetes_secret_chain_list" { + count = local.is_dockerjsonconfig_chain == true ? 1 : 0 + name = local.helm_secret_name + namespace = local.es_helm_rls_namespace + chart = "${path.module}/../../chart/${local.helm_raw_chart_name}" + version = local.helm_raw_chart_version + timeout = 600 + values = [ + <<-EOF + resources: + - apiVersion: external-secrets.io/v1beta1 + kind: ExternalSecret + metadata: + name: "${var.es_kubernetes_secret_name}" + namespace: "${var.es_kubernetes_namespace}" + spec: + refreshInterval: ${var.es_refresh_interval} + secretStoreRef: + name: "${var.eso_store_name}" + kind: "${local.secret_store_ref_kind}" + target: + name: "${var.es_kubernetes_secret_name}" + template: + engineVersion: v2 + type: "${local.es_kubernetes_secret_type}" + metadata: + annotations: + ${local.reloader_annotation} + data: + ${local.data_chain} + data: +%{for index, element in var.es_container_registry_secrets_chain~} + - secretKey: secretid_${index} + remoteRef: + key: "${var.sm_secret_type}/${element.sm_secret_id}" +%{endfor~} + EOF + ] +} + +### Define kubernetes secret to be installed in cluster for opaque secret type based on SM user credential secret type +resource "helm_release" "kubernetes_secret_user_pw" { + count = var.sm_secret_type == "username_password" ? 1 : 0 + name = local.helm_secret_name + namespace = var.es_kubernetes_namespace + chart = "${path.module}/../../chart/${local.helm_raw_chart_name}" + version = local.helm_raw_chart_version + timeout = 600 + values = [ + <<-EOF + resources: + - apiVersion: external-secrets.io/v1alpha1 + kind: ExternalSecret + metadata: + name: "${var.es_kubernetes_secret_name}" + namespace: "${var.es_kubernetes_namespace}" + spec: + refreshInterval: ${var.es_refresh_interval} + secretStoreRef: + name: "${var.eso_store_name}" + kind: "${local.secret_store_ref_kind}" + target: + name: "${var.es_kubernetes_secret_name}" + template: + engineVersion: v2 + type: "${local.es_kubernetes_secret_type}" + metadata: + annotations: + ${local.reloader_annotation} + data: + ${local.data} + data: + - secretKey: username + remoteRef: + key: "username_password/${var.sm_secret_id}" + property: username + - secretKey: password + remoteRef: + key: "username_password/${var.sm_secret_id}" + property: password + EOF + ] +} + +### Define kubernetes secret to be installed in cluster for certificate secret based on SM certificate secret type +resource "helm_release" "kubernetes_secret_certificate" { + count = local.is_certificate ? 1 : 0 #checkov:skip=CKV_SECRET_6 + name = local.helm_secret_name + namespace = var.es_kubernetes_namespace + chart = "${path.module}/../../chart/${local.helm_raw_chart_name}" + version = local.helm_raw_chart_version + timeout = 600 + values = [ + <<-EOF + resources: + - apiVersion: external-secrets.io/v1beta1 + kind: ExternalSecret + metadata: + name: "${var.es_kubernetes_secret_name}" + namespace: "${var.es_kubernetes_namespace}" + spec: + refreshInterval: ${var.es_refresh_interval} + secretStoreRef: + name: "${var.eso_store_name}" + kind: "${local.secret_store_ref_kind}" + target: + name: "${var.es_kubernetes_secret_name}" + template: + engineVersion: v2 + type: "${local.es_kubernetes_secret_type}" + metadata: + annotations: + ${local.reloader_annotation} + data: + ${local.certificate_template} + data: + ${local.certificate_spec_data} + EOF + ] +} + +### Define kubernetes secret to be installed in cluster for key-value secret based on SM kv secret type based on keyid or key path +resource "helm_release" "kubernetes_secret_kv_key" { + count = local.is_kv && local.kv_remoteref_property != "" ? 1 : 0 + name = local.helm_secret_name + namespace = var.es_kubernetes_namespace + chart = "${path.module}/../../chart/${local.helm_raw_chart_name}" + version = local.helm_raw_chart_version + timeout = 600 + values = [ + <<-EOF + resources: + - apiVersion: external-secrets.io/v1beta1 + kind: ExternalSecret + metadata: + name: "${var.es_kubernetes_secret_name}" + namespace: "${var.es_kubernetes_namespace}" + spec: + refreshInterval: ${var.es_refresh_interval} + secretStoreRef: + name: "${var.eso_store_name}" + kind: "${local.secret_store_ref_kind}" + target: + name: "${var.es_kubernetes_secret_name}" + template: + engineVersion: v2 + type: "${local.es_kubernetes_secret_type}" + metadata: + annotations: + ${local.reloader_annotation} + data: + secret: "{{ .${local.kv_remoteref_property} }}" + data: + - secretKey: "${local.kv_remoteref_property}" + remoteRef: + key: "${local.es_remoteref_key}" + property: "${local.kv_remoteref_property}" + EOF + ] +} + +### Define kubernetes secret to be installed in cluster for key-value secret based on SM kv secret type pulling all the keys structure +resource "helm_release" "kubernetes_secret_kv_all" { + count = local.is_kv && local.kv_remoteref_property == "" ? 1 : 0 + name = local.helm_secret_name + namespace = var.es_kubernetes_namespace + chart = "${path.module}/../../chart/${local.helm_raw_chart_name}" + version = local.helm_raw_chart_version + timeout = 600 + values = [ + <<-EOF + resources: + - apiVersion: external-secrets.io/v1beta1 + kind: ExternalSecret + metadata: + name: "${var.es_kubernetes_secret_name}" + namespace: "${var.es_kubernetes_namespace}" + spec: + refreshInterval: ${var.es_refresh_interval} + secretStoreRef: + name: "${var.eso_store_name}" + kind: "${local.secret_store_ref_kind}" + target: + name: "${var.es_kubernetes_secret_name}" + template: + engineVersion: v2 + type: "${local.es_kubernetes_secret_type}" + metadata: + annotations: + ${local.reloader_annotation} + data: + secret: '{{ .keys }}' + data: + - secretKey: keys + remoteRef: + key: "${local.es_remoteref_key}" + EOF + ] +} diff --git a/examples/advanced/main.tf b/modules/eso-external-secret/outputs.tf similarity index 89% rename from examples/advanced/main.tf rename to modules/eso-external-secret/outputs.tf index 558c2107..b16a1a35 100644 --- a/examples/advanced/main.tf +++ b/modules/eso-external-secret/outputs.tf @@ -1,3 +1,3 @@ ############################################################################## -# Complete example +# Outputs ############################################################################## diff --git a/modules/eso-external-secret/variables.tf b/modules/eso-external-secret/variables.tf new file mode 100644 index 00000000..3dbb168f --- /dev/null +++ b/modules/eso-external-secret/variables.tf @@ -0,0 +1,139 @@ +variable "eso_store_scope" { + description = "Set to 'cluster' to configure ESO store as with cluster scope (ClusterSecretStore) or 'namespace' for regular namespaced scope (SecretStore). This value is used to configure the externalsecret reference" + type = string + default = "cluster" + + validation { + condition = var.eso_store_scope == "cluster" || var.eso_store_scope == "namespace" + error_message = "The eso_store_deployment value must be one of the following: cluster, namespace" + } +} + +variable "es_kubernetes_namespace" { + description = "Namespace to use to generate the externalsecret" + type = string +} + +variable "es_kubernetes_secret_name" { + description = "Name of the secret to use for the kubernetes secret object" + type = string +} + +variable "es_refresh_interval" { + description = "Specify interval for es secret synchronization. See recommendations for specifying/customizing refresh interval in this IBM Cloud article > https://cloud.ibm.com/docs/secrets-manager?topic=secrets-manager-tutorial-kubernetes-secrets#kubernetes-secrets-best-practices" + default = "1h" + type = string + validation { + condition = can(regex("^[1-9][0-9]?[smh]$", var.es_refresh_interval)) + error_message = "The refresh interval must be a value between 1 and 99s(seconds)/m(minutes)/h(hours)." + } +} +variable "eso_store_name" { + description = "ESO store name to use when creating the externalsecret. Cannot be null and it is mandatory" + type = string +} + +variable "es_kubernetes_secret_type" { + description = "Secret type/format to be installed in the Kubernetes/Openshift cluster by ESO. Valid inputs are `opaque` `dockerconfigjson` and `tls`" + type = string + validation { + condition = can(regex("^opaque$|^dockerconfigjson$|^tls$|^$", var.es_kubernetes_secret_type)) + # If it is empty, no secret will be created. + error_message = "The es_kubernetes_secret_type value must be one of the following: opaque, dockerconfigjson, tls or leave it empty." + } +} + +variable "es_kubernetes_secret_data_key" { + description = "Data key to be used in Kubernetes Opaque secret. Only needed when 'es_kubernetes_secret_type' is configured as `opaque` and sm_secret_type is set to either 'arbitrary' or 'iam_credentials'" + type = string + default = null +} + +variable "sm_secret_type" { + description = "Secrets-manager secret type to be used as source data by ESO. Valid input types are 'arbitrary', 'username_password' and 'iam_credentials'" + type = string + validation { + condition = can(regex("^iam_credentials$|^username_password$|^arbitrary$|^imported_cert$|^public_cert$|^private_cert|^kv$|$^$", var.sm_secret_type)) + # If it is empty, no secret will be created + error_message = "The sm_secret_type value must be one of the following: iam_credentials, username_password, arbitrary, imported_cert, public_cert, private_cert, kv or leave it empty." + } +} + +variable "sm_secret_id" { + description = "Secrets-Manager secret ID where source data will be synchronized with Kubernetes secret. It can be null only in the case of a dockerjsonconfig secrets chain" + type = string +} + +variable "es_container_registry" { + type = string + default = "us.icr.io" + description = "The registry URL to be used in dockerconfigjson" +} + +variable "es_container_registry_email" { + type = string + description = "Optional - Email to be used in dockerconfigjson" + default = null +} + +variable "es_container_registry_secrets_chain" { + description = "Structure to generate a chain of secrets into a single dockerjsonconfig secret for multiple registries authentication." + type = list(object({ + es_container_registry = string + sm_secret_id = string # id of the secret storing the apikey that will be used for the secrets chain + es_container_registry_email = optional(string, null) + })) + default = [] + nullable = false +} + +variable "es_helm_rls_name" { + description = "Name to use for the helm release for externalsecrets resource. Must be unique in the namespace" + type = string + validation { + condition = can(regex("^[0-9A-Za-z-]+$", var.es_helm_rls_name)) + error_message = "The value of the helm release for the es resource must match ^[0-9A-Za-z-]+$ regexp" + } +} + +variable "es_helm_rls_namespace" { + description = "Namespace to deploy the helm release for the externalsecret. Default if null is the externalsecret namespace" + type = string + validation { + condition = var.es_helm_rls_namespace == null || can(regex("^[0-9A-Za-z-]+$", var.es_helm_rls_namespace)) + error_message = "The value of the helm release for the es resource must match ^[0-9A-Za-z-]+$ regexp" + } + default = null +} + +variable "sm_kv_keyid" { + description = "Secrets-Manager key value (kv) keyid" + type = string + default = null +} + +variable "sm_kv_keypath" { + description = "Secrets-Manager key value (kv) keypath" + type = string + default = null +} + +variable "sm_certificate_has_intermediate" { + description = "The secret manager certificate is provided with intermediate certificate. By enabling this flag the certificate body on kube will contain certificate and intermediate content, otherwise only certificate will be added. Valid only for public and imported certificate" + type = bool + default = true +} + +variable "reloader_watching" { + description = "Flag to enable/disable the reloader watching. If enabled the reloader will watch for changes in the secret and reload the associated annotated pods if needed" + type = bool + default = false +} + +# provider is affected by https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4803 +# check for its status before switching to false +variable "sm_certificate_bundle" { + description = "Flag to enable if the public/intermediate certificate is bundled. If enabled public key is managed as bundled with intermediate and private key, otherwise the template considers the public key not bundled with intermediate certificate and private key" + type = bool + default = true +} diff --git a/modules/eso-external-secret/version.tf b/modules/eso-external-secret/version.tf new file mode 100644 index 00000000..26ee8a3e --- /dev/null +++ b/modules/eso-external-secret/version.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.0.0" + required_providers { + # Use "greater than or equal to" range in modules + helm = { + source = "hashicorp/helm" + version = ">= 2.8.0" + } + } +} diff --git a/modules/eso-secretstore/README.md b/modules/eso-secretstore/README.md new file mode 100644 index 00000000..49b93013 --- /dev/null +++ b/modules/eso-secretstore/README.md @@ -0,0 +1,54 @@ +# ESO (Namespaced) Secret Store Module + +This module allows to configure an [SecretStore](https://external-secrets.io/latest/api/secretstore/) resource for an ESO secret store with namespace scope, in the desired namespace and with the desired configurations. + +For more information about SecretStore resource and about ESO please refer to the ESO documentation available [here](https://external-secrets.io/v0.8.3/guides/introduction/) + +This module supports SecretStore two authentication configurations to pull/push secrets with the configured Secrets Manager instance: +- apikey authentication +- trusted profile authentication + +For more information about Trusted Profiles refer to the IBM Cloud documentation available [here](https://cloud.ibm.com/docs/account?topic=account-create-trusted-profile&interface=ui) + + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.0.0 | +| [helm](#requirement\_helm) | >= 2.8.0 | +| [kubernetes](#requirement\_kubernetes) | >= 2.16.1, <3.0.0 | + +### Modules + +No modules. + +### Resources + +| Name | Type | +|------|------| +| [helm_release.external_secret_store_apikey](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | +| [helm_release.external_secret_store_tp](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | +| [kubernetes_secret.eso_secretsstore_secret](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret) | resource | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [eso\_authentication](#input\_eso\_authentication) | Authentication method, Possible values are api\_key or/and trusted\_profile. | `string` | `"trusted_profile"` | no | +| [region](#input\_region) | Region where Secrets Manager is deployed. It will be used to build the regional URL to the service | `string` | n/a | yes | +| [service\_endpoints](#input\_service\_endpoints) | The service endpoint type to communicate with the provided secrets manager instance. Possible values are `public` or `private`. This also will set the iam endpoint for containerAuth when enabling Trusted Profile/CR based authentication. | `string` | `"public"` | no | +| [sstore\_helm\_rls\_name](#input\_sstore\_helm\_rls\_name) | Name of helm release for external secret | `string` | `"external-secret-store"` | no | +| [sstore\_namespace](#input\_sstore\_namespace) | Namespace to create the SecretStore. The namespace must exist as it is not created by this module | `string` | n/a | yes | +| [sstore\_secret\_apikey](#input\_sstore\_secret\_apikey) | APIkey to be stored into sstore\_secret\_name to authenticate on Secrets Manager instance | `string` | `null` | no | +| [sstore\_secret\_name](#input\_sstore\_secret\_name) | Secret name to be used/referenced in the ESO secretstore to pull from Secrets Manager | `string` | `"ibm-secret"` | no | +| [sstore\_secrets\_manager\_guid](#input\_sstore\_secrets\_manager\_guid) | Secrets manager instance GUID for secretstore where secrets will be stored or fetched from | `string` | n/a | yes | +| [sstore\_store\_name](#input\_sstore\_store\_name) | Name of the SecretStore to create | `string` | n/a | yes | +| [sstore\_trusted\_profile\_name](#input\_sstore\_trusted\_profile\_name) | The name of the trusted profile to use for the secretstore. This allows ESO to use CRI based authentication to access secrets manager. The trusted profile must be created in advance | `string` | `null` | no | + +### Outputs + +| Name | Description | +|------|-------------| +| [helm\_release\_secret\_store](#output\_helm\_release\_secret\_store) | SecretStore helm release. Returning the helm release for trusted profile or apikey authentication according to the authentication type | + diff --git a/modules/eso-secretstore/main.tf b/modules/eso-secretstore/main.tf new file mode 100644 index 00000000..0c14b62d --- /dev/null +++ b/modules/eso-secretstore/main.tf @@ -0,0 +1,99 @@ +locals { + helm_raw_chart_name = "raw" + helm_raw_chart_version = "0.2.5" + + + # preliminary authentication validation - one of sstore_secret_apikey and sstore_trusted_profile_name must be valid + auth_validate_condition = var.sstore_secret_apikey == null && var.sstore_trusted_profile_name == null + auth_esstore_msg = "One of the variables sstore_secret_apikey and sstore_trusted_profile_name must be provided, cannot be both set to null" + # tflint-ignore: terraform_unused_declarations + auth_validate_check = regex("^${local.auth_esstore_msg}$", (!local.auth_validate_condition ? local.auth_esstore_msg : "")) + + # auth is apikey so the variable sstore_secret_apikey cannot be null + api_key_esstore_validate_condition = var.eso_authentication == "api_key" && var.sstore_secret_apikey == null + api_key_esstore_msg = "API Key authentication is enabled and scope for store is cluster, therefore sstore_secret_apikey must be provided." + # tflint-ignore: terraform_unused_declarations + api_key_esstore_validate_check = regex("^${local.api_key_esstore_msg}$", (!local.api_key_esstore_validate_condition ? local.api_key_esstore_msg : "")) + + # auth is trustedprofile so the variable sstore_trusted_profile_name cannot be null + tp_esstore_validate_condition = var.eso_authentication == "trusted_profile" && var.sstore_trusted_profile_name == null + tp_esstore_msg = "Trusted profile authentication is enabled, therefore sstore_trusted_profile_name must be provided." + # tflint-ignore: terraform_unused_declarations + tp_esstore_validate_check = regex("^${local.tp_esstore_msg}$", (!local.tp_esstore_validate_condition ? local.tp_esstore_msg : "")) + + # endpoints definition according to endpoints to use are private or public (var.service_endpoints) + iam_endpoint = "${var.service_endpoints == "private" ? "private." : ""}iam.cloud.ibm.com" + regional_endpoint = var.service_endpoints == "private" ? "private.${var.region}" : var.region +} + +### creating secret to store apikey to authenticate on secretsmanager for apikey authentication +resource "kubernetes_secret" "eso_secretsstore_secret" { + count = var.eso_authentication == "api_key" ? 1 : 0 + metadata { + name = var.sstore_secret_name + namespace = var.sstore_namespace #checkov:skip=CKV_K8S_21 + } + + data = { + apiKey = var.sstore_secret_apikey + } + type = "opaque" +} + +### Define secret store used to connect with SM instance for apikey auth +resource "helm_release" "external_secret_store_apikey" { + count = var.eso_authentication == "api_key" ? 1 : 0 + name = substr(join("-", [var.sstore_namespace, var.sstore_helm_rls_name]), 0, 52) + namespace = var.sstore_namespace + chart = "${path.module}/../../chart/${local.helm_raw_chart_name}" + version = local.helm_raw_chart_version + timeout = 600 + values = [ + <<-EOF + resources: + - apiVersion: external-secrets.io/v1beta1 + kind: SecretStore + metadata: + name: "${var.sstore_store_name}" + namespace: "${var.sstore_namespace}" + spec: + provider: + ibm: + serviceUrl: "https://${var.sstore_secrets_manager_guid}.${local.regional_endpoint}.secrets-manager.appdomain.cloud" + auth: + secretRef: + secretApiKeySecretRef: + name: "${var.sstore_secret_name}" + key: apiKey + EOF + ] +} + +# Trusted profile authentication Use ContainerAuth with CRI based authentication (trusted profile support) +resource "helm_release" "external_secret_store_tp" { + count = var.eso_authentication == "trusted_profile" ? 1 : 0 + name = substr(join("-", [var.sstore_namespace, var.sstore_helm_rls_name]), 0, 52) + namespace = var.sstore_namespace + chart = "${path.module}/../../chart/${local.helm_raw_chart_name}" + version = local.helm_raw_chart_version + timeout = 600 + values = [ + <<-EOF + resources: + - apiVersion: external-secrets.io/v1beta1 + kind: SecretStore + metadata: + name: "${var.sstore_store_name}" + namespace: "${var.sstore_namespace}" + spec: + provider: + ibm: + serviceUrl: "https://${var.sstore_secrets_manager_guid}.${local.regional_endpoint}.secrets-manager.appdomain.cloud" + auth: + containerAuth: + profile: "${var.sstore_trusted_profile_name}" + iamEndpoint: "https://${local.iam_endpoint}" + tokenLocation: /var/run/secrets/tokens/sa-token + EOF + ] +} diff --git a/modules/eso-secretstore/outputs.tf b/modules/eso-secretstore/outputs.tf new file mode 100644 index 00000000..dfd963f1 --- /dev/null +++ b/modules/eso-secretstore/outputs.tf @@ -0,0 +1,8 @@ +############################################################################## +# Outputs +############################################################################## + +output "helm_release_secret_store" { + value = var.eso_authentication == "trusted_profile" ? helm_release.external_secret_store_tp : helm_release.external_secret_store_apikey + description = "SecretStore helm release. Returning the helm release for trusted profile or apikey authentication according to the authentication type" +} diff --git a/modules/eso-secretstore/variables.tf b/modules/eso-secretstore/variables.tf new file mode 100644 index 00000000..345acaa3 --- /dev/null +++ b/modules/eso-secretstore/variables.tf @@ -0,0 +1,72 @@ +######## eso generic configurations + +variable "region" { + description = "Region where Secrets Manager is deployed. It will be used to build the regional URL to the service" + type = string +} + +variable "sstore_helm_rls_name" { + description = "Name of helm release for external secret" + type = string + default = "external-secret-store" +} + +variable "service_endpoints" { + type = string + description = "The service endpoint type to communicate with the provided secrets manager instance. Possible values are `public` or `private`. This also will set the iam endpoint for containerAuth when enabling Trusted Profile/CR based authentication." + default = "public" + validation { + condition = contains(["public", "private"], var.service_endpoints) + error_message = "The specified service_endpoints is not a valid selection!" + } +} + +############################################################################## +# Authentication configuration for clusterstore that can be one of api_key or trusted_profile +############################################################################## +variable "eso_authentication" { + type = string + description = "Authentication method, Possible values are api_key or/and trusted_profile." + default = "trusted_profile" + validation { + condition = contains(["api_key", "trusted_profile"], var.eso_authentication) + error_message = "Authentication mode allowed are api_key or/and trusted_profile." + } +} + +####### apikey authentication + +variable "sstore_secret_name" { + description = "Secret name to be used/referenced in the ESO secretstore to pull from Secrets Manager" + default = "ibm-secret" + type = string +} + +variable "sstore_secret_apikey" { + description = "APIkey to be stored into sstore_secret_name to authenticate on Secrets Manager instance" + type = string + default = null +} + +####### trusted profile + +variable "sstore_trusted_profile_name" { + type = string + description = "The name of the trusted profile to use for the secretstore. This allows ESO to use CRI based authentication to access secrets manager. The trusted profile must be created in advance" + default = null +} + +variable "sstore_secrets_manager_guid" { + type = string + description = "Secrets manager instance GUID for secretstore where secrets will be stored or fetched from" +} + +variable "sstore_namespace" { + type = string + description = "Namespace to create the SecretStore. The namespace must exist as it is not created by this module" +} + +variable "sstore_store_name" { + type = string + description = "Name of the SecretStore to create" +} diff --git a/modules/eso-secretstore/version.tf b/modules/eso-secretstore/version.tf new file mode 100644 index 00000000..168b3dc2 --- /dev/null +++ b/modules/eso-secretstore/version.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">= 1.0.0" + required_providers { + # Use "greater than or equal to" range in modules + kubernetes = { + source = "hashicorp/kubernetes" + version = ">= 2.16.1, <3.0.0" + } + helm = { + source = "hashicorp/helm" + version = ">= 2.8.0" + } + } +} diff --git a/modules/eso-trusted-profile/README.md b/modules/eso-trusted-profile/README.md new file mode 100644 index 00000000..6b8063b7 --- /dev/null +++ b/modules/eso-trusted-profile/README.md @@ -0,0 +1,45 @@ +# ESO Trusted Profile Module + +This module allows to create and configure an Trusted Profile to authenticate with ESO operator. + +For more information about Trusted Profiles refer to the IBM Cloud documentation available [here](https://cloud.ibm.com/docs/account?topic=account-create-trusted-profile&interface=ui) + + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.0.0 | +| [ibm](#requirement\_ibm) | >= 1.51.0 | + +### Modules + +No modules. + +### Resources + +| Name | Type | +|------|------| +| [ibm_iam_trusted_profile.trusted_profile](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_trusted_profile) | resource | +| [ibm_iam_trusted_profile_claim_rule.claim_rule](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_trusted_profile_claim_rule) | resource | +| [ibm_iam_trusted_profile_policy.policy](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_trusted_profile_policy) | resource | +| [ibm_iam_trusted_profile_policy.policy_multiple_secrets_groups](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_trusted_profile_policy) | resource | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [secret\_groups\_id](#input\_secret\_groups\_id) | The list of secret groups to limit access to for the trusted profile to create. | `list(string)` | `[]` | no | +| [secrets\_manager\_guid](#input\_secrets\_manager\_guid) | Secrets manager instance GUID where secrets will be stored or fetched from and the trusted profile will allow access to. | `string` | n/a | yes | +| [tp\_cluster\_crn](#input\_tp\_cluster\_crn) | Target cluster CRN for the trusted profile. Used when creating trusted profile | `string` | n/a | yes | +| [tp\_namespace](#input\_tp\_namespace) | Namespace to configure in the Trusted Profile on IAM. Its value must be the namespace where the operator is deployed and running. | `string` | n/a | yes | +| [trusted\_profile\_claim\_rule\_type](#input\_trusted\_profile\_claim\_rule\_type) | Trusted profile claim rule type, set the value to 'ROKS\_SA' for ROKS clusters, set to ROKS for IKS clusters | `string` | `"ROKS_SA"` | no | +| [trusted\_profile\_name](#input\_trusted\_profile\_name) | The name of the trusted profile to be used. This allows ESO to use CRI based authentication to access secrets manager. The trusted profile must be created in advance | `string` | n/a | yes | + +### Outputs + +| Name | Description | +|------|-------------| +| [trusted\_profile\_id](#output\_trusted\_profile\_id) | ID of the trusted profile | +| [trusted\_profile\_name](#output\_trusted\_profile\_name) | Name of the trusted profile | + diff --git a/modules/eso-trusted-profile/main.tf b/modules/eso-trusted-profile/main.tf new file mode 100644 index 00000000..5602acd5 --- /dev/null +++ b/modules/eso-trusted-profile/main.tf @@ -0,0 +1,83 @@ +### Trusted Profiles resources + +# creates a trusted profile to use for container authentication in external secrets operator +resource "ibm_iam_trusted_profile" "trusted_profile" { + name = var.trusted_profile_name + description = "a trusted profile to access the secrets manager instance: ${var.secrets_manager_guid}." +} + +# The following Rule allows incoming requests from +# the external-secrets SA in external-secrets namespce in the +# target cluster with the retrieved cluster's CRN. +resource "ibm_iam_trusted_profile_claim_rule" "claim_rule" { + profile_id = ibm_iam_trusted_profile.trusted_profile.id + type = "Profile-CR" + name = "${var.trusted_profile_name}-rule" + cr_type = var.trusted_profile_claim_rule_type + + dynamic "conditions" { + for_each = [ + { + claim = "name" + operator = "EQUALS" + value = "\"external-secrets\"" + }, + { + claim = "namespace", + operator = "EQUALS", + value = "\"${var.tp_namespace}\"", + }, + { + claim = "crn", + operator = "EQUALS", + value = "\"${var.tp_cluster_crn}\"" + } + ] + + content { + claim = conditions.value["claim"] + operator = conditions.value["operator"] + value = conditions.value["value"] + } + } +} + +# This Trusted Profile policy grants access to the provided secrets +# manager instance, if one of more secret group ids are provided, it will then +# restrict access to these secret groups with SecretsReader role. + +# migration definition to avoid destruction of resources with support of multiple secrets group +moved { + from = module.your_trusted_profile_module_name.ibm_iam_trusted_profile_policy.policy + to = module.your_trusted_profile_module_name.ibm_iam_trusted_profile_policy.policy[0] +} + +# This Trusted Profile policy grants access to the provided secrets +# manager instance, if no secrets group id or one secrets group id is provided to restrict the access to the Secrets Manager instance +resource "ibm_iam_trusted_profile_policy" "policy" { + count = length(var.secret_groups_id) <= 1 ? 1 : 0 + profile_id = ibm_iam_trusted_profile.trusted_profile.id + description = length(var.secret_groups_id) == 0 ? "IAM Trusted Profile Policy to access the secrets in the target secret groups and secrets manager instance and not restricted to any secrets group" : "IAM Trusted Profile Policy to access the secrets in the target secret group and secrets manager instance" + roles = ["SecretsReader"] + resources { + service = "secrets-manager" + resource_type = length(var.secret_groups_id) == 1 ? "secret-group" : null + resource = length(var.secret_groups_id) == 1 ? var.secret_groups_id[0] : null + resource_instance_id = var.secrets_manager_guid + } +} + +# This Trusted Profile policy grants acccess to the provided secrets +# manager instance, if two or more secrets groups id are provided to restrict the access to the Secrets Manager instance +resource "ibm_iam_trusted_profile_policy" "policy_multiple_secrets_groups" { + count = length(var.secret_groups_id) > 1 ? length(var.secret_groups_id) : 0 + profile_id = ibm_iam_trusted_profile.trusted_profile.id + description = "IAM Trusted Profile Policy to access the secrets in the target secrets group ${var.secret_groups_id[count.index]} and secrets manager instance" + roles = ["SecretsReader"] + resources { + service = "secrets-manager" + resource_type = "secret-group" + resource = var.secret_groups_id[count.index] + resource_instance_id = var.secrets_manager_guid + } +} diff --git a/modules/eso-trusted-profile/outputs.tf b/modules/eso-trusted-profile/outputs.tf new file mode 100644 index 00000000..f5ad9114 --- /dev/null +++ b/modules/eso-trusted-profile/outputs.tf @@ -0,0 +1,13 @@ +############################################################################## +# Outputs +############################################################################## + +output "trusted_profile_id" { + value = ibm_iam_trusted_profile.trusted_profile.id + description = "ID of the trusted profile" +} + +output "trusted_profile_name" { + value = ibm_iam_trusted_profile.trusted_profile.name + description = "Name of the trusted profile" +} diff --git a/modules/eso-trusted-profile/variables.tf b/modules/eso-trusted-profile/variables.tf new file mode 100644 index 00000000..7832b810 --- /dev/null +++ b/modules/eso-trusted-profile/variables.tf @@ -0,0 +1,35 @@ +variable "trusted_profile_name" { + type = string + description = "The name of the trusted profile to be used. This allows ESO to use CRI based authentication to access secrets manager. The trusted profile must be created in advance" +} + +variable "secrets_manager_guid" { + type = string + description = "Secrets manager instance GUID where secrets will be stored or fetched from and the trusted profile will allow access to." +} + +variable "secret_groups_id" { + type = list(string) + description = "The list of secret groups to limit access to for the trusted profile to create." + default = [] +} + +variable "tp_cluster_crn" { + type = string + description = "Target cluster CRN for the trusted profile. Used when creating trusted profile" +} + +variable "trusted_profile_claim_rule_type" { + description = "Trusted profile claim rule type, set the value to 'ROKS_SA' for ROKS clusters, set to ROKS for IKS clusters" + type = string + default = "ROKS_SA" + validation { + condition = var.trusted_profile_claim_rule_type == "ROKS_SA" || var.trusted_profile_claim_rule_type == "ROKS" + error_message = "The trusted_profile_claim_rule_type value must be one of the following: ROKS_SA, ROKS" + } +} + +variable "tp_namespace" { + description = "Namespace to configure in the Trusted Profile on IAM. Its value must be the namespace where the operator is deployed and running." + type = string +} diff --git a/modules/eso-trusted-profile/version.tf b/modules/eso-trusted-profile/version.tf new file mode 100644 index 00000000..268432a0 --- /dev/null +++ b/modules/eso-trusted-profile/version.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">= 1.0.0" + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">= 1.51.0" + } + } +} diff --git a/tests/go.mod b/tests/go.mod index b2418749..a25d6933 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -1,12 +1,13 @@ module github.com/terraform-ibm-modules/terraform-ibm-external-secrets-operator -go 1.22.0 - -toolchain go1.23.2 +go 1.22.2 require ( + github.com/gruntwork-io/terratest v0.47.2 github.com/stretchr/testify v1.9.0 - github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper v1.41.3 + github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper v1.41.2 + gopkg.in/yaml.v3 v3.0.1 + k8s.io/apimachinery v0.31.2 ) require ( @@ -20,7 +21,7 @@ require ( github.com/IBM-Cloud/power-go-client v1.8.3 // indirect github.com/IBM/cloud-databases-go-sdk v0.7.0 // indirect github.com/IBM/go-sdk-core/v5 v5.18.1 // indirect - github.com/IBM/platform-services-go-sdk v0.71.0 // indirect + github.com/IBM/platform-services-go-sdk v0.70.0 // indirect github.com/IBM/project-go-sdk v0.3.6 // indirect github.com/IBM/schematics-go-sdk v0.3.0 // indirect github.com/IBM/vpc-go-sdk v1.0.2 // indirect @@ -30,18 +31,23 @@ require ( github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/aws/aws-sdk-go v1.44.281 // indirect + github.com/aws/aws-sdk-go v1.44.284 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect + github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect github.com/cloudflare/circl v1.3.7 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.5.0 // indirect github.com/go-git/go-git/v5 v5.12.0 // indirect - github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.21.5 // indirect github.com/go-openapi/errors v0.22.0 // indirect @@ -56,29 +62,35 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.19.0 // indirect + github.com/go-sql-driver/mysql v1.4.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect github.com/google/s2a-go v0.1.4 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.4 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect github.com/googleapis/gax-go/v2 v2.11.0 // indirect - github.com/gruntwork-io/terratest v0.47.2 // indirect + github.com/gruntwork-io/go-commons v0.8.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-getter v1.7.6 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect - github.com/hashicorp/go-version v1.7.0 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/hcl/v2 v2.17.0 // indirect - github.com/hashicorp/terraform-json v0.23.0 // indirect + github.com/hashicorp/terraform-json v0.22.1 // indirect + github.com/imdario/mergo v0.3.11 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jinzhu/copier v0.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect - github.com/klauspost/compress v1.16.5 // indirect + github.com/klauspost/compress v1.16.6 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-zglob v0.0.4 // indirect @@ -86,16 +98,26 @@ require ( github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/moby/spdystream v0.4.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/pquerna/otp v1.2.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/skeema/knownhosts v1.2.2 // indirect + github.com/spf13/pflag v1.0.5 // indirect github.com/tmccombs/hcl2json v0.5.0 // indirect github.com/ulikunitz/xz v0.5.11 // indirect + github.com/urfave/cli v1.22.2 // indirect + github.com/x448/float16 v0.8.4 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect - github.com/zclconf/go-cty v1.15.0 // indirect + github.com/zclconf/go-cty v1.14.4 // indirect go.mongodb.org/mongo-driver v1.14.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/otel v1.16.0 // indirect @@ -103,21 +125,31 @@ require ( go.opentelemetry.io/otel/trace v1.16.0 // indirect golang.org/x/crypto v0.28.0 // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.25.0 // indirect + golang.org/x/net v0.26.0 // indirect golang.org/x/oauth2 v0.10.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.26.0 // indirect + golang.org/x/term v0.25.0 // indirect golang.org/x/text v0.19.0 // indirect + golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/api v0.127.0 // indirect + google.golang.org/api v0.128.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect google.golang.org/grpc v1.58.3 // indirect - google.golang.org/protobuf v1.33.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.29.2 // indirect + k8s.io/client-go v0.29.2 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect + k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/tests/go.sum b/tests/go.sum index 398594d6..28da8cb3 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -199,8 +199,8 @@ github.com/IBM/go-sdk-core/v5 v5.9.2/go.mod h1:YlOwV9LeuclmT/qi/LAK2AsobbAP42veV github.com/IBM/go-sdk-core/v5 v5.10.2/go.mod h1:WZPFasUzsKab/2mzt29xPcfruSk5js2ywAPwW4VJjdI= github.com/IBM/go-sdk-core/v5 v5.18.1 h1:wdftQO8xejECTWTKF3FGXyW0McKxxDAopH7MKwA187c= github.com/IBM/go-sdk-core/v5 v5.18.1/go.mod h1:3ywpylZ41WhWPusqtpJZWopYlt2brebcphV7mA2JncU= -github.com/IBM/platform-services-go-sdk v0.71.0 h1:8miTTzH42EO+HslEOc8YWpL+RlJjgezM88R1SxL3fWY= -github.com/IBM/platform-services-go-sdk v0.71.0/go.mod h1:1yvG28ExlZ09gfBPH7flAQ6eZf7kYA4hbEEyYlbT97Y= +github.com/IBM/platform-services-go-sdk v0.70.0 h1:G/jEzG/8SEEc+ZDXqAsPGPWcWD2UGy99LBhPX5iiD2E= +github.com/IBM/platform-services-go-sdk v0.70.0/go.mod h1:1yvG28ExlZ09gfBPH7flAQ6eZf7kYA4hbEEyYlbT97Y= github.com/IBM/project-go-sdk v0.3.6 h1:DRiANKnAePevFsIKSvR89SUaMa2xsd7YKK71Ka1eqKI= github.com/IBM/project-go-sdk v0.3.6/go.mod h1:FOJM9ihQV3EEAY6YigcWiTNfVCThtdY8bLC/nhQHFvo= github.com/IBM/schematics-go-sdk v0.3.0 h1:Vwxw85SONflakiBsNHAfViKLyp9zJiH5/hh6SewOP5Q= @@ -230,10 +230,13 @@ github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:W github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= -github.com/aws/aws-sdk-go v1.44.281 h1:z/ptheJvINaIAsKXthxONM+toTKw2pxyk700Hfm6yUw= -github.com/aws/aws-sdk-go v1.44.281/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.284 h1:Oc5Kubi43/VCkerlt3ZU3KpBju6BpNkoG3s7E8vj/O8= +github.com/aws/aws-sdk-go v1.44.284/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -255,14 +258,20 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -276,18 +285,24 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go. github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 h1:skJKxRtNmevLqnayafdLe2AsenqRupVmzZSqrvb5caU= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= @@ -302,8 +317,9 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/analysis v0.21.5 h1:3tHfEBh6Ia8eKc4M7khOGjPOAlWKJ10d877Cr9teujI= @@ -342,11 +358,18 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4= github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M= github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -379,12 +402,15 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -402,6 +428,9 @@ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -424,6 +453,8 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= @@ -435,8 +466,8 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= -github.com/googleapis/enterprise-certificate-proxy v0.2.4 h1:uGy6JWR/uMIILU8wbf+OkstIrNiMjGpEIyhx8f6W7s4= -github.com/googleapis/enterprise-certificate-proxy v0.2.4/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= +github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= @@ -450,6 +481,8 @@ github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cU github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/gruntwork-io/go-commons v0.8.0 h1:k/yypwrPqSeYHevLlEDmvmgQzcyTwrlZGRaxEM6G0ro= +github.com/gruntwork-io/go-commons v0.8.0/go.mod h1:gtp0yTtIBExIZp7vyIV9I0XQkVwiQZze678hvDXof78= github.com/gruntwork-io/terratest v0.47.2 h1:t6iWwsqJH7Gx0RwXleU/vjc+2c0JXRMdj3DxYXTBssQ= github.com/gruntwork-io/terratest v0.47.2/go.mod h1:LnYX8BN5WxUMpDr8rtD39oToSL4CBERWSCusbJ0d/64= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -471,18 +504,19 @@ github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISH github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= -github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl/v2 v2.17.0 h1:z1XvSUyXd1HP10U4lrLg5e0JMVz6CPaJvAgxM0KNZVY= github.com/hashicorp/hcl/v2 v2.17.0/go.mod h1:gJyW2PTShkJqQBKpAmPO3yxMxIuoXkOF2TpqXzrQyx4= -github.com/hashicorp/terraform-json v0.23.0 h1:sniCkExU4iKtTADReHzACkk8fnpQXrdD2xoR+lppBkI= -github.com/hashicorp/terraform-json v0.23.0/go.mod h1:MHdXbBAbSg0GvzuWazEGKAn/cyNfIB7mN6y7KJN6y2c= +github.com/hashicorp/terraform-json v0.22.1 h1:xft84GZR0QzjPVWs4lRUwvTcPnegqlyS7orfb5Ltvec= +github.com/hashicorp/terraform-json v0.22.1/go.mod h1:JbWSQCLFSXFFhg42T7l9iJwdGXBYV8fmmD6o/ML4p3A= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= @@ -493,15 +527,19 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= -github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= -github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk= +github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -517,12 +555,16 @@ github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjS github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/mattn/go-zglob v0.0.4 h1:LQi2iOm0/fGgu80AioIJ/1j9w9Oh+9DZ39J4VAGzHQM= github.com/mattn/go-zglob v0.0.4/go.mod h1:MxxjyoXXnMxfIpxTK2GAkw1w8glPsQILx3N5wrKakiY= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -534,7 +576,18 @@ github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTS github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8= +github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= @@ -564,6 +617,8 @@ github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+ github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= @@ -592,20 +647,31 @@ github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= +github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= @@ -622,14 +688,18 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper v1.41.3 h1:jFFZQaSfyiubV43YRsTYWnTw72zrIXMd1NMcNUsyzHM= -github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper v1.41.3/go.mod h1:oaVFDggUnSvcBRZSS7B4DMEuFCj4ouhuKnnKOVepIoI= +github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper v1.41.2 h1:H92aR4OtIOCUT5dXZ+s+jtN9zYPsfljipgl8rRiEYRg= +github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper v1.41.2/go.mod h1:KWJrd8D0yTISg0rNzake2ow7m3HKsooi95GHaz5sMJY= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmccombs/hcl2json v0.5.0 h1:cT2sXStOzKL06c8ZTf9vh+0N8GKGzV7+9RUaY5/iUP8= github.com/tmccombs/hcl2json v0.5.0/go.mod h1:B0ZpBthAKbQur6yZRKrtaqDmYLCvgnwHOBApE0faCpU= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= @@ -645,8 +715,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zclconf/go-cty v1.15.0 h1:tTCRWxsexYUmtt/wVxgDClUe+uQusuI443uL6e+5sXQ= -github.com/zclconf/go-cty v1.15.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= +github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8= +github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= go.mongodb.org/mongo-driver v1.11.3/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= @@ -800,8 +870,8 @@ golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -852,8 +922,10 @@ golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -979,6 +1051,8 @@ golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -1017,6 +1091,7 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -1026,6 +1101,7 @@ golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= @@ -1102,8 +1178,8 @@ google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= -google.golang.org/api v0.127.0 h1:v7rj0vA0imM3Ou81k1eyFxQNScLzn71EyGnJDr+V/XI= -google.golang.org/api v0.127.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= +google.golang.org/api v0.128.0 h1:RjPESny5CnQRn9V6siglged+DZCgfu9l6mO9dkX9VOg= +google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1272,8 +1348,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1285,6 +1361,8 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= @@ -1307,6 +1385,24 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.29.2 h1:hBC7B9+MU+ptchxEqTNW2DkUosJpp1P+Wn6YncZ474A= +k8s.io/api v0.29.2/go.mod h1:sdIaaKuU7P44aoyyLlikSLayT6Vb7bvJNCX105xZXY0= +k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= +k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/client-go v0.29.2 h1:FEg85el1TeZp+/vYJM7hkDlSTFZ+c5nnK44DJ4FyoRg= +k8s.io/client-go v0.29.2/go.mod h1:knlvFZE58VpqbQpJNbCbctTVXcd35mMyAAwBdpt4jrA= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/tests/other_test.go b/tests/other_test.go index d03784f3..aefbfbbb 100644 --- a/tests/other_test.go +++ b/tests/other_test.go @@ -1,18 +1,130 @@ -// Tests in this file are NOT run in the PR pipeline. They are run in the continuous testing pipeline along with the ones in pr_test.go +// Tests in this file are run in the PR pipeline package test import ( + "log" + "os" "testing" + "github.com/gruntwork-io/terratest/modules/k8s" "github.com/stretchr/testify/assert" + "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/cloudinfo" + "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testhelper" ) -func TestRunBasicExample(t *testing.T) { +const esoEnrollSMExample = "examples/eso-enroll-into-servicemesh" + +func setupOptionsEnrollEso(t *testing.T, prefix string, exampleDir string, implicitDestroy []string, terraformVars map[string]interface{}) *testhelper.TestOptions { + options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ + Testing: t, + TerraformDir: exampleDir, + Prefix: prefix, + ResourceGroup: resourceGroup, + IgnoreDestroys: testhelper.Exemptions{ // Ignore for consistency check + List: []string{ + "module.ocp_all_inclusive.module.cluster_proxy.helm_release.cluster_proxy", + "module.ocp_all_inclusive.module.cluster_proxy.helm_release.cluster_proxy_config", + "module.ocp_all_inclusive.module.service_mesh[0].helm_release.service_mesh_cse_proxy", + "module.ocp_all_inclusive.module.service_mesh[0].helm_release.service_mesh_control_plane", + "module.ocp_all_inclusive.module.cluster_proxy.null_resource.configure_proxy", + "module.ocp_all_inclusive.module.ocp_console_patch.null_resource.patch_console_pods", + }, + }, + IgnoreUpdates: testhelper.Exemptions{ // Ignore for consistency check + List: []string{ + "module.service_mesh.helm_release.service_mesh_cse_proxy", + "module.service_mesh.helm_release.service_mesh_control_plane", + "module.ocp_all_inclusive.module.cluster_proxy.helm_release.cluster_proxy", + "module.ocp_all_inclusive.module.cluster_proxy.helm_release.cluster_proxy_config", + "module.ocp_all_inclusive.module.service_mesh[0].helm_release.service_mesh_cse_proxy", + "module.ocp_all_inclusive.module.service_mesh[0].helm_release.service_mesh_control_plane", + "module.ocp_all_inclusive.module.cluster_proxy.null_resource.configure_proxy", + "module.ocp_all_inclusive.module.ocp_console_patch.null_resource.patch_console_pods", + }, + }, + TerraformVars: terraformVars, + ImplicitDestroy: implicitDestroy, + ImplicitRequired: false, + }) + + return options +} + +func TestRunEnrollESOServiceMeshExample(t *testing.T) { t.Parallel() - options := setupOptions(t, "mod-template-basic", "examples/basic") + terraformVars := map[string]interface{}{} + // deploying eso on default node + terraformVars["eso_deployment_nodes_configuration"] = "private" + terraformVars["existing_sm_instance_crn"] = smCRN + terraformVars["existing_sm_instance_guid"] = smGuid + terraformVars["existing_sm_instance_region"] = smRegion + implicitDestroy := []string{ // Ignore full destroy to speed up tests + "module.eso_apikey_namespace_secretstore.helm_release.external_secret_store_apikey[0]", + "module.eso_tp_namespace_secretstore_multisg.helm_release.external_secret_store_tp[0]", + "module.eso_clusterstore.helm_release.cluster_secret_store_apikey[0]", + "module.eso_tp_namespace_secretstore_nosecgroup.helm_release.external_secret_store_tp[0]", + "module.eso_tp_namespace_secretstores[0].helm_release.external_secret_store_tp[0]", + "module.eso_tp_namespace_secretstores[1].helm_release.external_secret_store_tp[0]", + } + + options := setupOptionsEnrollEso(t, "esosm", esoEnrollSMExample, implicitDestroy, terraformVars) + + options.SkipTestTearDown = true + defer func() { + options.TestTearDown() + }() output, err := options.RunTestConsistency() - assert.Nil(t, err, "This should not have errored") + + if assert.Nil(t, err, "Consistency test should not have errored") { + outputs := options.LastTestTerraformOutputs + _, tfOutputsErr := testhelper.ValidateTerraformOutputs(outputs, "cluster_id") + if assert.Nil(t, tfOutputsErr, tfOutputsErr) { + log.Println("Prefix used " + options.Prefix) + + clusterId := outputs["cluster_id"].(string) + + log.Println("clusterId " + clusterId) + + // building the list of secrets to test + namespaces_for_apikey_login := []string{"apikeynspace1", "apikeynspace2", "apikeynspace3", "apikeynspace4"} + namespaces_for_tp_login := []string{"tpnspace1", "tpnspace2"} + + secretsMap := map[string]string{ + "dockerconfigjson-uc": namespaces_for_apikey_login[0], + "dockerconfigjson-arb": namespaces_for_apikey_login[2], + options.Prefix + "-arbitrary-arb-tp-0": namespaces_for_tp_login[0], + options.Prefix + "-arbitrary-arb-tp-1": namespaces_for_tp_login[1], + options.Prefix + "-arbitrary-arb-tp-multisg-1": "tpns-multisg", + options.Prefix + "-arbitrary-arb-tp-multisg-2": "tpns-multisg", + options.Prefix + "-arbitrary-arb-tp-nosg": "tpns-nosg", + } + + log.Printf("secretsMap %s", secretsMap) + + // get cluster config + log.Println("Loading cluster configuration with id " + clusterId) + cloudinfosvc, err := cloudinfo.NewCloudInfoServiceFromEnv("TF_VAR_ibmcloud_api_key", cloudinfo.CloudInfoServiceOptions{}) + if assert.Nil(t, err, "Error creating cloud info service") { + clusterConfigPath, err := cloudinfosvc.GetClusterConfigConfigPath(clusterId) + defer func() { + // attempt to remove cluster config file after test + _ = os.Remove(clusterConfigPath) + }() + if assert.Nil(t, err, "Error getting cluster config path") { + // for each secret to test configure Terratest with cluster config + // the test checks if each secret is correctly created in the cluster + for secretName, secretNamespace := range secretsMap { + ocOptions := k8s.NewKubectlOptions("", clusterConfigPath, secretNamespace) + log.Printf("Testing secret name %s namespace %s\n", secretName, secretNamespace) + _, err := k8s.GetSecretE(t, ocOptions, secretName) + assert.Nil(t, err, "Error retrieving secret "+secretName+" in namespace "+secretNamespace) + } + } + } + } + } + assert.NotNil(t, output, "Expected some output") } diff --git a/tests/pr_test.go b/tests/pr_test.go index 370bfac3..302faa12 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -1,45 +1,416 @@ -// Tests in this file are run in the PR pipeline and the continuous testing pipeline +// Tests in this file are run in the PR pipeline package test import ( + "log" + "os" "testing" + "time" + "github.com/gruntwork-io/terratest/modules/k8s" "github.com/stretchr/testify/assert" + "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/cloudinfo" + "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/common" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testhelper" + "gopkg.in/yaml.v3" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// Use existing resource group -const resourceGroup = "geretain-test-resources" -const advancedExampleDir = "examples/advanced" +// Resource groups are maintained https://github.ibm.com/GoldenEye/ge-dev-account-management +const resourceGroup = "geretain-test-ext-secrets-sync" +const defaultExampleTerraformDir = "examples/all-combined" +const basicExampleTerraformDir = "examples/basic" -func setupOptions(t *testing.T, prefix string, dir string) *testhelper.TestOptions { +// deploying eso on edge node to have it able to connect to SM and IAM on public network +const esoWorkersSelector = "edge" + +// Define a struct with fields that match the structure of the YAML data +const yamlLocation = "../common-dev-assets/common-go-assets/common-permanent-resources.yaml" + +type Config struct { + SmGuid string `yaml:"secretsManagerGuid"` + SmCRN string `yaml:"secretsManagerCRN"` + SmRegion string `yaml:"secretsManagerRegion"` + RgId string `yaml:"resourceGroupTestPermanentId"` + CisName string `yaml:"cisInstanceName"` + + // secret ids for the secrets composing the imported certificate to create + ImpCertIntermediateSecretId string `yaml:"imported_certificate_intermediate_secret_id"` + ImpCertPublicSecretId string `yaml:"imported_certificate_public_secret_id"` + ImpCertPrivateSecretId string `yaml:"imported_certificate_private_secret_id"` + ImpCertificateSmGuid string `yaml:"imported_certificate_sm_id"` + ImpCertificateSmRegion string `yaml:"imported_certificate_sm_region"` + + // acme private apikey references for CA + AcmeLEPrivateKeySmGuid string `yaml:"acme_letsencrypt_private_key_sm_id"` + AcmeLEPrivateKeySmRegion string `yaml:"acme_letsencrypt_private_key_sm_region"` + AcmeLEPrivateKeySecretId string `yaml:"acme_letsencrypt_private_key_secret_id"` + + // sDNLB serviceID + SdnlbServiceidName string `yaml:"sdnlbServiceIdName"` +} + +var smGuid string +var smCRN string +var smRegion string +var rgId string +var cisName string +var impCertificateSmRegion string +var impCertificateSmGuid string +var impCertIntermediateSecretID string +var impCertPublicSecretID string +var impCertPrivateSecretID string +var acmeLEPrivateKeySmGuid string +var acmeLEPrivateKeySmRegion string +var acmeLEPrivateKeySecretId string +var sdnlbServiceIdName string + +// terraform vars for all-combined test (including Upgrade one) +var allCombinedTerraformVars map[string]interface{} + +// TestMain will be run before any parallel tests, used to read data from yaml for use with tests +func TestMain(m *testing.M) { + // Read the YAML file contents + data, err := os.ReadFile(yamlLocation) + if err != nil { + log.Fatal(err) + } + // Create a struct to hold the YAML data + var config Config + // Unmarshal the YAML data into the struct + err = yaml.Unmarshal(data, &config) + if err != nil { + log.Fatal(err) + } + + // Parse the SM guid and region from data and setting all-combined test input values used in TestRunDefaultExample and TestRunUpgradeExample + smGuid = config.SmGuid + smCRN = config.SmCRN + smRegion = config.SmRegion + cisName = config.CisName + rgId = config.RgId + impCertIntermediateSecretID = config.ImpCertIntermediateSecretId + impCertPrivateSecretID = config.ImpCertPrivateSecretId + impCertPublicSecretID = config.ImpCertPublicSecretId + acmeLEPrivateKeySmGuid = config.AcmeLEPrivateKeySmGuid + acmeLEPrivateKeySmRegion = config.AcmeLEPrivateKeySmRegion + acmeLEPrivateKeySecretId = config.AcmeLEPrivateKeySecretId + impCertificateSmGuid = config.ImpCertificateSmGuid + impCertificateSmRegion = config.ImpCertificateSmRegion + + sdnlbServiceIdName = config.SdnlbServiceidName + err = log.Output(1, "TestMain using sdnlbServiceIdName "+sdnlbServiceIdName) + if err != nil { + log.Fatal(err) + } + + allCombinedTerraformVars = map[string]interface{}{ + "existing_cis_instance_name": cisName, + "existing_cis_instance_resource_group_id": rgId, + // imported certificate and public certificate creation management + "existing_sm_instance_crn": smCRN, + "existing_sm_instance_guid": smGuid, + "existing_sm_instance_region": smRegion, + "imported_certificate_sm_region": impCertificateSmRegion, + "imported_certificate_sm_id": impCertificateSmGuid, + "imported_certificate_intermediate_secret_id": impCertIntermediateSecretID, + "imported_certificate_public_secret_id": impCertPublicSecretID, + "imported_certificate_private_secret_id": impCertPrivateSecretID, + "acme_letsencrypt_private_key_secret_id": acmeLEPrivateKeySecretId, + "acme_letsencrypt_private_key_sm_id": acmeLEPrivateKeySmGuid, + "acme_letsencrypt_private_key_sm_region": acmeLEPrivateKeySmRegion, + "eso_deployment_nodes_configuration": esoWorkersSelector, + // setting skip_iam_authorization_policy to true because using the existing secrets manager instance and the policy already exists + "skip_iam_authorization_policy": true, + "existing_sdnlb_serviceid_name": sdnlbServiceIdName, + "service_endpoints": "public", + } + + os.Exit(m.Run()) +} + +var ignoreUpdates = []string{ + "module.es_kubernetes_secret_usr_pass.helm_release.external_secrets_operator[0]", + "module.es_kubernetes_secret_arbitrary_cloudant.helm_release.external_secrets_operator[0]", + "module.es_kubernetes_secret_arbitrary_cr_registry.helm_release.external_secrets_operator[0]", + "module.es_kubernetes_secret_image_pull.helm_release.external_secrets_operator[0]", + "module.external_secrets_operator.helm_release.external_secrets_operator", + "module.external_secrets_operator.helm_release.pod_reloader[0]", + "module.external_secret_arbitrary_cloudant.helm_release.kubernetes_secret[0]", + "module.external_secret_tp_multisg_2.helm_release.kubernetes_secret[0]", + "module.external_secret_imported_certificate[0].helm_release.kubernetes_secret_certificate[0]", + "module.external_secret_tp[0].helm_release.kubernetes_secret[0]", + "module.external_secret_private_certificate.helm_release.kubernetes_secret_certificate[0]", + "module.external_secret_kv_multiplekeys.helm_release.kubernetes_secret_kv_all[0]", + "module.external_secret_arbitrary_cr_registry.helm_release.kubernetes_secret[0]", + "module.external_secret_secret_image_pull.helm_release.kubernetes_secret[0]", + "module.external_secret_public_certificate[0].helm_release.kubernetes_secret_certificate[0]", + "module.external_secret_kv_singlekey.helm_release.kubernetes_secret_kv_key[0]", + "module.external_secret_tp[1].helm_release.kubernetes_secret[0]", + "module.external_secret_tp_multisg_1.helm_release.kubernetes_secret[0]", + "module.external_secret_usr_pass.helm_release.kubernetes_secret_user_pw[0]", + "module.external_secret_tp_nosg.helm_release.kubernetes_secret[0]", + "module.sdnlb_eso_secret.helm_release.sdnlb_external_secret", +} + +func setupOptions(t *testing.T, prefix string, terraformDir string, terraformVars map[string]interface{}) *testhelper.TestOptions { options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ Testing: t, - TerraformDir: dir, + TerraformDir: terraformDir, Prefix: prefix, ResourceGroup: resourceGroup, + TerraformVars: terraformVars, + + IgnoreUpdates: testhelper.Exemptions{ + List: ignoreUpdates, + }, + ImplicitDestroy: []string{ + // workaround for the issue https://github.ibm.com/GoldenEye/issues/issues/10743 + // when the issue is fixed on IKS, so the destruction of default workers pool is correctly managed on provider/clusters service the next two entries should be removed + "'module.ocp_base.ibm_container_vpc_worker_pool.autoscaling_pool[\"default\"]'", + "'module.ocp_base.ibm_container_vpc_worker_pool.pool[\"default\"]'", + }, + + IgnoreDestroys: testhelper.Exemptions{ // Ignore for consistency check + List: []string{ + // adding resources to ignore for modules version update - to be removed after the merge + "module.ocp_base.time_sleep.wait_operators", + }, + }, }) + return options } -func TestRunAdvancedExample(t *testing.T) { +func TestRunDefaultExample(t *testing.T) { t.Parallel() - options := setupOptions(t, "mod-template", advancedExampleDir) + options := setupOptions(t, "eso", defaultExampleTerraformDir, allCombinedTerraformVars) + options.SkipTestTearDown = true + defer func() { + options.TestTearDown() + }() output, err := options.RunTestConsistency() - assert.Nil(t, err, "This should not have errored") + + if assert.Nil(t, err, "Consistency test should not have errored") { + outputs := options.LastTestTerraformOutputs + _, tfOutputsErr := testhelper.ValidateTerraformOutputs(outputs, "cluster_id") + if assert.Nil(t, tfOutputsErr, tfOutputsErr) { + log.Println("Prefix used " + options.Prefix) + + clusterId := outputs["cluster_id"].(string) + + log.Println("clusterId " + clusterId) + + // building the list of secrets to test + namespaces_for_apikey_login := []string{"apikeynspace1", "apikeynspace2", "apikeynspace3", "apikeynspace4"} + namespaces_for_tp_login := []string{"tpnspace1", "tpnspace2"} + + secretsMap := map[string]string{ + "dockerconfigjson-uc": namespaces_for_apikey_login[0], + // temporary disabled cloudant resource key secret test + // https://github.ibm.com/GoldenEye/issues/issues/7726 + // "cloudant-opaque-arb": namespaces_for_apikey_login[1], + "dockerconfigjson-arb": namespaces_for_apikey_login[2], + "pvtcertificate-tls": namespaces_for_apikey_login[2], + "kv-single-key": namespaces_for_apikey_login[3], + "kv-multiple-keys": namespaces_for_apikey_login[3], + "dockerconfigjson-iam": namespaces_for_apikey_login[3], + "dockerconfigjson-chain": namespaces_for_apikey_login[3], + options.Prefix + "-arbitrary-arb-tp-0": namespaces_for_tp_login[0], + options.Prefix + "-arbitrary-arb-tp-1": namespaces_for_tp_login[1], + options.Prefix + "-arbitrary-arb-tp-multisg-1": "tpns-multisg", + options.Prefix + "-arbitrary-arb-tp-multisg-2": "tpns-multisg", + options.Prefix + "-arbitrary-arb-tp-nosg": "tpns-nosg", + options.Prefix + "-arbitrary-arb-cstore-tp": "eso-cstore-tp-namespace", + // sdnlb secret + "sdnlb-config": "kube-system", + } + + log.Printf("secretsMap %s", secretsMap) + + // get cluster config + log.Println("Loading cluster configuration with id " + clusterId) + cloudinfosvc, err := cloudinfo.NewCloudInfoServiceFromEnv("TF_VAR_ibmcloud_api_key", cloudinfo.CloudInfoServiceOptions{}) + if assert.Nil(t, err, "Error creating cloud info service") { + clusterConfigPath, err := cloudinfosvc.GetClusterConfigConfigPath(clusterId) + defer func() { + // attempt to remove cluster config file after test + _ = os.Remove(clusterConfigPath) + }() + if assert.Nil(t, err, "Error getting cluster config path") { + // for each secret to test configure Terratest with cluster config + // the test checks if each secret is correctly created in the cluster + for secretName, secretNamespace := range secretsMap { + ocOptions := k8s.NewKubectlOptions("", clusterConfigPath, secretNamespace) + log.Printf("Testing secret name %s namespace %s\n", secretName, secretNamespace) + _, err := k8s.GetSecretE(t, ocOptions, secretName) + assert.Nil(t, err, "Error retrieving secret "+secretName+" in namespace "+secretNamespace) + } + } + } + } + } + assert.NotNil(t, output, "Expected some output") } func TestRunUpgradeExample(t *testing.T) { t.Parallel() - options := setupOptions(t, "mod-template-upg", advancedExampleDir) - + options := setupOptions(t, "eso-upg", defaultExampleTerraformDir, allCombinedTerraformVars) output, err := options.RunTestUpgrade() if !options.UpgradeTestSkipped { assert.Nil(t, err, "This should not have errored") assert.NotNil(t, output, "Expected some output") } } + +func TestReloaderOperational(t *testing.T) { + t.Parallel() + // terraform vars for reloader test + reloaderTerraformVars := map[string]interface{}{} + + reloaderTerraformVars["existing_sm_instance_guid"] = smGuid + reloaderTerraformVars["existing_sm_instance_region"] = smRegion + + options := setupOptions(t, "reloader", basicExampleTerraformDir, reloaderTerraformVars) + + options.SkipTestTearDown = true + defer func() { + options.TestTearDown() + }() + + _, err := options.RunTestConsistency() + if assert.Nil(t, err, "Consistency test should not have errored") { + outputs := options.LastTestTerraformOutputs + _, tfOutputsErr := testhelper.ValidateTerraformOutputs(outputs, "cluster_id") + if assert.Nil(t, tfOutputsErr, tfOutputsErr) { + + // get cluster config + cloudinfosvc, err := cloudinfo.NewCloudInfoServiceFromEnv("TF_VAR_ibmcloud_api_key", cloudinfo.CloudInfoServiceOptions{}) + if assert.Nil(t, err, "Error creating cloud info service") { + clusterConfigPath, err := cloudinfosvc.GetClusterConfigConfigPath(outputs["cluster_id"].(string)) + defer func() { + // attempt to remove cluster config file after test + _ = os.Remove(clusterConfigPath) + }() + if assert.Nil(t, err, "Error getting cluster config path") { + sampleApp := "./samples/sample.yaml" + deploymentName := "example-deployment" + namespace := "reloader-test-ns" + containerName := "busybox-container" + secretName := "example-secret" + secretValue := "top-secret" + updatedSecret := "./samples/updated_secret.yaml" // pragma: allowlist secret + updatedSecretValue := "updated-secret" + + sleepBetweenRetries := 20 * time.Second + // configure Terratest with cluster config + ocOptions := k8s.NewKubectlOptions("", clusterConfigPath, namespace) + // deploy sample app + applyError := k8s.KubectlApplyE(t, ocOptions, sampleApp) + if assert.Nil(t, applyError, "Error applying sample app") { + // confirm app is running + k8s.WaitUntilDeploymentAvailable(t, ocOptions, deploymentName, 20, sleepBetweenRetries) + k8s.WaitUntilSecretAvailable(t, ocOptions, secretName, 20, sleepBetweenRetries) + // Check that the secret value is correct + // Get pod name from deployment + pods, err := GetPodNamesFromDeployment(t, ocOptions, deploymentName) + if assert.Nil(t, err, "Error getting pod names") { + initialPod := k8s.GetPod(t, ocOptions, pods[0]) + k8s.WaitUntilPodAvailable(t, ocOptions, initialPod.Name, 20, sleepBetweenRetries) + logs := k8s.GetPodLogs(t, ocOptions, initialPod, containerName) + if assert.Contains(t, logs, secretValue, "Initial Secret value not found in logs") { + t.Log("Initial secret value found in logs") + t.Log(logs) + } + // update secret with updated secret + applyError = k8s.KubectlApplyE(t, ocOptions, updatedSecret) + if assert.Nil(t, applyError, "Error applying updated secret") { + // Set a timeout duration + timeout := 20 * time.Second + + // Create a channel to signal the end of the timeout + timeoutChan := time.After(timeout) + var newPodName string + failed := false + // Loop until a new initialPod is found or until timeout + // Using a label on the for loop allows us to break out of the loop, otherwise the break would only break out of the select statement + Loop: + for { + select { + case <-timeoutChan: + // Handle the timeout case + assert.Fail(t, "timeout reached while waiting for initialPod to change") + failed = true + break Loop + default: + // Sleep to avoid busy waiting + time.Sleep(time.Second) + + // Update initialPod names + currentPods, err := GetPodNamesFromDeployment(t, ocOptions, deploymentName) + if err != nil { + t.Log("Error getting initialPod names") + break + } + + for _, pod := range currentPods { + if !common.StrArrayContains(pods, pod) { + newPodName = pod + break Loop + } + } + + if newPodName != "" { + break + } + } + } + if !failed { + k8s.WaitUntilDeploymentAvailable(t, ocOptions, deploymentName, 20, sleepBetweenRetries) + newPod := k8s.GetPod(t, ocOptions, newPodName) + k8s.WaitUntilPodAvailable(t, ocOptions, newPod.Name, 20, sleepBetweenRetries) + // confirm app restarted and picked up new secret by checking logs + newLogs := k8s.GetPodLogs(t, ocOptions, newPod, containerName) + if assert.Contains(t, newLogs, updatedSecretValue, "Updated Secret value not found in logs") { + t.Log("Updated secret value found in logs") + t.Log(newLogs) + } + } + } + } + } + } + } + + } + } +} + +func GetPodNamesFromDeployment(t *testing.T, options *k8s.KubectlOptions, deploymentName string) ([]string, error) { + // Get the deployment object + deployment, err := k8s.GetDeploymentE(t, options, deploymentName) + if err != nil { + return nil, err + } + + // Construct the label selector from the deployment + labelSelector := metav1.FormatLabelSelector(deployment.Spec.Selector) + + // List Pods using label selector + pods, err := k8s.ListPodsE(t, options, metav1.ListOptions{LabelSelector: labelSelector}) + if err != nil { + return nil, err + } + + // Extract the pod names + var podNames []string + for _, pod := range pods { + podNames = append(podNames, pod.Name) + } + + return podNames, nil +} diff --git a/tests/samples/README.md b/tests/samples/README.md new file mode 100644 index 00000000..e467be55 --- /dev/null +++ b/tests/samples/README.md @@ -0,0 +1,4 @@ +# Sample App + +This is a sample app to test the reloader is in a working state. First the test deploys sample.yaml, +then it deploys updated_secret.yaml. The reloader should detect the change and redeploy the pod. diff --git a/tests/samples/sample.yaml b/tests/samples/sample.yaml new file mode 100644 index 00000000..50e1fd93 --- /dev/null +++ b/tests/samples/sample.yaml @@ -0,0 +1,53 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: reloader-test-ns +--- +apiVersion: v1 +kind: Secret +metadata: + name: example-secret + namespace: reloader-test-ns + annotations: + reloader.stakater.com/auto: "true" +data: + # base64 encoded 'top-secret' + mysecret: dG9wLXNlY3JldAo= # pragma: allowlist secret +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: example-deployment + namespace: reloader-test-ns + annotations: + reloader.stakater.com/auto: "true" +spec: + replicas: 1 + selector: + matchLabels: + app: example-busybox + template: + metadata: + labels: + app: example-busybox + spec: + nodeSelector: + dedicated: edge + containers: + - name: busybox-container + image: busybox + command: ["/bin/sh"] + args: ["-c", "while true; do echo $(date);echo $MY_SECRET; sleep 5; done"] + env: + - name: MY_SECRET + valueFrom: + secretKeyRef: + name: example-secret + key: mysecret + resources: + requests: + memory: "64Mi" + cpu: "250m" + limits: + memory: "128Mi" + cpu: "500m" diff --git a/tests/samples/updated_secret.yaml b/tests/samples/updated_secret.yaml new file mode 100644 index 00000000..1029a9c9 --- /dev/null +++ b/tests/samples/updated_secret.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Secret +metadata: + name: example-secret + namespace: reloader-test-ns + annotations: + reloader.stakater.com/auto: "true" +data: + # base64 encoded 'updated-secret' + mysecret: dXBkYXRlZC1zZWNyZXQK # pragma: allowlist secret diff --git a/variables.tf b/variables.tf index df604346..20b5f463 100644 --- a/variables.tf +++ b/variables.tf @@ -1,9 +1,152 @@ -######################################################################################################################## -# Input Variables -######################################################################################################################## - -#variable "my_variable" { -# type = string -# description = "A description of my variable" -# default = "default_value" -#} +######## eso generic configurations + +variable "eso_namespace" { + description = "Namespace to create and be used to install ESO components including helm releases. If eso_store_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster_store in it" + type = string + default = null +} + +variable "existing_eso_namespace" { + description = "Existing Namespace to be used to install ESO components including helm releases. If eso_store_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster_store in it" + type = string + default = null +} + +# ESO deployment cluster nodes configuration +variable "eso_cluster_nodes_configuration" { + description = "Configuration to use to customise ESO deployment on specific cluster nodes. Setting appropriate values will result in customising ESO helm release. Default value is null to keep ESO standard deployment." + type = object({ + nodeSelector = object({ + label = string + value = string + }) + tolerations = object({ + key = string + operator = string + value = string + effect = string + }) + }) + default = null +} + +# ESO deployment cluster pods configuration +variable "eso_pod_configuration" { + description = "Configuration to use to customise ESO deployment on specific pods. Setting appropriate values will result in customising ESO helm release. Default value is {} to keep ESO standard deployment. Ignore the key if not required." + type = object({ + annotations = optional(object({ + # The annotations for external secret controller pods. + external_secrets = optional(map(string), {}) + # The annotations for external secret cert controller pods. + external_secrets_cert_controller = optional(map(string), {}) + # The annotations for external secret controller pods. + external_secrets_webhook = optional(map(string), {}) + }), {}) + + labels = optional(object({ + # The labels for external secret controller pods. + external_secrets = optional(map(string), {}) + # The labels for external secret cert controller pods. + external_secrets_cert_controller = optional(map(string), {}) + # The labels for external secret controller pods. + external_secrets_webhook = optional(map(string), {}) + }), {}) + }) + + default = {} +} + +# ESO +variable "eso_enroll_in_servicemesh" { + description = "Flag to enroll ESO into istio servicemesh" + type = bool + default = false +} + +# Reloader variables full documentation https://github.com/stakater/Reloader/tree/master#helm-charts +variable "reloader_deployed" { + description = "Whether to deploy reloader or not https://github.com/stakater/Reloader" + type = bool + default = true +} +variable "reloader_reload_strategy" { + description = "The reload strategy to use for reloader. Possible values are `env-vars` or `annotations`. Default value is `annotations`" + type = string + default = "annotations" + validation { + condition = contains(["env-vars", "annotations"], var.reloader_reload_strategy) + error_message = "The specified reloader_reload_strategy is not a valid selection! Valid values are `env-vars` or `annotations`" + } +} +variable "reloader_namespaces_to_ignore" { + description = "List of comma separated namespaces to ignore for reloader. If multiple are provided they are combined with the AND operator" + type = string + default = null +} +variable "reloader_resources_to_ignore" { + description = "List of comma separated resources to ignore for reloader. If multiple are provided they are combined with the AND operator" + type = string + default = null +} +variable "reloader_namespaces_selector" { + description = "List of comma separated label selectors, if multiple are provided they are combined with the AND operator" + type = string + default = null +} +variable "reloader_resource_label_selector" { + description = "List of comma separated label selectors, if multiple are provided they are combined with the AND operator" + type = string + default = null +} +variable "reloader_ignore_secrets" { + description = "Whether to ignore secret changes or not" + type = bool + default = false +} +variable "reloader_ignore_configmaps" { + description = "Whether to ignore configmap changes or not" + type = bool + default = false +} +variable "reloader_is_openshift" { + description = "Enable OpenShift DeploymentConfigs" + type = bool + default = true +} +variable "reloader_is_argo_rollouts" { + description = "Enable Argo Rollouts" + type = bool + default = false +} +variable "reloader_reload_on_create" { + description = "Enable reload on create events" + type = bool + default = true + +} +variable "reloader_sync_after_restart" { + description = "Enable sync after Reloader restarts for Add events, works only when reloadOnCreate is true" + type = bool + default = true + +} +variable "reloader_pod_monitor_metrics" { + description = "Enable to scrape Reloader's Prometheus metrics" + type = bool + default = false +} + +variable "reloader_log_format" { + description = "The log format to use for reloader. Possible values are `json` or `text`. Default value is `json`" + type = string + default = "text" + validation { + condition = contains(["json", "text"], var.reloader_log_format) + error_message = "The specified reloader_log_format is not a valid selection! Valid values are `json` or `text`" + } +} +variable "reloader_custom_values" { + description = "String containing custom values to be used for reloader helm chart. See https://github.com/stakater/Reloader/blob/master/deployments/kubernetes/chart/reloader/values.yaml" + type = string + default = null +} diff --git a/version.tf b/version.tf index f15f6031..60946dae 100644 --- a/version.tf +++ b/version.tf @@ -1,12 +1,14 @@ terraform { required_version = ">= 1.3.0" - # If your module requires any terraform providers, uncomment the "required_providers" section below and add all required providers. - # Each required provider's version should be a flexible range to future proof the module's usage with upcoming minor and patch versions. - - # required_providers { - # ibm = { - # source = "IBM-Cloud/ibm" - # version = ">= 1.64.0, < 2.0.0" - # } - # } + required_providers { + # Use "greater than or equal to" range in modules + kubernetes = { + source = "hashicorp/kubernetes" + version = ">= 2.16.1, < 3.0.0" + } + helm = { + source = "hashicorp/helm" + version = ">= 2.11.0, < 3.0.0" + } + } } From 33cad1fd2ee798ea01b58ea80ea47b427ef40c27 Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Fri, 15 Nov 2024 16:25:24 +0530 Subject: [PATCH 02/40] init commit --- README.md | 11 +++++------ examples/basic/main.tf | 10 +++++----- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 117f2c14..61c4312f 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,13 @@ This module automates the installation and configuration of the [External Secret ## Overview * [terraform-ibm-external-secrets-operator](#terraform-ibm-external-secrets-operator) +* [Submodules](./modules) + * [eso-clusterstore](./modules/eso-clusterstore) + * [eso-external-secret](./modules/eso-external-secret) + * [eso-secretstore](./modules/eso-secretstore) + * [eso-trusted-profile](./modules/eso-trusted-profile) * [Examples](./examples) * [Basic Example](./examples/basic) - * [Example that uses trusted profiles (container authentication)](./examples/trusted-profiles-authentication) - * [Example to deploy the External Secret Operator and to create a different set of resources in terms of secrets, secret groups, stores and auth configurations](./examples/all-combined) - * [Example to deploy the External Secret Operator enrolled into RedHat Service Mesh](./examples/eso-enroll-into-servicemesh) * [Contributing](#contributing) @@ -493,10 +495,7 @@ module "es_kubernetes_secret" { ## Examples -- [ Example to deploy the External Secret Operator and to create a different set of resources in terms of secrets, secret groups, stores and auth configurations](examples/all-combined) - [ Basic Example](examples/basic) -- [ Example to deploy the External Secret Operator enrolled into RedHat Service Mesh](examples/eso-enroll-into-servicemesh) -- [ Example that uses trusted profiles (container authentication)](examples/trusted-profiles-authentication) diff --git a/examples/basic/main.tf b/examples/basic/main.tf index cef27c90..c65107b4 100644 --- a/examples/basic/main.tf +++ b/examples/basic/main.tf @@ -72,11 +72,11 @@ locals { # VPC creation module "vpc" { - source = "terraform-ibm-modules/vpc/ibm" - version = "1.2.0" - vpc_name = "${var.prefix}-vpc" - resource_group_id = module.resource_group.resource_group_id - vpc_tags = [] + source = "terraform-ibm-modules/vpc/ibm" + version = "1.1.2" + vpc_name = "${var.prefix}-vpc" + resource_group_id = module.resource_group.resource_group_id + vpc_tags = [] } # OCP CLUSTER creation From 7331b34236d3943a4e5c57a3f438c824c8f38096 Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Mon, 9 Dec 2024 11:28:56 +0530 Subject: [PATCH 03/40] added basic example --- common-dev-assets | 2 +- examples/basic/main.tf | 211 ++++++++++++++++++++++++++++++------ examples/basic/outputs.tf | 11 +- examples/basic/variables.tf | 6 + examples/basic/version.tf | 2 +- 5 files changed, 191 insertions(+), 41 deletions(-) diff --git a/common-dev-assets b/common-dev-assets index 81754c2e..57d98817 160000 --- a/common-dev-assets +++ b/common-dev-assets @@ -1 +1 @@ -Subproject commit 81754c2ee99c3bcc5fd2a69f5a06c21543bb87cb +Subproject commit 57d98817a27fce42e28bf46b61240056bf9dd210 diff --git a/examples/basic/main.tf b/examples/basic/main.tf index 4804a7d3..3a583f3c 100644 --- a/examples/basic/main.tf +++ b/examples/basic/main.tf @@ -16,7 +16,7 @@ locals { sm_guid = var.existing_sm_instance_guid == null ? ibm_resource_instance.secrets_manager[0].guid : var.existing_sm_instance_guid - + # https://github.ibm.com/GoldenEye/issues/issues/5268 - deployment region will match to sm_region as workaround sm_region = var.existing_sm_instance_region == null ? var.region : var.existing_sm_instance_region sm_acct_id = var.existing_sm_instance_guid == null ? module.iam_secrets_engine[0].acct_secret_group_id : module.secrets_manager_group_acct[0].secret_group_id es_namespace_apikey = "es-operator" # pragma: allowlist secret @@ -40,52 +40,191 @@ module "resource_group" { ################################################################## locals { - cluster_vpc_subnets = { - default = [ - { - id = ibm_is_subnet.subnet_zone_1.id - cidr_block = ibm_is_subnet.subnet_zone_1.ipv4_cidr_block - zone = ibm_is_subnet.subnet_zone_1.zone - } - ] + + subnets = [ + for subnet in module.vpc.vpc.subnets : + { + id = subnet.id + zone = subnet.zone + cidr_block = subnet.cidr_block + } + ] + cluster_vpc_subnets = { + private = local.subnets, + edge = local.subnets, + transit = local.subnets } + # cluster_vpc_subnets = { + # zone-1 = [ + # for zone in module.vpc.subnet_zone_list : + # { + # id = zone.id + # zone = zone.zone + # cidr_block = zone.cidr + # } + # ] + # } + # OCP Configuration - worker_pools = [ + # OCP Configuration + ocp_worker_pools = [ + { + subnet_prefix = "private" + pool_name = "default" + machine_type = "bx2.4x16" + workers_per_zone = 1 + labels = { "dedicated" : "private" } + operating_system = "REDHAT_8_64" + }, + { + subnet_prefix = "edge" + pool_name = "edge" + machine_type = "bx2.4x16" + workers_per_zone = 1 + labels = { "dedicated" : "edge" } + operating_system = "REDHAT_8_64" + }, { - subnet_prefix = "default" - pool_name = "default" # ibm_container_vpc_cluster automatically names default pool "default" (See https://github.com/IBM-Cloud/terraform-provider-ibm/issues/2849) + subnet_prefix = "transit" + pool_name = "transit" machine_type = "bx2.4x16" - workers_per_zone = 2 # minimum of 2 is allowed when using single zone + workers_per_zone = 1 + labels = { "dedicated" : "transit" } operating_system = "REDHAT_8_64" } ] -} -# VPC creation -resource "ibm_is_vpc" "vpc" { - name = "${var.prefix}-vpc" - resource_group = module.resource_group.resource_group_id - address_prefix_management = "auto" - tags = var.resource_tags -} -resource "ibm_is_public_gateway" "gateway" { - name = "${var.prefix}-gateway-1" - vpc = ibm_is_vpc.vpc.id - resource_group = module.resource_group.resource_group_id - zone = "${var.region}-1" -} + // subnets = [ for v in module.vpc.vpc.subnet : { id = v.subnet_ids} ] + + } + -resource "ibm_is_subnet" "subnet_zone_1" { - name = "${var.prefix}-subnet-1" - vpc = ibm_is_vpc.vpc.id - resource_group = module.resource_group.resource_group_id - zone = "${var.region}-1" - total_ipv4_address_count = 256 - public_gateway = ibm_is_public_gateway.gateway.id +module "vpc" { + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git?ref=update_submodules" + vpc_name = "${var.prefix}-vpc" + resource_group_id = module.resource_group.resource_group_id + locations = ["us-south-1", "us-south-2", "us-south-3"] + vpc_tags = var.resource_tags + address_prefixes = [ + { + name = "${var.prefix}-us-south-1" + location = "us-south-1" + ip_range = "10.10.10.0/24" + }, + { + name = "${var.prefix}-us-south-2" + location = "us-south-2" + ip_range = "10.10.20.0/24" + }, + { + name = "${var.prefix}-us-south-3" + location = "us-south-3" + ip_range = "10.10.30.0/24" + } + ] + subnet_name_prefix = "${var.prefix}-subnet" + default_network_acl_name = "${var.prefix}-nacl" + default_routing_table_name = "${var.prefix}-routing-table" + default_security_group_name = "${var.prefix}-sg" + create_gateway = true + public_gateway_name_prefix = "${var.prefix}-pw" + number_of_addresses = 16 + } +module "security_group" { + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/security-group?ref=update_submodules" + create_security_group = true + name = "${var.prefix}-vpc-sg" + vpc_id = module.vpc.vpc.vpc_id + resource_group_id = module.resource_group.resource_group_id + security_group_rules = [ + { + name = "allow_all_inbound" + remote = "0.0.0.0/0" + direction = "inbound" + } + ] +} +module "network_acl" { + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/network-acl?ref=update_submodules" + name = "${var.prefix}-vpc-acl" + vpc_id = module.vpc.vpc.vpc_id + resource_group_id = module.resource_group.resource_group_id + rules = [ + { + name = "iks-create-worker-nodes-inbound" + action = "allow" + source = "161.26.0.0/16" + destination = "0.0.0.0/0" + direction = "inbound" + }, + { + name = "iks-nodes-to-master-inbound" + action = "allow" + source = "166.8.0.0/14" + destination = "0.0.0.0/0" + direction = "inbound" + }, + { + name = "iks-create-worker-nodes-outbound" + action = "allow" + source = "0.0.0.0/0" + destination = "161.26.0.0/16" + direction = "outbound" + }, + { + name = "iks-worker-to-master-outbound" + action = "allow" + source = "0.0.0.0/0" + destination = "166.8.0.0/14" + direction = "outbound" + }, + { + name = "allow-all-https-inbound" + source = "0.0.0.0/0" + action = "allow" + destination = "0.0.0.0/0" + direction = "inbound" + tcp = { + source_port_min = 443 + source_port_max = 443 + port_min = 1 + port_max = 65535 + } + }, + { + name = "allow-all-https-outbound" + source = "0.0.0.0/0" + action = "allow" + destination = "0.0.0.0/0" + direction = "outbound" + tcp = { + source_port_min = 1 + source_port_max = 65535 + port_min = 443 + port_max = 443 + } + }, + { + name = "deny-all-outbound" + action = "deny" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "outbound" + }, + { + name = "deny-all-inbound" + action = "deny" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "inbound" + } + ] + tags = var.tags +} # OCP CLUSTER creation module "ocp_base" { @@ -95,9 +234,9 @@ module "ocp_base" { resource_group_id = module.resource_group.resource_group_id region = var.region force_delete_storage = true - vpc_id = ibm_is_vpc.vpc.id + vpc_id = module.vpc.vpc.vpc_id vpc_subnets = local.cluster_vpc_subnets - worker_pools = local.worker_pools + worker_pools = local.ocp_worker_pools tags = [] use_existing_cos = false # outbound required by cluster proxy diff --git a/examples/basic/outputs.tf b/examples/basic/outputs.tf index e124314b..03dae42d 100644 --- a/examples/basic/outputs.tf +++ b/examples/basic/outputs.tf @@ -1,7 +1,12 @@ ############################################################################## # Outputs ############################################################################## -output "cluster_id" { - description = "ID of the cluster deployed" - value = module.ocp_base.cluster_id +# output "cluster_id" { +# description = "ID of the cluster deployed" +# value = module.ocp_base.cluster_id +# } + +output "vpc" { + description = "Configuration of newly created or existing VPC instace." + value = module.vpc } diff --git a/examples/basic/variables.tf b/examples/basic/variables.tf index b7006743..2b39aeb1 100644 --- a/examples/basic/variables.tf +++ b/examples/basic/variables.tf @@ -58,3 +58,9 @@ variable "existing_sm_instance_region" { description = "Existing Secrets Manager Region. Required if value is passed into var.existing_instance_guid." default = null } + +variable "tags" { + description = "List of Tags for the ACL" + type = list(string) + default = null +} \ No newline at end of file diff --git a/examples/basic/version.tf b/examples/basic/version.tf index 8ec2e629..79a5e10c 100644 --- a/examples/basic/version.tf +++ b/examples/basic/version.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 1.3.0" + required_version = ">= 1.0.0" required_providers { kubernetes = { source = "hashicorp/kubernetes" From c1bb232bec3cc36360f723e4e53a6caf85a6327a Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Fri, 27 Dec 2024 14:49:46 +0530 Subject: [PATCH 04/40] update the PR to use public image --- README.md | 6 + common-dev-assets | 2 +- examples/basic/main.tf | 175 +++++++------- examples/basic/outputs.tf | 2 +- examples/basic/variables.tf | 2 +- .../trusted-profiles-authentication/README.md | 18 ++ .../trusted-profiles-authentication/main.tf | 217 ++++++++++++++++++ .../outputs.tf | 3 + .../providers.tf | 40 ++++ .../variables.tf | 95 ++++++++ .../version.tf | 21 ++ main.tf | 8 +- tests/pr_test.go | 87 ------- variables.tf | 24 ++ 14 files changed, 511 insertions(+), 189 deletions(-) create mode 100644 examples/trusted-profiles-authentication/README.md create mode 100644 examples/trusted-profiles-authentication/main.tf create mode 100644 examples/trusted-profiles-authentication/outputs.tf create mode 100644 examples/trusted-profiles-authentication/providers.tf create mode 100644 examples/trusted-profiles-authentication/variables.tf create mode 100644 examples/trusted-profiles-authentication/version.tf diff --git a/README.md b/README.md index 61c4312f..13e60a45 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ This module automates the installation and configuration of the [External Secret * [eso-trusted-profile](./modules/eso-trusted-profile) * [Examples](./examples) * [Basic Example](./examples/basic) + * [Example that uses trusted profiles (container authentication)](./examples/trusted-profiles-authentication) * [Contributing](#contributing) @@ -496,6 +497,7 @@ module "es_kubernetes_secret" { ## Examples - [ Basic Example](examples/basic) +- [ Example that uses trusted profiles (container authentication)](examples/trusted-profiles-authentication) @@ -527,6 +529,8 @@ module "es_kubernetes_secret" { |------|-------------|------|---------|:--------:| | [eso\_cluster\_nodes\_configuration](#input\_eso\_cluster\_nodes\_configuration) | Configuration to use to customise ESO deployment on specific cluster nodes. Setting appropriate values will result in customising ESO helm release. Default value is null to keep ESO standard deployment. |
object({
nodeSelector = object({
label = string
value = string
})
tolerations = object({
key = string
operator = string
value = string
effect = string
})
})
| `null` | no | | [eso\_enroll\_in\_servicemesh](#input\_eso\_enroll\_in\_servicemesh) | Flag to enroll ESO into istio servicemesh | `bool` | `false` | no | +| [eso\_image\_repo](#input\_eso\_image\_repo) | The repository for the External Secrets Operator image. Default is `ghcr.io/external-secrets/external-secrets`. | `string` | `"ghcr.io/external-secrets/external-secrets"` | no | +| [eso\_image\_tag\_digest](#input\_eso\_image\_tag\_digest) | The tag or digest for the External Secrets Operator image. Provide a digest in the format `sha256:xxxxx...` for immutability or leave it as a tag version. | `string` | `"v0.11.0-ubi@sha256:b5f685b86cf684020e863c6c2ed91e8a79cad68260d7149ddee073ece2573d6f"` | no | | [eso\_namespace](#input\_eso\_namespace) | Namespace to create and be used to install ESO components including helm releases. If eso\_store\_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster\_store in it | `string` | `null` | no | | [eso\_pod\_configuration](#input\_eso\_pod\_configuration) | Configuration to use to customise ESO deployment on specific pods. Setting appropriate values will result in customising ESO helm release. Default value is {} to keep ESO standard deployment. Ignore the key if not required. |
object({
annotations = optional(object({
# The annotations for external secret controller pods.
external_secrets = optional(map(string), {})
# The annotations for external secret cert controller pods.
external_secrets_cert_controller = optional(map(string), {})
# The annotations for external secret controller pods.
external_secrets_webhook = optional(map(string), {})
}), {})

labels = optional(object({
# The labels for external secret controller pods.
external_secrets = optional(map(string), {})
# The labels for external secret cert controller pods.
external_secrets_cert_controller = optional(map(string), {})
# The labels for external secret controller pods.
external_secrets_webhook = optional(map(string), {})
}), {})
})
| `{}` | no | | [existing\_eso\_namespace](#input\_existing\_eso\_namespace) | Existing Namespace to be used to install ESO components including helm releases. If eso\_store\_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster\_store in it | `string` | `null` | no | @@ -534,6 +538,8 @@ module "es_kubernetes_secret" { | [reloader\_deployed](#input\_reloader\_deployed) | Whether to deploy reloader or not https://github.com/stakater/Reloader | `bool` | `true` | no | | [reloader\_ignore\_configmaps](#input\_reloader\_ignore\_configmaps) | Whether to ignore configmap changes or not | `bool` | `false` | no | | [reloader\_ignore\_secrets](#input\_reloader\_ignore\_secrets) | Whether to ignore secret changes or not | `bool` | `false` | no | +| [reloader\_image\_repo](#input\_reloader\_image\_repo) | The repository for the Stakater Reloader image. Default is `ghcr.io/stakater/reloader`. | `string` | `"ghcr.io/stakater/reloader"` | no | +| [reloader\_image\_tag\_digest](#input\_reloader\_image\_tag\_digest) | The tag or digest for the Stakater Reloader image. Provide a digest in the format `sha256:xxxxx...` for immutability or leave it as a tag version. | `string` | `"v1.2.0-ubi@sha256:375736e6690986559022cae504bebd8dfe14a37ac0305176f8826362c29732d6f"` | no | | [reloader\_is\_argo\_rollouts](#input\_reloader\_is\_argo\_rollouts) | Enable Argo Rollouts | `bool` | `false` | no | | [reloader\_is\_openshift](#input\_reloader\_is\_openshift) | Enable OpenShift DeploymentConfigs | `bool` | `true` | no | | [reloader\_log\_format](#input\_reloader\_log\_format) | The log format to use for reloader. Possible values are `json` or `text`. Default value is `json` | `string` | `"text"` | no | diff --git a/common-dev-assets b/common-dev-assets index 57d98817..5cf7d9c5 160000 --- a/common-dev-assets +++ b/common-dev-assets @@ -1 +1 @@ -Subproject commit 57d98817a27fce42e28bf46b61240056bf9dd210 +Subproject commit 5cf7d9c5c426495cab1abd4e367416a2562edc2d diff --git a/examples/basic/main.tf b/examples/basic/main.tf index 3a583f3c..949ff4dc 100644 --- a/examples/basic/main.tf +++ b/examples/basic/main.tf @@ -41,7 +41,7 @@ module "resource_group" { locals { - subnets = [ + subnets = [ for subnet in module.vpc.vpc.subnets : { id = subnet.id @@ -49,25 +49,12 @@ locals { cidr_block = subnet.cidr_block } ] - cluster_vpc_subnets = { + cluster_vpc_subnets = { private = local.subnets, - edge = local.subnets, + edge = local.subnets, transit = local.subnets } - # cluster_vpc_subnets = { - # zone-1 = [ - # for zone in module.vpc.subnet_zone_list : - # { - # id = zone.id - # zone = zone.zone - # cidr_block = zone.cidr - # } - # ] - # } - - # OCP Configuration - # OCP Configuration ocp_worker_pools = [ { subnet_prefix = "private" @@ -95,10 +82,7 @@ locals { } ] - - // subnets = [ for v in module.vpc.vpc.subnet : { id = v.subnet_ids} ] - - } +} module "vpc" { @@ -107,7 +91,7 @@ module "vpc" { resource_group_id = module.resource_group.resource_group_id locations = ["us-south-1", "us-south-2", "us-south-3"] vpc_tags = var.resource_tags - address_prefixes = [ + address_prefixes = [ { name = "${var.prefix}-us-south-1" location = "us-south-1" @@ -131,16 +115,16 @@ module "vpc" { create_gateway = true public_gateway_name_prefix = "${var.prefix}-pw" number_of_addresses = 16 - + } module "security_group" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/security-group?ref=update_submodules" + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/security-group?ref=update_submodules" create_security_group = true name = "${var.prefix}-vpc-sg" vpc_id = module.vpc.vpc.vpc_id - resource_group_id = module.resource_group.resource_group_id - security_group_rules = [ + resource_group_id = module.resource_group.resource_group_id + security_group_rules = [ { name = "allow_all_inbound" remote = "0.0.0.0/0" @@ -148,82 +132,83 @@ module "security_group" { } ] } + module "network_acl" { source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/network-acl?ref=update_submodules" name = "${var.prefix}-vpc-acl" vpc_id = module.vpc.vpc.vpc_id resource_group_id = module.resource_group.resource_group_id - rules = [ - { - name = "iks-create-worker-nodes-inbound" - action = "allow" - source = "161.26.0.0/16" - destination = "0.0.0.0/0" - direction = "inbound" - }, - { - name = "iks-nodes-to-master-inbound" - action = "allow" - source = "166.8.0.0/14" - destination = "0.0.0.0/0" - direction = "inbound" - }, - { - name = "iks-create-worker-nodes-outbound" - action = "allow" - source = "0.0.0.0/0" - destination = "161.26.0.0/16" - direction = "outbound" - }, - { - name = "iks-worker-to-master-outbound" - action = "allow" - source = "0.0.0.0/0" - destination = "166.8.0.0/14" - direction = "outbound" - }, - { - name = "allow-all-https-inbound" - source = "0.0.0.0/0" - action = "allow" - destination = "0.0.0.0/0" - direction = "inbound" - tcp = { - source_port_min = 443 - source_port_max = 443 - port_min = 1 - port_max = 65535 - } - }, - { - name = "allow-all-https-outbound" - source = "0.0.0.0/0" - action = "allow" - destination = "0.0.0.0/0" - direction = "outbound" - tcp = { - source_port_min = 1 - source_port_max = 65535 - port_min = 443 - port_max = 443 - } - }, - { - name = "deny-all-outbound" - action = "deny" - source = "0.0.0.0/0" - destination = "0.0.0.0/0" - direction = "outbound" - }, - { - name = "deny-all-inbound" - action = "deny" - source = "0.0.0.0/0" - destination = "0.0.0.0/0" - direction = "inbound" + rules = [ + { + name = "iks-create-worker-nodes-inbound" + action = "allow" + source = "161.26.0.0/16" + destination = "0.0.0.0/0" + direction = "inbound" + }, + { + name = "iks-nodes-to-master-inbound" + action = "allow" + source = "166.8.0.0/14" + destination = "0.0.0.0/0" + direction = "inbound" + }, + { + name = "iks-create-worker-nodes-outbound" + action = "allow" + source = "0.0.0.0/0" + destination = "161.26.0.0/16" + direction = "outbound" + }, + { + name = "iks-worker-to-master-outbound" + action = "allow" + source = "0.0.0.0/0" + destination = "166.8.0.0/14" + direction = "outbound" + }, + { + name = "allow-all-https-inbound" + source = "0.0.0.0/0" + action = "allow" + destination = "0.0.0.0/0" + direction = "inbound" + tcp = { + source_port_min = 443 + source_port_max = 443 + port_min = 1 + port_max = 65535 } - ] - tags = var.tags + }, + { + name = "allow-all-https-outbound" + source = "0.0.0.0/0" + action = "allow" + destination = "0.0.0.0/0" + direction = "outbound" + tcp = { + source_port_min = 1 + source_port_max = 65535 + port_min = 443 + port_max = 443 + } + }, + { + name = "deny-all-outbound" + action = "deny" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "outbound" + }, + { + name = "deny-all-inbound" + action = "deny" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "inbound" + } + ] + tags = var.tags } # OCP CLUSTER creation diff --git a/examples/basic/outputs.tf b/examples/basic/outputs.tf index 03dae42d..6ac61f44 100644 --- a/examples/basic/outputs.tf +++ b/examples/basic/outputs.tf @@ -8,5 +8,5 @@ output "vpc" { description = "Configuration of newly created or existing VPC instace." - value = module.vpc + value = module.vpc } diff --git a/examples/basic/variables.tf b/examples/basic/variables.tf index 2b39aeb1..ef464326 100644 --- a/examples/basic/variables.tf +++ b/examples/basic/variables.tf @@ -63,4 +63,4 @@ variable "tags" { description = "List of Tags for the ACL" type = list(string) default = null -} \ No newline at end of file +} diff --git a/examples/trusted-profiles-authentication/README.md b/examples/trusted-profiles-authentication/README.md new file mode 100644 index 00000000..4fdeb95f --- /dev/null +++ b/examples/trusted-profiles-authentication/README.md @@ -0,0 +1,18 @@ +# Example that uses trusted profiles (container authentication) + +This example shows how external secrets can be configured to use trusted profile with compute resource-based authentication. + +Resources with trusted profiles with compute resource can authenticate with IAM tokens that are generated by the compute resources. This type of authentication avoids key-related operations, such as rotation. + +The example shows also how to configure external secrets with trusted profiles in a multitenant configuration, by creating two different trusted profiles, the related external secrets resources, the stores and deploying the ESO into the cluster + +This example includes the following operations: + +- Creates a Secrets Manager instance and two different secrets groups for each tenant (represented by tenant namespace) +- Creates a trusted profile to access the created instance and secret group with secrets reader-only access, for each tenant +- Installs and configures external secrets operator +- Creates a secret store with trusted profile container authentication for each tenant + +In addiction to the mentioned details, this example includes guidance on: +- customising the deployment of external secrets operator on specific cluster's worker nodes: variable `eso_deployment_nodes_configuration` allows to configure nodeSelector and tolerations setting for the ESO deployment +- creating Virtual Private Endpoints (VPE) towards IAM and Secrets Manager private endpoints in the case of `service_endpoints` set to **private** diff --git a/examples/trusted-profiles-authentication/main.tf b/examples/trusted-profiles-authentication/main.tf new file mode 100644 index 00000000..b2b74549 --- /dev/null +++ b/examples/trusted-profiles-authentication/main.tf @@ -0,0 +1,217 @@ +module "resource_group" { + source = "terraform-ibm-modules/resource-group/ibm" + version = "1.1.6" + # if an existing resource group is not set (null) create a new one using prefix + resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null + existing_resource_group_name = var.resource_group +} + +locals { + sm_service_plan = "trial" + trusted_profile_name = "${var.prefix}-eso-tp" + secret_manager_instance_name = "${var.prefix}-sm-instance" #checkov:skip=CKV_SECRET_6 + secret_group_name = "${var.prefix}-sm-secret-group" #checkov:skip=CKV_SECRET_6 + es_kubernetes_namespaces = ["${var.prefix}-tp-test-1", "${var.prefix}-tp-test-2"] # namespace to create the externalsecrets resources for secrets sync + + validate_sm_region_cnd = var.existing_sm_instance_guid != null && var.existing_sm_instance_region == null + validate_sm_region_msg = "existing_sm_instance_region must also be set when value given for existing_sm_instance_guid." + # tflint-ignore: terraform_unused_declarations + validate_sm_region_chk = regex( + "^${local.validate_sm_region_msg}$", + (!local.validate_sm_region_cnd + ? local.validate_sm_region_msg + : "")) + + # validation for secrets manager crn to be set for existing secrets manager instance if using private service endpoints + validate_sm_crn_cnd = var.existing_sm_instance_guid != null && var.existing_sm_instance_crn == null && var.service_endpoints == "private" + validate_sm_crn_msg = "existing_sm_instance_crn must also be set when value given for existing_sm_instance_guid if service_endpoints is private." + # tflint-ignore: terraform_unused_declarations + validate_sm_crn_chk = regex( + "^${local.validate_sm_crn_msg}$", + (!local.validate_sm_crn_cnd + ? local.validate_sm_crn_msg + : "")) + + sm_guid = var.existing_sm_instance_guid == null ? ibm_resource_instance.secrets_manager[0].guid : var.existing_sm_instance_guid + # if service_endpoints is not private the crn for SM is not needed because of VPE creation is not needed + sm_crn = var.existing_sm_instance_crn == null ? (var.service_endpoints == "private" ? ibm_resource_instance.secrets_manager[0].crn : "") : var.existing_sm_instance_crn + + sm_region = var.existing_sm_instance_region == null ? var.region : var.existing_sm_instance_region + +} + +############################################################################## +## Create prerequisite. Secrets Manager, Secret Group and a Trusted Profile +############################################################################## + +resource "ibm_resource_instance" "secrets_manager" { + count = var.existing_sm_instance_guid == null ? 1 : 0 + name = local.secret_manager_instance_name + service = "secrets-manager" + plan = local.sm_service_plan + location = local.sm_region + resource_group_id = module.resource_group.resource_group_id + timeouts { + create = "20m" # Extending provisioning time to 20 minutes + } +} + +## Secret Group for organizing secrets + +module "secrets_manager_groups" { + source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" + version = "1.2.2" + count = length(kubernetes_namespace.examples) + region = local.sm_region + secrets_manager_guid = local.sm_guid + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_group_name = "${local.secret_group_name}_${count.index}" + secret_group_description = "secret ${count.index} used for examples" #tfsec:ignore:general-secrets-no-plaintext-exposure +} + +# We retrieve metadata of the cluster to get the cluster's CRN. +# The CRN then will be used in the Trusted Profile Rule +data "ibm_container_vpc_cluster" "cluster" { + name = var.cluster_name_id +} + +################################################################## +## Example creating two arbitrary dummy secrets for test +################################################################## + +# creating the namespace to create the ES resources and the dummy secrets +resource "kubernetes_namespace" "examples" { + count = length(local.es_kubernetes_namespaces) + metadata { + name = local.es_kubernetes_namespaces[count.index] + } +} + +module "sm_arbitrary_secrets" { + count = length(kubernetes_namespace.examples) + source = "terraform-ibm-modules/secrets-manager-secret/ibm" + version = "1.3.2" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_id = module.secrets_manager_groups[count.index].secret_group_id + secret_type = "arbitrary" + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_name = "${var.prefix}-eso-test-dummy-secret-${count.index}" #checkov:skip=CKV_SECRET_6 + secret_description = "# ${count.index} example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_payload_password = "dummy_secret_value_${count.index}" # pragma: allowlist secret +} + +# creating trusted profiles +module "external_secrets_trusted_profiles" { + count = length(kubernetes_namespace.examples) + source = "../../modules/eso-trusted-profile" + trusted_profile_name = "${local.trusted_profile_name}_${count.index}" + secrets_manager_guid = local.sm_guid + secret_groups_id = [module.secrets_manager_groups[count.index].secret_group_id] + tp_cluster_crn = data.ibm_container_vpc_cluster.cluster.crn + trusted_profile_claim_rule_type = "ROKS_SA" + tp_namespace = var.eso_namespace +} + +######################################################################## +## Deploying ESO +######################################################################## + +module "external_secrets_operator" { + source = "../../" + eso_namespace = var.eso_namespace + eso_cluster_nodes_configuration = var.eso_deployment_nodes_configuration == null ? null : { + nodeSelector = { + label = "dedicated" + value = var.eso_deployment_nodes_configuration + } + tolerations = { + key = "dedicated" + operator = "Equal" + value = var.eso_deployment_nodes_configuration + effect = "NoExecute" + } + } +} + +######################################################################## +## Deploying ESO SecretStores +######################################################################## + +module "eso_namespace_secretstores" { + count = length(kubernetes_namespace.examples) + depends_on = [ + module.external_secrets_operator + ] + source = "../../modules/eso-secretstore" + eso_authentication = "trusted_profile" + region = local.sm_region + sstore_namespace = kubernetes_namespace.examples[count.index].metadata[0].name + sstore_secrets_manager_guid = local.sm_guid + sstore_store_name = "${kubernetes_namespace.examples[count.index].metadata[0].name}-store" # each store created with the name of the namespace with "-store" as suffix + sstore_trusted_profile_name = module.external_secrets_trusted_profiles[count.index].trusted_profile_name + service_endpoints = var.service_endpoints + sstore_helm_rls_name = "es-store-${count.index}" + sstore_secret_name = "secretstore-api-key" #checkov:skip=CKV_SECRET_6 +} + +###################################### +# creating eso externalsecret objects +###################################### + +module "external_secrets" { + depends_on = [ + module.eso_namespace_secretstores + ] + count = length(kubernetes_namespace.examples) + source = "../../modules/eso-external-secret" + eso_store_scope = "namespace" + es_kubernetes_namespace = kubernetes_namespace.examples[count.index].metadata[0].name + es_kubernetes_secret_name = "${var.prefix}-arbitrary-arb-${count.index}" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "arbitrary" #checkov:skip=CKV_SECRET_6 + sm_secret_id = module.sm_arbitrary_secrets[count.index].secret_id #checkov:skip=CKV_SECRET_6 + es_kubernetes_secret_type = "opaque" + es_kubernetes_secret_data_key = "apikey" + es_refresh_interval = "5m" + eso_store_name = "${kubernetes_namespace.examples[count.index].metadata[0].name}-store" # each store created with the name of the namespace with "-store" as suffix + es_container_registry = "us.icr.io" + es_container_registry_email = "goldeneye@us.ibm.com" + es_helm_rls_name = "es-${count.index}" +} + +###################################### +# creating VPEs +###################################### + +module "vpes" { + source = "terraform-ibm-modules/vpe-gateway/ibm" + version = "4.3.0" + count = var.service_endpoints == "private" ? 1 : 0 + region = var.region + prefix = "vpe" + vpc_name = var.vpe_vpc_name + vpc_id = var.vpe_vpc_id + subnet_zone_list = [ + for index, subnet in var.vpe_vpc_subnets : { + name = "${var.region}-${index}" + zone = "${var.region}-${index}" + id = subnet + acl_name = "acl" + public_gateway = true + } + ] + resource_group_id = var.vpe_vpc_resource_group_id # pragma: allowlist secret + security_group_ids = [var.vpe_vpc_security_group_id] + cloud_services = [] + cloud_service_by_crn = [ + { + name = "iam-${var.region}" + crn = "crn:v1:bluemix:public:iam-svcs:global:::endpoint:private.iam.cloud.ibm.com" + }, + { + name = "sm-${var.region}" + crn = local.sm_crn + } + ] + service_endpoints = "private" +} diff --git a/examples/trusted-profiles-authentication/outputs.tf b/examples/trusted-profiles-authentication/outputs.tf new file mode 100644 index 00000000..b16a1a35 --- /dev/null +++ b/examples/trusted-profiles-authentication/outputs.tf @@ -0,0 +1,3 @@ +############################################################################## +# Outputs +############################################################################## diff --git a/examples/trusted-profiles-authentication/providers.tf b/examples/trusted-profiles-authentication/providers.tf new file mode 100644 index 00000000..249afe5e --- /dev/null +++ b/examples/trusted-profiles-authentication/providers.tf @@ -0,0 +1,40 @@ +data "ibm_container_cluster_config" "cluster_config" { + cluster_name_id = var.cluster_name_id + resource_group_id = module.resource_group.resource_group_id +} + +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key +} + +data "ibm_iam_auth_token" "token_data" {} + +provider "restapi" { + uri = "https:" + write_returns_object = true + debug = false # set to true to show detailed logs, but use carefully as it might print API key values. + headers = { + Accept = "application/json" + Authorization = data.ibm_iam_auth_token.token_data.iam_access_token + Content-Type = "application/json" + } +} + +provider "kubernetes" { + client_certificate = data.ibm_container_cluster_config.cluster_config.admin_certificate + client_key = data.ibm_container_cluster_config.cluster_config.admin_key + cluster_ca_certificate = data.ibm_container_cluster_config.cluster_config.ca_certificate + host = data.ibm_container_cluster_config.cluster_config.host + token = data.ibm_container_cluster_config.cluster_config.token +} + + +provider "helm" { + kubernetes { + client_certificate = data.ibm_container_cluster_config.cluster_config.admin_certificate + client_key = data.ibm_container_cluster_config.cluster_config.admin_key + cluster_ca_certificate = data.ibm_container_cluster_config.cluster_config.ca_certificate + host = data.ibm_container_cluster_config.cluster_config.host + token = data.ibm_container_cluster_config.cluster_config.token + } +} diff --git a/examples/trusted-profiles-authentication/variables.tf b/examples/trusted-profiles-authentication/variables.tf new file mode 100644 index 00000000..00328482 --- /dev/null +++ b/examples/trusted-profiles-authentication/variables.tf @@ -0,0 +1,95 @@ +variable "ibmcloud_api_key" { + type = string + description = "APIkey that's associated with the account to use, set via environment variable TF_VAR_ibmcloud_api_key" + sensitive = true +} + +variable "cluster_name_id" { + type = string + description = "Cluser Name or ID where resources will be created" +} + +variable "resource_group" { + type = string + description = "An existing resource group name to use for this example, if unset a new resource group will be created" + default = null +} + + +variable "prefix" { + description = "Prefix for name of all resource created by this example" + type = string + default = "eso-tp" +} + +variable "service_endpoints" { + type = string + description = "The service endpoint type to communicate with the provided secrets manager instance. Possible values are `public` or `private`. This also will set the iam endpoint for containerAuth when enabling Trusted Profile/CR based authentication." + default = "public" +} + +variable "region" { + type = string + description = "Region where resources will be created" + default = "us-south" +} + +variable "existing_sm_instance_guid" { + type = string + description = "Existing Secrets Manager GUID. If not provided a new instance will be provisioned" + default = null +} + +variable "existing_sm_instance_crn" { + type = string + description = "Existing Secrets Manager CRN. If existing_sm_instance_guid is provided, also this input must be provided." + default = null +} + +variable "existing_sm_instance_region" { + type = string + description = "Existing Secrets Manager Region. Required if value is passed into var.existing_sm_instance_guid" + default = null +} + +variable "eso_namespace" { + type = string + description = "Namespace to deploy the External secrets Operator into" + default = "es-operator" +} + +variable "vpe_vpc_name" { + type = string + description = "Name of the VPC where to create the VPE endpoint in the case of private connections. Required only if service_endpoints is private" + default = null +} + +variable "vpe_vpc_id" { + type = string + description = "ID of the VPC where to create the VPE endpoint in the case of private connections. Required only if service_endpoints is private" + default = null +} + +variable "vpe_vpc_subnets" { + type = list(string) + description = "List of VPC subnets to use to create the VPE endpoints. Required only if service_endpoints is private" + default = [] +} + +variable "vpe_vpc_resource_group_id" { + type = string + description = "ID of resource group to use to create the VPE endpoint in the case of private connections (the same of the VPC usually). Required only if service_endpoints is private" + default = null +} + +variable "vpe_vpc_security_group_id" { + type = string + description = "ID of security group to use to create the VPE endpoint in the case of private connections (one of the VPC). Required only if service_endpoints is private" + default = null +} + +variable "eso_deployment_nodes_configuration" { + type = string + description = "Configuration to deploy ESO on specific cluster nodes. The value of this variable will be used for NodeSelector label value and tolerations configuration. If null standard ESO deployment is done." + default = null +} diff --git a/examples/trusted-profiles-authentication/version.tf b/examples/trusted-profiles-authentication/version.tf new file mode 100644 index 00000000..4ab524a2 --- /dev/null +++ b/examples/trusted-profiles-authentication/version.tf @@ -0,0 +1,21 @@ +terraform { + required_version = ">= 1.0.0" + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = ">= 2.16.1" + } + helm = { + source = "hashicorp/helm" + version = ">= 2.8.0" + } + ibm = { + source = "IBM-Cloud/ibm" + version = ">= 1.52.0" + } + restapi = { + source = "Mastercard/restapi" + version = ">= 1.18.0" + } + } +} diff --git a/main.tf b/main.tf index b39cc714..1fc6d8b1 100644 --- a/main.tf +++ b/main.tf @@ -7,11 +7,11 @@ ## Install ESO locals { - eso_image_tag_digest = "v0.10.5-ubi@sha256:2d4583ff06dd9e186076cc11f2c4782f17e32da28fe18b1144d89806213d17cd" # datasource: icr.io/ibm-iac/external-secrets - eso_image_repo = "icr.io/ibm-iac/external-secrets" + eso_image_tag_digest = var.eso_image_tag_digest + eso_image_repo = var.eso_image_repo - reloader_image_tag_digest = "v1.1.0-ubi@sha256:d2adccbac4da35a8b31aa21bfbc44da47d8676a41b91fd8f3b192f386f72aa20" # datasource: icr.io/ibm-iac/reloader - reloader_image_repo = "icr.io/ibm-iac/reloader" + reloader_image_tag_digest = var.reloader_image_tag_digest + reloader_image_repo = var.reloader_image_repo } # creating namespace to deploy ESO into RedHat ServiceMesh diff --git a/tests/pr_test.go b/tests/pr_test.go index b1ded690..b63f6e08 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -2,7 +2,6 @@ package test import ( - "log" "os" "testing" "time" @@ -12,7 +11,6 @@ import ( "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/cloudinfo" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/common" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testhelper" - "gopkg.in/yaml.v3" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -20,18 +18,9 @@ import ( const resourceGroup = "geretain-test-ext-secrets-sync" const basicExampleTerraformDir = "examples/basic" -// deploying eso on edge node to have it able to connect to SM and IAM on public network -const esoWorkersSelector = "edge" - -// Define a struct with fields that match the structure of the YAML data -const yamlLocation = "../common-dev-assets/common-go-assets/common-permanent-resources.yaml" - type Config struct { SmGuid string `yaml:"secretsManagerGuid"` - SmCRN string `yaml:"secretsManagerCRN"` SmRegion string `yaml:"secretsManagerRegion"` - RgId string `yaml:"resourceGroupTestPermanentId"` - CisName string `yaml:"cisInstanceName"` // secret ids for the secrets composing the imported certificate to create ImpCertIntermediateSecretId string `yaml:"imported_certificate_intermediate_secret_id"` @@ -50,83 +39,7 @@ type Config struct { } var smGuid string -var smCRN string var smRegion string -var rgId string -var cisName string -var impCertificateSmRegion string -var impCertificateSmGuid string -var impCertIntermediateSecretID string -var impCertPublicSecretID string -var impCertPrivateSecretID string -var acmeLEPrivateKeySmGuid string -var acmeLEPrivateKeySmRegion string -var acmeLEPrivateKeySecretId string -var sdnlbServiceIdName string - -// terraform vars for all-combined test (including Upgrade one) -var allCombinedTerraformVars map[string]interface{} - -// TestMain will be run before any parallel tests, used to read data from yaml for use with tests -func TestMain(m *testing.M) { - // Read the YAML file contents - data, err := os.ReadFile(yamlLocation) - if err != nil { - log.Fatal(err) - } - // Create a struct to hold the YAML data - var config Config - // Unmarshal the YAML data into the struct - err = yaml.Unmarshal(data, &config) - if err != nil { - log.Fatal(err) - } - - // Parse the SM guid and region from data and setting all-combined test input values used in TestRunDefaultExample and TestRunUpgradeExample - smGuid = config.SmGuid - smCRN = config.SmCRN - smRegion = config.SmRegion - cisName = config.CisName - rgId = config.RgId - impCertIntermediateSecretID = config.ImpCertIntermediateSecretId - impCertPrivateSecretID = config.ImpCertPrivateSecretId - impCertPublicSecretID = config.ImpCertPublicSecretId - acmeLEPrivateKeySmGuid = config.AcmeLEPrivateKeySmGuid - acmeLEPrivateKeySmRegion = config.AcmeLEPrivateKeySmRegion - acmeLEPrivateKeySecretId = config.AcmeLEPrivateKeySecretId - impCertificateSmGuid = config.ImpCertificateSmGuid - impCertificateSmRegion = config.ImpCertificateSmRegion - - sdnlbServiceIdName = config.SdnlbServiceidName - err = log.Output(1, "TestMain using sdnlbServiceIdName "+sdnlbServiceIdName) - if err != nil { - log.Fatal(err) - } - - allCombinedTerraformVars = map[string]interface{}{ - "existing_cis_instance_name": cisName, - "existing_cis_instance_resource_group_id": rgId, - // imported certificate and public certificate creation management - "existing_sm_instance_crn": smCRN, - "existing_sm_instance_guid": smGuid, - "existing_sm_instance_region": smRegion, - "imported_certificate_sm_region": impCertificateSmRegion, - "imported_certificate_sm_id": impCertificateSmGuid, - "imported_certificate_intermediate_secret_id": impCertIntermediateSecretID, - "imported_certificate_public_secret_id": impCertPublicSecretID, - "imported_certificate_private_secret_id": impCertPrivateSecretID, - "acme_letsencrypt_private_key_secret_id": acmeLEPrivateKeySecretId, - "acme_letsencrypt_private_key_sm_id": acmeLEPrivateKeySmGuid, - "acme_letsencrypt_private_key_sm_region": acmeLEPrivateKeySmRegion, - "eso_deployment_nodes_configuration": esoWorkersSelector, - // setting skip_iam_authorization_policy to true because using the existing secrets manager instance and the policy already exists - "skip_iam_authorization_policy": true, - "existing_sdnlb_serviceid_name": sdnlbServiceIdName, - "service_endpoints": "public", - } - - os.Exit(m.Run()) -} var ignoreUpdates = []string{ "module.es_kubernetes_secret_usr_pass.helm_release.external_secrets_operator[0]", diff --git a/variables.tf b/variables.tf index 20b5f463..d70a16ba 100644 --- a/variables.tf +++ b/variables.tf @@ -150,3 +150,27 @@ variable "reloader_custom_values" { type = string default = null } + +variable "eso_image_repo" { + type = string + description = "The repository for the External Secrets Operator image. Default is `ghcr.io/external-secrets/external-secrets`." + default = "ghcr.io/external-secrets/external-secrets" +} + +variable "eso_image_tag_digest" { + type = string + description = "The tag or digest for the External Secrets Operator image. Provide a digest in the format `sha256:xxxxx...` for immutability or leave it as a tag version." + default = "v0.11.0-ubi@sha256:b5f685b86cf684020e863c6c2ed91e8a79cad68260d7149ddee073ece2573d6f" +} + +variable "reloader_image_repo" { + type = string + description = "The repository for the Stakater Reloader image. Default is `ghcr.io/stakater/reloader`." + default = "ghcr.io/stakater/reloader" +} + +variable "reloader_image_tag_digest" { + type = string + description = "The tag or digest for the Stakater Reloader image. Provide a digest in the format `sha256:xxxxx...` for immutability or leave it as a tag version." + default = "v1.2.0-ubi@sha256:375736e6690986559022cae504bebd8dfe14a37ac0305176f8826362c29732d6f" +} From 758af0fddf63a4e9d7b361f0cd050be5d9f46946 Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Wed, 1 Jan 2025 13:07:21 +0530 Subject: [PATCH 05/40] updated the image logic --- main.tf | 23 ++++++++++++++--------- renovate.json | 20 +++++++++++++++++++- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/main.tf b/main.tf index 1fc6d8b1..f97ba2c7 100644 --- a/main.tf +++ b/main.tf @@ -7,10 +7,13 @@ ## Install ESO locals { - eso_image_tag_digest = var.eso_image_tag_digest + eso_digest = "v0.11.0-ubi@sha256:b5f685b86cf684020e863c6c2ed91e8a79cad68260d7149ddee073ece2573d6f" + reloader_digest = "v1.2.0-ubi@sha256:375736e6690986559022cae504bebd8dfe14a37ac0305176f8826362c29732d6f" + + eso_image_tag_digest = var.eso_image_tag_digest != null || var.eso_image_tag_digest != "" ? var.eso_image_tag_digest : local.eso_digest eso_image_repo = var.eso_image_repo - reloader_image_tag_digest = var.reloader_image_tag_digest + reloader_image_tag_digest = var.reloader_image_tag_digest != null ? var.reloader_image_tag_digest : local.reloader_digest reloader_image_repo = var.reloader_image_repo } @@ -180,11 +183,12 @@ EOF resource "helm_release" "external_secrets_operator" { depends_on = [module.eso_namespace, data.kubernetes_namespace.existing_eso_namespace] - name = "external-secrets" - namespace = local.eso_namespace - chart = "oci://icr.io/ibm-iac-charts/external-secrets" - version = "0.10.5" - wait = true + name = "external-secrets" + namespace = local.eso_namespace + chart = "external-secrets/external-secrets" + version = "0.12.1" + wait = true + repository = "https://charts.external-secrets.io" set { name = "image.repository" @@ -231,9 +235,10 @@ resource "helm_release" "pod_reloader" { count = var.reloader_deployed == true ? 1 : 0 name = "reloader" namespace = local.eso_namespace - chart = "oci://icr.io/ibm-iac-charts/reloader" - version = "1.1.0" + chart = "stakater/reloader" + version = "1.2.0" wait = true + repository = "https://stakater.github.io/stakater-charts" # Set the deployment image name and tag set { diff --git a/renovate.json b/renovate.json index 8954b604..808f9f18 100644 --- a/renovate.json +++ b/renovate.json @@ -1,4 +1,22 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": ["github>terraform-ibm-modules/common-dev-assets:commonRenovateConfig"] + "extends": ["github>terraform-ibm-modules/common-dev-assets:commonRenovateConfig"], + "regexManagers": [ + { + "fileMatch": ["\\.tf$"], + "matchStrings": [ + "[\\w-]+_digest\\s*=\\s*\"(?[\\w.-]+)@(?sha256:[a-f0-9]+)\"" + ], + "datasourceTemplate": "docker" + } + ], + "labels": ["renovate"], + "packageRules": [ + { + "matchManagers": ["regex"], + "groupName": "Image Digest Updates", + "commitMessageExtra": "to latest digest", + "group": true + } + ] } From 2ffdff03f432c26ba1ac9284a96be5f6ee9c3c13 Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Tue, 7 Jan 2025 13:03:31 +0530 Subject: [PATCH 06/40] resolve conflicts --- README.md | 4 +--- common-dev-assets | 2 +- examples/basic/main.tf | 6 +++--- examples/basic/version.tf | 2 +- main.tf | 12 +++++------- variables.tf | 12 ------------ version.tf | 2 +- 7 files changed, 12 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 13e60a45..a4a31e2d 100644 --- a/README.md +++ b/README.md @@ -505,7 +505,7 @@ module "es_kubernetes_secret" { | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.3.0 | +| [terraform](#requirement\_terraform) | >= 1.0.0 | | [helm](#requirement\_helm) | >= 2.11.0, < 3.0.0 | | [kubernetes](#requirement\_kubernetes) | >= 2.16.1, < 3.0.0 | @@ -538,8 +538,6 @@ module "es_kubernetes_secret" { | [reloader\_deployed](#input\_reloader\_deployed) | Whether to deploy reloader or not https://github.com/stakater/Reloader | `bool` | `true` | no | | [reloader\_ignore\_configmaps](#input\_reloader\_ignore\_configmaps) | Whether to ignore configmap changes or not | `bool` | `false` | no | | [reloader\_ignore\_secrets](#input\_reloader\_ignore\_secrets) | Whether to ignore secret changes or not | `bool` | `false` | no | -| [reloader\_image\_repo](#input\_reloader\_image\_repo) | The repository for the Stakater Reloader image. Default is `ghcr.io/stakater/reloader`. | `string` | `"ghcr.io/stakater/reloader"` | no | -| [reloader\_image\_tag\_digest](#input\_reloader\_image\_tag\_digest) | The tag or digest for the Stakater Reloader image. Provide a digest in the format `sha256:xxxxx...` for immutability or leave it as a tag version. | `string` | `"v1.2.0-ubi@sha256:375736e6690986559022cae504bebd8dfe14a37ac0305176f8826362c29732d6f"` | no | | [reloader\_is\_argo\_rollouts](#input\_reloader\_is\_argo\_rollouts) | Enable Argo Rollouts | `bool` | `false` | no | | [reloader\_is\_openshift](#input\_reloader\_is\_openshift) | Enable OpenShift DeploymentConfigs | `bool` | `true` | no | | [reloader\_log\_format](#input\_reloader\_log\_format) | The log format to use for reloader. Possible values are `json` or `text`. Default value is `json` | `string` | `"text"` | no | diff --git a/common-dev-assets b/common-dev-assets index 65fb5703..cd5f6cf3 160000 --- a/common-dev-assets +++ b/common-dev-assets @@ -1 +1 @@ -Subproject commit 65fb57037c604e5f4ec5b63c8f093d583df2d53a +Subproject commit cd5f6cf3583de87d96d2bcf6852d9ad7af7a5193 diff --git a/examples/basic/main.tf b/examples/basic/main.tf index 949ff4dc..02faada0 100644 --- a/examples/basic/main.tf +++ b/examples/basic/main.tf @@ -299,7 +299,7 @@ module "secrets_manager_group_acct" { module "iam_secrets_engine" { count = var.existing_sm_instance_guid == null ? 1 : 0 source = "terraform-ibm-modules/secrets-manager-iam-engine/ibm" - version = "1.2.3" + version = "1.2.6" region = local.sm_region secrets_manager_guid = ibm_resource_instance.secrets_manager[0].guid iam_secret_generator_service_id_name = "${var.prefix}-sid:0.0.1:${ibm_resource_instance.secrets_manager[0].name}-iam-secret-generator:automated:simple-service:secret-manager:" @@ -364,7 +364,7 @@ module "external_secrets_operator" { ## Create dynamic Service ID API key and add to secret manager module "dynamic_serviceid_apikey1" { source = "terraform-ibm-modules/iam-serviceid-apikey-secrets-manager/ibm" - version = "1.1.0" + version = "1.1.1" region = local.sm_region #tfsec:ignore:general-secrets-no-plaintext-exposure sm_iam_secret_name = "${var.prefix}-${var.sm_iam_secret_name}" @@ -418,7 +418,7 @@ locals { # Create username_password secret and store in secret manager module "sm_userpass_secret" { source = "terraform-ibm-modules/secrets-manager-secret/ibm" - version = "1.3.2" + version = "1.4.0" region = local.sm_region secrets_manager_guid = local.sm_guid secret_group_id = local.sm_acct_id diff --git a/examples/basic/version.tf b/examples/basic/version.tf index 79a5e10c..ca7aad4c 100644 --- a/examples/basic/version.tf +++ b/examples/basic/version.tf @@ -15,7 +15,7 @@ terraform { } ibm = { source = "IBM-Cloud/ibm" - version = "= 1.68.0" + version = "= 1.70.0" } } } diff --git a/main.tf b/main.tf index f97ba2c7..d8ccd7d5 100644 --- a/main.tf +++ b/main.tf @@ -7,14 +7,13 @@ ## Install ESO locals { - eso_digest = "v0.11.0-ubi@sha256:b5f685b86cf684020e863c6c2ed91e8a79cad68260d7149ddee073ece2573d6f" - reloader_digest = "v1.2.0-ubi@sha256:375736e6690986559022cae504bebd8dfe14a37ac0305176f8826362c29732d6f" + eso_digest = "v0.11.0-ubi@sha256:b5f685b86cf684020e863c6c2ed91e8a79cad68260d7149ddee073ece2573d6f" eso_image_tag_digest = var.eso_image_tag_digest != null || var.eso_image_tag_digest != "" ? var.eso_image_tag_digest : local.eso_digest eso_image_repo = var.eso_image_repo - reloader_image_tag_digest = var.reloader_image_tag_digest != null ? var.reloader_image_tag_digest : local.reloader_digest - reloader_image_repo = var.reloader_image_repo + reloader_image_tag_digest = "v1.2.1-ubi@sha256:78d3b7269d00df1b9550584dba817299b5842c48038db1f1603255914033307f" # datasource: icr.io/ibm-iac/reloader + reloader_image_repo = "icr.io/ibm-iac/reloader" } # creating namespace to deploy ESO into RedHat ServiceMesh @@ -185,7 +184,7 @@ resource "helm_release" "external_secrets_operator" { name = "external-secrets" namespace = local.eso_namespace - chart = "external-secrets/external-secrets" + chart = "external-secrets" version = "0.12.1" wait = true repository = "https://charts.external-secrets.io" @@ -235,10 +234,9 @@ resource "helm_release" "pod_reloader" { count = var.reloader_deployed == true ? 1 : 0 name = "reloader" namespace = local.eso_namespace - chart = "stakater/reloader" + chart = "oci://icr.io/ibm-iac-charts/reloader" version = "1.2.0" wait = true - repository = "https://stakater.github.io/stakater-charts" # Set the deployment image name and tag set { diff --git a/variables.tf b/variables.tf index d70a16ba..adadc1b6 100644 --- a/variables.tf +++ b/variables.tf @@ -162,15 +162,3 @@ variable "eso_image_tag_digest" { description = "The tag or digest for the External Secrets Operator image. Provide a digest in the format `sha256:xxxxx...` for immutability or leave it as a tag version." default = "v0.11.0-ubi@sha256:b5f685b86cf684020e863c6c2ed91e8a79cad68260d7149ddee073ece2573d6f" } - -variable "reloader_image_repo" { - type = string - description = "The repository for the Stakater Reloader image. Default is `ghcr.io/stakater/reloader`." - default = "ghcr.io/stakater/reloader" -} - -variable "reloader_image_tag_digest" { - type = string - description = "The tag or digest for the Stakater Reloader image. Provide a digest in the format `sha256:xxxxx...` for immutability or leave it as a tag version." - default = "v1.2.0-ubi@sha256:375736e6690986559022cae504bebd8dfe14a37ac0305176f8826362c29732d6f" -} diff --git a/version.tf b/version.tf index 60946dae..dfc5b80a 100644 --- a/version.tf +++ b/version.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 1.3.0" + required_version = ">= 1.0.0" required_providers { # Use "greater than or equal to" range in modules kubernetes = { From 4944e7ac33f09e327f14a28363f01bd40cec3324 Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Sat, 11 Jan 2025 18:26:45 +0530 Subject: [PATCH 07/40] testing --- examples/basic/main.tf | 873 +++++++++++++++++++----------------- examples/basic/outputs.tf | 12 + examples/basic/variables.tf | 22 + 3 files changed, 493 insertions(+), 414 deletions(-) diff --git a/examples/basic/main.tf b/examples/basic/main.tf index 02faada0..1b5502fa 100644 --- a/examples/basic/main.tf +++ b/examples/basic/main.tf @@ -2,26 +2,26 @@ # Locals ############################################################################## -locals { - - # general - validate_sm_region_cnd = var.existing_sm_instance_guid != null && var.existing_sm_instance_region == null - validate_sm_region_msg = "existing_sm_instance_region must also be set when value given for existing_sm_instance_guid." - # tflint-ignore: terraform_unused_declarations - validate_sm_region_chk = regex( - "^${local.validate_sm_region_msg}$", - (!local.validate_sm_region_cnd - ? local.validate_sm_region_msg - : "")) - - sm_guid = var.existing_sm_instance_guid == null ? ibm_resource_instance.secrets_manager[0].guid : var.existing_sm_instance_guid - - # https://github.ibm.com/GoldenEye/issues/issues/5268 - deployment region will match to sm_region as workaround - sm_region = var.existing_sm_instance_region == null ? var.region : var.existing_sm_instance_region - sm_acct_id = var.existing_sm_instance_guid == null ? module.iam_secrets_engine[0].acct_secret_group_id : module.secrets_manager_group_acct[0].secret_group_id - es_namespace_apikey = "es-operator" # pragma: allowlist secret - eso_namespace = "apikeynspace1" -} +# locals { + +# # general +# validate_sm_region_cnd = var.existing_sm_instance_guid != null && var.existing_sm_instance_region == null +# validate_sm_region_msg = "existing_sm_instance_region must also be set when value given for existing_sm_instance_guid." +# # tflint-ignore: terraform_unused_declarations +# validate_sm_region_chk = regex( +# "^${local.validate_sm_region_msg}$", +# (!local.validate_sm_region_cnd +# ? local.validate_sm_region_msg +# : "")) + +# sm_guid = var.existing_sm_instance_guid == null ? ibm_resource_instance.secrets_manager[0].guid : var.existing_sm_instance_guid + +# # https://github.ibm.com/GoldenEye/issues/issues/5268 - deployment region will match to sm_region as workaround +# sm_region = var.existing_sm_instance_region == null ? var.region : var.existing_sm_instance_region +# sm_acct_id = var.existing_sm_instance_guid == null ? module.iam_secrets_engine[0].acct_secret_group_id : module.secrets_manager_group_acct[0].secret_group_id +# es_namespace_apikey = "es-operator" # pragma: allowlist secret +# eso_namespace = "apikeynspace1" +# } ################################################################## # Resource Group @@ -38,76 +38,111 @@ module "resource_group" { ################################################################## # Create VPC, public gateway and subnets ################################################################## - + # cidr_zone_combinations = flatten([ + # for cidr in local.vpc_cidr_bases : [ + # for zone in var.zones : { + # cidr_base = cidr + # zone = zone + # } + # ] + # ]) + + # subnets = [ + # for subnet in module.vpc.subnets : + # { + # id = subnet.id + # zone = subnet.zone + # cidr_block = subnet.cidr_block + # } + # ] + # cluster_vpc_subnets = { + # private = local.subnets, + # edge = local.subnets, + # transit = local.subnets + # } locals { - subnets = [ - for subnet in module.vpc.vpc.subnets : - { - id = subnet.id - zone = subnet.zone - cidr_block = subnet.cidr_block - } - ] - cluster_vpc_subnets = { - private = local.subnets, - edge = local.subnets, - transit = local.subnets + subnets = flatten([ + for k, v in module.zone_subnet_addrs :[ + for network in v.networks : { + zone = k + cidr = network.cidr_block + } + # { + # zone = k + # cidrs = v.networks + # } + # for zone in cidr.networks : { + # cidr = zone.cidr_block + + # } + ] + ]) +} + + + + # cidr_blocks = ["192.168.0.0/20", "192.168.16.0/20", "192.168.32.0/20"] + + # ocp_worker_pools = [ + # { + # subnet_prefix = "private" + # pool_name = "default" + # machine_type = "bx2.4x16" + # workers_per_zone = 1 + # labels = { "dedicated" : "private" } + # operating_system = "REDHAT_8_64" + # }, + # { + # subnet_prefix = "edge" + # pool_name = "edge" + # machine_type = "bx2.4x16" + # workers_per_zone = 1 + # labels = { "dedicated" : "edge" } + # operating_system = "REDHAT_8_64" + # }, + # { + # subnet_prefix = "transit" + # pool_name = "transit" + # machine_type = "bx2.4x16" + # workers_per_zone = 1 + # labels = { "dedicated" : "transit" } + # operating_system = "REDHAT_8_64" + # } + # ] + +output "subnets" { + value = local.subnets +} + +resource "null_resource" "subnet_mappings" { + count = length(var.zones) + + triggers = { + name = "zone-${var.zones[count.index]}" + new_bits = 2 } +} - ocp_worker_pools = [ - { - subnet_prefix = "private" - pool_name = "default" - machine_type = "bx2.4x16" - workers_per_zone = 1 - labels = { "dedicated" : "private" } - operating_system = "REDHAT_8_64" - }, - { - subnet_prefix = "edge" - pool_name = "edge" - machine_type = "bx2.4x16" - workers_per_zone = 1 - labels = { "dedicated" : "edge" } - operating_system = "REDHAT_8_64" - }, - { - subnet_prefix = "transit" - pool_name = "transit" - machine_type = "bx2.4x16" - workers_per_zone = 1 - labels = { "dedicated" : "transit" } - operating_system = "REDHAT_8_64" - } - ] +module "zone_subnet_addrs" { + source = "git::https://github.com/hashicorp/terraform-cidr-subnets.git?ref=v1.0.0" + for_each = var.cidr_bases + base_cidr_block = each.value + + networks = null_resource.subnet_mappings[*].triggers } +# output "zone_subnet_addrs" { +# value = module.zone_subnet_addrs +# } module "vpc" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git?ref=update_submodules" + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git?ref=v1.5.0" vpc_name = "${var.prefix}-vpc" resource_group_id = module.resource_group.resource_group_id - locations = ["us-south-1", "us-south-2", "us-south-3"] + locations = [] vpc_tags = var.resource_tags - address_prefixes = [ - { - name = "${var.prefix}-us-south-1" - location = "us-south-1" - ip_range = "10.10.10.0/24" - }, - { - name = "${var.prefix}-us-south-2" - location = "us-south-2" - ip_range = "10.10.20.0/24" - }, - { - name = "${var.prefix}-us-south-3" - location = "us-south-3" - ip_range = "10.10.30.0/24" - } - ] subnet_name_prefix = "${var.prefix}-subnet" default_network_acl_name = "${var.prefix}-nacl" default_routing_table_name = "${var.prefix}-routing-table" @@ -118,340 +153,350 @@ module "vpc" { } -module "security_group" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/security-group?ref=update_submodules" - create_security_group = true - name = "${var.prefix}-vpc-sg" - vpc_id = module.vpc.vpc.vpc_id - resource_group_id = module.resource_group.resource_group_id - security_group_rules = [ - { - name = "allow_all_inbound" - remote = "0.0.0.0/0" - direction = "inbound" - } - ] -} - -module "network_acl" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/network-acl?ref=update_submodules" - name = "${var.prefix}-vpc-acl" - vpc_id = module.vpc.vpc.vpc_id - resource_group_id = module.resource_group.resource_group_id - rules = [ - { - name = "iks-create-worker-nodes-inbound" - action = "allow" - source = "161.26.0.0/16" - destination = "0.0.0.0/0" - direction = "inbound" - }, - { - name = "iks-nodes-to-master-inbound" - action = "allow" - source = "166.8.0.0/14" - destination = "0.0.0.0/0" - direction = "inbound" - }, - { - name = "iks-create-worker-nodes-outbound" - action = "allow" - source = "0.0.0.0/0" - destination = "161.26.0.0/16" - direction = "outbound" - }, - { - name = "iks-worker-to-master-outbound" - action = "allow" - source = "0.0.0.0/0" - destination = "166.8.0.0/14" - direction = "outbound" - }, - { - name = "allow-all-https-inbound" - source = "0.0.0.0/0" - action = "allow" - destination = "0.0.0.0/0" - direction = "inbound" - tcp = { - source_port_min = 443 - source_port_max = 443 - port_min = 1 - port_max = 65535 - } - }, - { - name = "allow-all-https-outbound" - source = "0.0.0.0/0" - action = "allow" - destination = "0.0.0.0/0" - direction = "outbound" - tcp = { - source_port_min = 1 - source_port_max = 65535 - port_min = 443 - port_max = 443 - } - }, - { - name = "deny-all-outbound" - action = "deny" - source = "0.0.0.0/0" - destination = "0.0.0.0/0" - direction = "outbound" - }, - { - name = "deny-all-inbound" - action = "deny" - source = "0.0.0.0/0" - destination = "0.0.0.0/0" - direction = "inbound" - } - ] - tags = var.tags -} - +# module "address_prefix"{ +# source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/vpc-address-prefix" +# count = local.subnets +# } + +# module "subnets" { +# source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/subnet" +# count = local.subnets + +# } + +# module "security_group" { +# source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/security-group?ref=update_submodules" +# create_security_group = true +# name = "${var.prefix}-vpc-sg" +# vpc_id = module.vpc.vpc.vpc_id +# resource_group_id = module.resource_group.resource_group_id +# security_group_rules = [ +# { +# name = "allow_all_inbound" +# remote = "0.0.0.0/0" +# direction = "inbound" +# } +# ] +# } + +# module "network_acl" { +# source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/network-acl?ref=update_submodules" +# name = "${var.prefix}-vpc-acl" +# vpc_id = module.vpc.vpc.vpc_id +# resource_group_id = module.resource_group.resource_group_id +# rules = [ +# { +# name = "iks-create-worker-nodes-inbound" +# action = "allow" +# source = "161.26.0.0/16" +# destination = "0.0.0.0/0" +# direction = "inbound" +# }, +# { +# name = "iks-nodes-to-master-inbound" +# action = "allow" +# source = "166.8.0.0/14" +# destination = "0.0.0.0/0" +# direction = "inbound" +# }, +# { +# name = "iks-create-worker-nodes-outbound" +# action = "allow" +# source = "0.0.0.0/0" +# destination = "161.26.0.0/16" +# direction = "outbound" +# }, +# { +# name = "iks-worker-to-master-outbound" +# action = "allow" +# source = "0.0.0.0/0" +# destination = "166.8.0.0/14" +# direction = "outbound" +# }, +# { +# name = "allow-all-https-inbound" +# source = "0.0.0.0/0" +# action = "allow" +# destination = "0.0.0.0/0" +# direction = "inbound" +# tcp = { +# source_port_min = 443 +# source_port_max = 443 +# port_min = 1 +# port_max = 65535 +# } +# }, +# { +# name = "allow-all-https-outbound" +# source = "0.0.0.0/0" +# action = "allow" +# destination = "0.0.0.0/0" +# direction = "outbound" +# tcp = { +# source_port_min = 1 +# source_port_max = 65535 +# port_min = 443 +# port_max = 443 +# } +# }, +# { +# name = "deny-all-outbound" +# action = "deny" +# source = "0.0.0.0/0" +# destination = "0.0.0.0/0" +# direction = "outbound" +# }, +# { +# name = "deny-all-inbound" +# action = "deny" +# source = "0.0.0.0/0" +# destination = "0.0.0.0/0" +# direction = "inbound" +# } +# ] +# tags = var.tags +# } # OCP CLUSTER creation -module "ocp_base" { - source = "terraform-ibm-modules/base-ocp-vpc/ibm" - version = "3.34.0" - cluster_name = "${var.prefix}-vpc" - resource_group_id = module.resource_group.resource_group_id - region = var.region - force_delete_storage = true - vpc_id = module.vpc.vpc.vpc_id - vpc_subnets = local.cluster_vpc_subnets - worker_pools = local.ocp_worker_pools - tags = [] - use_existing_cos = false - # outbound required by cluster proxy - disable_outbound_traffic_protection = true -} - -############################################################################## -# Init cluster config for helm and kubernetes providers -############################################################################## - -data "ibm_container_cluster_config" "cluster_config" { - cluster_name_id = module.ocp_base.cluster_id - resource_group_id = module.resource_group.resource_group_id -} - -# Wait time to allow cluster refreshes components after provisioning -resource "time_sleep" "wait_45_seconds" { - depends_on = [data.ibm_container_cluster_config.cluster_config] - create_duration = "45s" -} - -# Create namespace for apikey auth -resource "kubernetes_namespace" "apikey_namespace" { - - metadata { - name = local.es_namespace_apikey - } - lifecycle { - ignore_changes = [ - metadata[0].annotations, - metadata[0].labels - ] - } - depends_on = [ - time_sleep.wait_45_seconds - ] -} - -######################################## -# Secrets-Manager and IAM configuration -######################################## - -# IAM user policy, Secret Manager instance, Service ID for IAM engine, IAM service ID policies, associated Service ID API key stored in a secret object in account level secret-group and IAM engine configuration -resource "ibm_resource_instance" "secrets_manager" { - count = var.existing_sm_instance_guid == null ? 1 : 0 - name = "${var.prefix}-sm" - service = "secrets-manager" - plan = var.sm_service_plan - location = local.sm_region - tags = var.resource_tags - resource_group_id = module.resource_group.resource_group_id - timeouts { - create = "30m" # Extending provisioning time to 30 minutes - } - provider = ibm.ibm-sm -} - -# Additional Secrets-Manager Secret-Group for SERVICE level secrets -module "secrets_manager_group_acct" { - source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" - version = "1.2.2" - count = var.existing_sm_instance_guid == null ? 0 : 1 - region = local.sm_region - secrets_manager_guid = local.sm_guid - #tfsec:ignore:general-secrets-no-plaintext-exposure - secret_group_name = "${var.prefix}-account-secret-group" #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value - secret_group_description = "Secret-Group for storing account credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure - depends_on = [module.iam_secrets_engine] - providers = { - ibm = ibm.ibm-sm - } -} - -# Configure instance with IAM engine -module "iam_secrets_engine" { - count = var.existing_sm_instance_guid == null ? 1 : 0 - source = "terraform-ibm-modules/secrets-manager-iam-engine/ibm" - version = "1.2.6" - region = local.sm_region - secrets_manager_guid = ibm_resource_instance.secrets_manager[0].guid - iam_secret_generator_service_id_name = "${var.prefix}-sid:0.0.1:${ibm_resource_instance.secrets_manager[0].name}-iam-secret-generator:automated:simple-service:secret-manager:" - iam_secret_generator_apikey_name = "${var.prefix}-iam-secret-generator-apikey" - new_secret_group_name = "${var.prefix}-account-secret-group" - iam_secret_generator_apikey_secret_name = "${var.prefix}-iam-secret-generator-apikey-secret" - iam_engine_name = "iam-engine" - providers = { - ibm = ibm.ibm-sm - } -} - -################################################################## -# Create service-id, policy to pull secrets from secret manager -################################################################## - -# Create service-id -resource "ibm_iam_service_id" "secret_puller" { - name = "sid:0.0.1:${var.prefix}-secret-puller:automated:simple-service:secret-manager:" - description = "ServiceID that can pull secrets from Secret Manager" -} - -# Create policy to allow new service id to pull secrets from secrets manager -resource "ibm_iam_service_policy" "secret_puller_policy" { - iam_service_id = ibm_iam_service_id.secret_puller.id - roles = ["Viewer", "SecretsReader"] - - resources { - service = "secrets-manager" - resource_instance_id = local.sm_guid - resource_type = "secret-group" - resource = local.sm_acct_id - } -} - -################################################################## -# ESO deployment -################################################################## - -module "external_secrets_operator" { - source = "../../" - eso_namespace = local.eso_namespace - - eso_cluster_nodes_configuration = { - nodeSelector = { - label = "dedicated" - value = "edge" - } - tolerations = { - key = "dedicated" - operator = "Equal" - value = "edge" - effect = "NoExecute" - } - } - - depends_on = [ - kubernetes_namespace.apikey_namespace - ] -} -# -## Create dynamic Service ID API key and add to secret manager -module "dynamic_serviceid_apikey1" { - source = "terraform-ibm-modules/iam-serviceid-apikey-secrets-manager/ibm" - version = "1.1.1" - region = local.sm_region - #tfsec:ignore:general-secrets-no-plaintext-exposure - sm_iam_secret_name = "${var.prefix}-${var.sm_iam_secret_name}" - sm_iam_secret_description = "Example of dynamic IAM secret / apikey" #tfsec:ignore:general-secrets-no-plaintext-exposure - serviceid_id = ibm_iam_service_id.secret_puller.id - secrets_manager_guid = local.sm_guid - secret_group_id = local.sm_acct_id - depends_on = [module.iam_secrets_engine, ibm_iam_service_policy.secret_puller_policy, ibm_iam_service_id.secret_puller] - providers = { - ibm = ibm.ibm-sm - } -} - -## Data source to get API Key from secret manager secret-puller-secret -data "ibm_sm_iam_credentials_secret" "secret_puller_secret" { - instance_id = local.sm_guid - #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static type - secret_id = module.dynamic_serviceid_apikey1.secret_id - provider = ibm.ibm-sm -} - -################################################################## -# ESO ClusterStore creation with apikey authentication -################################################################## -module "eso_clusterstore" { - source = "../../modules/eso-clusterstore" - eso_authentication = "api_key" - clusterstore_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key - region = local.sm_region - clusterstore_helm_rls_name = "cluster-store" - clusterstore_secret_name = "generic-cluster-api-key" #checkov:skip=CKV_SECRET_6 - clusterstore_name = "cluster-store" - clusterstore_secrets_manager_guid = local.sm_guid - eso_namespace = local.eso_namespace - service_endpoints = "public" - depends_on = [ - module.external_secrets_operator, - ] -} - -################################################################## -# creation of generic username/password secret -# (for example to store artifactory username and API key) -################################################################## - -locals { - # secret value for sm_userpass_secret - userpass_apikey = sensitive("password-payload-example") -} - -# Create username_password secret and store in secret manager -module "sm_userpass_secret" { - source = "terraform-ibm-modules/secrets-manager-secret/ibm" - version = "1.4.0" - region = local.sm_region - secrets_manager_guid = local.sm_guid - secret_group_id = local.sm_acct_id - #tfsec:ignore:general-secrets-no-plaintext-exposure - secret_name = "${var.prefix}-usernamepassword-secret" # checkov:skip=CKV_SECRET_6 - secret_description = "example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure # checkov:skip=CKV_SECRET_6 - secret_payload_password = local.userpass_apikey - secret_type = "username_password" #checkov:skip=CKV_SECRET_6 - #tfsec:ignore:general-secrets-no-plaintext-exposure - secret_username = "artifactory-user" # checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value - secret_auto_rotation = false - secret_auto_rotation_interval = 0 - secret_auto_rotation_unit = null - providers = { - ibm = ibm.ibm-sm - } -} - -################################################################## -# ESO externalsecrets with cluster scope and apikey authentication -################################################################## - -# ESO externalsecret with cluster scope creating a dockerconfigjson type secret -module "external_secret_usr_pass" { - depends_on = [module.external_secrets_operator] - source = "../../modules/eso-external-secret" - es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 - sm_secret_type = "username_password" #checkov:skip=CKV_SECRET_6 - sm_secret_id = module.sm_userpass_secret.secret_id - es_kubernetes_namespace = kubernetes_namespace.apikey_namespace.metadata[0].name - eso_store_name = "cluster-store" - es_container_registry = "wcp-my-team-docker-local.artifactory.swg-devops.com" - es_kubernetes_secret_name = "dockerconfigjson-uc" #checkov:skip=CKV_SECRET_6 - es_helm_rls_name = "es-docker-uc" - reloader_watching = true -} +# module "ocp_base" { +# source = "terraform-ibm-modules/base-ocp-vpc/ibm" +# version = "3.34.0" +# cluster_name = "${var.prefix}-vpc" +# resource_group_id = module.resource_group.resource_group_id +# region = var.region +# force_delete_storage = true +# vpc_id = module.vpc.vpc.vpc_id +# vpc_subnets = local.cluster_vpc_subnets +# worker_pools = local.ocp_worker_pools +# tags = [] +# use_existing_cos = false +# # outbound required by cluster proxy +# disable_outbound_traffic_protection = true +# } + +# ############################################################################## +# # Init cluster config for helm and kubernetes providers +# ############################################################################## + +# data "ibm_container_cluster_config" "cluster_config" { +# cluster_name_id = module.ocp_base.cluster_id +# resource_group_id = module.resource_group.resource_group_id +# } + +# # Wait time to allow cluster refreshes components after provisioning +# resource "time_sleep" "wait_45_seconds" { +# depends_on = [data.ibm_container_cluster_config.cluster_config] +# create_duration = "45s" +# } + +# # Create namespace for apikey auth +# resource "kubernetes_namespace" "apikey_namespace" { + +# metadata { +# name = local.es_namespace_apikey +# } +# lifecycle { +# ignore_changes = [ +# metadata[0].annotations, +# metadata[0].labels +# ] +# } +# depends_on = [ +# time_sleep.wait_45_seconds +# ] +# } + +# ######################################## +# # Secrets-Manager and IAM configuration +# ######################################## + +# # IAM user policy, Secret Manager instance, Service ID for IAM engine, IAM service ID policies, associated Service ID API key stored in a secret object in account level secret-group and IAM engine configuration +# resource "ibm_resource_instance" "secrets_manager" { +# count = var.existing_sm_instance_guid == null ? 1 : 0 +# name = "${var.prefix}-sm" +# service = "secrets-manager" +# plan = var.sm_service_plan +# location = local.sm_region +# tags = var.resource_tags +# resource_group_id = module.resource_group.resource_group_id +# timeouts { +# create = "30m" # Extending provisioning time to 30 minutes +# } +# provider = ibm.ibm-sm +# } + +# # Additional Secrets-Manager Secret-Group for SERVICE level secrets +# module "secrets_manager_group_acct" { +# source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" +# version = "1.2.2" +# count = var.existing_sm_instance_guid == null ? 0 : 1 +# region = local.sm_region +# secrets_manager_guid = local.sm_guid +# #tfsec:ignore:general-secrets-no-plaintext-exposure +# secret_group_name = "${var.prefix}-account-secret-group" #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value +# secret_group_description = "Secret-Group for storing account credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure +# depends_on = [module.iam_secrets_engine] +# providers = { +# ibm = ibm.ibm-sm +# } +# } + +# # Configure instance with IAM engine +# module "iam_secrets_engine" { +# count = var.existing_sm_instance_guid == null ? 1 : 0 +# source = "terraform-ibm-modules/secrets-manager-iam-engine/ibm" +# version = "1.2.6" +# region = local.sm_region +# secrets_manager_guid = ibm_resource_instance.secrets_manager[0].guid +# iam_secret_generator_service_id_name = "${var.prefix}-sid:0.0.1:${ibm_resource_instance.secrets_manager[0].name}-iam-secret-generator:automated:simple-service:secret-manager:" +# iam_secret_generator_apikey_name = "${var.prefix}-iam-secret-generator-apikey" +# new_secret_group_name = "${var.prefix}-account-secret-group" +# iam_secret_generator_apikey_secret_name = "${var.prefix}-iam-secret-generator-apikey-secret" +# iam_engine_name = "iam-engine" +# providers = { +# ibm = ibm.ibm-sm +# } +# } + +# ################################################################## +# # Create service-id, policy to pull secrets from secret manager +# ################################################################## + +# # Create service-id +# resource "ibm_iam_service_id" "secret_puller" { +# name = "sid:0.0.1:${var.prefix}-secret-puller:automated:simple-service:secret-manager:" +# description = "ServiceID that can pull secrets from Secret Manager" +# } + +# # Create policy to allow new service id to pull secrets from secrets manager +# resource "ibm_iam_service_policy" "secret_puller_policy" { +# iam_service_id = ibm_iam_service_id.secret_puller.id +# roles = ["Viewer", "SecretsReader"] + +# resources { +# service = "secrets-manager" +# resource_instance_id = local.sm_guid +# resource_type = "secret-group" +# resource = local.sm_acct_id +# } +# } + +# ################################################################## +# # ESO deployment +# ################################################################## + +# module "external_secrets_operator" { +# source = "../../" +# eso_namespace = local.eso_namespace + +# eso_cluster_nodes_configuration = { +# nodeSelector = { +# label = "dedicated" +# value = "edge" +# } +# tolerations = { +# key = "dedicated" +# operator = "Equal" +# value = "edge" +# effect = "NoExecute" +# } +# } + +# depends_on = [ +# kubernetes_namespace.apikey_namespace +# ] +# } +# # +# ## Create dynamic Service ID API key and add to secret manager +# module "dynamic_serviceid_apikey1" { +# source = "terraform-ibm-modules/iam-serviceid-apikey-secrets-manager/ibm" +# version = "1.1.1" +# region = local.sm_region +# #tfsec:ignore:general-secrets-no-plaintext-exposure +# sm_iam_secret_name = "${var.prefix}-${var.sm_iam_secret_name}" +# sm_iam_secret_description = "Example of dynamic IAM secret / apikey" #tfsec:ignore:general-secrets-no-plaintext-exposure +# serviceid_id = ibm_iam_service_id.secret_puller.id +# secrets_manager_guid = local.sm_guid +# secret_group_id = local.sm_acct_id +# depends_on = [module.iam_secrets_engine, ibm_iam_service_policy.secret_puller_policy, ibm_iam_service_id.secret_puller] +# providers = { +# ibm = ibm.ibm-sm +# } +# } + +# ## Data source to get API Key from secret manager secret-puller-secret +# data "ibm_sm_iam_credentials_secret" "secret_puller_secret" { +# instance_id = local.sm_guid +# #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static type +# secret_id = module.dynamic_serviceid_apikey1.secret_id +# provider = ibm.ibm-sm +# } + +# ################################################################## +# # ESO ClusterStore creation with apikey authentication +# ################################################################## +# module "eso_clusterstore" { +# source = "../../modules/eso-clusterstore" +# eso_authentication = "api_key" +# clusterstore_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key +# region = local.sm_region +# clusterstore_helm_rls_name = "cluster-store" +# clusterstore_secret_name = "generic-cluster-api-key" #checkov:skip=CKV_SECRET_6 +# clusterstore_name = "cluster-store" +# clusterstore_secrets_manager_guid = local.sm_guid +# eso_namespace = local.eso_namespace +# service_endpoints = "public" +# depends_on = [ +# module.external_secrets_operator, +# ] +# } + +# ################################################################## +# # creation of generic username/password secret +# # (for example to store artifactory username and API key) +# ################################################################## + +# locals { +# # secret value for sm_userpass_secret +# userpass_apikey = sensitive("password-payload-example") +# } + +# # Create username_password secret and store in secret manager +# module "sm_userpass_secret" { +# source = "terraform-ibm-modules/secrets-manager-secret/ibm" +# version = "1.4.0" +# region = local.sm_region +# secrets_manager_guid = local.sm_guid +# secret_group_id = local.sm_acct_id +# #tfsec:ignore:general-secrets-no-plaintext-exposure +# secret_name = "${var.prefix}-usernamepassword-secret" # checkov:skip=CKV_SECRET_6 +# secret_description = "example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure # checkov:skip=CKV_SECRET_6 +# secret_payload_password = local.userpass_apikey +# secret_type = "username_password" #checkov:skip=CKV_SECRET_6 +# #tfsec:ignore:general-secrets-no-plaintext-exposure +# secret_username = "artifactory-user" # checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value +# secret_auto_rotation = false +# secret_auto_rotation_interval = 0 +# secret_auto_rotation_unit = null +# providers = { +# ibm = ibm.ibm-sm +# } +# } + +# ################################################################## +# # ESO externalsecrets with cluster scope and apikey authentication +# ################################################################## + +# # ESO externalsecret with cluster scope creating a dockerconfigjson type secret +# module "external_secret_usr_pass" { +# depends_on = [module.external_secrets_operator] +# source = "../../modules/eso-external-secret" +# es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 +# sm_secret_type = "username_password" #checkov:skip=CKV_SECRET_6 +# sm_secret_id = module.sm_userpass_secret.secret_id +# es_kubernetes_namespace = kubernetes_namespace.apikey_namespace.metadata[0].name +# eso_store_name = "cluster-store" +# es_container_registry = "wcp-my-team-docker-local.artifactory.swg-devops.com" +# es_kubernetes_secret_name = "dockerconfigjson-uc" #checkov:skip=CKV_SECRET_6 +# es_helm_rls_name = "es-docker-uc" +# reloader_watching = true +# } diff --git a/examples/basic/outputs.tf b/examples/basic/outputs.tf index 6ac61f44..ef91e695 100644 --- a/examples/basic/outputs.tf +++ b/examples/basic/outputs.tf @@ -10,3 +10,15 @@ output "vpc" { description = "Configuration of newly created or existing VPC instace." value = module.vpc } + +# output "security_group" { +# value = module.security_group +# } + +# output "network_acl" { +# value= module.network_acl +# } + +# output "subnets" { +# value = module.subnet +# } \ No newline at end of file diff --git a/examples/basic/variables.tf b/examples/basic/variables.tf index ef464326..dfae95fe 100644 --- a/examples/basic/variables.tf +++ b/examples/basic/variables.tf @@ -64,3 +64,25 @@ variable "tags" { type = list(string) default = null } + +variable "zones" { + description = "List of zones" + type = list(string) + default = ["1", "2", "3"] +} + +variable "cidr_bases" { + description = "A list of base CIDR blocks for each network zone" + type = map(string) + default = { + private = "192.168.0.0/20", + transit = "192.168.16.0/20", + edge = "192.168.32.0/20" + } +} + +variable "new_bits" { + description = "Number of additional address bits to use for numbering the new networks" + type = number + default = 2 +} From dfff84cdef4dd9d35c5a70cb06912e82826b5326 Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Mon, 13 Jan 2025 15:00:25 +0530 Subject: [PATCH 08/40] updated the all-combined example --- README.md | 4 +- common-dev-assets | 2 +- cra-config.yaml | 6 +- examples/all-combined/README.md | 87 ++ examples/all-combined/clusterstore.tf | 154 ++++ examples/all-combined/importedcertificate.tf | 88 ++ examples/all-combined/kv.tf | 70 ++ examples/all-combined/main.tf | 444 +++++++++ examples/all-combined/outputs.tf | 23 + examples/all-combined/privatecertificate.tf | 60 ++ examples/all-combined/provider.tf | 31 + examples/all-combined/publiccertificate.tf | 67 ++ examples/all-combined/sdnlb-secret.tf | 37 + examples/all-combined/secretsmanager.tf | 152 ++++ examples/all-combined/secretstore.tf | 201 ++++ .../all-combined/tpauth_cluster_sstore.tf | 102 +++ .../all-combined/tpauth_namespaced_sstore.tf | 344 +++++++ examples/all-combined/variables.tf | 355 ++++++++ examples/all-combined/version.tf | 25 + examples/basic/main.tf | 858 +++++++++--------- examples/basic/outputs.tf | 23 +- examples/basic/variables.tf | 91 +- examples/basic/version.tf | 4 + main.tf | 17 +- tests/pr_test.go | 173 ++++ variables.tf | 12 - 26 files changed, 2936 insertions(+), 494 deletions(-) create mode 100644 examples/all-combined/README.md create mode 100644 examples/all-combined/clusterstore.tf create mode 100644 examples/all-combined/importedcertificate.tf create mode 100644 examples/all-combined/kv.tf create mode 100644 examples/all-combined/main.tf create mode 100644 examples/all-combined/outputs.tf create mode 100644 examples/all-combined/privatecertificate.tf create mode 100644 examples/all-combined/provider.tf create mode 100644 examples/all-combined/publiccertificate.tf create mode 100644 examples/all-combined/sdnlb-secret.tf create mode 100644 examples/all-combined/secretsmanager.tf create mode 100644 examples/all-combined/secretstore.tf create mode 100644 examples/all-combined/tpauth_cluster_sstore.tf create mode 100644 examples/all-combined/tpauth_namespaced_sstore.tf create mode 100644 examples/all-combined/variables.tf create mode 100644 examples/all-combined/version.tf diff --git a/README.md b/README.md index a4a31e2d..5aa3ead9 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ This module automates the installation and configuration of the [External Secret * [Examples](./examples) * [Basic Example](./examples/basic) * [Example that uses trusted profiles (container authentication)](./examples/trusted-profiles-authentication) + * [Example to deploy the External Secret Operator and to create a different set of resources in terms of secrets, secret groups, stores and auth configurations](./examples/all-combined) * [Contributing](#contributing) @@ -496,6 +497,7 @@ module "es_kubernetes_secret" { ## Examples +- [ Example to deploy the External Secret Operator and to create a different set of resources in terms of secrets, secret groups, stores and auth configurations](examples/all-combined) - [ Basic Example](examples/basic) - [ Example that uses trusted profiles (container authentication)](examples/trusted-profiles-authentication) @@ -529,8 +531,6 @@ module "es_kubernetes_secret" { |------|-------------|------|---------|:--------:| | [eso\_cluster\_nodes\_configuration](#input\_eso\_cluster\_nodes\_configuration) | Configuration to use to customise ESO deployment on specific cluster nodes. Setting appropriate values will result in customising ESO helm release. Default value is null to keep ESO standard deployment. |
object({
nodeSelector = object({
label = string
value = string
})
tolerations = object({
key = string
operator = string
value = string
effect = string
})
})
| `null` | no | | [eso\_enroll\_in\_servicemesh](#input\_eso\_enroll\_in\_servicemesh) | Flag to enroll ESO into istio servicemesh | `bool` | `false` | no | -| [eso\_image\_repo](#input\_eso\_image\_repo) | The repository for the External Secrets Operator image. Default is `ghcr.io/external-secrets/external-secrets`. | `string` | `"ghcr.io/external-secrets/external-secrets"` | no | -| [eso\_image\_tag\_digest](#input\_eso\_image\_tag\_digest) | The tag or digest for the External Secrets Operator image. Provide a digest in the format `sha256:xxxxx...` for immutability or leave it as a tag version. | `string` | `"v0.11.0-ubi@sha256:b5f685b86cf684020e863c6c2ed91e8a79cad68260d7149ddee073ece2573d6f"` | no | | [eso\_namespace](#input\_eso\_namespace) | Namespace to create and be used to install ESO components including helm releases. If eso\_store\_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster\_store in it | `string` | `null` | no | | [eso\_pod\_configuration](#input\_eso\_pod\_configuration) | Configuration to use to customise ESO deployment on specific pods. Setting appropriate values will result in customising ESO helm release. Default value is {} to keep ESO standard deployment. Ignore the key if not required. |
object({
annotations = optional(object({
# The annotations for external secret controller pods.
external_secrets = optional(map(string), {})
# The annotations for external secret cert controller pods.
external_secrets_cert_controller = optional(map(string), {})
# The annotations for external secret controller pods.
external_secrets_webhook = optional(map(string), {})
}), {})

labels = optional(object({
# The labels for external secret controller pods.
external_secrets = optional(map(string), {})
# The labels for external secret cert controller pods.
external_secrets_cert_controller = optional(map(string), {})
# The labels for external secret controller pods.
external_secrets_webhook = optional(map(string), {})
}), {})
})
| `{}` | no | | [existing\_eso\_namespace](#input\_existing\_eso\_namespace) | Existing Namespace to be used to install ESO components including helm releases. If eso\_store\_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster\_store in it | `string` | `null` | no | diff --git a/common-dev-assets b/common-dev-assets index cd5f6cf3..66d1c66f 160000 --- a/common-dev-assets +++ b/common-dev-assets @@ -1 +1 @@ -Subproject commit cd5f6cf3583de87d96d2bcf6852d9ad7af7a5193 +Subproject commit 66d1c66f5e189696eb8769f8f10a8cc80816172f diff --git a/cra-config.yaml b/cra-config.yaml index b947753b..bd320bfc 100644 --- a/cra-config.yaml +++ b/cra-config.yaml @@ -1,9 +1,11 @@ -# More info about this file at https://github.com/terraform-ibm-modules/common-pipeline-assets/blob/main/.github/workflows/terraform-test-pipeline.md#cra-config-yaml version: "v1" CRA_TARGETS: - - CRA_TARGET: "examples/basic" + - CRA_TARGET: "examples/all-combined" CRA_IGNORE_RULES_FILE: "cra-tf-validate-ignore-rules.json" CRA_ENVIRONMENT_VARIABLES: # An optional map of environment variables for CRA, where the key is the variable name and value is the value. Useful for providing TF_VARs. TF_VAR_existing_cis_instance_name: "test_value_for_cis_instance_name" TF_VAR_existing_cis_instance_resource_group_id: "test_value_for_cis_instance_rg_id" TF_VAR_existing_sdnlb_serviceid_name: "test_value_for_existing_sdnlb_serviceid_name" + # SCC_INSTANCE_ID: "" # The SCC instance ID to use to download profile for CRA scan. If not provided, a default global value will be used. + # SCC_REGION: "" # The IBM Cloud region that the SCC instance is in. If not provided, a default global value will be used. + # PROFILE_ID: "" # The Profile ID input for CRA SCC scan. Ensure to use a US-specific ID. If not provided, a default global value will be used. diff --git a/examples/all-combined/README.md b/examples/all-combined/README.md new file mode 100644 index 00000000..d540f909 --- /dev/null +++ b/examples/all-combined/README.md @@ -0,0 +1,87 @@ +# Example to deploy the External Secret Operator and to create a different set of resources in terms of secrets, secret groups, stores and auth configurations + +This end-to-end example performs the following actions +- Loads an existing resource group or creates a new one +- Provisions a standard GoldenEye OCP infrastructure with VPC, COS instance and an OpenShift cluster +- Configures an hybrid ESO configuration with a set of different stores to cover use-cases + - a ClusterSecretStore with API key authentication + - a ClusterSecretStore with Trusted profile authentication + - two namespaced SecretStore with API key authentication + - two namespaced SecretStore with Trusted Profile authentication based on a policy restricted to a single secrets group + - one namespaced SecretStore with Trusted Profile authentication based on a policy restricted to multiple secrets groups + - one namespaced SecretStore with Trusted Profile authentication based on a policy not restricted to any secrets group +- Creates/Loads the following resources to complete the mentioned use-cases + - Loads an existing Secrets Manager instance or creates a new one + - Creates Secrets Manager IAM engine configuration and secret group(s) + - Creates service ID (secret-puller) configured with IAM policies to pull secrets from SM + - Deploys a dockerconfigjson secret for an artifactory registry + - Creates username_password Secrets Manager secret to store artifactory credentials + - Deploys external secrets in designated namespace + - Creates a ClusterSecretStore using API key authentication to access secrets from designated namespace + - Installs and configures external secret operator + - Deploys another dockerconfigjson secret for an artifactory registry + - Deploys external secrets in designated namespace + - Creates a ClusterSecretStore using Trusted Profile authentication to access secrets from designated namespace + - Deploys an opaque secret for Cloudant credentials (temporary disabled due to issue https://github.ibm.com/GoldenEye/issues/issues/7726) + - Creates Cloudant instance and resource key + - Creates arbitrary Secrets Manager secret to store resource key + - Deploys external secrets in designated namespace + - Uses existing ClusterSecretStore to access secrets from designated namespace + - Deploys a dockerconfigjson secret from an arbitrary secret to authenticate in container registry + - Creates arbitrary Secrets Manager secret to store existing API key + - Deploys external secrets in designated namespaces + - Creates a SecretStore (using API key authentication) to access secrets from designated namespace + - Deploys a dockerconfigjson secret from a dynamic IAM secret to authenticate in container registry + - Creates ServiceID (imagePull) with IAM policies to read from container registry namespace + - Creates IAM Secrets Manager secret and dynamic API key that is associated with a imagePull Service ID + - Deploys external secrets in designated namespaces + - Creates a SecretStore(using API key authentication) to access secrets from designated namespace + - Deploys a dockerconfigjson secret from a set of dynamic IAM secrets to authenticate in a set of container registries + - Creates a set of ServiceIDs (imagePull) with IAM policies to read from container registry namespace for each secret to create (`${var.prefix}-image-pull-service-id-chain-sec-1/2/3`) + - Creates a set of IAM Secrets Manager secrets and dynamic API key that are associated with the imagePull ServiceIDs created at the step above + - Deploys external secrets resource in designated namespaces for the dockerjsonconfig secret building the secrets chain and using an existing secrets store + - Creates and deploys a set of arbitrary secrets to cover the different use-cases for namespaced SecretStores + - Creates and deploys a public certificate through CIS integration and public certificate engine module + - Creates and deploys a private certificate and private certificate engine module + - Loads certificate components stored on Secrets Manager as arbitrary secrets and then use these to create and deploy an imported certificate with public and intermediate certificates and public certificate private key + - Creates and deploys a key-value secret with single key-value couple + - Creates and deploys a key-value secret with multiple key-value couples + - Creates a dynamic secret on Secrets Manager from the sDNLB entitled service ID and configures an ExternalSecret CRD on the cluster to create and synch the sDNLB secret with the expected format + + +In order to create the intermediate certificate the following parameters are needed: +- imported_certificate_sm_id: Secrets Manager ID where the componenents for the imported certificate are stored +- imported_certificate_sm_region: region of the Secrets Manager instance where the componenents for the imported certificate are stored +- imported_certificate_intermediate_secret_id: secret ID to load the intermediate certificate component for the imported certificate +- imported_certificate_public_secret_id: secret ID to load the public certificate component for the imported certificate +- imported_certificate_private_secret_id: secret ID to load the private key component for the imported certificate + +In order to generate the public certificate the following mutually exclusive parameters are needed: +1. `acme_letsencrypt_private_key`: the Let's Encrypt ACME private key value (more details available [here](https://cloud.ibm.com/docs/secrets-manager?topic=secrets-manager-prepare-order-certificates#create-acme-account)) +2. Let's Encrypt ACME Secrets Manager secret details: + - `acme_letsencrypt_private_key_secret_id`: secret ID to load the Let's Encrypt acme private key for the public certificate generation + - `acme_letsencrypt_private_key_sm_id`: Secrets Manager ID where the Let's Encrypt acme private key for the public certificate generation is stored + - `acme_letsencrypt_private_key_sm_region`: region of the Secrets Manager instance where the Let's Encrypt acme private key for the public certificate generation is stored + +If a value is provided for `acme_letsencrypt_private_key` the other ones are not needed and not used, otherwise if it is **null** all the remaining ones (Secrets Manager ID, region and secret ID for Let's Encrypt ACME key) are needed to create a public certificate. + +In the case all the mentioned parameters are left with their default **null** value, the related secrets will not be created. + +The example is split into separated templates related with their specific scope: +- main.tf for the VPC, cluster, VPE, ESO operator deployment and namespaces preliminary creation +- clusterstore.tf for ESO ClusterSecretsStore configuration with API key authentication, including two different externalsecrets and secret types configuration (username/password and arbitrary) +- secretstore.tf for ESO secretstore configuration with API key authentication and namespace isolation, including two different externalsecrets and secrets configuration (arbitrary and image pull API key secret using imagepull-apikey-secrets-manager-module) +- secretsmanager.tf for Secrets Manager instance configuration, along with IAM serviceID and API keys and secrets groups +- kv.tf for key-value (single and multiple keys) secrets +- publiccertificate.tf for public certificate management +- privatecertificate.tf for private certificate management +- importedcertificate.tf for imported certificate management +- tpauth_namespaced_sstore.tf for ESO SecretsStore and externalsecret configuration with Trusted Profile authentication and namespace isolation +- tpauth_cluster_sstore.tf for ESO ClusterSecretsStore and externalsecret configuration with Trusted Profile authentication + + +## Important note about input region and existing SecretManager region parameters + +Due to the https://github.ibm.com/GoldenEye/issues/issues/5268 the test is currently using the existing SecretManager region to deploy the VPC and the cluster if this value is not null. Instead if null it follows what set through `var.region` + +This logic is achieved through the local `sm_region` variable that is then used to create resources. diff --git a/examples/all-combined/clusterstore.tf b/examples/all-combined/clusterstore.tf new file mode 100644 index 00000000..07b2367c --- /dev/null +++ b/examples/all-combined/clusterstore.tf @@ -0,0 +1,154 @@ +############################################################################## +# This template shows how to create an ESO clusterstore, a secrets store cluster scoped, with api key authentication +# Two different secret types +# - username & password +# - arbitrary (for Cloudant resource key) +# are created and configured in two different externalsecret resources in two different namespaces +# leveraging on the same ESO clusterstore +# The username/password secret is stored into a dockerconfigjson K8s secret type +# The arbitrary secret is stored into an opaque K8s secret type +############################################################################## + +# creation of the ESO ClusterStore (cluster wide scope) with apikey authentication +module "eso_clusterstore" { + source = "../../modules/eso-clusterstore" + eso_authentication = "api_key" + clusterstore_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key + region = local.sm_region + clusterstore_helm_rls_name = "cluster-store" + clusterstore_secret_name = "generic-cluster-api-key" #checkov:skip=CKV_SECRET_6 + clusterstore_name = "cluster-store" + clusterstore_secrets_manager_guid = local.sm_guid + eso_namespace = var.eso_namespace + service_endpoints = var.service_endpoints + depends_on = [ + module.external_secrets_operator + ] +} + +################################################################## +# creation of generic username/password secret +# (for example to store artifactory username and API key) +################################################################## + +locals { + # secret value for sm_userpass_secret + userpass_apikey = sensitive("password-payload-example") +} + +# Create username_password secret and store in secret manager +module "sm_userpass_secret" { + source = "terraform-ibm-modules/secrets-manager-secret/ibm" + version = "1.4.0" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_id = module.secrets_manager_group.secret_group_id + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_name = "${var.prefix}-usernamepassword-secret" # checkov:skip=CKV_SECRET_6 + secret_description = "example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure # checkov:skip=CKV_SECRET_6 + secret_payload_password = local.userpass_apikey + secret_type = "username_password" #checkov:skip=CKV_SECRET_6 + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_username = "artifactory-user" # checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + secret_auto_rotation = false + secret_auto_rotation_interval = 0 + secret_auto_rotation_unit = null + providers = { + ibm = ibm.ibm-sm + } +} + +################################################################## +# ESO externalsecrets with cluster scope and apikey authentication +################################################################## + +# ESO externalsecret with cluster scope creating a dockerconfigjson type secret +module "external_secret_usr_pass" { + depends_on = [module.eso_clusterstore] + source = "../../modules/eso-external-secret" + es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "username_password" #checkov:skip=CKV_SECRET_6 + sm_secret_id = module.sm_userpass_secret.secret_id + es_kubernetes_namespace = kubernetes_namespace.apikey_namespaces[0].metadata[0].name + eso_store_name = "cluster-store" + es_container_registry = "wcp-my-team-docker-local.artifactory.swg-devops.com" + es_kubernetes_secret_name = "dockerconfigjson-uc" #checkov:skip=CKV_SECRET_6 + es_helm_rls_name = "es-docker-uc" +} + +### temporary disabled the test on the Cloudant resource key blocking the tests because of potential issue with Cloudant instance creation +### https://github.ibm.com/GoldenEye/issues/issues/7726 + +################################################################## +# creation of arbitrary secret to store Cloudant resource key +# A Cloudant instance is created in advance to create its resource key +################################################################## + +############################################################################## +# Basic cloudant instance + database +############################################################################## + +# module "cloudant" { +# source = "terraform-ibm-modules/cloudant/ibm" +# version = "1.1.7" +# resource_group_id = module.resource_group.resource_group_id +# instance_name = "${var.prefix}-cloudant" +# access_tags = [] +# region = var.region +# tags = var.resource_tags +# plan = "lite" +# database_config = [] +# } + +# # load cloudant instance details when ready +# data "ibm_cloudant" "instance" { +# # forcing on depend instead of id because it triggers a validation error +# depends_on = [module.cloudant] +# # id = module.cloudant.instance_id +# name = module.cloudant.instance_name +# resource_group_id = module.resource_group.resource_group_id +# } + +# # create resource key for cloudant instance +# resource "ibm_resource_key" "resource_key" { +# name = "cd-resource-key" +# role = "Manager" +# resource_instance_id = data.ibm_cloudant.instance.id +# timeouts { +# create = "15m" +# delete = "15m" +# } +# } + +# # Creates the arbitrary secret to store the cloudant resource key in secrets manager +# module "sm_arbitrary_cloudant_secret" { +# source = "terraform-ibm-modules/secrets-manager-secret/ibm" +# version = "1.1.1" +# region = local.sm_region +# secrets_manager_guid = local.sm_guid +# secret_group_id = module.secrets_manager_group.secret_group_id +# secret_type = "arbitrary" +# #tfsec:ignore:general-secrets-no-plaintext-exposure +# secret_name = "${var.prefix}-cloudant-rk-secret" #checkov:skip=CKV_SECRET_6 +# secret_description = "example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure +# secret_payload_password = ibm_resource_key.resource_key.credentials["apikey"] +# providers = { +# ibm = ibm.ibm-sm +# } +# } + +# # ESO externalsecret with cluster scope creating opaque type secret +# module "external_secret_arbitrary_cloudant" { +# depends_on = [module.eso_clusterstore] +# source = "../../modules/eso-external-secret" +# eso_store_scope = "cluster" +# es_kubernetes_secret_type = "opaque" +# sm_secret_type = "arbitrary" +# sm_secret_id = module.sm_arbitrary_cloudant_secret.secret_id +# es_kubernetes_namespace = kubernetes_namespace.apikey_namespaces[1].metadata[0].name +# eso_store_name = "cluster-store" +# es_refresh_interval = "5m" +# es_kubernetes_secret_data_key = "apikey" +# es_kubernetes_secret_name = "cloudant-opaque-arb" #checkov:skip=CKV_SECRET_6 +# es_helm_rls_name = "es-cloudant-arb" +# } diff --git a/examples/all-combined/importedcertificate.tf b/examples/all-combined/importedcertificate.tf new file mode 100644 index 00000000..8ef5cf35 --- /dev/null +++ b/examples/all-combined/importedcertificate.tf @@ -0,0 +1,88 @@ +################################################################## +# imported certificate for secrets manager +################################################################## + +locals { + + # validation for secrets manager region to be set for existing secrets manager instance + validate_imported_sm_region_cnd = var.imported_certificate_sm_id != null && var.imported_certificate_sm_region == null + validate_imported_sm_region_msg = "imported_certificate_sm_region must also be set when value given for imported_certificate_sm_id" + # tflint-ignore: terraform_unused_declarations + validate_imported_sm_region_chk = regex( + "^${local.validate_imported_sm_region_msg}$", + (!local.validate_imported_sm_region_cnd + ? local.validate_imported_sm_region_msg + : "")) + + validate_imported_sm_cnd = (var.imported_certificate_public_secret_id != null && var.imported_certificate_private_secret_id != null) && var.imported_certificate_sm_id == null + validate_imported_sm_msg = "If imported_certificate_public_secret_id and imported_certificate_private_secret_id to create an imported certificate also imported_certificate_sm_id must be set" + # tflint-ignore: terraform_unused_declarations + validate_imported_sm_chk = regex( + "^${local.validate_imported_sm_msg}$", + (!local.validate_imported_sm_cnd + ? local.validate_imported_sm_msg + : "")) +} + +# loading from Secrets Manager the three components (private key, intermediate and public cert) composing the imported certificate +data "ibm_sm_arbitrary_secret" "imported_certificate_intermediate" { + count = var.imported_certificate_intermediate_secret_id != null ? 1 : 0 + region = var.imported_certificate_sm_region + instance_id = var.imported_certificate_sm_id + secret_id = var.imported_certificate_intermediate_secret_id +} + +data "ibm_sm_arbitrary_secret" "imported_certificate_private" { + count = var.imported_certificate_private_secret_id != null ? 1 : 0 + region = var.imported_certificate_sm_region + instance_id = var.imported_certificate_sm_id + secret_id = var.imported_certificate_private_secret_id +} + +data "ibm_sm_arbitrary_secret" "imported_certificate_public" { + count = var.imported_certificate_public_secret_id != null ? 1 : 0 + region = var.imported_certificate_sm_region + instance_id = var.imported_certificate_sm_id + secret_id = var.imported_certificate_public_secret_id +} + +# composing the imported certificate +resource "ibm_sm_imported_certificate" "secrets_manager_imported_certificate" { + count = var.imported_certificate_public_secret_id != null && var.imported_certificate_private_secret_id != null ? 1 : 0 + instance_id = local.sm_guid + region = local.sm_region + name = "${var.prefix}-sm-imported-cert" + custom_metadata = { "key" : "value" } + description = "Imported certificate for ${var.prefix}-sm-imported-cert" + secret_group_id = module.secrets_manager_group.secret_group_id + certificate = data.ibm_sm_arbitrary_secret.imported_certificate_public[0].payload + intermediate = var.imported_certificate_intermediate_secret_id != null ? data.ibm_sm_arbitrary_secret.imported_certificate_intermediate[0].payload : null + private_key = data.ibm_sm_arbitrary_secret.imported_certificate_private[0].payload + provider = ibm.ibm-sm +} + +# definition of the flag handling the intermediate section +locals { + imported_certificate_has_intermediate = var.imported_certificate_intermediate_secret_id != null ? true : false +} + +# eso externalsecret object for imported certificate in secrets store with apikey authentication +module "external_secret_imported_certificate" { + count = var.imported_certificate_public_secret_id != null && var.imported_certificate_private_secret_id != null ? 1 : 0 + depends_on = [ + module.eso_apikey_namespace_secretstore_1 + ] + source = "../../modules/eso-external-secret" + eso_store_scope = "namespace" + es_kubernetes_secret_type = "tls" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "imported_cert" #tfsec:ignore:general-secrets-no-plaintext-exposure + sm_secret_id = ibm_sm_imported_certificate.secrets_manager_imported_certificate[0].secret_id + es_kubernetes_namespace = kubernetes_namespace.apikey_namespaces[2].metadata[0].name + eso_store_name = "${var.es_namespaces_apikey[2]}-store" + es_refresh_interval = var.es_refresh_interval + es_kubernetes_secret_name = "impcertificate-tls" #tfsec:ignore:general-secrets-no-plaintext-exposure #checkov:skip=CKV_SECRET_6 + es_helm_rls_name = "es-impcertificate" + sm_certificate_has_intermediate = local.imported_certificate_has_intermediate + # setting the value to false as the secret's components on SM are split in "not bundled" format + sm_certificate_bundle = false +} diff --git a/examples/all-combined/kv.tf b/examples/all-combined/kv.tf new file mode 100644 index 00000000..80b0e57b --- /dev/null +++ b/examples/all-combined/kv.tf @@ -0,0 +1,70 @@ +################################################################## +# Management of kv secrets +################################################################## + +################################################################## +# Single key kv secret +################################################################## + +resource "ibm_sm_kv_secret" "secrets_manager_kv_secret_singlekey" { + instance_id = local.sm_guid + region = local.sm_region + custom_metadata = { "meta_key" : "meta_value" } + data = { "secret_key" : "secret_value" } + description = "Extended description for this secret." + labels = ["my-label"] + secret_group_id = module.secrets_manager_group.secret_group_id + name = "${var.prefix}-sm-kv-secret" + provider = ibm.ibm-sm +} + +################################################################## +# Multiple keys kv secret +################################################################## + +resource "ibm_sm_kv_secret" "secrets_manager_kv_secret_multiplekeys" { + instance_id = local.sm_guid + region = local.sm_region + custom_metadata = { "meta_key" : "meta_value" } + data = { "secret_key1" : "secret_value1", "secret_key2" : "secret_value2", "secret_key3" : "secret_value3" } # checkov:skip=CKV_SECRET_6 + description = "Extended description for this secret." + labels = ["my-label"] + secret_group_id = module.secrets_manager_group.secret_group_id + name = "${var.prefix}-sm-kv-multikeys-secret" + provider = ibm.ibm-sm +} + +# eso externalsecret object for single key kv secret configured with apikey authentication secretstore +module "external_secret_kv_singlekey" { + depends_on = [ + module.eso_apikey_namespace_secretstore_2 + ] + source = "../../modules/eso-external-secret" + eso_store_scope = "namespace" + es_kubernetes_secret_type = "opaque" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "kv" #tfsec:ignore:general-secrets-no-plaintext-exposure + sm_secret_id = ibm_sm_kv_secret.secrets_manager_kv_secret_singlekey.secret_id + es_kubernetes_namespace = kubernetes_namespace.apikey_namespaces[3].metadata[0].name + eso_store_name = "${var.es_namespaces_apikey[3]}-store" + es_refresh_interval = var.es_refresh_interval + es_kubernetes_secret_name = "kv-single-key" #tfsec:ignore:general-secrets-no-plaintext-exposure #checkov:skip=CKV_SECRET_6 + es_helm_rls_name = "kv-single-key" + sm_kv_keyid = "secret_key" +} + +# eso externalsecret object for multiple keys kv secret configured with apikey authentication secretstore +module "external_secret_kv_multiplekeys" { + depends_on = [ + module.eso_apikey_namespace_secretstore_2 + ] + source = "../../modules/eso-external-secret" + eso_store_scope = "namespace" + es_kubernetes_secret_type = "opaque" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "kv" #tfsec:ignore:general-secrets-no-plaintext-exposure + sm_secret_id = ibm_sm_kv_secret.secrets_manager_kv_secret_multiplekeys.secret_id + es_kubernetes_namespace = kubernetes_namespace.apikey_namespaces[3].metadata[0].name + eso_store_name = "${var.es_namespaces_apikey[3]}-store" + es_refresh_interval = var.es_refresh_interval + es_kubernetes_secret_name = "kv-multiple-keys" #tfsec:ignore:general-secrets-no-plaintext-exposure #checkov:skip=CKV_SECRET_6 + es_helm_rls_name = "kv-multiple-keys" +} diff --git a/examples/all-combined/main.tf b/examples/all-combined/main.tf new file mode 100644 index 00000000..e53ee0e6 --- /dev/null +++ b/examples/all-combined/main.tf @@ -0,0 +1,444 @@ +################################################################## +# Resource Group +################################################################## + +module "resource_group" { + source = "terraform-ibm-modules/resource-group/ibm" + version = "1.1.6" + # if an existing resource group is not set (null) create a new one using prefix + resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null + existing_resource_group_name = var.resource_group +} + +################################################################## +# Create VPC, public gateway and subnets +################################################################## + +locals { + + # sDNLB entitled account API key - if null the ibmcloud_api_key will be used + sdnlb_ibmcloud_api_key = var.sdnlb_ibmcloud_api_key == null ? var.ibmcloud_api_key : var.sdnlb_ibmcloud_api_key + + vpc_cidr_bases = { + private = "192.168.0.0/20", + transit = "192.168.16.0/20", + edge = "192.168.32.0/20" + } + + subnet_prefix = flatten([ + for k, v in module.zone_subnet_addrs : [ + for zone, cidr in v.network_cidr_blocks : { + cidr = cidr + label = k + zone = zone + zone_index = split("-", zone)[1] + } + ] + ]) + + +merged_subnets = [ + for subnet in module.subnets : + merge( + subnet, + { + label = lookup([for sk in local.subnet_prefix : sk if sk.cidr == subnet.subnet_ipv4_cidr][0], "label", "") + zone = lookup([for sk in local.subnet_prefix : sk if sk.cidr == subnet.subnet_ipv4_cidr][0], "zone", "") + } + ) +] + +subnets = { + edge = [for subnet in local.merged_subnets : {id = subnet.subnet_id, cidr_block = subnet.subnet_ipv4_cidr, zone = subnet.zone} if subnet.label == "edge"], + private = [for subnet in local.merged_subnets : {id = subnet.subnet_id, cidr_block = subnet.subnet_ipv4_cidr, zone = subnet.zone} if subnet.label == "private"], + transit = [for subnet in local.merged_subnets : {id = subnet.subnet_id, cidr_block = subnet.subnet_ipv4_cidr, zone = subnet.zone} if subnet.label == "transit"] +} + + ocp_worker_pools = [ + { + subnet_prefix = "private" + pool_name = "default" + machine_type = "bx2.4x16" + workers_per_zone = 1 + labels = { "dedicated" : "private" } + operating_system = "REDHAT_8_64" + }, + { + subnet_prefix = "edge" + pool_name = "edge" + machine_type = "bx2.4x16" + workers_per_zone = 1 + labels = { "dedicated" : "edge" } + operating_system = "REDHAT_8_64" + }, + { + subnet_prefix = "transit" + pool_name = "transit" + machine_type = "bx2.4x16" + workers_per_zone = 1 + labels = { "dedicated" : "transit" } + operating_system = "REDHAT_8_64" + } +] + +} + + +resource "null_resource" "subnet_mappings" { + count = length(var.zones) + + triggers = { + name = "${var.region}-${var.zones[count.index]}" + new_bits = 2 + } +} + +module "zone_subnet_addrs" { + source = "git::https://github.com/hashicorp/terraform-cidr-subnets.git?ref=v1.0.0" + for_each = var.cidr_bases + + base_cidr_block = each.value + + networks = null_resource.subnet_mappings[*].triggers +} + +module "vpc" { + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git?ref=v1.5.0" + vpc_name = "${var.prefix}-vpc" + resource_group_id = module.resource_group.resource_group_id + locations = [] + vpc_tags = var.resource_tags + subnet_name_prefix = "${var.prefix}-subnet" + default_network_acl_name = "${var.prefix}-nacl" + default_routing_table_name = "${var.prefix}-routing-table" + default_security_group_name = "${var.prefix}-sg" + create_gateway = true + public_gateway_name_prefix = "${var.prefix}-pw" + number_of_addresses = 16 + auto_assign_address_prefix = false +} + +module "subnet_prefix" { + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/vpc-address-prefix?ref=v1.5.0" + count = length(local.subnet_prefix) + name = "${var.prefix}-z-${local.subnet_prefix[count.index].label}-${split("-", local.subnet_prefix[count.index].zone)[2]}" + location = local.subnet_prefix[count.index].zone + vpc_id = module.vpc.vpc.vpc_id + ip_range = local.subnet_prefix[count.index].cidr +} + + +module "subnets" { + depends_on = [module.subnet_prefix] + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/subnet?ref=v1.5.0" + count = length(local.subnet_prefix) + location = local.subnet_prefix[count.index].zone + vpc_id = module.vpc.vpc.vpc_id + ip_range = local.subnet_prefix[count.index].cidr + name = "${var.prefix}-subnet-${local.subnet_prefix[count.index].label}-${split("-", local.subnet_prefix[count.index].zone)[2]}" + public_gateway = local.subnet_prefix[count.index].label == "edge" ? module.public_gateways[split("-", local.subnet_prefix[count.index].zone)[2] - 1].public_gateway_id : null + subnet_access_control_list = module.network_acl.network_acl_id +} + +module "public_gateways" { + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/public-gateway?ref=v1.5.0" + count = length(var.zones) + vpc_id = module.vpc.vpc.vpc_id + location = "${var.region}-${var.zones[count.index]}" + name = "${var.prefix}-vpc-gateway-${var.zones[count.index]}" + resource_group_id = module.resource_group.resource_group_id + tags = var.tags +} + +module "security_group" { + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/security-group?ref=v1.5.0" + depends_on = [module.vpc] + create_security_group = false + resource_group_id = module.resource_group.resource_group_id + security_group = "${var.prefix}-sg" + security_group_rules = [ + { + name = "allow_all_inbound" + remote = "0.0.0.0/0" + direction = "inbound" + } + ] +} + +locals { + allow_subnet_cidr_inbound_rules = [ + for k, v in module.zone_subnet_addrs : + { + name = "allow-traffic-subnet-${k}-inbound" + action = "allow" + source = v.base_cidr_block + destination = "0.0.0.0/0" + direction = "inbound" + } + ] + allow_subnet_cidr_outbound_rules = [ + for k, v in module.zone_subnet_addrs : + { + name = "allow-traffic-subnet-${k}-outbound" + action = "allow" + source = "0.0.0.0/0" + destination = v.base_cidr_block + direction = "outbound" + } + ] + acl_rules = flatten( + [ + local.allow_subnet_cidr_inbound_rules, + local.allow_subnet_cidr_outbound_rules, + var.acl_rules_list + ] + ) +} + +module "network_acl" { + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/network-acl" + name = "${var.prefix}-vpc-acl" + vpc_id = module.vpc.vpc.vpc_id + resource_group_id = module.resource_group.resource_group_id + rules = local.acl_rules + tags = var.tags +} + +# OCP CLUSTER creation +module "ocp_base" { + source = "terraform-ibm-modules/base-ocp-vpc/ibm" + version = "3.35.10" + cluster_name = "${var.prefix}-vpc" + resource_group_id = module.resource_group.resource_group_id + region = var.region + force_delete_storage = true + vpc_id = module.vpc.vpc.vpc_id + vpc_subnets = local.subnets + worker_pools = local.ocp_worker_pools + tags = [] + use_existing_cos = false + # outbound required by cluster proxy + disable_outbound_traffic_protection = true +} + +# OCP CLUSTER creation +module "ocp_base" { + source = "terraform-ibm-modules/base-ocp-vpc/ibm" + version = "3.36.0" + cluster_name = "${var.prefix}-cluster" + resource_group_id = module.resource_group.resource_group_id + region = var.region + force_delete_storage = true + vpc_id = module.vpc.vpc_id + vpc_subnets = module.vpc.subnets + worker_pools = local.ocp_worker_pools + tags = [] + use_existing_cos = false + # outbound required by cluster proxy + disable_outbound_traffic_protection = true +} + +############################################################################## +# Init cluster config for helm and kubernetes providers +############################################################################## + +data "ibm_container_cluster_config" "cluster_config" { + cluster_name_id = module.ocp_base.cluster_id + resource_group_id = module.resource_group.resource_group_id +} + +# Wait time to allow cluster refreshes components after provisioning +resource "time_sleep" "wait_45_seconds" { + depends_on = [data.ibm_container_cluster_config.cluster_config] + create_duration = "45s" +} + +######################################## +## CIS to own public certificate +######################################## + +data "ibm_cis" "cis_instance" { + name = var.existing_cis_instance_name + resource_group_id = var.existing_cis_instance_resource_group_id +} + +###################################### +# VPEs creation in the case of private for service endpoint +###################################### + +module "vpes" { + source = "terraform-ibm-modules/vpe-gateway/ibm" + version = "4.3.0" + count = var.service_endpoints == "private" ? 1 : 0 + region = var.region + prefix = "vpe" + vpc_name = "${var.prefix}-vpc" + vpc_id = module.vpc.vpc_id + subnet_zone_list = [ + for index, subnet in module.vpc.subnets.transit : { + name = "${local.sm_region}-${index}" + zone = subnet.zone + id = subnet.id + acl_name = "acl" + public_gateway = true + } + ] + resource_group_id = module.resource_group.resource_group_id # pragma: allowlist secret + cloud_services = [] + cloud_service_by_crn = [ + { + name = "iam-${var.region}" + crn = "crn:v1:bluemix:public:iam-svcs:global:::endpoint:private.iam.cloud.ibm.com" + }, + { + name = "sm-${var.region}" + crn = local.sm_crn + } + ] + service_endpoints = "private" + depends_on = [ibm_resource_instance.secrets_manager] +} + +################################################################## +# ESO deployment +################################################################## + +module "external_secrets_operator" { + source = "../../" + eso_namespace = var.eso_namespace + + eso_cluster_nodes_configuration = var.eso_deployment_nodes_configuration == null ? null : { + nodeSelector = { + label = "dedicated" + value = var.eso_deployment_nodes_configuration + } + tolerations = { + key = "dedicated" + operator = "Equal" + value = var.eso_deployment_nodes_configuration + effect = "NoExecute" + } + } + + depends_on = [ + kubernetes_namespace.apikey_namespaces, kubernetes_namespace.tp_namespaces + ] +} + +################################################################## +# Preliminary creation of namespaces to use for +# clusterstore and namespaced secretstores (to be configured with apikey authentication) +################################################################## + +# Creating the namespaces for apikey authentication secrets stores +resource "kubernetes_namespace" "apikey_namespaces" { + count = length(var.es_namespaces_apikey) + metadata { + name = var.es_namespaces_apikey[count.index] + } + lifecycle { + ignore_changes = [ + metadata[0].annotations, + metadata[0].labels + ] + } + depends_on = [ + time_sleep.wait_45_seconds + ] +} + +variable "zones" { + description = "List of zones" + type = list(string) + default = ["1", "2", "3"] +} + +variable "cidr_bases" { + description = "A list of base CIDR blocks for each network zone" + type = map(string) + default = { + private = "192.168.0.0/20", + transit = "192.168.16.0/20", + edge = "192.168.32.0/20" + } +} + +variable "new_bits" { + description = "Number of additional address bits to use for numbering the new networks" + type = number + default = 2 +} + +variable "acl_rules_list" { + description = "Access control list rule set per network zone" + default = [ + { + name = "iks-create-worker-nodes-inbound" + action = "allow" + source = "161.26.0.0/16" + destination = "0.0.0.0/0" + direction = "inbound" + }, + { + name = "iks-nodes-to-master-inbound" + action = "allow" + source = "166.8.0.0/14" + destination = "0.0.0.0/0" + direction = "inbound" + }, + { + name = "iks-create-worker-nodes-outbound" + action = "allow" + source = "0.0.0.0/0" + destination = "161.26.0.0/16" + direction = "outbound" + }, + { + name = "iks-worker-to-master-outbound" + action = "allow" + source = "0.0.0.0/0" + destination = "166.8.0.0/14" + direction = "outbound" + }, + { + name = "allow-all-https-inbound" + source = "0.0.0.0/0" + action = "allow" + destination = "0.0.0.0/0" + direction = "inbound" + tcp = { + source_port_min = 443 + source_port_max = 443 + port_min = 1 + port_max = 65535 + } + }, + { + name = "allow-all-https-outbound" + source = "0.0.0.0/0" + action = "allow" + destination = "0.0.0.0/0" + direction = "outbound" + tcp = { + source_port_min = 1 + source_port_max = 65535 + port_min = 443 + port_max = 443 + } + }, + { + name = "deny-all-outbound" + action = "deny" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "outbound" + }, + { + name = "deny-all-inbound" + action = "deny" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "inbound" + } + ] +} \ No newline at end of file diff --git a/examples/all-combined/outputs.tf b/examples/all-combined/outputs.tf new file mode 100644 index 00000000..547bb0b2 --- /dev/null +++ b/examples/all-combined/outputs.tf @@ -0,0 +1,23 @@ +############################################################################## +# Outputs +############################################################################## + +# output "secret_manager_guid" { +# value = module.image_pull.secret_manager_guid +# description = "GUID of Secrets-Manager containing secret" +# } + +# output "serviceid_name" { +# description = "Name of the ServiceID created to access Container Registry" +# value = module.image_pull.serviceid_name +# } + +# output "serviceid_apikey_secret_id" { +# description = "ID of the Secret Manager Secret containing ServiceID API Key" +# value = module.image_pull.serviceid_apikey_secret_id +# } + +output "cluster_id" { + description = "ID of the cluster deployed" + value = module.ocp_base.cluster_id +} diff --git a/examples/all-combined/privatecertificate.tf b/examples/all-combined/privatecertificate.tf new file mode 100644 index 00000000..e092408d --- /dev/null +++ b/examples/all-combined/privatecertificate.tf @@ -0,0 +1,60 @@ +################################################################## +# Private certificate secret configuration +################################################################## + +# private certificate common name, Certificate Authority common name and certificate template name definition +locals { + pvt_cert_common_name = var.pvt_cert_common_name == null ? "pvt-${var.prefix}.goldeneye.dev.cloud.ibm.com" : var.pvt_cert_common_name + pvt_root_ca_common_name = var.pvt_root_ca_common_name == null ? "pvt-${var.prefix}.goldeneye.dev.cloud.ibm.com" : var.pvt_root_ca_common_name + pvt_certificate_template_name = var.pvt_certificate_template_name != null ? var.pvt_certificate_template_name : "pvt-${var.prefix}-cert-template" +} + +# private certificate engine +module "secrets_manager_private_secret_engine" { + source = "terraform-ibm-modules/secrets-manager-private-cert-engine/ibm" + version = "1.3.5" + secrets_manager_guid = local.sm_guid + region = local.sm_region + root_ca_name = var.pvt_ca_name != null ? var.pvt_ca_name : "pvt-${var.prefix}-goldeneye-root-ca" + root_ca_common_name = local.pvt_root_ca_common_name + root_ca_max_ttl = var.pvt_ca_max_ttl + intermediate_ca_name = "pvt-${var.prefix}-goldeneye-intermediate-ca" + certificate_template_name = local.pvt_certificate_template_name + providers = { + ibm = ibm.ibm-sm + } +} + +# private certificate generation +module "secrets_manager_private_certificate" { + depends_on = [module.secrets_manager_private_secret_engine] + source = "terraform-ibm-modules/secrets-manager-private-cert/ibm" + version = "1.3.2" + cert_name = "${var.prefix}-sm-private-cert" + cert_description = "Private certificate for ${local.pvt_cert_common_name}" + cert_secrets_group_id = module.secrets_manager_group.secret_group_id + cert_template = local.pvt_certificate_template_name + cert_common_name = local.pvt_cert_common_name + secrets_manager_guid = local.sm_guid + secrets_manager_region = local.sm_region + providers = { + ibm = ibm.ibm-sm + } +} + +# eso externalsecret object for private certificate in secrets store with apikey authentication +module "external_secret_private_certificate" { + depends_on = [ + module.eso_apikey_namespace_secretstore_1 + ] + source = "../../modules/eso-external-secret" + eso_store_scope = "namespace" + es_kubernetes_secret_type = "tls" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "private_cert" #tfsec:ignore:general-secrets-no-plaintext-exposure + sm_secret_id = module.secrets_manager_private_certificate.secret_id + es_kubernetes_namespace = kubernetes_namespace.apikey_namespaces[2].metadata[0].name + eso_store_name = "${var.es_namespaces_apikey[2]}-store" + es_refresh_interval = var.es_refresh_interval + es_kubernetes_secret_name = "pvtcertificate-tls" #tfsec:ignore:general-secrets-no-plaintext-exposure #checkov:skip=CKV_SECRET_6 + es_helm_rls_name = "es-pvtcertificate" +} diff --git a/examples/all-combined/provider.tf b/examples/all-combined/provider.tf new file mode 100644 index 00000000..1bee7827 --- /dev/null +++ b/examples/all-combined/provider.tf @@ -0,0 +1,31 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.region +} + +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.existing_sm_instance_region == null ? var.region : var.existing_sm_instance_region + alias = "ibm-sm" +} + +provider "ibm" { + ibmcloud_api_key = local.sdnlb_ibmcloud_api_key + region = var.region + alias = "ibm-sdnlb" +} + +provider "kubernetes" { + host = data.ibm_container_cluster_config.cluster_config.host + token = data.ibm_container_cluster_config.cluster_config.token + cluster_ca_certificate = data.ibm_container_cluster_config.cluster_config.ca_certificate +} + + +provider "helm" { + kubernetes { + host = data.ibm_container_cluster_config.cluster_config.host + token = data.ibm_container_cluster_config.cluster_config.token + cluster_ca_certificate = data.ibm_container_cluster_config.cluster_config.ca_certificate + } +} diff --git a/examples/all-combined/publiccertificate.tf b/examples/all-combined/publiccertificate.tf new file mode 100644 index 00000000..789289c3 --- /dev/null +++ b/examples/all-combined/publiccertificate.tf @@ -0,0 +1,67 @@ +################################################################## +# Public certificate secret configuration +################################################################## + +# A public certificate engine, consisting of a certificate authority (LetEncrypt) +# and a DNS provider authorisation (CIS) are configured as a pre-requisite to +# secrets manager generating certificates +module "secrets_manager_public_cert_engine" { + count = (var.acme_letsencrypt_private_key != null || (var.acme_letsencrypt_private_key_sm_id != null && var.acme_letsencrypt_private_key_secret_id != null && var.acme_letsencrypt_private_key_sm_region != null)) ? 1 : 0 + source = "terraform-ibm-modules/secrets-manager-public-cert-engine/ibm" + version = "1.0.2" + secrets_manager_guid = local.sm_guid + region = local.sm_region + internet_services_crn = data.ibm_cis.cis_instance.id + ca_config_name = var.ca_name != null ? var.ca_name : "${var.prefix}-goldeneye-ca" + dns_config_name = var.dns_provider_name != null ? var.dns_provider_name : "${var.prefix}-goldeneye-dns" + private_key_secrets_manager_instance_guid = var.acme_letsencrypt_private_key_sm_id + private_key_secrets_manager_secret_id = var.acme_letsencrypt_private_key_secret_id + private_key_secrets_manager_region = var.acme_letsencrypt_private_key_sm_region + acme_letsencrypt_private_key = var.acme_letsencrypt_private_key + skip_iam_authorization_policy = var.skip_iam_authorization_policy + providers = { + ibm = ibm.ibm-sm + ibm.secret-store = ibm.ibm-sm + } +} + +# public certificate common name definition +locals { + cert_common_name = var.cert_common_name == null ? "${var.prefix}-2.goldeneye.dev.cloud.ibm.com" : var.cert_common_name +} + +# public certificate creation +module "secrets_manager_public_certificate" { + count = (var.acme_letsencrypt_private_key != null || (var.acme_letsencrypt_private_key_sm_id != null && var.acme_letsencrypt_private_key_secret_id != null && var.acme_letsencrypt_private_key_sm_region != null)) ? 1 : 0 + depends_on = [module.secrets_manager_public_cert_engine] + source = "terraform-ibm-modules/secrets-manager-public-cert/ibm" + version = "1.2.1" + cert_common_name = local.cert_common_name + cert_description = "Certificate for ${local.cert_common_name}" + cert_name = "${var.prefix}-sm-public-cert" + cert_secrets_group_id = module.secrets_manager_group.secret_group_id + secrets_manager_ca_name = var.ca_name != null ? var.ca_name : "${var.prefix}-goldeneye-ca" + secrets_manager_dns_provider_name = var.dns_provider_name != null ? var.dns_provider_name : "${var.prefix}-goldeneye-dns" + secrets_manager_guid = local.sm_guid + secrets_manager_region = local.sm_region + bundle_certs = var.public_certificate_bundle +} + +# eso externalsecret object for public certificate in secrets store with apikey authentication +module "external_secret_public_certificate" { + count = (var.acme_letsencrypt_private_key != null || (var.acme_letsencrypt_private_key_sm_id != null && var.acme_letsencrypt_private_key_secret_id != null && var.acme_letsencrypt_private_key_sm_region != null)) ? 1 : 0 + depends_on = [ + module.eso_apikey_namespace_secretstore_1 + ] + source = "../../modules/eso-external-secret" + eso_store_scope = "namespace" + es_kubernetes_secret_type = "tls" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "public_cert" #tfsec:ignore:general-secrets-no-plaintext-exposure + sm_secret_id = module.secrets_manager_public_certificate[0].secret_id + es_kubernetes_namespace = kubernetes_namespace.apikey_namespaces[2].metadata[0].name + eso_store_name = "${var.es_namespaces_apikey[2]}-store" + es_refresh_interval = var.es_refresh_interval + es_kubernetes_secret_name = "pubcertificate-tls" #tfsec:ignore:general-secrets-no-plaintext-exposure #checkov:skip=CKV_SECRET_6 + es_helm_rls_name = "es-pubcertificate" + sm_certificate_bundle = var.public_certificate_bundle +} diff --git a/examples/all-combined/sdnlb-secret.tf b/examples/all-combined/sdnlb-secret.tf new file mode 100644 index 00000000..feae005f --- /dev/null +++ b/examples/all-combined/sdnlb-secret.tf @@ -0,0 +1,37 @@ +############################################################################## +# Load cluster and serviceID details +############################################################################## + +# data "ibm_iam_service_id" "existing_sdnlb_serviceid" { +# name = var.existing_sdnlb_serviceid_name +# } + +# creating a dynamic secret on SM to generate the serviceID API key +# module "dynamic_sdnlb_serviceid_apikey_by_sm_serviceid_apikey" { +# source = "terraform-ibm-modules/iam-serviceid-apikey-secrets-manager/ibm" +# version = "1.1.1" +# region = local.sm_region +# sm_iam_secret_name = "${var.prefix}-sdnlb-secret" +# sm_iam_secret_description = "sdnlb serviceID apikey secret" +# secrets_manager_guid = local.sm_guid +# serviceid_id = data.ibm_iam_service_id.existing_sdnlb_serviceid.service_ids[0].id +# secret_group_id = module.secrets_manager_group.secret_group_id +# providers = { +# ibm = ibm.ibm-sm +# } +# } + +# module "sdnlb_eso_secret" { +# depends_on = [module.external_secrets_operator] +# source = "git::https://github.ibm.com/GoldenEye/sdnlb-module.git//modules/sdnlb-eso-secret-module?ref=3.5.0" +# sdnlb_service_id = data.ibm_iam_service_id.existing_sdnlb_serviceid.service_ids[0].id +# sdnlb_api_key_sm_id = module.dynamic_sdnlb_serviceid_apikey_by_sm_serviceid_apikey.secret_id +# #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static type +# externalsecret_helm_release_new_namespace = "sdnlb-secret-helm-release-namespace" +# eso_store_name = "cluster-store" +# eso_store_scope = "cluster" + +# providers = { +# ibm = ibm.ibm-sdnlb +# } +# } diff --git a/examples/all-combined/secretsmanager.tf b/examples/all-combined/secretsmanager.tf new file mode 100644 index 00000000..be004b72 --- /dev/null +++ b/examples/all-combined/secretsmanager.tf @@ -0,0 +1,152 @@ +############################################################################## +# Secrets manager validations +############################################################################## + +locals { + + # validation for secrets manager region to be set for existing secrets manager instance + validate_sm_region_cnd = var.existing_sm_instance_guid != null && var.existing_sm_instance_region == null + validate_sm_region_msg = "existing_sm_instance_region must also be set when value given for existing_sm_instance_guid." + # tflint-ignore: terraform_unused_declarations + validate_sm_region_chk = regex( + "^${local.validate_sm_region_msg}$", + (!local.validate_sm_region_cnd + ? local.validate_sm_region_msg + : "")) + + # validation for secrets manager crn to be set for existing secrets manager instance if using private service endpoints + validate_sm_crn_cnd = var.existing_sm_instance_guid != null && var.existing_sm_instance_crn == null && var.service_endpoints == "private" + validate_sm_crn_msg = "existing_sm_instance_crn must also be set when value given for existing_sm_instance_guid if service_endpoints is private." + # tflint-ignore: terraform_unused_declarations + validate_sm_crn_chk = regex( + "^${local.validate_sm_crn_msg}$", + (!local.validate_sm_crn_cnd + ? local.validate_sm_crn_msg + : "")) + + # setting the secrets manager resource id to use + sm_guid = var.existing_sm_instance_guid == null ? ibm_resource_instance.secrets_manager[0].guid : var.existing_sm_instance_guid + + # if service_endpoints is not private the crn for SM is not needed because of VPE creation is not needed + sm_crn = var.existing_sm_instance_crn == null ? (var.service_endpoints == "private" ? ibm_resource_instance.secrets_manager[0].crn : "") : var.existing_sm_instance_crn + + # https://github.ibm.com/GoldenEye/issues/issues/5268 - deployment region will match to sm_region as workaround + sm_region = var.existing_sm_instance_region == null ? var.region : var.existing_sm_instance_region + sm_acct_id = var.existing_sm_instance_guid == null ? module.iam_secrets_engine[0].acct_secret_group_id : module.secrets_manager_group_acct[0].secret_group_id +} + + +######################################## +# Secrets-Manager and IAM configuration +######################################## + +# IAM user policy, Secret Manager instance, Service ID for IAM engine, IAM service ID policies, associated Service ID API key stored in a secret object in account level secret-group and IAM engine configuration +resource "ibm_resource_instance" "secrets_manager" { + count = var.existing_sm_instance_guid == null ? 1 : 0 + name = "${var.prefix}-sm" + service = "secrets-manager" + plan = var.sm_service_plan + location = local.sm_region + tags = var.resource_tags + resource_group_id = module.resource_group.resource_group_id + timeouts { + create = "30m" # Extending provisioning time to 30 minutes + } + provider = ibm.ibm-sm +} + +# Configure IAM secrets engine +module "iam_secrets_engine" { + count = var.existing_sm_instance_guid == null ? 1 : 0 + source = "terraform-ibm-modules/secrets-manager-iam-engine/ibm" + version = "1.2.6" + region = local.sm_region + secrets_manager_guid = ibm_resource_instance.secrets_manager[0].guid + iam_secret_generator_service_id_name = "${var.prefix}-sid:0.0.1:${ibm_resource_instance.secrets_manager[0].name}-iam-secret-generator:automated:simple-service:secret-manager:" + iam_secret_generator_apikey_name = "${var.prefix}-iam-secret-generator-apikey" + new_secret_group_name = "${var.prefix}-account-secret-group" + iam_secret_generator_apikey_secret_name = "${var.prefix}-iam-secret-generator-apikey-secret" + iam_engine_name = "iam-engine" + endpoint_type = var.service_endpoints + providers = { + ibm = ibm.ibm-sm + } +} + +# create secrets group for secrets +module "secrets_manager_group" { + source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" + version = "1.2.2" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_name = "${var.prefix}-secret-group" #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + secret_group_description = "Secret-Group for storing account credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure + providers = { + ibm = ibm.ibm-sm + } +} + +# additional secrets manager secret group for service level secrets +module "secrets_manager_group_acct" { + source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" + version = "1.2.2" + count = var.existing_sm_instance_guid == null ? 0 : 1 + region = local.sm_region + secrets_manager_guid = local.sm_guid + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_group_name = "${var.prefix}-account-secret-group" #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + secret_group_description = "Secret-Group for storing account credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure + depends_on = [module.iam_secrets_engine] + providers = { + ibm = ibm.ibm-sm + } +} + +################################################################## +# Create IAM serviceId, IAM policy and IAM API key to pull secrets from secret manager +################################################################## + +# Create service-id +resource "ibm_iam_service_id" "secret_puller" { + name = "sid:0.0.1:${var.prefix}-secret-puller:automated:simple-service:secret-manager:" + description = "ServiceID that can pull secrets from Secret Manager" +} + +# Create policy to allow new service id to pull secrets from secrets manager +resource "ibm_iam_service_policy" "secret_puller_policy" { + iam_service_id = ibm_iam_service_id.secret_puller.id + roles = ["Viewer", "SecretsReader"] + + resources { + service = "secrets-manager" + resource_instance_id = local.sm_guid + resource_type = "secret-group" + resource = module.secrets_manager_group.secret_group_id + } +} + +# create dynamic Service ID API key and add to secret manager +module "dynamic_serviceid_apikey1" { + source = "terraform-ibm-modules/iam-serviceid-apikey-secrets-manager/ibm" + version = "1.1.1" + region = local.sm_region + #tfsec:ignore:general-secrets-no-plaintext-exposure + sm_iam_secret_name = "${var.prefix}-${var.sm_iam_secret_name}" + sm_iam_secret_description = "Example of dynamic IAM secret / apikey" #tfsec:ignore:general-secrets-no-plaintext-exposure + serviceid_id = ibm_iam_service_id.secret_puller.id + secrets_manager_guid = local.sm_guid + secret_group_id = local.sm_acct_id + depends_on = [module.iam_secrets_engine, ibm_iam_service_policy.secret_puller_policy, ibm_iam_service_id.secret_puller] + providers = { + ibm = ibm.ibm-sm + } +} + + +# data source to get the API key to pull secrets from secrets manager +data "ibm_sm_iam_credentials_secret" "secret_puller_secret" { + instance_id = local.sm_guid + #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static type + secret_id = module.dynamic_serviceid_apikey1.secret_id + provider = ibm.ibm-sm +} diff --git a/examples/all-combined/secretstore.tf b/examples/all-combined/secretstore.tf new file mode 100644 index 00000000..ceb7c1dd --- /dev/null +++ b/examples/all-combined/secretstore.tf @@ -0,0 +1,201 @@ +############################################################################## +# This template shows how to create ESO secretstores, a secrets store namespace scoped, with api key authentication +# Two different secretstores are created in two different namespaces, allowing to achive namespace isolation +# Two different secret types +# - arbitrary (to store image pull API key) +# - Image pull API key secret using imagepull-apikey-secrets-manager-module +# are created and configured in two different externalsecret resources configured with the two different secretstores +# Both the secrets are store into a dockerconfigjson K8s secret type +# The Image pull API key secret is stored into an opaque K8s secret type +############################################################################## + +# creation of namespace scoped secretstore with apikey authentication +module "eso_apikey_namespace_secretstore_1" { + depends_on = [module.external_secrets_operator] + source = "../../modules/eso-secretstore" + eso_authentication = "api_key" + region = local.sm_region + sstore_namespace = kubernetes_namespace.apikey_namespaces[2].metadata[0].name + sstore_secrets_manager_guid = local.sm_guid + sstore_store_name = "${var.es_namespaces_apikey[2]}-store" + sstore_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key + service_endpoints = var.service_endpoints + sstore_helm_rls_name = "es-store" + sstore_secret_name = "generic-cluster-api-key" #checkov:skip=CKV_SECRET_6 +} + +module "eso_apikey_namespace_secretstore_2" { + depends_on = [module.external_secrets_operator] + source = "../../modules/eso-secretstore" + eso_authentication = "api_key" + region = local.sm_region + sstore_namespace = kubernetes_namespace.apikey_namespaces[3].metadata[0].name + sstore_secrets_manager_guid = local.sm_guid + sstore_store_name = "${var.es_namespaces_apikey[3]}-store" + sstore_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key + service_endpoints = var.service_endpoints + sstore_helm_rls_name = "es-store" + sstore_secret_name = "generic-cluster-api-key" #checkov:skip=CKV_SECRET_6 +} + +################################################################## +# Arbitrary secret (for example image pull secret) +################################################################## + +locals { + # image pull API key value for sm_arbitrary_imagepull_secret + imagepull_apikey = sensitive("imagepull-payload-example") +} + +# create the arbitrary secret and store in secret manager +module "sm_arbitrary_imagepull_secret" { + source = "terraform-ibm-modules/secrets-manager-secret/ibm" + version = "1.4.0" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_id = module.secrets_manager_group.secret_group_id + secret_type = "arbitrary" + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_name = "${var.prefix}-imagepull-apikey-secret" #checkov:skip=CKV_SECRET_6 + secret_description = "example secret for provided image pull API key" #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_payload_password = local.imagepull_apikey + providers = { + ibm = ibm.ibm-sm + } +} + +# creation of externalsecret for the arbitrary secret in namespaced secretstore with API key authentication +# secrets stored in K8s dockerconfigjson secret type +module "external_secret_arbitrary_cr_registry" { + depends_on = [ + module.eso_apikey_namespace_secretstore_1 + ] + source = "../../modules/eso-external-secret" + eso_store_scope = "namespace" + es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "arbitrary" + sm_secret_id = module.sm_arbitrary_imagepull_secret.secret_id + es_kubernetes_namespace = kubernetes_namespace.apikey_namespaces[2].metadata[0].name + es_container_registry = "test.icr.com" + es_container_registry_email = "terraform@ibm.com" + eso_store_name = "${var.es_namespaces_apikey[2]}-store" + es_refresh_interval = var.es_refresh_interval + es_kubernetes_secret_name = "dockerconfigjson-arb" #checkov:skip=CKV_SECRET_6 + es_helm_rls_name = "es-docker-arb" +} + +################################################################## +# Image pull API key secret using imagepull-apikey-secrets-manager-module +################################################################## + +# create image pull serviceID and secret and store in secrets manager +# module "image_pull" { +# source = "git::https://github.ibm.com/GoldenEye/imagepull-apikey-secrets-manager-module.git?ref=1.1.7" +# resource_group_id = module.resource_group.resource_group_id +# secrets_manager_guid = local.sm_guid +# cr_namespace_name = var.cr_namespace_name +# region = local.sm_region +# #tfsec:ignore:general-secrets-no-plaintext-exposure +# service_id_secret_name = "${var.prefix}-image-pull-service-id" +# service_id_secret_group_id = module.secrets_manager_group.secret_group_id +# depends_on = [module.iam_secrets_engine, module.secrets_manager_group] +# providers = { +# ibm = ibm.ibm-sm +# } +# } + +# # ESO external secret storing the secret in the cluster as dockerconfigson type (from image pull IAM dynamic credential/secret) using namespaced secretstore +# module "external_secret_secret_image_pull" { +# source = "../../modules/eso-external-secret" +# depends_on = [ +# module.eso_apikey_namespace_secretstore_2, +# ] +# eso_store_scope = "namespace" +# es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 +# sm_secret_type = "iam_credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure +# sm_secret_id = module.image_pull.serviceid_apikey_secret_id +# es_kubernetes_namespace = kubernetes_namespace.apikey_namespaces[3].metadata[0].name +# es_container_registry = "test.icr.com" +# es_container_registry_email = "terraform@ibm.com" +# es_refresh_interval = var.es_refresh_interval +# eso_store_name = "${var.es_namespaces_apikey[3]}-store" +# es_kubernetes_secret_name = "dockerconfigjson-iam" #tfsec:ignore:general-secrets-no-plaintext-exposure #checkov:skip=CKV_SECRET_6 +# es_helm_rls_name = "es-docker-iam" +# } + +# ################################################################## +# # Image pull API key secrets using imagepull-apikey-secrets-manager-module +# # to be configured in a single chain of secrets +# ################################################################## + +# # create image pull serviceID and secret and store in secrets manager +# module "image_pull_chain_secret_1" { +# source = "git::https://github.ibm.com/GoldenEye/imagepull-apikey-secrets-manager-module.git?ref=1.1.7" +# resource_group_id = module.resource_group.resource_group_id +# secrets_manager_guid = local.sm_guid +# cr_namespace_name = var.cr_namespace_name +# region = local.sm_region +# #tfsec:ignore:general-secrets-no-plaintext-exposure +# service_id_secret_name = "${var.prefix}-image-pull-service-id-chain-sec-1" +# service_id_secret_group_id = module.secrets_manager_group.secret_group_id +# depends_on = [module.iam_secrets_engine, module.secrets_manager_group] +# providers = { +# ibm = ibm.ibm-sm +# } +# } + +# # create image pull serviceID and secret and store in secrets manager +# module "image_pull_chain_secret_2" { +# source = "git::https://github.ibm.com/GoldenEye/imagepull-apikey-secrets-manager-module.git?ref=1.1.7" +# resource_group_id = module.resource_group.resource_group_id +# secrets_manager_guid = local.sm_guid +# cr_namespace_name = var.cr_namespace_name +# region = local.sm_region +# #tfsec:ignore:general-secrets-no-plaintext-exposure +# service_id_secret_name = "${var.prefix}-image-pull-service-id-chain-sec-2" +# service_id_secret_group_id = module.secrets_manager_group.secret_group_id +# depends_on = [module.iam_secrets_engine, module.secrets_manager_group] +# providers = { +# ibm = ibm.ibm-sm +# } +# } + +# # create image pull serviceID and secret and store in secrets manager +# module "image_pull_chain_secret_3" { +# source = "git::https://github.ibm.com/GoldenEye/imagepull-apikey-secrets-manager-module.git?ref=1.1.7" +# resource_group_id = module.resource_group.resource_group_id +# secrets_manager_guid = local.sm_guid +# cr_namespace_name = var.cr_namespace_name +# region = local.sm_region +# #tfsec:ignore:general-secrets-no-plaintext-exposure +# service_id_secret_name = "${var.prefix}-image-pull-service-id-chain-sec-3" +# service_id_secret_group_id = module.secrets_manager_group.secret_group_id +# depends_on = [module.iam_secrets_engine, module.secrets_manager_group] +# providers = { +# ibm = ibm.ibm-sm +# } +# } + +# module "external_secret_secret_image_pull_chain" { +# source = "../../modules/eso-external-secret" +# depends_on = [module.eso_apikey_namespace_secretstore_2, ] +# eso_store_scope = "namespace" +# es_kubernetes_secret_type = "dockerconfigjson" +# sm_secret_type = "iam_credentials" +# eso_store_name = "${var.es_namespaces_apikey[3]}-store" +# es_kubernetes_secret_name = "dockerconfigjson-chain" +# es_helm_rls_name = "es-docker-iam-chain" +# es_kubernetes_namespace = kubernetes_namespace.apikey_namespaces[3].metadata[0].name +# sm_secret_id = null # null is accepted only in the case of a dockerjsonconfig secret with secrets chain +# es_container_registry_secrets_chain = [ +# { +# "es_container_registry" : "test1.icr.com", "sm_secret_id" : module.image_pull_chain_secret_1.serviceid_apikey_secret_id, "es_container_registry_email" : "terraform1@ibm.com" +# }, +# { +# "es_container_registry" : "test2.icr.com", "sm_secret_id" : module.image_pull_chain_secret_2.serviceid_apikey_secret_id, "es_container_registry_email" : null +# }, +# { +# "es_container_registry" : "test3.icr.com", "sm_secret_id" : module.image_pull_chain_secret_3.serviceid_apikey_secret_id, "es_container_registry_email" : "" +# } +# ] +# } diff --git a/examples/all-combined/tpauth_cluster_sstore.tf b/examples/all-combined/tpauth_cluster_sstore.tf new file mode 100644 index 00000000..1b46373d --- /dev/null +++ b/examples/all-combined/tpauth_cluster_sstore.tf @@ -0,0 +1,102 @@ +#################################################################################### +# clustersecretstore with trusted profile auth +# creation of clustersecretstore, secretsgroup and externalsecrets resource +# for csecretstore supporting authentication by trusted profile +#################################################################################### + +# creating a secrets group for clustersecretstore with trustedprofile auth +module "tp_clusterstore_secrets_manager_group" { + source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" + version = "1.2.2" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_name = "${var.prefix}-cpstore-tp-secret-group" #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + secret_group_description = "Secret-Group for storing account credentials for clusterstore tp authentication" #tfsec:ignore:general-secrets-no-plaintext-exposure + providers = { + ibm = ibm.ibm-sm + } +} + +locals { + cstore_store_name = "cluster-store-tpauth" + cstore_trusted_profile_name = "${var.prefix}-eso-cstore-tp" + cstore_tp_namespace = "eso-cstore-tp-namespace" +} + +# creating trusted profiles for the secrets groups created with module tp_clusterstore_secrets_manager_group +module "external_secrets_clusterstore_trusted_profile" { + source = "../../modules/eso-trusted-profile" + trusted_profile_name = local.cstore_trusted_profile_name + secrets_manager_guid = local.sm_guid + secret_groups_id = [module.tp_clusterstore_secrets_manager_group.secret_group_id] + tp_cluster_crn = module.ocp_base.cluster_crn + trusted_profile_claim_rule_type = "ROKS_SA" + tp_namespace = var.eso_namespace +} + +# creation of the ESO ClusterStore (cluster wide scope) with trustedprofile authentication +module "eso_clusterstore_tpauth" { + source = "../../modules/eso-clusterstore" + eso_authentication = "trusted_profile" + clusterstore_trusted_profile_name = local.cstore_trusted_profile_name + region = local.sm_region + clusterstore_helm_rls_name = "${local.cstore_store_name}-rls" + clusterstore_name = local.cstore_store_name + clusterstore_secrets_manager_guid = local.sm_guid + eso_namespace = var.eso_namespace + service_endpoints = var.service_endpoints + depends_on = [ + module.external_secrets_operator + ] +} + +# arbitrary secret to be synched through the clustersecretstore with TP authentication +module "sm_cstore_arbitrary_secret_tp" { + source = "terraform-ibm-modules/secrets-manager-secret/ibm" + version = "1.4.0" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_id = module.tp_clusterstore_secrets_manager_group.secret_group_id + secret_type = "arbitrary" + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_name = "${var.prefix}-eso-test-dummy-secret-cstore-tp" #checkov:skip=CKV_SECRET_6 + secret_description = "eso_test_dummy_cstore_secret_tp example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_payload_password = "dummy_secret_value_eso_test_dummy_cstore_secret_tp" # pragma: allowlist secret + providers = { + ibm = ibm.ibm-sm + } +} + +# Creating the namespaces for TP authentication clusterstore to store the secrets +resource "kubernetes_namespace" "clusterstore_tpauth_secrets_namespace" { + metadata { + name = local.cstore_tp_namespace + } + lifecycle { + ignore_changes = [ + metadata[0].annotations, + metadata[0].labels + ] + } + depends_on = [ + time_sleep.wait_45_seconds + ] +} + +# eso externalsecret object with clustersecretstore trusted profiles authentication +module "cstore_external_secret_tp" { + depends_on = [module.eso_clusterstore_tpauth] + source = "../../modules/eso-external-secret" + eso_store_scope = "cluster" + es_kubernetes_namespace = kubernetes_namespace.clusterstore_tpauth_secrets_namespace.metadata[0].name + es_kubernetes_secret_name = "${var.prefix}-arbitrary-arb-cstore-tp" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "arbitrary" #checkov:skip=CKV_SECRET_6 + sm_secret_id = module.sm_cstore_arbitrary_secret_tp.secret_id #checkov:skip=CKV_SECRET_6 + es_kubernetes_secret_type = "opaque" + es_kubernetes_secret_data_key = "apikey" + es_refresh_interval = "5m" + eso_store_name = local.cstore_store_name # each store created with the name of the namespace with "-store" as suffix + es_container_registry = "us.icr.io" + es_container_registry_email = "goldeneye@us.ibm.com" + es_helm_rls_name = "es-tp" +} diff --git a/examples/all-combined/tpauth_namespaced_sstore.tf b/examples/all-combined/tpauth_namespaced_sstore.tf new file mode 100644 index 00000000..7d95ccc2 --- /dev/null +++ b/examples/all-combined/tpauth_namespaced_sstore.tf @@ -0,0 +1,344 @@ +#################################################################################### +# namespaced secretstores with trusted profile auth: +# creation of namespaces, secretstores, secretsgroups and externalsecrets resources +# for namespaced secretstores supporting authentication by trusted profiles +#################################################################################### + +# Create namespaces for trusted profile auth secretsstores +resource "kubernetes_namespace" "tp_namespaces" { + count = length(var.es_namespaces_tp) + metadata { + name = var.es_namespaces_tp[count.index] + } + lifecycle { + ignore_changes = [ + metadata[0].annotations, + metadata[0].labels + ] + } + depends_on = [ + time_sleep.wait_45_seconds + ] +} + +# SecretStore with trustedprofile auth for each namespace +module "eso_tp_namespace_secretstores" { + depends_on = [module.external_secrets_operator] + count = length(var.es_namespaces_tp) + source = "../../modules/eso-secretstore" + eso_authentication = "trusted_profile" + region = local.sm_region + sstore_namespace = kubernetes_namespace.tp_namespaces[count.index].metadata[0].name + sstore_secrets_manager_guid = local.sm_guid + sstore_store_name = "${var.es_namespaces_tp[count.index]}-store" # each store created with the name of the namespace with "-store" as suffix + sstore_trusted_profile_name = module.external_secrets_trusted_profiles[count.index].trusted_profile_name + service_endpoints = var.service_endpoints + sstore_helm_rls_name = "es-store-${count.index}" + sstore_secret_name = "secretstore-tp-${count.index}" #checkov:skip=CKV_SECRET_6 +} + +# creating a secrets group for each namespace to be used for namespaced secretstores with trustedprofile auth +module "tp_secrets_manager_groups" { + source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" + version = "1.2.2" + count = length(var.es_namespaces_tp) + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_name = "${var.prefix}-tp-secret-group-${count.index}" #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + secret_group_description = "Secret-Group for storing account credentials for tp authentication" #tfsec:ignore:general-secrets-no-plaintext-exposure + providers = { + ibm = ibm.ibm-sm + } +} + +# creating trusted profiles for the secrets groups created with module tp_secrets_manager_groups +module "external_secrets_trusted_profiles" { + count = length(var.es_namespaces_tp) + source = "../../modules/eso-trusted-profile" + trusted_profile_name = "${var.prefix}-eso-tp-${count.index}" + secrets_manager_guid = local.sm_guid + secret_groups_id = [module.tp_secrets_manager_groups[count.index].secret_group_id] + tp_cluster_crn = module.ocp_base.cluster_crn + trusted_profile_claim_rule_type = "ROKS_SA" + tp_namespace = var.eso_namespace +} + +# arbitrary secrets in each namespace and each related secrets group +module "sm_arbitrary_secrets_tp" { + count = length(var.es_namespaces_tp) + source = "terraform-ibm-modules/secrets-manager-secret/ibm" + version = "1.4.0" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_id = module.tp_secrets_manager_groups[count.index].secret_group_id + secret_type = "arbitrary" + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_name = "${var.prefix}-eso-test-dummy-secret-tp-${count.index}" #checkov:skip=CKV_SECRET_6 + secret_description = "eso_test_dummy_secret_tp example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_payload_password = "dummy_secret_value_eso_test_dummy_secret_tp" # pragma: allowlist secret + providers = { + ibm = ibm.ibm-sm + } +} + +# eso externalsecret object with trusted profiles authentication for each namespace +module "external_secret_tp" { + depends_on = [ + module.eso_tp_namespace_secretstores + ] + count = length(var.es_namespaces_tp) + source = "../../modules/eso-external-secret" + eso_store_scope = "namespace" + es_kubernetes_namespace = kubernetes_namespace.tp_namespaces[count.index].metadata[0].name + es_kubernetes_secret_name = "${var.prefix}-arbitrary-arb-tp-${count.index}" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "arbitrary" #checkov:skip=CKV_SECRET_6 + sm_secret_id = module.sm_arbitrary_secrets_tp[count.index].secret_id #checkov:skip=CKV_SECRET_6 + es_kubernetes_secret_type = "opaque" + es_kubernetes_secret_data_key = "apikey" + es_refresh_interval = "5m" + eso_store_name = "${var.es_namespaces_tp[count.index]}-store" # each store created with the name of the namespace with "-store" as suffix + es_container_registry = "us.icr.io" + es_container_registry_email = "goldeneye@us.ibm.com" + es_helm_rls_name = "es-tp" +} + +###################################################################################################### +# namespaced secretstores with trusted profile authentication and policy bound to multiple secrets groups +###################################################################################################### + +# Create namespace for tp auth with policy for multiple secrets groups +resource "kubernetes_namespace" "tp_namespace_multisg" { + metadata { + name = var.es_namespace_tp_multi_sg + } + lifecycle { + ignore_changes = [ + metadata[0].annotations, + metadata[0].labels + ] + } + depends_on = [ + time_sleep.wait_45_seconds + ] +} + +# SecretStore with trustedprofile auth and TP policy bound to multiple secrets groups +module "eso_tp_namespace_secretstore_multisg" { + depends_on = [module.external_secrets_operator] + source = "../../modules/eso-secretstore" + eso_authentication = "trusted_profile" + region = local.sm_region + sstore_namespace = kubernetes_namespace.tp_namespace_multisg.metadata[0].name + sstore_secrets_manager_guid = local.sm_guid + sstore_store_name = "${var.es_namespace_tp_multi_sg}-store" # each store created with the name of the namespace with "-store" as suffix + sstore_trusted_profile_name = module.external_secrets_trusted_profile_multisg.trusted_profile_name + service_endpoints = var.service_endpoints + sstore_helm_rls_name = "es-store-tp-multisg" + sstore_secret_name = "secretstore-tp-multisg" #checkov:skip=CKV_SECRET_6 +} + +# creating two secrets groups for a single namespace to test trusted profile policy on multiple secrets groups +module "tp_secrets_manager_group_multi_1" { + source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" + version = "1.2.2" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_name = "${var.prefix}-tp-secret-group-multisg-1" #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + secret_group_description = "Secret-Group n.1 for storing account credentials for tp authentication with multi secrets group policy" #tfsec:ignore:general-secrets-no-plaintext-exposure + providers = { + ibm = ibm.ibm-sm + } +} + +module "tp_secrets_manager_group_multi_2" { + source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" + version = "1.2.2" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_name = "${var.prefix}-tp-secret-group-multisg-21" #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + secret_group_description = "Secret-Group n.2 for storing account credentials for tp authentication with multi secrets group policy" #tfsec:ignore:general-secrets-no-plaintext-exposure + providers = { + ibm = ibm.ibm-sm + } +} + +# arbitrary secret for secrets group 1 +module "sm_arbitrary_secret_tp_multisg_1" { + source = "terraform-ibm-modules/secrets-manager-secret/ibm" + version = "1.4.0" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_id = module.tp_secrets_manager_group_multi_1.secret_group_id + secret_type = "arbitrary" + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_name = "${var.prefix}-eso-test-dummy-secret-tp-multisg-1" #checkov:skip=CKV_SECRET_6 + secret_description = "eso_test_dummy_secret_tp_multisg_1 example secret in existing secret manager instance for tp auth for secrets group n.1" #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_payload_password = "dummy_secret_value_eso_test_dummy_secret_tp" # pragma: allowlist secret + providers = { + ibm = ibm.ibm-sm + } +} + +# arbitrary secret for secrets group 2 +module "sm_arbitrary_secret_tp_multisg_2" { + source = "terraform-ibm-modules/secrets-manager-secret/ibm" + version = "1.4.0" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_id = module.tp_secrets_manager_group_multi_2.secret_group_id + secret_type = "arbitrary" + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_name = "${var.prefix}-eso-test-dummy-secret-tp-multisg-2" #checkov:skip=CKV_SECRET_6 + secret_description = "eso_test_dummy_secret_tp_multisg_2 example secret in existing secret manager instance for tp auth for secrets group n.2" #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_payload_password = "dummy_secret_value_eso_test_dummy_secret_tp" # pragma: allowlist secret + providers = { + ibm = ibm.ibm-sm + } +} + +# creating trusted profile with TP policy bound to multiple secrets groups +module "external_secrets_trusted_profile_multisg" { + source = "../../modules/eso-trusted-profile" + trusted_profile_name = "${var.prefix}-eso-tp-multisg" + secrets_manager_guid = local.sm_guid + secret_groups_id = [module.tp_secrets_manager_group_multi_1.secret_group_id, module.tp_secrets_manager_group_multi_2.secret_group_id] + tp_cluster_crn = module.ocp_base.cluster_crn + trusted_profile_claim_rule_type = "ROKS_SA" + tp_namespace = var.eso_namespace +} + +# first eso externalsecret object with trusted profile authentication and TP policy bound to multiple secrets groups +module "external_secret_tp_multisg_1" { + depends_on = [ + module.eso_tp_namespace_secretstore_multisg + ] + source = "../../modules/eso-external-secret" + eso_store_scope = "namespace" + es_kubernetes_namespace = kubernetes_namespace.tp_namespace_multisg.metadata[0].name + es_kubernetes_secret_name = "${var.prefix}-arbitrary-arb-tp-multisg-1" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "arbitrary" #checkov:skip=CKV_SECRET_6 + sm_secret_id = module.sm_arbitrary_secret_tp_multisg_1.secret_id #checkov:skip=CKV_SECRET_6 + es_kubernetes_secret_type = "opaque" + es_kubernetes_secret_data_key = "apikey" + es_refresh_interval = "5m" + eso_store_name = "${var.es_namespace_tp_multi_sg}-store" # each store created with the name of the namespace with "-store" as suffix + es_container_registry = "us.icr.io" + es_container_registry_email = "goldeneye@us.ibm.com" + es_helm_rls_name = "es-tp-multisg-1" +} + +# second eso externalsecret object with trusted profile authentication and TP policy bound to multiple secrets groups +module "external_secret_tp_multisg_2" { + depends_on = [ + module.eso_tp_namespace_secretstore_multisg + ] + source = "../../modules/eso-external-secret" + eso_store_scope = "namespace" + es_kubernetes_namespace = kubernetes_namespace.tp_namespace_multisg.metadata[0].name + es_kubernetes_secret_name = "${var.prefix}-arbitrary-arb-tp-multisg-2" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "arbitrary" #checkov:skip=CKV_SECRET_6 + sm_secret_id = module.sm_arbitrary_secret_tp_multisg_2.secret_id #checkov:skip=CKV_SECRET_6 + es_kubernetes_secret_type = "opaque" + es_kubernetes_secret_data_key = "apikey" + es_refresh_interval = "5m" + eso_store_name = "${var.es_namespace_tp_multi_sg}-store" # each store created with the name of the namespace with "-store" as suffix + es_container_registry = "us.icr.io" + es_container_registry_email = "goldeneye@us.ibm.com" + es_helm_rls_name = "es-tp-multisg-2" +} + +###################################################################################################### +# namespaced secretstores with trusted profile authentication and policy not bound to any secrets group +###################################################################################################### + +# Create namespace for trusted profile authentication with policy without secrets group +resource "kubernetes_namespace" "tp_namespace_tpnosg" { + metadata { + name = var.es_namespace_tp_no_sg + } + lifecycle { + ignore_changes = [ + metadata[0].annotations, + metadata[0].labels + ] + } + depends_on = [ + time_sleep.wait_45_seconds + ] +} + +# SecretStore with trusted profile authentication and TP policy without secrets group +module "eso_tp_namespace_secretstore_nosecgroup" { + depends_on = [module.external_secrets_operator] + source = "../../modules/eso-secretstore" + eso_authentication = "trusted_profile" + region = local.sm_region + sstore_namespace = kubernetes_namespace.tp_namespace_tpnosg.metadata[0].name + sstore_secrets_manager_guid = local.sm_guid + sstore_store_name = "${var.es_namespace_tp_no_sg}-store" # each store created with the name of the namespace with "-store" as suffix + sstore_trusted_profile_name = module.external_secrets_trusted_profile_nosecgroup.trusted_profile_name + service_endpoints = var.service_endpoints + sstore_helm_rls_name = "es-store-tp-nosg" + sstore_secret_name = "secretstore-tp-nosg" #checkov:skip=CKV_SECRET_6 +} + +# creating secrets group for a single namespace to test trusted profile policy without any secret group in the TP policy +module "tp_secrets_manager_group_not_for_policy" { + source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" + version = "1.2.2" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_name = "${var.prefix}-tp-secret-group-not-for-policy" #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + secret_group_description = "Secret-Group for storing account credentials for tp authentication not to be added to the TP policy" #tfsec:ignore:general-secrets-no-plaintext-exposure + providers = { + ibm = ibm.ibm-sm + } +} + +# arbitrary secret to use with external secret with auth using TP and policy not restricted to secrets group +module "sm_arbitrary_secret_tp_nosecgroup" { + source = "terraform-ibm-modules/secrets-manager-secret/ibm" + version = "1.4.0" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_id = module.tp_secrets_manager_group_not_for_policy.secret_group_id + secret_type = "arbitrary" + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_name = "${var.prefix}-eso-test-dummy-secret-tp-nosecgroup" #checkov:skip=CKV_SECRET_6 + secret_description = "eso_test_dummy_secret_tp_nosecgroup example secret in existing secret manager instance for tp auth for secrets group not in TP policy" #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_payload_password = "dummy_secret_value_eso_test_dummy_secret_tp" # pragma: allowlist secret + providers = { + ibm = ibm.ibm-sm + } +} + +# creating trusted profile with policy not restricted to secrets groups +module "external_secrets_trusted_profile_nosecgroup" { + source = "../../modules/eso-trusted-profile" + trusted_profile_name = "${var.prefix}-eso-tp-nosecgroup" + secrets_manager_guid = local.sm_guid + secret_groups_id = [] + tp_cluster_crn = module.ocp_base.cluster_crn + trusted_profile_claim_rule_type = "ROKS_SA" + tp_namespace = var.eso_namespace +} + +# eso externalsecret object with trusted profile authentication without secrects group in the policy +module "external_secret_tp_nosg" { + depends_on = [ + module.eso_tp_namespace_secretstore_nosecgroup + ] + source = "../../modules/eso-external-secret" + eso_store_scope = "namespace" + es_kubernetes_namespace = kubernetes_namespace.tp_namespace_tpnosg.metadata[0].name + es_kubernetes_secret_name = "${var.prefix}-arbitrary-arb-tp-nosg" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "arbitrary" #checkov:skip=CKV_SECRET_6 + sm_secret_id = module.sm_arbitrary_secret_tp_nosecgroup.secret_id #checkov:skip=CKV_SECRET_6 + es_kubernetes_secret_type = "opaque" + es_kubernetes_secret_data_key = "apikey" + es_refresh_interval = "5m" + eso_store_name = "${var.es_namespace_tp_no_sg}-store" # each store created with the name of the namespace with "-store" as suffix + es_container_registry = "us.icr.io" + es_container_registry_email = "goldeneye@us.ibm.com" + es_helm_rls_name = "es-tp-nosg" +} diff --git a/examples/all-combined/variables.tf b/examples/all-combined/variables.tf new file mode 100644 index 00000000..41262af4 --- /dev/null +++ b/examples/all-combined/variables.tf @@ -0,0 +1,355 @@ +####################################################################### +# Generic +####################################################################### + +variable "prefix" { + description = "Prefix for name of all resource created by this example" + type = string + default = "eso-example" +} + +variable "region" { + type = string + description = "Region where resources will be created." + default = "us-south" +} + +variable "ibmcloud_api_key" { + type = string + description = "APIkey that's associated with the account to use, set via environment variable TF_VAR_ibmcloud_api_key or .tfvars file." + sensitive = true +} + +variable "resource_group" { + type = string + description = "An existing resource group name to use for this example, if unset a new resource group will be created" + default = null +} + +# tflint-ignore: terraform_unused_declarations +variable "resource_tags" { + type = list(string) + description = "Optional list of tags to be added to created resources" + default = [] +} + +## Image-pull module +variable "sm_iam_secret_name" { + type = string + description = "Name of SM IAM secret (dynamic ServiceID API Key) to be created" + default = "sm-iam-secret-puller" #tfsec:ignore:general-secrets-no-plaintext-exposure +} + +variable "sm_service_plan" { + type = string + description = "Secrets-Manager trial plan" + default = "trial" +} +variable "cr_namespace_name" { + type = string + description = "Container registry namespace name to be configured in IAM policy." + default = "cr-namespace" +} + + +## ESO Module + +variable "eso_namespace" { + type = string + description = "Namespace to deploy the External secrets Operator into" + default = "es-operator" +} + +variable "es_namespaces_apikey" { + type = list(string) + description = "Namespace(s) where secrets and secretstore will be created for apikey auth" + default = ["apikeynspace1", "apikeynspace2", "apikeynspace3", "apikeynspace4"] +} + +variable "es_namespaces_tp" { + type = list(string) + description = "Namespace(s) for the secrets synched through trusted profile authentication." + default = ["tpnspace1", "tpnspace2"] +} + +variable "es_namespace_tp_multi_sg" { + type = string + description = "Namespace for the secrets synched through trusted profile authentication and TP policy with multiple secrets groups policy." + default = "tpns-multisg" +} + +variable "es_namespace_tp_no_sg" { + type = string + description = "Namespace for the secret synched through trusted profile authentication and TP policy without secrets groups." + default = "tpns-nosg" +} + +variable "es_refresh_interval" { + description = "Specify interval for es secret synchronization" + default = "1h" + type = string +} + +variable "existing_sm_instance_guid" { + type = string + description = "Existing Secrets Manager GUID. If not provided a new instance will be provisioned" + default = null +} + +variable "existing_sm_instance_crn" { + type = string + description = "Existing Secrets Manager CRN. If existing_sm_instance_guid is provided, also this input must be provided." + default = null +} + +variable "existing_sm_instance_region" { + type = string + description = "Existing Secrets Manager Region. Required if value is passed into var.existing_instance_guid." + default = null +} + +variable "service_endpoints" { + type = string + description = "The service endpoint type to communicate with the provided secrets manager instance. Possible values are `public` or `private`. This also will set the iam endpoint for containerAuth when enabling Trusted Profile/CR based authentication." + default = "public" +} + +variable "eso_deployment_nodes_configuration" { + type = string + description = "Configuration to deploy ESO on specific cluster nodes. The value of this variable will be used for NodeSelector label value and tolerations configuration. If null standard ESO deployment is done on default workers pool." + default = null +} + +## public certificate secret configuration +variable "skip_iam_authorization_policy" { + type = bool + default = false + description = "To skip the CIS IAM policy creation. To set to true if already exists (i.e. if using an existing SM instance)" +} + +variable "cert_common_name" { + description = "Public certificate common name. If null it will be set to [prefix value].goldeneye.dev.cloud.ibm.com" + type = string + default = null +} + +variable "ca_name" { + type = string + description = "Secret Managers certificate authority name. If null it will be set to [prefix value]-goldeneye-ca" + default = null +} + +variable "dns_provider_name" { + type = string + description = "Secret Managers DNS provider name. If null it will be set to [prefix value]-goldeneye-dns" + default = null +} + +variable "public_certificate_bundle" { + description = "Flag to enable the certificate bundle. If enabled the intermediate certificate is expected to be bundled with public, otherwise the template considers the intermediate field explicitly" + type = bool + default = true +} + +variable "acme_letsencrypt_private_key_sm_id" { + type = string + description = "Secrets Manager id where the Acme Lets Encrypt private key for certificate authority is stored" + default = null +} + +variable "acme_letsencrypt_private_key_secret_id" { + type = string + description = "Secret id for the Acme Lets Encrypt private key for certificate authority stored in Secrets Manager" + default = null +} + +variable "acme_letsencrypt_private_key_sm_region" { + type = string + description = "Region of the Secrets Manager id where the Acme Lets Encrypt private key for certificate authority is stored" + default = null +} + +variable "acme_letsencrypt_private_key" { + type = string + description = "Acme Lets Encrypt private key for certificate authority" + default = null +} + +# imported certificate +variable "imported_certificate_sm_id" { + type = string + default = null + description = "Secrets Manager instance id where the components for the intermediate certificate are stored" +} + +variable "imported_certificate_sm_region" { + type = string + default = null + description = "Region of the Secrets Manager instance where the components for the intermediate certificate are stored" +} + +variable "imported_certificate_intermediate_secret_id" { + type = string + default = null + description = "Secret id where the intermediate certificate for the imported certificate is stored" +} + +variable "imported_certificate_public_secret_id" { + type = string + default = null + description = "Secret id where the public certificate for the imported certificate is stored" +} + +variable "imported_certificate_private_secret_id" { + type = string + default = null + description = "Secret id where the private key for the imported certificate is stored" +} + +variable "existing_cis_instance_name" { + type = string + description = "Existing CIS instance name to create the dns configuration for the public certificate" + nullable = false +} + +variable "existing_cis_instance_resource_group_id" { + type = string + description = "Resource group ID of the existing CIS instance name to create the dns configuration for the public certificate" + nullable = false +} + +### private certificate secret configuration +variable "pvt_cert_common_name" { + description = "Private certificate common name. If null it will be set to pvt-[prefix value].goldeneye.dev.cloud.ibm.com" + type = string + default = null +} + +variable "pvt_ca_name" { + type = string + description = "Secret Managers certificate authority name. If null it will be set to pvt-[prefix value]-goldeneye-ca" + default = null +} + +variable "pvt_root_ca_common_name" { + type = string + description = "Root CA common name for the private certificate. If null it will be set to pvt-[prefix value].goldeneye.dev.cloud.ibm.com" + default = null +} + +variable "pvt_ca_max_ttl" { + type = string + description = "Private certificate CA max TTL" + default = "8760h" +} + +variable "pvt_certificate_template_name" { + type = string + description = "Template name for the private certificate to create" + default = null +} + +### sDNLB secret management + +variable "sdnlb_ibmcloud_api_key" { + type = string + description = "APIkey that's associated with the account owning the sDNLB entitled serviceID. If null the ibmcloud_api_key will be used." + sensitive = true + default = null +} + +variable "existing_sdnlb_serviceid_name" { + type = string + description = "The service ID with access to provision the sDNLB. The example creates an API key for this service ID." +} + +variable "zones" { + description = "List of zones" + type = list(string) + default = ["1", "2", "3"] +} + +variable "cidr_bases" { + description = "A list of base CIDR blocks for each network zone" + type = map(string) + default = { + private = "192.168.0.0/20", + transit = "192.168.16.0/20", + edge = "192.168.32.0/20" + } +} + +variable "acl_rules_list" { + description = "Access control list rule set per network zone" + type = list(object) + default = [ + { + name = "iks-create-worker-nodes-inbound" + action = "allow" + source = "161.26.0.0/16" + destination = "0.0.0.0/0" + direction = "inbound" + }, + { + name = "iks-nodes-to-master-inbound" + action = "allow" + source = "166.8.0.0/14" + destination = "0.0.0.0/0" + direction = "inbound" + }, + { + name = "iks-create-worker-nodes-outbound" + action = "allow" + source = "0.0.0.0/0" + destination = "161.26.0.0/16" + direction = "outbound" + }, + { + name = "iks-worker-to-master-outbound" + action = "allow" + source = "0.0.0.0/0" + destination = "166.8.0.0/14" + direction = "outbound" + }, + { + name = "allow-all-https-inbound" + source = "0.0.0.0/0" + action = "allow" + destination = "0.0.0.0/0" + direction = "inbound" + tcp = { + source_port_min = 443 + source_port_max = 443 + port_min = 1 + port_max = 65535 + } + }, + { + name = "allow-all-https-outbound" + source = "0.0.0.0/0" + action = "allow" + destination = "0.0.0.0/0" + direction = "outbound" + tcp = { + source_port_min = 1 + source_port_max = 65535 + port_min = 443 + port_max = 443 + } + }, + { + name = "deny-all-outbound" + action = "deny" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "outbound" + }, + { + name = "deny-all-inbound" + action = "deny" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "inbound" + } + ] +} diff --git a/examples/all-combined/version.tf b/examples/all-combined/version.tf new file mode 100644 index 00000000..3c68e49f --- /dev/null +++ b/examples/all-combined/version.tf @@ -0,0 +1,25 @@ +terraform { + required_version = ">= 1.1.0" + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = ">= 2.16.1" + } + helm = { + source = "hashicorp/helm" + version = ">= 2.11.0" + } + time = { + source = "hashicorp/time" + version = ">= 0.9.1" + } + ibm = { + source = "IBM-Cloud/ibm" + version = ">= 1.62.0" + } + null = { + source = "hashicorp/null" + version = ">= 3.2.1, < 4.0.0" + } + } +} diff --git a/examples/basic/main.tf b/examples/basic/main.tf index 1b5502fa..b6979bc2 100644 --- a/examples/basic/main.tf +++ b/examples/basic/main.tf @@ -2,26 +2,26 @@ # Locals ############################################################################## -# locals { - -# # general -# validate_sm_region_cnd = var.existing_sm_instance_guid != null && var.existing_sm_instance_region == null -# validate_sm_region_msg = "existing_sm_instance_region must also be set when value given for existing_sm_instance_guid." -# # tflint-ignore: terraform_unused_declarations -# validate_sm_region_chk = regex( -# "^${local.validate_sm_region_msg}$", -# (!local.validate_sm_region_cnd -# ? local.validate_sm_region_msg -# : "")) - -# sm_guid = var.existing_sm_instance_guid == null ? ibm_resource_instance.secrets_manager[0].guid : var.existing_sm_instance_guid - -# # https://github.ibm.com/GoldenEye/issues/issues/5268 - deployment region will match to sm_region as workaround -# sm_region = var.existing_sm_instance_region == null ? var.region : var.existing_sm_instance_region -# sm_acct_id = var.existing_sm_instance_guid == null ? module.iam_secrets_engine[0].acct_secret_group_id : module.secrets_manager_group_acct[0].secret_group_id -# es_namespace_apikey = "es-operator" # pragma: allowlist secret -# eso_namespace = "apikeynspace1" -# } +locals { + + # general + validate_sm_region_cnd = var.existing_sm_instance_guid != null && var.existing_sm_instance_region == null + validate_sm_region_msg = "existing_sm_instance_region must also be set when value given for existing_sm_instance_guid." + # tflint-ignore: terraform_unused_declarations + validate_sm_region_chk = regex( + "^${local.validate_sm_region_msg}$", + (!local.validate_sm_region_cnd + ? local.validate_sm_region_msg + : "")) + + sm_guid = var.existing_sm_instance_guid == null ? ibm_resource_instance.secrets_manager[0].guid : var.existing_sm_instance_guid + + # https://github.ibm.com/GoldenEye/issues/issues/5268 - deployment region will match to sm_region as workaround + sm_region = var.existing_sm_instance_region == null ? var.region : var.existing_sm_instance_region + sm_acct_id = var.existing_sm_instance_guid == null ? module.iam_secrets_engine[0].acct_secret_group_id : module.secrets_manager_group_acct[0].secret_group_id + es_namespace_apikey = "es-operator" # pragma: allowlist secret + eso_namespace = "apikeynspace1" +} ################################################################## # Resource Group @@ -38,88 +38,80 @@ module "resource_group" { ################################################################## # Create VPC, public gateway and subnets ################################################################## - # cidr_zone_combinations = flatten([ - # for cidr in local.vpc_cidr_bases : [ - # for zone in var.zones : { - # cidr_base = cidr - # zone = zone - # } - # ] - # ]) - - # subnets = [ - # for subnet in module.vpc.subnets : - # { - # id = subnet.id - # zone = subnet.zone - # cidr_block = subnet.cidr_block - # } - # ] - # cluster_vpc_subnets = { - # private = local.subnets, - # edge = local.subnets, - # transit = local.subnets - # } + locals { - subnets = flatten([ - for k, v in module.zone_subnet_addrs :[ - for network in v.networks : { - zone = k - cidr = network.cidr_block + + vpc_cidr_bases = { + private = "192.168.0.0/20", + transit = "192.168.16.0/20", + edge = "192.168.32.0/20" + } + + subnet_prefix = flatten([ + for k, v in module.zone_subnet_addrs : [ + for zone, cidr in v.network_cidr_blocks : { + cidr = cidr + label = k + zone = zone + zone_index = split("-", zone)[1] } - # { - # zone = k - # cidrs = v.networks - # } - # for zone in cidr.networks : { - # cidr = zone.cidr_block - - # } ] ]) -} + merged_subnets = [ + for subnet in module.subnets : + merge( + subnet, + { + label = lookup([for sk in local.subnet_prefix : sk if sk.cidr == subnet.subnet_ipv4_cidr][0], "label", "") + zone = lookup([for sk in local.subnet_prefix : sk if sk.cidr == subnet.subnet_ipv4_cidr][0], "zone", "") + } + ) + ] + + subnets = { + edge = [for subnet in local.merged_subnets : { id = subnet.subnet_id, cidr_block = subnet.subnet_ipv4_cidr, zone = subnet.zone } if subnet.label == "edge"], + private = [for subnet in local.merged_subnets : { id = subnet.subnet_id, cidr_block = subnet.subnet_ipv4_cidr, zone = subnet.zone } if subnet.label == "private"], + transit = [for subnet in local.merged_subnets : { id = subnet.subnet_id, cidr_block = subnet.subnet_ipv4_cidr, zone = subnet.zone } if subnet.label == "transit"] + } + + ocp_worker_pools = [ + { + subnet_prefix = "private" + pool_name = "default" + machine_type = "bx2.4x16" + workers_per_zone = 1 + labels = { "dedicated" : "private" } + operating_system = "REDHAT_8_64" + }, + { + subnet_prefix = "edge" + pool_name = "edge" + machine_type = "bx2.4x16" + workers_per_zone = 1 + labels = { "dedicated" : "edge" } + operating_system = "REDHAT_8_64" + }, + { + subnet_prefix = "transit" + pool_name = "transit" + machine_type = "bx2.4x16" + workers_per_zone = 1 + labels = { "dedicated" : "transit" } + operating_system = "REDHAT_8_64" + } + ] - # cidr_blocks = ["192.168.0.0/20", "192.168.16.0/20", "192.168.32.0/20"] - - # ocp_worker_pools = [ - # { - # subnet_prefix = "private" - # pool_name = "default" - # machine_type = "bx2.4x16" - # workers_per_zone = 1 - # labels = { "dedicated" : "private" } - # operating_system = "REDHAT_8_64" - # }, - # { - # subnet_prefix = "edge" - # pool_name = "edge" - # machine_type = "bx2.4x16" - # workers_per_zone = 1 - # labels = { "dedicated" : "edge" } - # operating_system = "REDHAT_8_64" - # }, - # { - # subnet_prefix = "transit" - # pool_name = "transit" - # machine_type = "bx2.4x16" - # workers_per_zone = 1 - # labels = { "dedicated" : "transit" } - # operating_system = "REDHAT_8_64" - # } - # ] - -output "subnets" { - value = local.subnets } + resource "null_resource" "subnet_mappings" { count = length(var.zones) triggers = { - name = "zone-${var.zones[count.index]}" + name = "${var.region}-${var.zones[count.index]}" new_bits = 2 } } @@ -133,16 +125,12 @@ module "zone_subnet_addrs" { networks = null_resource.subnet_mappings[*].triggers } -# output "zone_subnet_addrs" { -# value = module.zone_subnet_addrs -# } - module "vpc" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git?ref=v1.5.0" - vpc_name = "${var.prefix}-vpc" - resource_group_id = module.resource_group.resource_group_id - locations = [] - vpc_tags = var.resource_tags + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git?ref=v1.5.0" + vpc_name = "${var.prefix}-vpc" + resource_group_id = module.resource_group.resource_group_id + locations = [] + vpc_tags = var.resource_tags subnet_name_prefix = "${var.prefix}-subnet" default_network_acl_name = "${var.prefix}-nacl" default_routing_table_name = "${var.prefix}-routing-table" @@ -150,353 +138,337 @@ module "vpc" { create_gateway = true public_gateway_name_prefix = "${var.prefix}-pw" number_of_addresses = 16 + auto_assign_address_prefix = false +} + +module "subnet_prefix" { + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/vpc-address-prefix?ref=v1.5.0" + count = length(local.subnet_prefix) + name = "${var.prefix}-z-${local.subnet_prefix[count.index].label}-${split("-", local.subnet_prefix[count.index].zone)[2]}" + location = local.subnet_prefix[count.index].zone + vpc_id = module.vpc.vpc.vpc_id + ip_range = local.subnet_prefix[count.index].cidr +} + + +module "subnets" { + depends_on = [module.subnet_prefix] + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/subnet?ref=v1.5.0" + count = length(local.subnet_prefix) + location = local.subnet_prefix[count.index].zone + vpc_id = module.vpc.vpc.vpc_id + ip_range = local.subnet_prefix[count.index].cidr + name = "${var.prefix}-subnet-${local.subnet_prefix[count.index].label}-${split("-", local.subnet_prefix[count.index].zone)[2]}" + public_gateway = local.subnet_prefix[count.index].label == "edge" ? module.public_gateways[split("-", local.subnet_prefix[count.index].zone)[2] - 1].public_gateway_id : null + subnet_access_control_list = module.network_acl.network_acl_id +} + +module "public_gateways" { + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/public-gateway?ref=v1.5.0" + count = length(var.zones) + vpc_id = module.vpc.vpc.vpc_id + location = "${var.region}-${var.zones[count.index]}" + name = "${var.prefix}-vpc-gateway-${var.zones[count.index]}" + resource_group_id = module.resource_group.resource_group_id + tags = var.tags +} +module "security_group" { + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/security-group?ref=v1.5.0" + depends_on = [module.vpc] + create_security_group = false + resource_group_id = module.resource_group.resource_group_id + security_group = "${var.prefix}-sg" + security_group_rules = [ + { + name = "allow_all_inbound" + remote = "0.0.0.0/0" + direction = "inbound" + } + ] } -# module "address_prefix"{ -# source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/vpc-address-prefix" -# count = local.subnets -# } - -# module "subnets" { -# source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/subnet" -# count = local.subnets - -# } - -# module "security_group" { -# source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/security-group?ref=update_submodules" -# create_security_group = true -# name = "${var.prefix}-vpc-sg" -# vpc_id = module.vpc.vpc.vpc_id -# resource_group_id = module.resource_group.resource_group_id -# security_group_rules = [ -# { -# name = "allow_all_inbound" -# remote = "0.0.0.0/0" -# direction = "inbound" -# } -# ] -# } - -# module "network_acl" { -# source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/network-acl?ref=update_submodules" -# name = "${var.prefix}-vpc-acl" -# vpc_id = module.vpc.vpc.vpc_id -# resource_group_id = module.resource_group.resource_group_id -# rules = [ -# { -# name = "iks-create-worker-nodes-inbound" -# action = "allow" -# source = "161.26.0.0/16" -# destination = "0.0.0.0/0" -# direction = "inbound" -# }, -# { -# name = "iks-nodes-to-master-inbound" -# action = "allow" -# source = "166.8.0.0/14" -# destination = "0.0.0.0/0" -# direction = "inbound" -# }, -# { -# name = "iks-create-worker-nodes-outbound" -# action = "allow" -# source = "0.0.0.0/0" -# destination = "161.26.0.0/16" -# direction = "outbound" -# }, -# { -# name = "iks-worker-to-master-outbound" -# action = "allow" -# source = "0.0.0.0/0" -# destination = "166.8.0.0/14" -# direction = "outbound" -# }, -# { -# name = "allow-all-https-inbound" -# source = "0.0.0.0/0" -# action = "allow" -# destination = "0.0.0.0/0" -# direction = "inbound" -# tcp = { -# source_port_min = 443 -# source_port_max = 443 -# port_min = 1 -# port_max = 65535 -# } -# }, -# { -# name = "allow-all-https-outbound" -# source = "0.0.0.0/0" -# action = "allow" -# destination = "0.0.0.0/0" -# direction = "outbound" -# tcp = { -# source_port_min = 1 -# source_port_max = 65535 -# port_min = 443 -# port_max = 443 -# } -# }, -# { -# name = "deny-all-outbound" -# action = "deny" -# source = "0.0.0.0/0" -# destination = "0.0.0.0/0" -# direction = "outbound" -# }, -# { -# name = "deny-all-inbound" -# action = "deny" -# source = "0.0.0.0/0" -# destination = "0.0.0.0/0" -# direction = "inbound" -# } -# ] -# tags = var.tags -# } +locals { + allow_subnet_cidr_inbound_rules = [ + for k, v in module.zone_subnet_addrs : + { + name = "allow-traffic-subnet-${k}-inbound" + action = "allow" + source = v.base_cidr_block + destination = "0.0.0.0/0" + direction = "inbound" + } + ] + allow_subnet_cidr_outbound_rules = [ + for k, v in module.zone_subnet_addrs : + { + name = "allow-traffic-subnet-${k}-outbound" + action = "allow" + source = "0.0.0.0/0" + destination = v.base_cidr_block + direction = "outbound" + } + ] + acl_rules = flatten( + [ + local.allow_subnet_cidr_inbound_rules, + local.allow_subnet_cidr_outbound_rules, + var.acl_rules_list + ] + ) +} + +module "network_acl" { + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/network-acl" + name = "${var.prefix}-vpc-acl" + vpc_id = module.vpc.vpc.vpc_id + resource_group_id = module.resource_group.resource_group_id + rules = local.acl_rules + tags = var.tags +} + + # OCP CLUSTER creation -# module "ocp_base" { -# source = "terraform-ibm-modules/base-ocp-vpc/ibm" -# version = "3.34.0" -# cluster_name = "${var.prefix}-vpc" -# resource_group_id = module.resource_group.resource_group_id -# region = var.region -# force_delete_storage = true -# vpc_id = module.vpc.vpc.vpc_id -# vpc_subnets = local.cluster_vpc_subnets -# worker_pools = local.ocp_worker_pools -# tags = [] -# use_existing_cos = false -# # outbound required by cluster proxy -# disable_outbound_traffic_protection = true -# } - -# ############################################################################## -# # Init cluster config for helm and kubernetes providers -# ############################################################################## - -# data "ibm_container_cluster_config" "cluster_config" { -# cluster_name_id = module.ocp_base.cluster_id -# resource_group_id = module.resource_group.resource_group_id -# } - -# # Wait time to allow cluster refreshes components after provisioning -# resource "time_sleep" "wait_45_seconds" { -# depends_on = [data.ibm_container_cluster_config.cluster_config] -# create_duration = "45s" -# } - -# # Create namespace for apikey auth -# resource "kubernetes_namespace" "apikey_namespace" { - -# metadata { -# name = local.es_namespace_apikey -# } -# lifecycle { -# ignore_changes = [ -# metadata[0].annotations, -# metadata[0].labels -# ] -# } -# depends_on = [ -# time_sleep.wait_45_seconds -# ] -# } - -# ######################################## -# # Secrets-Manager and IAM configuration -# ######################################## - -# # IAM user policy, Secret Manager instance, Service ID for IAM engine, IAM service ID policies, associated Service ID API key stored in a secret object in account level secret-group and IAM engine configuration -# resource "ibm_resource_instance" "secrets_manager" { -# count = var.existing_sm_instance_guid == null ? 1 : 0 -# name = "${var.prefix}-sm" -# service = "secrets-manager" -# plan = var.sm_service_plan -# location = local.sm_region -# tags = var.resource_tags -# resource_group_id = module.resource_group.resource_group_id -# timeouts { -# create = "30m" # Extending provisioning time to 30 minutes -# } -# provider = ibm.ibm-sm -# } - -# # Additional Secrets-Manager Secret-Group for SERVICE level secrets -# module "secrets_manager_group_acct" { -# source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" -# version = "1.2.2" -# count = var.existing_sm_instance_guid == null ? 0 : 1 -# region = local.sm_region -# secrets_manager_guid = local.sm_guid -# #tfsec:ignore:general-secrets-no-plaintext-exposure -# secret_group_name = "${var.prefix}-account-secret-group" #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value -# secret_group_description = "Secret-Group for storing account credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure -# depends_on = [module.iam_secrets_engine] -# providers = { -# ibm = ibm.ibm-sm -# } -# } - -# # Configure instance with IAM engine -# module "iam_secrets_engine" { -# count = var.existing_sm_instance_guid == null ? 1 : 0 -# source = "terraform-ibm-modules/secrets-manager-iam-engine/ibm" -# version = "1.2.6" -# region = local.sm_region -# secrets_manager_guid = ibm_resource_instance.secrets_manager[0].guid -# iam_secret_generator_service_id_name = "${var.prefix}-sid:0.0.1:${ibm_resource_instance.secrets_manager[0].name}-iam-secret-generator:automated:simple-service:secret-manager:" -# iam_secret_generator_apikey_name = "${var.prefix}-iam-secret-generator-apikey" -# new_secret_group_name = "${var.prefix}-account-secret-group" -# iam_secret_generator_apikey_secret_name = "${var.prefix}-iam-secret-generator-apikey-secret" -# iam_engine_name = "iam-engine" -# providers = { -# ibm = ibm.ibm-sm -# } -# } - -# ################################################################## -# # Create service-id, policy to pull secrets from secret manager -# ################################################################## - -# # Create service-id -# resource "ibm_iam_service_id" "secret_puller" { -# name = "sid:0.0.1:${var.prefix}-secret-puller:automated:simple-service:secret-manager:" -# description = "ServiceID that can pull secrets from Secret Manager" -# } - -# # Create policy to allow new service id to pull secrets from secrets manager -# resource "ibm_iam_service_policy" "secret_puller_policy" { -# iam_service_id = ibm_iam_service_id.secret_puller.id -# roles = ["Viewer", "SecretsReader"] - -# resources { -# service = "secrets-manager" -# resource_instance_id = local.sm_guid -# resource_type = "secret-group" -# resource = local.sm_acct_id -# } -# } - -# ################################################################## -# # ESO deployment -# ################################################################## - -# module "external_secrets_operator" { -# source = "../../" -# eso_namespace = local.eso_namespace - -# eso_cluster_nodes_configuration = { -# nodeSelector = { -# label = "dedicated" -# value = "edge" -# } -# tolerations = { -# key = "dedicated" -# operator = "Equal" -# value = "edge" -# effect = "NoExecute" -# } -# } - -# depends_on = [ -# kubernetes_namespace.apikey_namespace -# ] -# } -# # -# ## Create dynamic Service ID API key and add to secret manager -# module "dynamic_serviceid_apikey1" { -# source = "terraform-ibm-modules/iam-serviceid-apikey-secrets-manager/ibm" -# version = "1.1.1" -# region = local.sm_region -# #tfsec:ignore:general-secrets-no-plaintext-exposure -# sm_iam_secret_name = "${var.prefix}-${var.sm_iam_secret_name}" -# sm_iam_secret_description = "Example of dynamic IAM secret / apikey" #tfsec:ignore:general-secrets-no-plaintext-exposure -# serviceid_id = ibm_iam_service_id.secret_puller.id -# secrets_manager_guid = local.sm_guid -# secret_group_id = local.sm_acct_id -# depends_on = [module.iam_secrets_engine, ibm_iam_service_policy.secret_puller_policy, ibm_iam_service_id.secret_puller] -# providers = { -# ibm = ibm.ibm-sm -# } -# } - -# ## Data source to get API Key from secret manager secret-puller-secret -# data "ibm_sm_iam_credentials_secret" "secret_puller_secret" { -# instance_id = local.sm_guid -# #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static type -# secret_id = module.dynamic_serviceid_apikey1.secret_id -# provider = ibm.ibm-sm -# } - -# ################################################################## -# # ESO ClusterStore creation with apikey authentication -# ################################################################## -# module "eso_clusterstore" { -# source = "../../modules/eso-clusterstore" -# eso_authentication = "api_key" -# clusterstore_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key -# region = local.sm_region -# clusterstore_helm_rls_name = "cluster-store" -# clusterstore_secret_name = "generic-cluster-api-key" #checkov:skip=CKV_SECRET_6 -# clusterstore_name = "cluster-store" -# clusterstore_secrets_manager_guid = local.sm_guid -# eso_namespace = local.eso_namespace -# service_endpoints = "public" -# depends_on = [ -# module.external_secrets_operator, -# ] -# } - -# ################################################################## -# # creation of generic username/password secret -# # (for example to store artifactory username and API key) -# ################################################################## - -# locals { -# # secret value for sm_userpass_secret -# userpass_apikey = sensitive("password-payload-example") -# } - -# # Create username_password secret and store in secret manager -# module "sm_userpass_secret" { -# source = "terraform-ibm-modules/secrets-manager-secret/ibm" -# version = "1.4.0" -# region = local.sm_region -# secrets_manager_guid = local.sm_guid -# secret_group_id = local.sm_acct_id -# #tfsec:ignore:general-secrets-no-plaintext-exposure -# secret_name = "${var.prefix}-usernamepassword-secret" # checkov:skip=CKV_SECRET_6 -# secret_description = "example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure # checkov:skip=CKV_SECRET_6 -# secret_payload_password = local.userpass_apikey -# secret_type = "username_password" #checkov:skip=CKV_SECRET_6 -# #tfsec:ignore:general-secrets-no-plaintext-exposure -# secret_username = "artifactory-user" # checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value -# secret_auto_rotation = false -# secret_auto_rotation_interval = 0 -# secret_auto_rotation_unit = null -# providers = { -# ibm = ibm.ibm-sm -# } -# } - -# ################################################################## -# # ESO externalsecrets with cluster scope and apikey authentication -# ################################################################## - -# # ESO externalsecret with cluster scope creating a dockerconfigjson type secret -# module "external_secret_usr_pass" { -# depends_on = [module.external_secrets_operator] -# source = "../../modules/eso-external-secret" -# es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 -# sm_secret_type = "username_password" #checkov:skip=CKV_SECRET_6 -# sm_secret_id = module.sm_userpass_secret.secret_id -# es_kubernetes_namespace = kubernetes_namespace.apikey_namespace.metadata[0].name -# eso_store_name = "cluster-store" -# es_container_registry = "wcp-my-team-docker-local.artifactory.swg-devops.com" -# es_kubernetes_secret_name = "dockerconfigjson-uc" #checkov:skip=CKV_SECRET_6 -# es_helm_rls_name = "es-docker-uc" -# reloader_watching = true -# } +module "ocp_base" { + source = "terraform-ibm-modules/base-ocp-vpc/ibm" + version = "3.35.10" + cluster_name = "${var.prefix}-vpc" + resource_group_id = module.resource_group.resource_group_id + region = var.region + force_delete_storage = true + vpc_id = module.vpc.vpc.vpc_id + vpc_subnets = local.subnets + worker_pools = local.ocp_worker_pools + tags = [] + use_existing_cos = false + # outbound required by cluster proxy + disable_outbound_traffic_protection = true +} + +############################################################################## +# Init cluster config for helm and kubernetes providers +############################################################################## + +data "ibm_container_cluster_config" "cluster_config" { + cluster_name_id = module.ocp_base.cluster_id + resource_group_id = module.resource_group.resource_group_id +} + +# Wait time to allow cluster refreshes components after provisioning +resource "time_sleep" "wait_45_seconds" { + depends_on = [data.ibm_container_cluster_config.cluster_config] + create_duration = "45s" +} + +# Create namespace for apikey auth +resource "kubernetes_namespace" "apikey_namespace" { + + metadata { + name = local.es_namespace_apikey + } + lifecycle { + ignore_changes = [ + metadata[0].annotations, + metadata[0].labels + ] + } + depends_on = [ + time_sleep.wait_45_seconds + ] +} + +######################################## +# Secrets-Manager and IAM configuration +######################################## + +# IAM user policy, Secret Manager instance, Service ID for IAM engine, IAM service ID policies, associated Service ID API key stored in a secret object in account level secret-group and IAM engine configuration +resource "ibm_resource_instance" "secrets_manager" { + count = var.existing_sm_instance_guid == null ? 1 : 0 + name = "${var.prefix}-sm" + service = "secrets-manager" + plan = var.sm_service_plan + location = local.sm_region + tags = var.resource_tags + resource_group_id = module.resource_group.resource_group_id + timeouts { + create = "30m" # Extending provisioning time to 30 minutes + } + provider = ibm.ibm-sm +} + +# Additional Secrets-Manager Secret-Group for SERVICE level secrets +module "secrets_manager_group_acct" { + source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" + version = "1.2.2" + count = var.existing_sm_instance_guid == null ? 0 : 1 + region = local.sm_region + secrets_manager_guid = local.sm_guid + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_group_name = "${var.prefix}-account-secret-group" #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + secret_group_description = "Secret-Group for storing account credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure + depends_on = [module.iam_secrets_engine] + providers = { + ibm = ibm.ibm-sm + } +} + +# Configure instance with IAM engine +module "iam_secrets_engine" { + count = var.existing_sm_instance_guid == null ? 1 : 0 + source = "terraform-ibm-modules/secrets-manager-iam-engine/ibm" + version = "1.2.6" + region = local.sm_region + secrets_manager_guid = ibm_resource_instance.secrets_manager[0].guid + iam_secret_generator_service_id_name = "${var.prefix}-sid:0.0.1:${ibm_resource_instance.secrets_manager[0].name}-iam-secret-generator:automated:simple-service:secret-manager:" + iam_secret_generator_apikey_name = "${var.prefix}-iam-secret-generator-apikey" + new_secret_group_name = "${var.prefix}-account-secret-group" + iam_secret_generator_apikey_secret_name = "${var.prefix}-iam-secret-generator-apikey-secret" + iam_engine_name = "iam-engine" + providers = { + ibm = ibm.ibm-sm + } +} + +################################################################## +# Create service-id, policy to pull secrets from secret manager +################################################################## + +# Create service-id +resource "ibm_iam_service_id" "secret_puller" { + name = "sid:0.0.1:${var.prefix}-secret-puller:automated:simple-service:secret-manager:" + description = "ServiceID that can pull secrets from Secret Manager" +} + +# Create policy to allow new service id to pull secrets from secrets manager +resource "ibm_iam_service_policy" "secret_puller_policy" { + iam_service_id = ibm_iam_service_id.secret_puller.id + roles = ["Viewer", "SecretsReader"] + + resources { + service = "secrets-manager" + resource_instance_id = local.sm_guid + resource_type = "secret-group" + resource = local.sm_acct_id + } +} + +################################################################## +# ESO deployment +################################################################## + +module "external_secrets_operator" { + source = "../../" + eso_namespace = local.eso_namespace + + eso_cluster_nodes_configuration = { + nodeSelector = { + label = "dedicated" + value = "edge" + } + tolerations = { + key = "dedicated" + operator = "Equal" + value = "edge" + effect = "NoExecute" + } + } + + depends_on = [ + kubernetes_namespace.apikey_namespace + ] +} +# +## Create dynamic Service ID API key and add to secret manager +module "dynamic_serviceid_apikey1" { + source = "terraform-ibm-modules/iam-serviceid-apikey-secrets-manager/ibm" + version = "1.1.1" + region = local.sm_region + #tfsec:ignore:general-secrets-no-plaintext-exposure + sm_iam_secret_name = "${var.prefix}-${var.sm_iam_secret_name}" + sm_iam_secret_description = "Example of dynamic IAM secret / apikey" #tfsec:ignore:general-secrets-no-plaintext-exposure + serviceid_id = ibm_iam_service_id.secret_puller.id + secrets_manager_guid = local.sm_guid + secret_group_id = local.sm_acct_id + depends_on = [module.iam_secrets_engine, ibm_iam_service_policy.secret_puller_policy, ibm_iam_service_id.secret_puller] + providers = { + ibm = ibm.ibm-sm + } +} + +## Data source to get API Key from secret manager secret-puller-secret +data "ibm_sm_iam_credentials_secret" "secret_puller_secret" { + instance_id = local.sm_guid + #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static type + secret_id = module.dynamic_serviceid_apikey1.secret_id + provider = ibm.ibm-sm +} + +################################################################## +# ESO ClusterStore creation with apikey authentication +################################################################## +module "eso_clusterstore" { + source = "../../modules/eso-clusterstore" + eso_authentication = "api_key" + clusterstore_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key + region = local.sm_region + clusterstore_helm_rls_name = "cluster-store" + clusterstore_secret_name = "generic-cluster-api-key" #checkov:skip=CKV_SECRET_6 + clusterstore_name = "cluster-store" + clusterstore_secrets_manager_guid = local.sm_guid + eso_namespace = local.eso_namespace + service_endpoints = "public" + depends_on = [ + module.external_secrets_operator, + ] +} + +################################################################## +# creation of generic username/password secret +# (for example to store artifactory username and API key) +################################################################## + +locals { + # secret value for sm_userpass_secret + userpass_apikey = sensitive("password-payload-example") +} + +# Create username_password secret and store in secret manager +module "sm_userpass_secret" { + source = "terraform-ibm-modules/secrets-manager-secret/ibm" + version = "1.4.0" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_id = local.sm_acct_id + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_name = "${var.prefix}-usernamepassword-secret" # checkov:skip=CKV_SECRET_6 + secret_description = "example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure # checkov:skip=CKV_SECRET_6 + secret_payload_password = local.userpass_apikey + secret_type = "username_password" #checkov:skip=CKV_SECRET_6 + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_username = "artifactory-user" # checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + secret_auto_rotation = false + secret_auto_rotation_interval = 0 + secret_auto_rotation_unit = null + providers = { + ibm = ibm.ibm-sm + } +} + +################################################################## +# ESO externalsecrets with cluster scope and apikey authentication +################################################################## + +# ESO externalsecret with cluster scope creating a dockerconfigjson type secret +module "external_secret_usr_pass" { + depends_on = [module.external_secrets_operator] + source = "../../modules/eso-external-secret" + es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "username_password" #checkov:skip=CKV_SECRET_6 + sm_secret_id = module.sm_userpass_secret.secret_id + es_kubernetes_namespace = kubernetes_namespace.apikey_namespace.metadata[0].name + eso_store_name = "cluster-store" + es_container_registry = "wcp-my-team-docker-local.artifactory.swg-devops.com" + es_kubernetes_secret_name = "dockerconfigjson-uc" #checkov:skip=CKV_SECRET_6 + es_helm_rls_name = "es-docker-uc" + reloader_watching = true +} diff --git a/examples/basic/outputs.tf b/examples/basic/outputs.tf index ef91e695..e124314b 100644 --- a/examples/basic/outputs.tf +++ b/examples/basic/outputs.tf @@ -1,24 +1,7 @@ ############################################################################## # Outputs ############################################################################## -# output "cluster_id" { -# description = "ID of the cluster deployed" -# value = module.ocp_base.cluster_id -# } - -output "vpc" { - description = "Configuration of newly created or existing VPC instace." - value = module.vpc +output "cluster_id" { + description = "ID of the cluster deployed" + value = module.ocp_base.cluster_id } - -# output "security_group" { -# value = module.security_group -# } - -# output "network_acl" { -# value= module.network_acl -# } - -# output "subnets" { -# value = module.subnet -# } \ No newline at end of file diff --git a/examples/basic/variables.tf b/examples/basic/variables.tf index dfae95fe..ea8c9a46 100644 --- a/examples/basic/variables.tf +++ b/examples/basic/variables.tf @@ -81,8 +81,91 @@ variable "cidr_bases" { } } -variable "new_bits" { - description = "Number of additional address bits to use for numbering the new networks" - type = number - default = 2 +variable "acl_rules_list" { + description = "Access control list rule set per network zone" + type = list( + object({ + name = string + action = string + source = string + destination = string + direction = string + tcp = optional(object({ + source_port_min = number + source_port_max = number + port_min = number + port_max = number + })) + }) + ) + default = [ + { + name = "iks-create-worker-nodes-inbound" + action = "allow" + source = "161.26.0.0/16" + destination = "0.0.0.0/0" + direction = "inbound" + }, + { + name = "iks-nodes-to-master-inbound" + action = "allow" + source = "166.8.0.0/14" + destination = "0.0.0.0/0" + direction = "inbound" + }, + { + name = "iks-create-worker-nodes-outbound" + action = "allow" + source = "0.0.0.0/0" + destination = "161.26.0.0/16" + direction = "outbound" + }, + { + name = "iks-worker-to-master-outbound" + action = "allow" + source = "0.0.0.0/0" + destination = "166.8.0.0/14" + direction = "outbound" + }, + { + name = "allow-all-https-inbound" + source = "0.0.0.0/0" + action = "allow" + destination = "0.0.0.0/0" + direction = "inbound" + tcp = { + source_port_min = 443 + source_port_max = 443 + port_min = 1 + port_max = 65535 + } + }, + { + name = "allow-all-https-outbound" + source = "0.0.0.0/0" + action = "allow" + destination = "0.0.0.0/0" + direction = "outbound" + tcp = { + source_port_min = 1 + source_port_max = 65535 + port_min = 443 + port_max = 443 + } + }, + { + name = "deny-all-outbound" + action = "deny" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "outbound" + }, + { + name = "deny-all-inbound" + action = "deny" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "inbound" + } + ] } diff --git a/examples/basic/version.tf b/examples/basic/version.tf index ca7aad4c..a4b04903 100644 --- a/examples/basic/version.tf +++ b/examples/basic/version.tf @@ -17,5 +17,9 @@ terraform { source = "IBM-Cloud/ibm" version = "= 1.70.0" } + null = { + source = "hashicorp/null" + version = ">= 3.2.1, < 4.0.0" + } } } diff --git a/main.tf b/main.tf index d8ccd7d5..a6589893 100644 --- a/main.tf +++ b/main.tf @@ -7,10 +7,8 @@ ## Install ESO locals { - eso_digest = "v0.11.0-ubi@sha256:b5f685b86cf684020e863c6c2ed91e8a79cad68260d7149ddee073ece2573d6f" - - eso_image_tag_digest = var.eso_image_tag_digest != null || var.eso_image_tag_digest != "" ? var.eso_image_tag_digest : local.eso_digest - eso_image_repo = var.eso_image_repo + eso_image_tag_digest = "v0.12.1-ubi@sha256:caff77c2aa933876205d0da3f6883a3e0313ced0a0f0ea49b1abeca4071d027a" # datasource: icr.io/ibm-iac/external-secrets + eso_image_repo = "icr.io/ibm-iac/external-secrets" reloader_image_tag_digest = "v1.2.1-ubi@sha256:78d3b7269d00df1b9550584dba817299b5842c48038db1f1603255914033307f" # datasource: icr.io/ibm-iac/reloader reloader_image_repo = "icr.io/ibm-iac/reloader" @@ -182,12 +180,11 @@ EOF resource "helm_release" "external_secrets_operator" { depends_on = [module.eso_namespace, data.kubernetes_namespace.existing_eso_namespace] - name = "external-secrets" - namespace = local.eso_namespace - chart = "external-secrets" - version = "0.12.1" - wait = true - repository = "https://charts.external-secrets.io" + name = "external-secrets" + namespace = local.eso_namespace + chart = "oci://icr.io/ibm-iac-charts/external-secrets" + version = "0.12.1" + wait = true set { name = "image.repository" diff --git a/tests/pr_test.go b/tests/pr_test.go index b63f6e08..302faa12 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -2,6 +2,7 @@ package test import ( + "log" "os" "testing" "time" @@ -11,16 +12,27 @@ import ( "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/cloudinfo" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/common" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testhelper" + "gopkg.in/yaml.v3" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // Resource groups are maintained https://github.ibm.com/GoldenEye/ge-dev-account-management const resourceGroup = "geretain-test-ext-secrets-sync" +const defaultExampleTerraformDir = "examples/all-combined" const basicExampleTerraformDir = "examples/basic" +// deploying eso on edge node to have it able to connect to SM and IAM on public network +const esoWorkersSelector = "edge" + +// Define a struct with fields that match the structure of the YAML data +const yamlLocation = "../common-dev-assets/common-go-assets/common-permanent-resources.yaml" + type Config struct { SmGuid string `yaml:"secretsManagerGuid"` + SmCRN string `yaml:"secretsManagerCRN"` SmRegion string `yaml:"secretsManagerRegion"` + RgId string `yaml:"resourceGroupTestPermanentId"` + CisName string `yaml:"cisInstanceName"` // secret ids for the secrets composing the imported certificate to create ImpCertIntermediateSecretId string `yaml:"imported_certificate_intermediate_secret_id"` @@ -39,7 +51,83 @@ type Config struct { } var smGuid string +var smCRN string var smRegion string +var rgId string +var cisName string +var impCertificateSmRegion string +var impCertificateSmGuid string +var impCertIntermediateSecretID string +var impCertPublicSecretID string +var impCertPrivateSecretID string +var acmeLEPrivateKeySmGuid string +var acmeLEPrivateKeySmRegion string +var acmeLEPrivateKeySecretId string +var sdnlbServiceIdName string + +// terraform vars for all-combined test (including Upgrade one) +var allCombinedTerraformVars map[string]interface{} + +// TestMain will be run before any parallel tests, used to read data from yaml for use with tests +func TestMain(m *testing.M) { + // Read the YAML file contents + data, err := os.ReadFile(yamlLocation) + if err != nil { + log.Fatal(err) + } + // Create a struct to hold the YAML data + var config Config + // Unmarshal the YAML data into the struct + err = yaml.Unmarshal(data, &config) + if err != nil { + log.Fatal(err) + } + + // Parse the SM guid and region from data and setting all-combined test input values used in TestRunDefaultExample and TestRunUpgradeExample + smGuid = config.SmGuid + smCRN = config.SmCRN + smRegion = config.SmRegion + cisName = config.CisName + rgId = config.RgId + impCertIntermediateSecretID = config.ImpCertIntermediateSecretId + impCertPrivateSecretID = config.ImpCertPrivateSecretId + impCertPublicSecretID = config.ImpCertPublicSecretId + acmeLEPrivateKeySmGuid = config.AcmeLEPrivateKeySmGuid + acmeLEPrivateKeySmRegion = config.AcmeLEPrivateKeySmRegion + acmeLEPrivateKeySecretId = config.AcmeLEPrivateKeySecretId + impCertificateSmGuid = config.ImpCertificateSmGuid + impCertificateSmRegion = config.ImpCertificateSmRegion + + sdnlbServiceIdName = config.SdnlbServiceidName + err = log.Output(1, "TestMain using sdnlbServiceIdName "+sdnlbServiceIdName) + if err != nil { + log.Fatal(err) + } + + allCombinedTerraformVars = map[string]interface{}{ + "existing_cis_instance_name": cisName, + "existing_cis_instance_resource_group_id": rgId, + // imported certificate and public certificate creation management + "existing_sm_instance_crn": smCRN, + "existing_sm_instance_guid": smGuid, + "existing_sm_instance_region": smRegion, + "imported_certificate_sm_region": impCertificateSmRegion, + "imported_certificate_sm_id": impCertificateSmGuid, + "imported_certificate_intermediate_secret_id": impCertIntermediateSecretID, + "imported_certificate_public_secret_id": impCertPublicSecretID, + "imported_certificate_private_secret_id": impCertPrivateSecretID, + "acme_letsencrypt_private_key_secret_id": acmeLEPrivateKeySecretId, + "acme_letsencrypt_private_key_sm_id": acmeLEPrivateKeySmGuid, + "acme_letsencrypt_private_key_sm_region": acmeLEPrivateKeySmRegion, + "eso_deployment_nodes_configuration": esoWorkersSelector, + // setting skip_iam_authorization_policy to true because using the existing secrets manager instance and the policy already exists + "skip_iam_authorization_policy": true, + "existing_sdnlb_serviceid_name": sdnlbServiceIdName, + "service_endpoints": "public", + } + + os.Exit(m.Run()) +} var ignoreUpdates = []string{ "module.es_kubernetes_secret_usr_pass.helm_release.external_secrets_operator[0]", @@ -94,6 +182,91 @@ func setupOptions(t *testing.T, prefix string, terraformDir string, terraformVar return options } +func TestRunDefaultExample(t *testing.T) { + t.Parallel() + + options := setupOptions(t, "eso", defaultExampleTerraformDir, allCombinedTerraformVars) + + options.SkipTestTearDown = true + defer func() { + options.TestTearDown() + }() + output, err := options.RunTestConsistency() + + if assert.Nil(t, err, "Consistency test should not have errored") { + outputs := options.LastTestTerraformOutputs + _, tfOutputsErr := testhelper.ValidateTerraformOutputs(outputs, "cluster_id") + if assert.Nil(t, tfOutputsErr, tfOutputsErr) { + log.Println("Prefix used " + options.Prefix) + + clusterId := outputs["cluster_id"].(string) + + log.Println("clusterId " + clusterId) + + // building the list of secrets to test + namespaces_for_apikey_login := []string{"apikeynspace1", "apikeynspace2", "apikeynspace3", "apikeynspace4"} + namespaces_for_tp_login := []string{"tpnspace1", "tpnspace2"} + + secretsMap := map[string]string{ + "dockerconfigjson-uc": namespaces_for_apikey_login[0], + // temporary disabled cloudant resource key secret test + // https://github.ibm.com/GoldenEye/issues/issues/7726 + // "cloudant-opaque-arb": namespaces_for_apikey_login[1], + "dockerconfigjson-arb": namespaces_for_apikey_login[2], + "pvtcertificate-tls": namespaces_for_apikey_login[2], + "kv-single-key": namespaces_for_apikey_login[3], + "kv-multiple-keys": namespaces_for_apikey_login[3], + "dockerconfigjson-iam": namespaces_for_apikey_login[3], + "dockerconfigjson-chain": namespaces_for_apikey_login[3], + options.Prefix + "-arbitrary-arb-tp-0": namespaces_for_tp_login[0], + options.Prefix + "-arbitrary-arb-tp-1": namespaces_for_tp_login[1], + options.Prefix + "-arbitrary-arb-tp-multisg-1": "tpns-multisg", + options.Prefix + "-arbitrary-arb-tp-multisg-2": "tpns-multisg", + options.Prefix + "-arbitrary-arb-tp-nosg": "tpns-nosg", + options.Prefix + "-arbitrary-arb-cstore-tp": "eso-cstore-tp-namespace", + // sdnlb secret + "sdnlb-config": "kube-system", + } + + log.Printf("secretsMap %s", secretsMap) + + // get cluster config + log.Println("Loading cluster configuration with id " + clusterId) + cloudinfosvc, err := cloudinfo.NewCloudInfoServiceFromEnv("TF_VAR_ibmcloud_api_key", cloudinfo.CloudInfoServiceOptions{}) + if assert.Nil(t, err, "Error creating cloud info service") { + clusterConfigPath, err := cloudinfosvc.GetClusterConfigConfigPath(clusterId) + defer func() { + // attempt to remove cluster config file after test + _ = os.Remove(clusterConfigPath) + }() + if assert.Nil(t, err, "Error getting cluster config path") { + // for each secret to test configure Terratest with cluster config + // the test checks if each secret is correctly created in the cluster + for secretName, secretNamespace := range secretsMap { + ocOptions := k8s.NewKubectlOptions("", clusterConfigPath, secretNamespace) + log.Printf("Testing secret name %s namespace %s\n", secretName, secretNamespace) + _, err := k8s.GetSecretE(t, ocOptions, secretName) + assert.Nil(t, err, "Error retrieving secret "+secretName+" in namespace "+secretNamespace) + } + } + } + } + } + + assert.NotNil(t, output, "Expected some output") +} + +func TestRunUpgradeExample(t *testing.T) { + t.Parallel() + + options := setupOptions(t, "eso-upg", defaultExampleTerraformDir, allCombinedTerraformVars) + output, err := options.RunTestUpgrade() + if !options.UpgradeTestSkipped { + assert.Nil(t, err, "This should not have errored") + assert.NotNil(t, output, "Expected some output") + } +} + func TestReloaderOperational(t *testing.T) { t.Parallel() // terraform vars for reloader test diff --git a/variables.tf b/variables.tf index adadc1b6..20b5f463 100644 --- a/variables.tf +++ b/variables.tf @@ -150,15 +150,3 @@ variable "reloader_custom_values" { type = string default = null } - -variable "eso_image_repo" { - type = string - description = "The repository for the External Secrets Operator image. Default is `ghcr.io/external-secrets/external-secrets`." - default = "ghcr.io/external-secrets/external-secrets" -} - -variable "eso_image_tag_digest" { - type = string - description = "The tag or digest for the External Secrets Operator image. Provide a digest in the format `sha256:xxxxx...` for immutability or leave it as a tag version." - default = "v0.11.0-ubi@sha256:b5f685b86cf684020e863c6c2ed91e8a79cad68260d7149ddee073ece2573d6f" -} From e65ede6431207f05990835f9e07d6de755cbc47c Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Mon, 13 Jan 2025 15:30:37 +0530 Subject: [PATCH 09/40] updated the all-combined example --- examples/all-combined/main.tf | 178 +++++------------------------ examples/all-combined/variables.tf | 6 +- examples/all-combined/version.tf | 2 +- examples/basic/README.md | 2 +- examples/basic/main.tf | 41 ++----- examples/basic/outputs.tf | 10 +- examples/basic/variables.tf | 4 +- main.tf | 20 ++-- tests/pr_test.go | 4 +- tests/samples/sample.yaml | 2 +- 10 files changed, 62 insertions(+), 207 deletions(-) diff --git a/examples/all-combined/main.tf b/examples/all-combined/main.tf index e53ee0e6..f5f00f80 100644 --- a/examples/all-combined/main.tf +++ b/examples/all-combined/main.tf @@ -19,12 +19,6 @@ locals { # sDNLB entitled account API key - if null the ibmcloud_api_key will be used sdnlb_ibmcloud_api_key = var.sdnlb_ibmcloud_api_key == null ? var.ibmcloud_api_key : var.sdnlb_ibmcloud_api_key - vpc_cidr_bases = { - private = "192.168.0.0/20", - transit = "192.168.16.0/20", - edge = "192.168.32.0/20" - } - subnet_prefix = flatten([ for k, v in module.zone_subnet_addrs : [ for zone, cidr in v.network_cidr_blocks : { @@ -37,49 +31,31 @@ locals { ]) -merged_subnets = [ - for subnet in module.subnets : + merged_subnets = [ + for subnet in module.subnets : merge( subnet, { - label = lookup([for sk in local.subnet_prefix : sk if sk.cidr == subnet.subnet_ipv4_cidr][0], "label", "") - zone = lookup([for sk in local.subnet_prefix : sk if sk.cidr == subnet.subnet_ipv4_cidr][0], "zone", "") + label = lookup([for sk in local.subnet_prefix : sk if sk.cidr == subnet.subnet_ipv4_cidr][0], "label", "") + zone = lookup([for sk in local.subnet_prefix : sk if sk.cidr == subnet.subnet_ipv4_cidr][0], "zone", "") } ) -] + ] -subnets = { - edge = [for subnet in local.merged_subnets : {id = subnet.subnet_id, cidr_block = subnet.subnet_ipv4_cidr, zone = subnet.zone} if subnet.label == "edge"], - private = [for subnet in local.merged_subnets : {id = subnet.subnet_id, cidr_block = subnet.subnet_ipv4_cidr, zone = subnet.zone} if subnet.label == "private"], - transit = [for subnet in local.merged_subnets : {id = subnet.subnet_id, cidr_block = subnet.subnet_ipv4_cidr, zone = subnet.zone} if subnet.label == "transit"] -} + subnets = { + default = [for subnet in local.merged_subnets : { id = subnet.subnet_id, cidr_block = subnet.subnet_ipv4_cidr, zone = subnet.zone } if subnet.label == "default"], + } ocp_worker_pools = [ - { - subnet_prefix = "private" - pool_name = "default" - machine_type = "bx2.4x16" - workers_per_zone = 1 - labels = { "dedicated" : "private" } - operating_system = "REDHAT_8_64" - }, - { - subnet_prefix = "edge" - pool_name = "edge" - machine_type = "bx2.4x16" - workers_per_zone = 1 - labels = { "dedicated" : "edge" } - operating_system = "REDHAT_8_64" - }, - { - subnet_prefix = "transit" - pool_name = "transit" - machine_type = "bx2.4x16" - workers_per_zone = 1 - labels = { "dedicated" : "transit" } - operating_system = "REDHAT_8_64" - } -] + { + subnet_prefix = "default" + pool_name = "default" + machine_type = "bx2.4x16" + workers_per_zone = 1 + labels = { "dedicated" : "default" } + operating_system = "REDHAT_8_64" + } + ] } @@ -129,14 +105,14 @@ module "subnet_prefix" { module "subnets" { - depends_on = [module.subnet_prefix] - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/subnet?ref=v1.5.0" - count = length(local.subnet_prefix) - location = local.subnet_prefix[count.index].zone - vpc_id = module.vpc.vpc.vpc_id - ip_range = local.subnet_prefix[count.index].cidr - name = "${var.prefix}-subnet-${local.subnet_prefix[count.index].label}-${split("-", local.subnet_prefix[count.index].zone)[2]}" - public_gateway = local.subnet_prefix[count.index].label == "edge" ? module.public_gateways[split("-", local.subnet_prefix[count.index].zone)[2] - 1].public_gateway_id : null + depends_on = [module.subnet_prefix] + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/subnet?ref=v1.5.0" + count = length(local.subnet_prefix) + location = local.subnet_prefix[count.index].zone + vpc_id = module.vpc.vpc.vpc_id + ip_range = local.subnet_prefix[count.index].cidr + name = "${var.prefix}-subnet-${local.subnet_prefix[count.index].label}-${split("-", local.subnet_prefix[count.index].zone)[2]}" + public_gateway = local.subnet_prefix[count.index].label == "default" ? module.public_gateways[split("-", local.subnet_prefix[count.index].zone)[2] - 1].public_gateway_id : null subnet_access_control_list = module.network_acl.network_acl_id } @@ -151,14 +127,14 @@ module "public_gateways" { } module "security_group" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/security-group?ref=v1.5.0" - depends_on = [module.vpc] + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/security-group?ref=v1.5.0" + depends_on = [module.vpc] create_security_group = false resource_group_id = module.resource_group.resource_group_id - security_group = "${var.prefix}-sg" + security_group = "${var.prefix}-sg" security_group_rules = [ { - name = "allow_all_inbound" + name = "allow_all_inbound" remote = "0.0.0.0/0" direction = "inbound" } @@ -346,99 +322,3 @@ resource "kubernetes_namespace" "apikey_namespaces" { time_sleep.wait_45_seconds ] } - -variable "zones" { - description = "List of zones" - type = list(string) - default = ["1", "2", "3"] -} - -variable "cidr_bases" { - description = "A list of base CIDR blocks for each network zone" - type = map(string) - default = { - private = "192.168.0.0/20", - transit = "192.168.16.0/20", - edge = "192.168.32.0/20" - } -} - -variable "new_bits" { - description = "Number of additional address bits to use for numbering the new networks" - type = number - default = 2 -} - -variable "acl_rules_list" { - description = "Access control list rule set per network zone" - default = [ - { - name = "iks-create-worker-nodes-inbound" - action = "allow" - source = "161.26.0.0/16" - destination = "0.0.0.0/0" - direction = "inbound" - }, - { - name = "iks-nodes-to-master-inbound" - action = "allow" - source = "166.8.0.0/14" - destination = "0.0.0.0/0" - direction = "inbound" - }, - { - name = "iks-create-worker-nodes-outbound" - action = "allow" - source = "0.0.0.0/0" - destination = "161.26.0.0/16" - direction = "outbound" - }, - { - name = "iks-worker-to-master-outbound" - action = "allow" - source = "0.0.0.0/0" - destination = "166.8.0.0/14" - direction = "outbound" - }, - { - name = "allow-all-https-inbound" - source = "0.0.0.0/0" - action = "allow" - destination = "0.0.0.0/0" - direction = "inbound" - tcp = { - source_port_min = 443 - source_port_max = 443 - port_min = 1 - port_max = 65535 - } - }, - { - name = "allow-all-https-outbound" - source = "0.0.0.0/0" - action = "allow" - destination = "0.0.0.0/0" - direction = "outbound" - tcp = { - source_port_min = 1 - source_port_max = 65535 - port_min = 443 - port_max = 443 - } - }, - { - name = "deny-all-outbound" - action = "deny" - source = "0.0.0.0/0" - destination = "0.0.0.0/0" - direction = "outbound" - }, - { - name = "deny-all-inbound" - action = "deny" - source = "0.0.0.0/0" - destination = "0.0.0.0/0" - direction = "inbound" - } - ] -} \ No newline at end of file diff --git a/examples/all-combined/variables.tf b/examples/all-combined/variables.tf index 41262af4..ce4ff298 100644 --- a/examples/all-combined/variables.tf +++ b/examples/all-combined/variables.tf @@ -273,15 +273,13 @@ variable "cidr_bases" { description = "A list of base CIDR blocks for each network zone" type = map(string) default = { - private = "192.168.0.0/20", - transit = "192.168.16.0/20", - edge = "192.168.32.0/20" + default = "192.168.32.0/20" } } variable "acl_rules_list" { description = "Access control list rule set per network zone" - type = list(object) + type = list(object) default = [ { name = "iks-create-worker-nodes-inbound" diff --git a/examples/all-combined/version.tf b/examples/all-combined/version.tf index 3c68e49f..5cc9cc6a 100644 --- a/examples/all-combined/version.tf +++ b/examples/all-combined/version.tf @@ -17,7 +17,7 @@ terraform { source = "IBM-Cloud/ibm" version = ">= 1.62.0" } - null = { + null = { source = "hashicorp/null" version = ">= 3.2.1, < 4.0.0" } diff --git a/examples/basic/README.md b/examples/basic/README.md index 504f852c..f77bef3c 100644 --- a/examples/basic/README.md +++ b/examples/basic/README.md @@ -8,7 +8,7 @@ This module provides a basic example to deploy the External Secrets Operator alo - **VPC and Subnet Configuration**: Establishes a Virtual Private Cloud (VPC) with associated subnets, setting up network segmentation and ACL rules. -- **OpenShift Cluster Provisioning**: Deploys an OpenShift (OCP) cluster, tailored for a cloud-native architecture with worker pools for private, transit, and edge network segments. +- **OpenShift Cluster Provisioning**: Deploys an OpenShift (OCP) cluster, tailored for a cloud-native architecture with worker pools. - **Secrets Manager Integration**: - Either utilizes an existing Secrets Manager instance or creates a new one. diff --git a/examples/basic/main.tf b/examples/basic/main.tf index b6979bc2..9f1594ea 100644 --- a/examples/basic/main.tf +++ b/examples/basic/main.tf @@ -41,13 +41,6 @@ module "resource_group" { locals { - - vpc_cidr_bases = { - private = "192.168.0.0/20", - transit = "192.168.16.0/20", - edge = "192.168.32.0/20" - } - subnet_prefix = flatten([ for k, v in module.zone_subnet_addrs : [ for zone, cidr in v.network_cidr_blocks : { @@ -72,34 +65,16 @@ locals { ] subnets = { - edge = [for subnet in local.merged_subnets : { id = subnet.subnet_id, cidr_block = subnet.subnet_ipv4_cidr, zone = subnet.zone } if subnet.label == "edge"], - private = [for subnet in local.merged_subnets : { id = subnet.subnet_id, cidr_block = subnet.subnet_ipv4_cidr, zone = subnet.zone } if subnet.label == "private"], - transit = [for subnet in local.merged_subnets : { id = subnet.subnet_id, cidr_block = subnet.subnet_ipv4_cidr, zone = subnet.zone } if subnet.label == "transit"] + default = [for subnet in local.merged_subnets : { id = subnet.subnet_id, cidr_block = subnet.subnet_ipv4_cidr, zone = subnet.zone } if subnet.label == "default"], } ocp_worker_pools = [ { - subnet_prefix = "private" + subnet_prefix = "default" pool_name = "default" machine_type = "bx2.4x16" workers_per_zone = 1 - labels = { "dedicated" : "private" } - operating_system = "REDHAT_8_64" - }, - { - subnet_prefix = "edge" - pool_name = "edge" - machine_type = "bx2.4x16" - workers_per_zone = 1 - labels = { "dedicated" : "edge" } - operating_system = "REDHAT_8_64" - }, - { - subnet_prefix = "transit" - pool_name = "transit" - machine_type = "bx2.4x16" - workers_per_zone = 1 - labels = { "dedicated" : "transit" } + labels = { "dedicated" : "default" } operating_system = "REDHAT_8_64" } ] @@ -159,7 +134,7 @@ module "subnets" { vpc_id = module.vpc.vpc.vpc_id ip_range = local.subnet_prefix[count.index].cidr name = "${var.prefix}-subnet-${local.subnet_prefix[count.index].label}-${split("-", local.subnet_prefix[count.index].zone)[2]}" - public_gateway = local.subnet_prefix[count.index].label == "edge" ? module.public_gateways[split("-", local.subnet_prefix[count.index].zone)[2] - 1].public_gateway_id : null + public_gateway = local.subnet_prefix[count.index].label == "default" ? module.public_gateways[split("-", local.subnet_prefix[count.index].zone)[2] - 1].public_gateway_id : null subnet_access_control_list = module.network_acl.network_acl_id } @@ -245,9 +220,9 @@ module "ocp_base" { disable_outbound_traffic_protection = true } -############################################################################## +############################################################################# # Init cluster config for helm and kubernetes providers -############################################################################## +############################################################################# data "ibm_container_cluster_config" "cluster_config" { cluster_name_id = module.ocp_base.cluster_id @@ -363,12 +338,12 @@ module "external_secrets_operator" { eso_cluster_nodes_configuration = { nodeSelector = { label = "dedicated" - value = "edge" + value = "default" } tolerations = { key = "dedicated" operator = "Equal" - value = "edge" + value = "default" effect = "NoExecute" } } diff --git a/examples/basic/outputs.tf b/examples/basic/outputs.tf index e124314b..18de0faf 100644 --- a/examples/basic/outputs.tf +++ b/examples/basic/outputs.tf @@ -1,7 +1,7 @@ ############################################################################## # Outputs -############################################################################## -output "cluster_id" { - description = "ID of the cluster deployed" - value = module.ocp_base.cluster_id -} +# ############################################################################## +# output "cluster_id" { +# description = "ID of the cluster deployed" +# value = module.ocp_base.cluster_id +# } diff --git a/examples/basic/variables.tf b/examples/basic/variables.tf index ea8c9a46..7b1c1cad 100644 --- a/examples/basic/variables.tf +++ b/examples/basic/variables.tf @@ -75,9 +75,7 @@ variable "cidr_bases" { description = "A list of base CIDR blocks for each network zone" type = map(string) default = { - private = "192.168.0.0/20", - transit = "192.168.16.0/20", - edge = "192.168.32.0/20" + default = "192.168.32.0/20" } } diff --git a/main.tf b/main.tf index a6589893..885884c3 100644 --- a/main.tf +++ b/main.tf @@ -7,11 +7,11 @@ ## Install ESO locals { - eso_image_tag_digest = "v0.12.1-ubi@sha256:caff77c2aa933876205d0da3f6883a3e0313ced0a0f0ea49b1abeca4071d027a" # datasource: icr.io/ibm-iac/external-secrets - eso_image_repo = "icr.io/ibm-iac/external-secrets" + eso_image_tag_digest = "v0.12.1-ubi@sha256:d38834043de0a4e4feeac8a08d0bc96b71ddd7fe1d4c8583ee3751badeaeb01d" + eso_image_repo = "ghcr.io/external-secrets/external-secrets" - reloader_image_tag_digest = "v1.2.1-ubi@sha256:78d3b7269d00df1b9550584dba817299b5842c48038db1f1603255914033307f" # datasource: icr.io/ibm-iac/reloader - reloader_image_repo = "icr.io/ibm-iac/reloader" + reloader_image_tag_digest = "v1.2.1-ubi@sha256:80a557100c6835c7e3c9842194250c9c4ca78f43200bc3a93a32e5b105ad11bb" + reloader_image_repo = "ghcr.io/stakater/reloader" } # creating namespace to deploy ESO into RedHat ServiceMesh @@ -182,9 +182,11 @@ resource "helm_release" "external_secrets_operator" { name = "external-secrets" namespace = local.eso_namespace - chart = "oci://icr.io/ibm-iac-charts/external-secrets" - version = "0.12.1" - wait = true + # chart = "oci://icr.io/ibm-iac-charts/external-secrets" + chart = "external-secrets" + version = "0.12.1" + wait = true + repository = "https://charts.external-secrets.io" set { name = "image.repository" @@ -230,8 +232,10 @@ resource "helm_release" "pod_reloader" { depends_on = [module.eso_namespace, data.kubernetes_namespace.existing_eso_namespace] count = var.reloader_deployed == true ? 1 : 0 name = "reloader" + //chart = "oci://icr.io/ibm-iac-charts/reloader" + chart = "reloader" namespace = local.eso_namespace - chart = "oci://icr.io/ibm-iac-charts/reloader" + repository = "https://stakater.github.io/stakater-charts" version = "1.2.0" wait = true diff --git a/tests/pr_test.go b/tests/pr_test.go index 302faa12..6e4ee3d9 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -21,8 +21,8 @@ const resourceGroup = "geretain-test-ext-secrets-sync" const defaultExampleTerraformDir = "examples/all-combined" const basicExampleTerraformDir = "examples/basic" -// deploying eso on edge node to have it able to connect to SM and IAM on public network -const esoWorkersSelector = "edge" +// deploying eso on default node to have it able to connect to SM and IAM on public network +const esoWorkersSelector = "default" // Define a struct with fields that match the structure of the YAML data const yamlLocation = "../common-dev-assets/common-go-assets/common-permanent-resources.yaml" diff --git a/tests/samples/sample.yaml b/tests/samples/sample.yaml index 50e1fd93..dfcf1a92 100644 --- a/tests/samples/sample.yaml +++ b/tests/samples/sample.yaml @@ -32,7 +32,7 @@ spec: app: example-busybox spec: nodeSelector: - dedicated: edge + dedicated: default containers: - name: busybox-container image: busybox From 8a3f283fc6722add89cdd4de37842a4e1c9fa9fb Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Wed, 15 Jan 2025 13:36:39 +0530 Subject: [PATCH 10/40] updated the PR test --- .cra/.fileignore | 3 + .github/CODEOWNERS | 4 +- .github/workflows/ci.yml | 15 - .github/workflows/release.yml | 12 - .gitignore | 31 +- .mdlrc | 2 + .pre-commit-config.yaml | 2 +- .secrets.baseline | 2 +- .whitesource | 3 + CODEOWNERS | 0 Makefile | 2 +- chart/raw/Chart.yaml | 15 + chart/raw/README.md | 60 ++ chart/raw/templates/_helpers.tpl | 45 ++ chart/raw/templates/resources.yaml | 9 + chart/raw/values.yaml | 17 + ci | 2 +- docs/upgradeplan.md | 29 + docs/upgradeplanexamples/main.tf.new | 618 ++++++++++++++++++ docs/upgradeplanexamples/main.tf.old | 457 +++++++++++++ docs/upgradeplanexamples/moved.tf.new | 54 ++ docs/upgradeplanexamples/variables.tf.new | 98 +++ docs/upgradeplanexamples/variables.tf.old | 77 +++ examples/all-combined/main.tf | 27 +- examples/all-combined/outputs.tf | 19 +- examples/all-combined/sdnlb-secret.tf | 37 -- examples/all-combined/secretsmanager.tf | 2 +- examples/all-combined/secretstore.tf | 116 ---- examples/all-combined/variables.tf | 37 +- examples/basic/README.md | 2 +- examples/basic/main.tf | 22 +- examples/basic/outputs.tf | 10 +- examples/basic/variables.tf | 46 +- .../trusted-profiles-authentication/main.tf | 2 +- main.tf | 1 - outputs.tf | 9 +- renovate.json | 14 +- tests/README.md | 3 + tests/go.mod | 57 +- tests/go.sum | 115 ++-- tests/pr_test.go | 26 +- tests/samples/sample.yaml | 2 +- 42 files changed, 1692 insertions(+), 412 deletions(-) create mode 100644 .cra/.fileignore delete mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/release.yml create mode 100644 .mdlrc create mode 100644 .whitesource create mode 100644 CODEOWNERS create mode 100644 chart/raw/Chart.yaml create mode 100644 chart/raw/README.md create mode 100644 chart/raw/templates/_helpers.tpl create mode 100644 chart/raw/templates/resources.yaml create mode 100644 chart/raw/values.yaml create mode 100644 docs/upgradeplan.md create mode 100644 docs/upgradeplanexamples/main.tf.new create mode 100644 docs/upgradeplanexamples/main.tf.old create mode 100644 docs/upgradeplanexamples/moved.tf.new create mode 100644 docs/upgradeplanexamples/variables.tf.new create mode 100644 docs/upgradeplanexamples/variables.tf.old delete mode 100644 examples/all-combined/sdnlb-secret.tf diff --git a/.cra/.fileignore b/.cra/.fileignore new file mode 100644 index 00000000..098e3a44 --- /dev/null +++ b/.cra/.fileignore @@ -0,0 +1,3 @@ +**/.terraform/* +common-dev-assets/* +tests/* diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 1f65b1e3..9ca7a60c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,2 @@ -# Primary owner should be listed first in list of global owners, followed by any secondary owners -* @SirSpidey @ocofaigh +# Primary owner should be listed first in list of global owners, follwed by any secondary owners +* @valerio-bontempi @DANIELBU diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 577cfcfa..00000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: CI-Pipeline - -# Controls when the workflow will run, when comment is created -on: - issue_comment: - types: - - created - -jobs: - call-terraform-ci-pipeline: - uses: terraform-ibm-modules/common-pipeline-assets/.github/workflows/common-terraform-module-ci-v2.yml@v1.22.5 - secrets: inherit - with: - craSCCv2: true - craConfigYamlFile: "cra-config.yaml" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 13edc440..00000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,12 +0,0 @@ -name: Release-Pipeline - -# Trigger on push(merge) to main branch -on: - push: - branches: - - main - -jobs: - call-terraform-release-pipeline: - uses: terraform-ibm-modules/common-pipeline-assets/.github/workflows/common-release.yml@v1.22.5 - secrets: inherit diff --git a/.gitignore b/.gitignore index 223ebaa2..7bee4643 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # Local .terraform directories **/.terraform/* - +testpod*.* # .tfstate files *.tfstate *.tfstate.* @@ -40,6 +40,9 @@ terraform.rc # Ignore .tfsec .tfsec/ +# Ignore brew lock +Brewfile.lock.json + # Ignore Mac files .DS_Store @@ -49,25 +52,9 @@ terraform.rc # Node modules /node_modules -# Visual Studio Code -.vscode/ - -### Go ### -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib +testpod*.yaml +precommit.txt -# Test binary, built with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Dependency directories (remove the comment below to include it) -# vendor/ - -# Go workspace file -go.work +# VS Code state +.vscode/ +*.code-workspace diff --git a/.mdlrc b/.mdlrc new file mode 100644 index 00000000..c32df301 --- /dev/null +++ b/.mdlrc @@ -0,0 +1,2 @@ +all +rule 'MD013', :tables => false diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 32155edc..9d1e8bd6 120000 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1 +1 @@ -common-dev-assets/module-assets/.pre-commit-config.yaml \ No newline at end of file +./common-dev-assets/module-assets/.pre-commit-config.yaml \ No newline at end of file diff --git a/.secrets.baseline b/.secrets.baseline index 83c2fe0a..ad443f6f 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "go.sum|^.secrets.baseline$", "lines": null }, - "generated_at": "2023-12-09T06:39:44Z", + "generated_at": "2023-12-11T12:45:00Z", "plugins_used": [ { "name": "AWSKeyDetector" diff --git a/.whitesource b/.whitesource new file mode 100644 index 00000000..df373213 --- /dev/null +++ b/.whitesource @@ -0,0 +1,3 @@ +{ + "settingsInheritedFrom": "GoldenEye/whitesource-config@master" +} diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 00000000..e69de29b diff --git a/Makefile b/Makefile index fa1444d3..b753a4a6 120000 --- a/Makefile +++ b/Makefile @@ -1 +1 @@ -common-dev-assets/module-assets/Makefile \ No newline at end of file +./common-dev-assets/module-assets/Makefile \ No newline at end of file diff --git a/chart/raw/Chart.yaml b/chart/raw/Chart.yaml new file mode 100644 index 00000000..0b7b2da6 --- /dev/null +++ b/chart/raw/Chart.yaml @@ -0,0 +1,15 @@ +apiVersion: v2 +description: A place for all the Kubernetes resources which don't already have a home +name: raw +version: v0.2.5 +kubeVersion: ">=1.16.0-0" +home: https://github.com/itscontained/charts/blob/master/itscontained/raw +keywords: + - raw + - incubator + - incubator-raw +sources: + - https://github.com/helm/charts/blob/master/incubator/raw +maintainers: + - name: DirtyCajunRice + email: nick@cajun.pro diff --git a/chart/raw/README.md b/chart/raw/README.md new file mode 100644 index 00000000..b79f84a8 --- /dev/null +++ b/chart/raw/README.md @@ -0,0 +1,60 @@ +# itscontained/raw + +The `itscontained/raw` chart takes a list of Kubernetes resources and +merges each resource with a default `metadata.labels` map and installs +the result. + +The Kubernetes resources can be "raw" ones defined under the `resources` key, or "templated" ones defined under the `templates` key. + +Some use cases for this chart include Helm-based installation and +maintenance of resources of kinds: +- LimitRange +- PriorityClass +- Secret + +## Usage + +### Raw resources + +#### STEP 1: Create a yaml file containing your raw resources. + +``` +# raw-priority-classes.yaml +resources: + - apiVersion: scheduling.k8s.io/v1beta1 + kind: PriorityClass + metadata: + name: common-critical + value: 100000000 + globalDefault: false + description: "This priority class should only be used for critical priority common pods." +``` + +#### STEP 2: Install your raw resources. + +``` +helm install raw-priority-classes itscontained/raw -f raw-priority-classes.yaml +``` + +### Templated resources + +#### STEP 1: Create a yaml file containing your templated resources. + +``` +# values.yaml + +templates: +- | + apiVersion: v1 + kind: Secret + metadata: + name: common-secret + stringData: + mykey: {{ .Values.mysecret }} +``` + +#### STEP 2: Install your templated resources. + +``` +helm install mysecret itscontained/raw -f values.yaml +``` diff --git a/chart/raw/templates/_helpers.tpl b/chart/raw/templates/_helpers.tpl new file mode 100644 index 00000000..f916d275 --- /dev/null +++ b/chart/raw/templates/_helpers.tpl @@ -0,0 +1,45 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "raw.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "raw.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "raw.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +raw.resource will create a resource template that can be +merged with each item in `.Values.resources`. +*/}} +{{- define "raw.resource" -}} +metadata: + labels: + app: {{ template "raw.name" . }} + chart: {{ template "raw.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- end }} diff --git a/chart/raw/templates/resources.yaml b/chart/raw/templates/resources.yaml new file mode 100644 index 00000000..83c900de --- /dev/null +++ b/chart/raw/templates/resources.yaml @@ -0,0 +1,9 @@ +{{- $template := fromYaml (include "raw.resource" .) -}} +{{- range .Values.resources }} +--- +{{ toYaml (merge . $template) -}} +{{- end }} +{{- range $i, $t := .Values.templates }} +--- +{{ toYaml (merge (tpl $t $ | fromYaml) $template) -}} +{{- end }} diff --git a/chart/raw/values.yaml b/chart/raw/values.yaml new file mode 100644 index 00000000..586f7276 --- /dev/null +++ b/chart/raw/values.yaml @@ -0,0 +1,17 @@ +resources: [] +# - apiVersion: scheduling.k8s.io/v1beta1 +# kind: PriorityClass +# metadata: +# name: app-low +# value: 70000 +# globalDefault: false +# description: "This priority class should only be used for low priority app pods." + +templates: [] +# - | +# apiVersion: v1 +# kind: Secret +# metadata: +# name: common-secret +# stringData: +# mykey: {{ .Values.mysecret }} diff --git a/ci b/ci index f9d799a5..f591e15b 120000 --- a/ci +++ b/ci @@ -1 +1 @@ -common-dev-assets/module-assets/ci \ No newline at end of file +./common-dev-assets/module-assets/ci \ No newline at end of file diff --git a/docs/upgradeplan.md b/docs/upgradeplan.md new file mode 100644 index 00000000..0544da84 --- /dev/null +++ b/docs/upgradeplan.md @@ -0,0 +1,29 @@ +# Updating from version 1.7.0 or earlier + +The External Secrets Operator module was redesigned with new features and to allow easier configurations of instances. The last version before the redesign was [1.7.0](https://github.ibm.com/GoldenEye/external-secrets-operator-module/releases/tag/1.7.0). + +:exclamation: **Important:** Pay attention to how you update from version 1.7.0 or earlier to the redesigned module. If you update directly, you might cause issues with your deployment. + +The following lists outlines some of the changes the prevent a direct update: + +- Version 1.7.0 and earlier creates some resources implicitly (for example, `stores` and `externalsecrets`). In later versions, you must define these resources explicitly in the Terraform. + + For example, in version 1.7.0 and earlier, the default value of the `eso_store_setup` input variable is `true`. This value causes the module to create a `ClusterStore` by default (or a `SecretStore` if the value of `eso_store_scope` is `namespace`). In versions after 1.7.0, you instantiate an `eso-clusterstore` or an `eso-secretstore` submodule. + + Likewise, for `externalsecret` resources, version 1.7.0 creates an `externalsecret` resource when it sets up secrets. In later versions, you create `externalsecret` resources through the `eso-external-secret` submodule. +- Some resources have different names in the redesigned version. +- The direct update destroys resources. Secrets that are controlled through the `externalsecrets` resource will also be destroyed, and this will cause disruption. + +For more information about the redesign, see GoldenEye issue [4758](https://github.ibm.com/GoldenEye/issues/issues/4758). + +## Example of using Terraform move to update with minimal disruption + +To update your existing deployments, you can use the Terraform `move` configuration block. For more information about the `move` block, see [Use configuration to move resources](https://developer.hashicorp.com/terraform/tutorials/configuration-language/move-config). + +The `docs/upgradeplanexamples` directory in this module contains a set of files to help you with your update, by providing an example of the same terraform template for the `1.7.0` module version and for the redesigned one. + +The `.old` files ([variables.tf.old](upgradeplanexamples/variables.tf.old) and [main.tf.old](upgradeplanexamples/main.tf.old)) describe the terraform template to deploy external-secrets-operator module with version 1.7.0. + +The `.new` files ([variables.tf.new](upgradeplanexamples/variables.tf.new) and [main.tf.new](upgradeplanexamples/main.tf.new)) describe how to upgrade then to the redesigned version. + +The [moved.tf.new](upgradeplanexamples/moved.tf.new) file defines how resources deployed with `1.7.0` template ("old" files) are renamed and moved when the updating with the redesigned version. By adding this file to your template, terraform will update the resources instead of destroying and re-creating them. diff --git a/docs/upgradeplanexamples/main.tf.new b/docs/upgradeplanexamples/main.tf.new new file mode 100644 index 00000000..909c47c5 --- /dev/null +++ b/docs/upgradeplanexamples/main.tf.new @@ -0,0 +1,618 @@ +############################################################################## +# Locals +############################################################################## + +locals { + # general + validate_sm_region_cnd = var.existing_sm_instance_guid != null && var.existing_sm_instance_region == null + validate_sm_region_msg = "existing_sm_instance_region must also be set when value given for existing_sm_instance_guid." + # tflint-ignore: terraform_unused_declarations + validate_sm_region_chk = regex( + "^${local.validate_sm_region_msg}$", + (!local.validate_sm_region_cnd + ? local.validate_sm_region_msg + : "")) + + sm_guid = var.existing_sm_instance_guid == null ? ibm_resource_instance.secrets_manager[0].guid : var.existing_sm_instance_guid + sm_region = var.existing_sm_instance_region == null ? var.region : var.existing_sm_instance_region + sm_acct_id = var.existing_sm_instance_guid == null ? module.iam_secrets_engine[0].acct_secret_group_id : module.secrets_manager_group_acct[0].secret_group_id + + # artifactory-registry-secret + artifactory_apikey = sensitive("artifactory-payload-example") + + # cr-registry-arbitrary-secret + imagepull_apikey = sensitive("imagepull-payload-example") +} + +################################################################## +# Resource Group +################################################################## + +module "resource_group" { + source = "terraform-ibm-modules/resource-group/ibm" + version = "1.1.5" + # if an existing resource group is not set (null) create a new one using prefix + resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null + existing_resource_group_name = var.resource_group +} + +################################################################## +# Create VPC, public gateway and subnets +################################################################## + +locals { + + # VPC Configuration + acl_rules_map = { + private = concat( + module.acl_profile.base_acl, + module.acl_profile.https_acl, + module.acl_profile.deny_all_acl + ) + } + vpc_cidr_bases = { + private = "192.168.0.0/20", + transit = "192.168.16.0/20", + edge = "192.168.32.0/20" + } + + # OCP Configuration + ocp_worker_pools = [ + { + subnet_prefix = "private" + pool_name = "default" + machine_type = "bx2.4x16" + workers_per_zone = 1 + labels = { "dedicated" : "private" } + }, + { + subnet_prefix = "edge" + pool_name = "edge" + machine_type = "bx2.4x16" + workers_per_zone = 1 + labels = { "dedicated" : "edge" } + }, + { + subnet_prefix = "transit" + pool_name = "transit" + machine_type = "bx2.4x16" + workers_per_zone = 1 + labels = { "dedicated" : "transit" } + } + ] +} + +# VPC ACLs +module "acl_profile" { + source = "git::https://github.ibm.com/GoldenEye/acl-profile-ocp.git?ref=1.3.1" +} + + +# VPC creation +module "vpc" { + source = "git::https://github.ibm.com/GoldenEye/vpc-module.git?ref=6.3.3" + unique_name = "${var.prefix}-vpc" + ibm_region = local.sm_region + resource_group_id = module.resource_group.resource_group_id + cidr_bases = local.vpc_cidr_bases + acl_rules_map = local.acl_rules_map + virtual_private_endpoints = {} + vpc_tags = [] +} + +# OCP CLUSTER creation +module "ocp_base" { + source = "terraform-ibm-modules/base-ocp-vpc/ibm" + version = "3.18.1" + ibmcloud_api_key = var.ibmcloud_api_key # pragma: allowlist secret + cluster_name = "${var.prefix}-vpc" + resource_group_id = module.resource_group.resource_group_id + region = local.sm_region + force_delete_storage = true + vpc_id = module.vpc.vpc_id + vpc_subnets = module.vpc.subnets + worker_pools = local.ocp_worker_pools + tags = [] + use_existing_cos = false +} + +############################################################################## +# Init cluster config for helm and kubernetes providers +############################################################################## + +data "ibm_container_cluster_config" "cluster_config" { + cluster_name_id = module.ocp_base.cluster_id + resource_group_id = module.resource_group.resource_group_id +} + +# Wait time to allow cluster refreshes components after provisioning +resource "time_sleep" "wait_45_seconds" { + depends_on = [data.ibm_container_cluster_config.cluster_config] + create_duration = "45s" +} + +# Create namespace +resource "kubernetes_namespace" "cluster_namespaces" { + for_each = toset(var.es_kubernetes_namespaces) + metadata { + name = each.value + } + lifecycle { + ignore_changes = [ + metadata[0].annotations, + metadata[0].labels + ] + } + depends_on = [ + time_sleep.wait_45_seconds + ] +} + +######################################## +# Secrets-Manager and IAM configuration +######################################## + +# IAM user policy, Secret Manager instance, Service ID for IAM engine, IAM service ID policies, associated Service ID API key stored in a secret object in account level secret-group and IAM engine configuration +resource "ibm_resource_instance" "secrets_manager" { + count = var.existing_sm_instance_guid == null ? 1 : 0 + name = "${var.prefix}-sm" + service = "secrets-manager" + plan = var.sm_service_plan + location = local.sm_region + tags = var.resource_tags + resource_group_id = module.resource_group.resource_group_id + timeouts { + create = "30m" # Extending provisioning time to 30 minutes + } +} + +# Configure instance with IAM engine +module "iam_secrets_engine" { + # providers = { + # restapi.nocontent = restapi.nocontent + # } + count = var.existing_sm_instance_guid == null ? 1 : 0 + source = "git::https://github.ibm.com/GoldenEye/secrets-manager-iam-engine-module.git?ref=2.0.6" + region = local.sm_region + secrets_manager_guid = ibm_resource_instance.secrets_manager[0].guid + create_iam_user_policy = false + iam_secret_generator_service_id_name = "${var.prefix}-sid:0.0.1:${ibm_resource_instance.secrets_manager[0].name}-iam-secret-generator:automated:simple-service:secret-manager:" + iam_secret_generator_apikey_name = "${var.prefix}-iam-secret-generator-apikey" + new_secret_group_name = "${var.prefix}-account-secret-group" + iam_secret_generator_apikey_secret_name = "${var.prefix}-iam-secret-generator-apikey-secret" + iam_engine_name = "iam-engine" +} + +# Creates secret group to place secrets +module "secrets_manager_group" { + source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" + version = "1.1.4" + # source = "git::https://github.ibm.com/GoldenEye/secrets-manager-secret-group-module.git?ref=2.0.1" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_name = "${var.prefix}-secret-group" #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + secret_group_description = "Secret-Group for storing account credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure +} + +# Additional Secrets-Manager Secret-Group for SERVICE level secrets +module "secrets_manager_group_acct" { + source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" + version = "1.1.4" + count = var.existing_sm_instance_guid == null ? 0 : 1 + # source = "git::https://github.ibm.com/GoldenEye/secrets-manager-secret-group-module.git?ref=2.0.1" + region = local.sm_region + secrets_manager_guid = local.sm_guid + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_group_name = "${var.prefix}-account-secret-group" #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + secret_group_description = "Secret-Group for storing account credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure + depends_on = [module.iam_secrets_engine] +} + +################################################################## +# Create service-id, policy to pull secrets from secret manager +################################################################## + +# Create service-id +resource "ibm_iam_service_id" "secret_puller" { + name = "sid:0.0.1:${var.prefix}-secret-puller:automated:simple-service:secret-manager:" + description = "ServiceID that can pull secrets from Secret Manager" +} +# Create policy to allow new service id to pull secrets from secrets manager +resource "ibm_iam_service_policy" "secret_puller_policy" { + iam_service_id = ibm_iam_service_id.secret_puller.id + roles = ["Viewer", "SecretsReader"] + + resources { + service = "secrets-manager" + resource_instance_id = local.sm_guid + resource_type = "secret-group" + resource = module.secrets_manager_group.secret_group_id + } +} + +################################################################## +# Artifactory-registry +################################################################## + +# Creates username_password secrets and stores in secret manager +module "sm_up_artifactory_secret" { + source = "git::https://github.ibm.com/GoldenEye/secrets-manager-secret-module.git?ref=3.1.1" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_id = module.secrets_manager_group.secret_group_id + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_name = "${var.prefix}-artifactory-up-secret" # checkov:skip=CKV_SECRET_6 + secret_description = "example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure # checkov:skip=CKV_SECRET_6 + secret_payload_password = local.artifactory_apikey # pragma: allowlist secret + secret_type = "username_password" #checkov:skip=CKV_SECRET_6 + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_username = "artifactory-user" # checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + secret_user_pass_auto_rotation = false +} + +# # Installing external secrets operator(ESO), cluster store and deploying external secret as dockerconfigson type +# module "eso_operator_clusterstore_deployment" { +# source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git?ref=1.7.0" +# depends_on = [ +# kubernetes_namespace.cluster_namespaces +# ] +# es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 -> externalsecret +# sm_secret_type = "username_password" #checkov:skip=CKV_SECRET_6 -> externalsecret +# sm_secret_id = module.sm_up_artifactory_secret.secret_id # -> externalsecret +# eso_setup = true +# es_kubernetes_namespaces = [var.es_kubernetes_namespaces[0]] # -> value to use in externalsecret +# secrets_manager_guid = local.sm_guid # -> cluster store +# eso_generic_secret_name = "generic-cluster-api-key" #checkov:skip=CKV_SECRET_6 # -> cluster store +# eso_store_name = "cluster-store" # -> cluster store +# es_container_registry = "wcp-my-team-docker-local.artifactory.swg-devops.com" # -> value to use in externalsecret +# region = local.sm_region # -> cluster store +# es_kubernetes_secret_name = "dockerconfigjson-uc" #checkov:skip=CKV_SECRET_6 # -> value to use in externalsecret +# es_helm_rls_name = "es-docker-uc" # -> value to use in externalsecret +# es_store_helm_rls_name = "cluster-store" # -> value to use in cluster store +# eso_authentication = ["api_key"] # -> value to use in cluster store +# } + +### from previous single to three modules (ESO + clusterstore + externalsecret) + +################################################################## +# ESO deployment +################################################################## + +module "eso_operator_deployment" { + depends_on = [ + kubernetes_namespace.cluster_namespaces + ] + source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git?ref=task_4882_5006_5196" + existing_eso_namespace = "external-secrets-operator" # default of previous module version while now it is not defaulted + service_endpoints = "public" # default of previous module version default + + eso_cluster_nodes_configuration = var.eso_deployment_nodes_configuration == null ? null : { + nodeSelector = { + label = "dedicated" + value = var.eso_deployment_nodes_configuration + } + tolerations = { + key = "dedicated" + operator = "Equal" + value = var.eso_deployment_nodes_configuration + effect = "NoExecute" + } + } + +} + +################################################################## +# ESO ClusterStore creation with apikey authentication +################################################################## + +module "eso_clusterstore_deployment" { + source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git//eso-clusterstore?ref=task_4882_5006_5196" + eso_authentication = "api_key" + clusterstore_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key # pragma: allowlist secret + region = local.sm_region + clusterstore_helm_rls_name = "cluster-store" + clusterstore_secret_name = "generic-cluster-api-key" #checkov:skip=CKV_SECRET_6 + clusterstore_name = "cluster-store" + clusterstore_secrets_manager_guid = local.sm_guid + eso_namespace = var.existing_eso_namespace + service_endpoints = var.service_endpoints + depends_on = [ + module.eso_operator_deployment + ] +} + +################################################################## +# ExternalSecret for ESO in cluster scope and apikey auth +################################################################## + +# Creation of ExternalSecret for cluster scope and deploying external secret as dockerconfigson type +module "external_secret_dockerconfigson_usr_pass_deployment" { + depends_on = [module.eso_clusterstore_deployment] + source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git//eso-external-secret?ref=task_4882_5006_5196" + es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "username_password" #checkov:skip=CKV_SECRET_6 + sm_secret_id = module.sm_up_artifactory_secret.secret_id + # es_kubernetes_namespace = var.es_kubernetes_namespaces[0] + es_kubernetes_namespace = kubernetes_namespace.cluster_namespaces[var.es_kubernetes_namespaces[0]].metadata[0].name # to create explicit dependency + eso_store_name = "cluster-store" + eso_store_scope = "cluster" + es_container_registry = "wcp-my-team-docker-local.artifactory.swg-devops.com" + es_kubernetes_secret_name = "dockerconfigjson-uc" #checkov:skip=CKV_SECRET_6 + es_helm_rls_name = "es-docker-uc" + es_helm_rls_namespace = var.existing_eso_namespace # to keep backward compatibility with previous version installing it in eso operator namespace +} + +################################################################## +# Cloudant-arbitrary-secret +################################################################## + +############################################################################## +# Basic cloudant instance + database +############################################################################## + +module "cloudant" { + source = "terraform-ibm-modules/cloudant/ibm" + version = "1.1.7" + resource_group_id = module.resource_group.resource_group_id + instance_name = "${var.prefix}-cloudant" + access_tags = [] + region = var.region + tags = var.resource_tags + database_config = [{ + db = "cloudant-db" + partitioned = false + shards = 3 + }] +} + +data "ibm_cloudant" "instance" { + name = module.cloudant.name + resource_group_id = module.resource_group.resource_group_id +} + +resource "ibm_resource_key" "resource_key" { + name = "cd-resource-key" + role = "Manager" + resource_instance_id = data.ibm_cloudant.instance.id + timeouts { + create = "15m" + delete = "15m" + } +} + +# Creates arbitrary secret and stores in secret manager +module "sm_arbitrary_cloudant_secret" { + source = "git::https://github.ibm.com/GoldenEye/secrets-manager-secret-module.git?ref=3.1.1" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_id = module.secrets_manager_group.secret_group_id + secret_type = "arbitrary" + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_name = "${var.prefix}-cloudant-rk-secret" #checkov:skip=CKV_SECRET_6 + secret_description = "example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_payload_password = ibm_resource_key.resource_key.credentials["apikey"] +} + +# # Deploying external secret as Opaque type using existing cluster store +# module "eso_clusterstore_externalsecret_opaque_create" { +# depends_on = [ +# module.eso_operator_clusterstore_deployment, +# kubernetes_namespace.cluster_namespaces +# ] +# source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git?ref=1.7.0" +# es_kubernetes_secret_type = "opaque" # -> externalsecret +# sm_secret_type = "arbitrary" # -> externalsecret +# sm_secret_id = module.sm_arbitrary_cloudant_secret.secret_id # -> externalsecret +# eso_setup = false +# eso_store_setup = false +# es_kubernetes_namespaces = [var.es_kubernetes_namespaces[1]] # -> value to use in externalsecret +# eso_store_name = "cluster-store" # -> value to use in externalsecret +# secrets_manager_guid = local.sm_guid # -> cluster store +# region = local.sm_region # -> cluster store +# es_kubernetes_secret_data_key = "apikey" # -> value to use in externalsecret +# es_kubernetes_secret_name = "cloudant-opaque-arb" #checkov:skip=CKV_SECRET_6 # -> value to use in externalsecret +# es_helm_rls_name = "es-cloudant-arb" # -> value to use in externalsecret +# eso_authentication = ["api_key"] # -> cluster store +# } + +### from previous single to singe module eso-external-secret + +################################################################## +# ExternalSecret for ESO in cluster scope and apikey auth +################################################################## + +# Creates externalsecret using existing cluster store and configure the secret as Opaque type +module "external_secret_opaque_arbitrary_deployment" { + depends_on = [module.eso_clusterstore_deployment] + source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git//eso-external-secret?ref=task_4882_5006_5196" + es_kubernetes_secret_type = "opaque" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "arbitrary" #checkov:skip=CKV_SECRET_6 + sm_secret_id = module.sm_arbitrary_cloudant_secret.secret_id + # es_kubernetes_namespace = var.es_kubernetes_namespaces[1] + es_kubernetes_namespace = kubernetes_namespace.cluster_namespaces[var.es_kubernetes_namespaces[1]].metadata[0].name # to create explicit dependency + eso_store_name = "cluster-store" + eso_store_scope = "cluster" + es_kubernetes_secret_data_key = "apikey" + es_kubernetes_secret_name = "cloudant-opaque-arb" #checkov:skip=CKV_SECRET_6 + es_helm_rls_name = "es-cloudant-arb" + es_helm_rls_namespace = var.existing_eso_namespace # to keep backward compatibility with previous version installing it in eso operator namespace +} + +################################################################## +# cr-registry-arbitrary-secret +################################################################## + +# Creates arbitrary secret and stores in secret manager +module "sm_arbitrary_imagepull_secret" { + source = "git::https://github.ibm.com/GoldenEye/secrets-manager-secret-module.git?ref=3.1.1" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_id = module.secrets_manager_group.secret_group_id + secret_type = "arbitrary" + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_name = "${var.prefix}-imagepull-apikey-secret" #checkov:skip=CKV_SECRET_6 + secret_description = "example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_payload_password = local.imagepull_apikey # pragma: allowlist secret +} + +# # Deploying external secret as dockerconfigson type using new namespace store +# module "eso_secretstore_create_externalsecret_arbitrary_create" { +# depends_on = [ +# module.eso_operator_clusterstore_deployment, +# kubernetes_namespace.cluster_namespaces +# ] +# source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git?ref=1.7.0" +# es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 # -> externalsecret +# sm_secret_type = "arbitrary" # -> externalsecret +# sm_secret_id = module.sm_arbitrary_imagepull_secret.secret_id # -> externalsecret +# eso_setup = false +# eso_store_setup = true +# eso_store_scope = "namespace" # -> secretstore +# es_kubernetes_namespaces = [var.es_kubernetes_namespaces[2]] # -> value to use in externalsecret +# es_container_registry_email = "terraform@ibm.com" # -> value to use in externalsecret +# eso_generic_secret_name = "generic-${var.es_kubernetes_namespaces[2]}-api-key" # -> secretstore +# eso_store_name = "${var.es_kubernetes_namespaces[2]}-store" # -> secretstore +# secrets_manager_guid = local.sm_guid # -> secretstore +# region = local.sm_region # -> secretstore +# es_kubernetes_secret_name = "dockerconfigjson-arb" #checkov:skip=CKV_SECRET_6 # -> value to use in externalsecret +# es_helm_rls_name = "es-docker-arb" # -> value to use in externalsecret +# es_store_helm_rls_name = "store" # -> value to use in externalsecret +# eso_authentication = ["api_key"] # -> secretstore + +# } + +### from previous single to two modules eso-secretstore + eso-external-secret + +# Deploying external secret as dockerconfigson type using new namespace store +# creation of Namespaced SecretStores with apikey authentication +module "eso_namespacedstore_apikeyauth_dockerconfigson_deployment" { + depends_on = [module.eso_clusterstore_deployment] + source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git//eso-secretstore?ref=task_4882_5006_5196" + eso_authentication = "api_key" + region = local.sm_region + sstore_namespace = kubernetes_namespace.cluster_namespaces[var.es_kubernetes_namespaces[2]].metadata[0].name + sstore_secrets_manager_guid = local.sm_guid + sstore_store_name = "${var.es_kubernetes_namespaces[2]}-store" + sstore_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key # pragma: allowlist secret + service_endpoints = var.service_endpoints + sstore_helm_rls_name = "store" + sstore_secret_name = "generic-${var.es_kubernetes_namespaces[2]}-api-key" +} + +# Deploying external secret as dockerconfigson type using new namespace store +# Creates externalsecret using previously created namespaced store and configure the secret as arbitrary type +module "external_secret_dockerconfigson_arbitrary_deployment" { + depends_on = [module.eso_clusterstore_deployment] + source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git//eso-external-secret?ref=task_4882_5006_5196" + es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "arbitrary" #checkov:skip=CKV_SECRET_6 + sm_secret_id = module.sm_arbitrary_imagepull_secret.secret_id + # es_kubernetes_namespace = var.es_kubernetes_namespaces[2] + es_kubernetes_namespace = kubernetes_namespace.cluster_namespaces[var.es_kubernetes_namespaces[2]].metadata[0].name # to create explicit dependency + eso_store_name = "${var.es_kubernetes_namespaces[2]}-store" + eso_store_scope = "namespace" + es_kubernetes_secret_name = "dockerconfigjson-arb" #checkov:skip=CKV_SECRET_6 + es_container_registry_email = "terraform@ibm.com" # -> value to use in externalsecret + es_helm_rls_name = "es-docker-arb" + es_helm_rls_namespace = var.existing_eso_namespace # to keep backward compatibility with previous version installing it in eso operator namespace +} + +################################################################## +# cr-registry-same-account +################################################################## + +# Create dynamic Service ID API key and add to secret manager +module "dynamic_serviceid_apikey1" { + source = "git::https://github.ibm.com/GoldenEye/iam-serviceid-apikey-secrets-manager-module.git?ref=2.0.2" + region = local.sm_region + #tfsec:ignore:general-secrets-no-plaintext-exposure + sm_iam_secret_name = "${var.prefix}-${var.sm_iam_secret_name}" + sm_iam_secret_description = "Example of dynamic IAM secret / apikey" #tfsec:ignore:general-secrets-no-plaintext-exposure + serviceid_id = ibm_iam_service_id.secret_puller.id + secrets_manager_guid = local.sm_guid + secret_group_id = local.sm_acct_id + depends_on = [module.iam_secrets_engine, ibm_iam_service_policy.secret_puller_policy, ibm_iam_service_id.secret_puller] +} + +# Creates image pull secrets and stores in secret manager +module "image_pull" { + source = "git::https://github.ibm.com/GoldenEye/imagepull-apikey-secrets-manager-module.git?ref=1.1.2" + resource_group_id = module.resource_group.resource_group_id + secrets_manager_guid = local.sm_guid + cr_namespace_name = var.cr_namespace_name + region = local.sm_region + #tfsec:ignore:general-secrets-no-plaintext-exposure + service_id_secret_name = "${var.prefix}-image-pull-service-id" + service_id_secret_group_id = module.secrets_manager_group.secret_group_id + depends_on = [module.iam_secrets_engine, module.secrets_manager_group] +} + +# Data source to get API Key from secret manager secret-puller-secret +data "ibm_sm_iam_credentials_secret" "secret_puller_secret" { + instance_id = local.sm_guid + #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static type + secret_id = module.dynamic_serviceid_apikey1.secret_id +} + +# # Deploying external secret as dockerconfigson type (from image pull IAM dynamic credential/secret) using new namespace store +# module "eso_secretstore_create_externalsecret_iamcredentials_create" { +# depends_on = [ +# module.eso_operator_clusterstore_deployment, +# kubernetes_namespace.cluster_namespaces +# ] +# source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git?ref=1.7.0" +# es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 -> externalsecret +# sm_secret_type = "iam_credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure -> externalsecret +# sm_secret_id = module.image_pull.serviceid_apikey_secret_id # -> externalsecret +# es_kubernetes_namespaces = [var.es_kubernetes_namespaces[3]] # -> externalsecret +# eso_setup = false +# eso_store_setup = true +# eso_store_scope = "namespace" # -> secret store +# es_container_registry_email = "terraform@ibm.com" # -> externalsecret +# es_refresh_interval = var.es_refresh_interval # -> externalsecret +# eso_generic_secret_name = "generic-${var.es_kubernetes_namespaces[3]}-api-key" # -> secret store +# eso_store_name = "${var.es_kubernetes_namespaces[3]}-store" # -> secret store +# secrets_manager_guid = local.sm_guid # -> secret store +# region = local.sm_region # -> secret store +# es_kubernetes_secret_name = "dockerconfigjson-iam" #tfsec:ignore:general-secrets-no-plaintext-exposure #checkov:skip=CKV_SECRET_6 # -> externalsecret +# es_helm_rls_name = "es-docker-iam" # -> externalsecret +# es_store_helm_rls_name = "store" # -> value to use in secret store +# eso_authentication = ["api_key"] # -> value to use in secret store +# } + +### from previous single to two modules eso-secretstore + eso-external-secret + +# Deploying external secret as dockerconfigson type (from image pull IAM dynamic credential/secret) using new namespace store +# creation of Namespaced SecretStores with apikey authentication +module "eso_namespacedstore_apikeyauth_iamcredentials_deployment" { + depends_on = [module.eso_clusterstore_deployment] + source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git//eso-secretstore?ref=task_4882_5006_5196" + eso_authentication = "api_key" + region = local.sm_region + sstore_namespace = kubernetes_namespace.cluster_namespaces[var.es_kubernetes_namespaces[3]].metadata[0].name + sstore_secrets_manager_guid = local.sm_guid + sstore_store_name = "${var.es_kubernetes_namespaces[3]}-store" + sstore_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key #tfsec:ignore:general-secrets-no-plaintext-exposure # pragma: allowlist secret -> secret store + service_endpoints = var.service_endpoints + sstore_helm_rls_name = "store" + sstore_secret_name = "generic-${var.es_kubernetes_namespaces[3]}-api-key" +} + +# Deploying external secret as dockerconfigson type using new namespace store +# Creates externalsecret using previously created namespaced store and configure the secret as iam_credentials type +module "external_secret_dockerconfigson_iamcredentials_deployment" { + depends_on = [module.eso_clusterstore_deployment] + source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git//eso-external-secret?ref=task_4882_5006_5196" + es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "iam_credentials" #checkov:skip=CKV_SECRET_6 + sm_secret_id = module.image_pull.serviceid_apikey_secret_id + # es_kubernetes_namespace = var.es_kubernetes_namespaces[3] + es_kubernetes_namespace = kubernetes_namespace.cluster_namespaces[var.es_kubernetes_namespaces[3]].metadata[0].name # to create explicit dependency + eso_store_name = "${var.es_kubernetes_namespaces[3]}-store" + eso_store_scope = "namespace" + es_kubernetes_secret_name = "dockerconfigjson-iam" #checkov:skip=CKV_SECRET_6 + es_helm_rls_name = "es-docker-iam" + es_container_registry_email = "terraform@ibm.com" + es_refresh_interval = var.es_refresh_interval + es_helm_rls_namespace = var.existing_eso_namespace # to keep backward compatibility with previous version installing it in eso operator namespace +} diff --git a/docs/upgradeplanexamples/main.tf.old b/docs/upgradeplanexamples/main.tf.old new file mode 100644 index 00000000..2f6f934d --- /dev/null +++ b/docs/upgradeplanexamples/main.tf.old @@ -0,0 +1,457 @@ +############################################################################## +# Locals +############################################################################## + +locals { + # general + validate_sm_region_cnd = var.existing_sm_instance_guid != null && var.existing_sm_instance_region == null + validate_sm_region_msg = "existing_sm_instance_region must also be set when value given for existing_sm_instance_guid." + # tflint-ignore: terraform_unused_declarations + validate_sm_region_chk = regex( + "^${local.validate_sm_region_msg}$", + (!local.validate_sm_region_cnd + ? local.validate_sm_region_msg + : "")) + + sm_guid = var.existing_sm_instance_guid == null ? ibm_resource_instance.secrets_manager[0].guid : var.existing_sm_instance_guid + sm_region = var.existing_sm_instance_region == null ? var.region : var.existing_sm_instance_region + sm_acct_id = var.existing_sm_instance_guid == null ? module.iam_secrets_engine[0].acct_secret_group_id : module.secrets_manager_group_acct[0].secret_group_id + + # artifactory-registry-secret + artifactory_apikey = sensitive("artifactory-payload-example") + + # cr-registry-arbitrary-secret + imagepull_apikey = sensitive("imagepull-payload-example") +} + +################################################################## +# Resource Group +################################################################## + +module "resource_group" { + source = "terraform-ibm-modules/resource-group/ibm" + version = "1.1.5" + # if an existing resource group is not set (null) create a new one using prefix + resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null + existing_resource_group_name = var.resource_group +} + +################################################################## +# Create VPC, public gateway and subnets +################################################################## + +locals { + + # VPC Configuration + acl_rules_map = { + private = concat( + module.acl_profile.base_acl, + module.acl_profile.https_acl, + module.acl_profile.deny_all_acl + ) + } + vpc_cidr_bases = { + private = "192.168.0.0/20", + transit = "192.168.16.0/20", + edge = "192.168.32.0/20" + } + + # OCP Configuration + ocp_worker_pools = [ + { + subnet_prefix = "private" + pool_name = "default" + machine_type = "bx2.4x16" + workers_per_zone = 1 + labels = { "dedicated" : "private" } + }, + { + subnet_prefix = "edge" + pool_name = "edge" + machine_type = "bx2.4x16" + workers_per_zone = 1 + labels = { "dedicated" : "edge" } + }, + { + subnet_prefix = "transit" + pool_name = "transit" + machine_type = "bx2.4x16" + workers_per_zone = 1 + labels = { "dedicated" : "transit" } + } + ] +} + +# VPC ACLs +module "acl_profile" { + source = "git::https://github.ibm.com/GoldenEye/acl-profile-ocp.git?ref=1.3.1" +} + + +# VPC creation +module "vpc" { + source = "git::https://github.ibm.com/GoldenEye/vpc-module.git?ref=6.3.3" + unique_name = "${var.prefix}-vpc" + ibm_region = local.sm_region + resource_group_id = module.resource_group.resource_group_id + cidr_bases = local.vpc_cidr_bases + acl_rules_map = local.acl_rules_map + virtual_private_endpoints = {} + vpc_tags = [] +} + +# OCP CLUSTER creation +module "ocp_base" { + source = "terraform-ibm-modules/base-ocp-vpc/ibm" + version = "3.18.1" + ibmcloud_api_key = var.ibmcloud_api_key # pragma: allowlist secret + cluster_name = "${var.prefix}-vpc" + resource_group_id = module.resource_group.resource_group_id + region = local.sm_region + force_delete_storage = true + vpc_id = module.vpc.vpc_id + vpc_subnets = module.vpc.subnets + worker_pools = local.ocp_worker_pools + tags = [] + use_existing_cos = false +} + +############################################################################## +# Init cluster config for helm and kubernetes providers +############################################################################## + +data "ibm_container_cluster_config" "cluster_config" { + cluster_name_id = module.ocp_base.cluster_id + resource_group_id = module.resource_group.resource_group_id +} + +# Wait time to allow cluster refreshes components after provisioning +resource "time_sleep" "wait_45_seconds" { + depends_on = [data.ibm_container_cluster_config.cluster_config] + create_duration = "45s" +} + +# Create namespace +resource "kubernetes_namespace" "cluster_namespaces" { + for_each = toset(var.es_kubernetes_namespaces) + metadata { + name = each.value + } + lifecycle { + ignore_changes = [ + metadata[0].annotations, + metadata[0].labels + ] + } + depends_on = [ + time_sleep.wait_45_seconds + ] +} + +######################################## +# Secrets-Manager and IAM configuration +######################################## + +# IAM user policy, Secret Manager instance, Service ID for IAM engine, IAM service ID policies, associated Service ID API key stored in a secret object in account level secret-group and IAM engine configuration +resource "ibm_resource_instance" "secrets_manager" { + count = var.existing_sm_instance_guid == null ? 1 : 0 + name = "${var.prefix}-sm" + service = "secrets-manager" + plan = var.sm_service_plan + location = local.sm_region + tags = var.resource_tags + resource_group_id = module.resource_group.resource_group_id + timeouts { + create = "30m" # Extending provisioning time to 30 minutes + } +} + +# Configure instance with IAM engine +module "iam_secrets_engine" { + # providers = { + # restapi.nocontent = restapi.nocontent + # } + count = var.existing_sm_instance_guid == null ? 1 : 0 + source = "git::https://github.ibm.com/GoldenEye/secrets-manager-iam-engine-module.git?ref=2.0.6" + region = local.sm_region + secrets_manager_guid = ibm_resource_instance.secrets_manager[0].guid + create_iam_user_policy = false + iam_secret_generator_service_id_name = "${var.prefix}-sid:0.0.1:${ibm_resource_instance.secrets_manager[0].name}-iam-secret-generator:automated:simple-service:secret-manager:" + iam_secret_generator_apikey_name = "${var.prefix}-iam-secret-generator-apikey" + new_secret_group_name = "${var.prefix}-account-secret-group" + iam_secret_generator_apikey_secret_name = "${var.prefix}-iam-secret-generator-apikey-secret" + iam_engine_name = "iam-engine" +} + +# Creates secret group to place secrets +module "secrets_manager_group" { + source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" + version = "1.1.4" + # source = "git::https://github.ibm.com/GoldenEye/secrets-manager-secret-group-module.git?ref=2.0.1" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_name = "${var.prefix}-secret-group" #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + secret_group_description = "Secret-Group for storing account credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure +} + +# Additional Secrets-Manager Secret-Group for SERVICE level secrets +module "secrets_manager_group_acct" { + source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" + version = "1.1.4" + count = var.existing_sm_instance_guid == null ? 0 : 1 + # source = "git::https://github.ibm.com/GoldenEye/secrets-manager-secret-group-module.git?ref=2.0.1" + region = local.sm_region + secrets_manager_guid = local.sm_guid + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_group_name = "${var.prefix}-account-secret-group" #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + secret_group_description = "Secret-Group for storing account credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure + depends_on = [module.iam_secrets_engine] +} + +################################################################## +# Create service-id, policy to pull secrets from secret manager +################################################################## + +# Create service-id +resource "ibm_iam_service_id" "secret_puller" { + name = "sid:0.0.1:${var.prefix}-secret-puller:automated:simple-service:secret-manager:" + description = "ServiceID that can pull secrets from Secret Manager" +} +# Create policy to allow new service id to pull secrets from secrets manager +resource "ibm_iam_service_policy" "secret_puller_policy" { + iam_service_id = ibm_iam_service_id.secret_puller.id + roles = ["Viewer", "SecretsReader"] + + resources { + service = "secrets-manager" + resource_instance_id = local.sm_guid + resource_type = "secret-group" + resource = module.secrets_manager_group.secret_group_id + } +} + +################################################################## +# Artifactory-registry +################################################################## + +# Creates username_password secrets and stores in secret manager +module "sm_up_artifactory_secret" { + source = "git::https://github.ibm.com/GoldenEye/secrets-manager-secret-module.git?ref=3.1.1" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_id = module.secrets_manager_group.secret_group_id + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_name = "${var.prefix}-artifactory-up-secret" # checkov:skip=CKV_SECRET_6 + secret_description = "example secret in existing secret manager instance" # tfsec:ignore:general-secrets-no-plaintext-exposure # checkov:skip=CKV_SECRET_6 + secret_payload_password = local.artifactory_apikey # pragma: allowlist secret + secret_type = "username_password" #checkov:skip=CKV_SECRET_6 + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_username = "artifactory-user" # checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value + secret_user_pass_auto_rotation = false +} + +# Installing external secrets operator(ESO), cluster store and deploying external secret as dockerconfigson type +module "eso_operator_clusterstore_deployment" { + source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git?ref=1.7.0" + depends_on = [ + kubernetes_namespace.cluster_namespaces + ] + es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "username_password" #checkov:skip=CKV_SECRET_6 + sm_secret_id = module.sm_up_artifactory_secret.secret_id + eso_setup = true + es_kubernetes_namespaces = [var.es_kubernetes_namespaces[0]] + eso_generic_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key # pragma: allowlist secret + secrets_manager_guid = local.sm_guid + eso_generic_secret_name = "generic-cluster-api-key" #checkov:skip=CKV_SECRET_6 + eso_store_name = "cluster-store" + es_container_registry = "wcp-my-team-docker-local.artifactory.swg-devops.com" + region = local.sm_region + es_kubernetes_secret_name = "dockerconfigjson-uc" #checkov:skip=CKV_SECRET_6 + es_helm_rls_name = "es-docker-uc" + es_store_helm_rls_name = "cluster-store" + eso_authentication = ["api_key"] + +} + +################################################################## +# Cloudant-arbitrary-secret +################################################################## + +############################################################################## +# Basic cloudant instance + database +############################################################################## + +module "cloudant" { + source = "terraform-ibm-modules/cloudant/ibm" + version = "1.1.7" + resource_group_id = module.resource_group.resource_group_id + instance_name = "${var.prefix}-cloudant" + access_tags = [] + region = var.region + tags = var.resource_tags + database_config = [{ + db = "cloudant-db" + partitioned = false + shards = 3 + }] +} + +data "ibm_cloudant" "instance" { + name = module.cloudant.name + resource_group_id = module.resource_group.resource_group_id +} + +resource "ibm_resource_key" "resource_key" { + name = "cd-resource-key" + role = "Manager" + resource_instance_id = data.ibm_cloudant.instance.id + timeouts { + create = "15m" + delete = "15m" + } +} + +# Creates arbitrary secret and stores in secret manager +module "sm_arbitrary_cloudant_secret" { + source = "git::https://github.ibm.com/GoldenEye/secrets-manager-secret-module.git?ref=3.1.1" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_id = module.secrets_manager_group.secret_group_id + secret_type = "arbitrary" + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_name = "${var.prefix}-cloudant-rk-secret" #checkov:skip=CKV_SECRET_6 + secret_description = "example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_payload_password = ibm_resource_key.resource_key.credentials["apikey"] +} + +# Deploying external secret as Opaque type using existing cluster store +module "eso_clusterstore_externalsecret_opaque_create" { + depends_on = [ + module.eso_operator_clusterstore_deployment, + kubernetes_namespace.cluster_namespaces + ] + source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git?ref=1.7.0" + es_kubernetes_secret_type = "opaque" + sm_secret_type = "arbitrary" + sm_secret_id = module.sm_arbitrary_cloudant_secret.secret_id + eso_setup = false + eso_store_setup = false + es_kubernetes_namespaces = [var.es_kubernetes_namespaces[1]] + eso_generic_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key # pragma: allowlist secret + eso_store_name = "cluster-store" + secrets_manager_guid = local.sm_guid + region = local.sm_region + es_kubernetes_secret_data_key = "apikey" + es_kubernetes_secret_name = "cloudant-opaque-arb" #checkov:skip=CKV_SECRET_6 + es_helm_rls_name = "es-cloudant-arb" + eso_authentication = ["api_key"] +} + +################################################################## +# cr-registry-arbitrary-secret +################################################################## + +# Creates arbitrary secret and stores in secret manager +module "sm_arbitrary_imagepull_secret" { + source = "git::https://github.ibm.com/GoldenEye/secrets-manager-secret-module.git?ref=3.1.1" + region = local.sm_region + secrets_manager_guid = local.sm_guid + secret_group_id = module.secrets_manager_group.secret_group_id + secret_type = "arbitrary" + #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_name = "${var.prefix}-imagepull-apikey-secret" #checkov:skip=CKV_SECRET_6 + secret_description = "example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure + secret_payload_password = local.imagepull_apikey # pragma: allowlist secret +} + +# Deploying external secret as dockerconfigson type using new namespace store +module "eso_secretstore_create_externalsecret_arbitrary_create" { + depends_on = [ + module.eso_operator_clusterstore_deployment, + kubernetes_namespace.cluster_namespaces + ] + source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git?ref=1.7.0" + es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "arbitrary" + sm_secret_id = module.sm_arbitrary_imagepull_secret.secret_id + eso_setup = false + eso_store_setup = true + eso_store_scope = "namespace" + es_kubernetes_namespaces = [var.es_kubernetes_namespaces[2]] + es_container_registry_email = "terraform@ibm.com" + eso_generic_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key # pragma: allowlist secret + eso_generic_secret_name = "generic-${var.es_kubernetes_namespaces[2]}-api-key" + eso_store_name = "${var.es_kubernetes_namespaces[2]}-store" + secrets_manager_guid = local.sm_guid + region = local.sm_region + es_kubernetes_secret_name = "dockerconfigjson-arb" #checkov:skip=CKV_SECRET_6 + es_helm_rls_name = "es-docker-arb" + es_store_helm_rls_name = "store" + eso_authentication = ["api_key"] + +} + +################################################################## +# cr-registry-same-account +################################################################## + +# Create dynamic Service ID API key and add to secret manager +module "dynamic_serviceid_apikey1" { + source = "git::https://github.ibm.com/GoldenEye/iam-serviceid-apikey-secrets-manager-module.git?ref=2.0.2" + region = local.sm_region + #tfsec:ignore:general-secrets-no-plaintext-exposure + sm_iam_secret_name = "${var.prefix}-${var.sm_iam_secret_name}" + sm_iam_secret_description = "Example of dynamic IAM secret / apikey" #tfsec:ignore:general-secrets-no-plaintext-exposure + serviceid_id = ibm_iam_service_id.secret_puller.id + secrets_manager_guid = local.sm_guid + secret_group_id = local.sm_acct_id + depends_on = [module.iam_secrets_engine, ibm_iam_service_policy.secret_puller_policy, ibm_iam_service_id.secret_puller] +} + +# Creates image pull secrets and stores in secret manager +module "image_pull" { + source = "git::https://github.ibm.com/GoldenEye/imagepull-apikey-secrets-manager-module.git?ref=1.1.2" + resource_group_id = module.resource_group.resource_group_id + secrets_manager_guid = local.sm_guid + cr_namespace_name = var.cr_namespace_name + region = local.sm_region + #tfsec:ignore:general-secrets-no-plaintext-exposure + service_id_secret_name = "${var.prefix}-image-pull-service-id" + service_id_secret_group_id = module.secrets_manager_group.secret_group_id + depends_on = [module.iam_secrets_engine, module.secrets_manager_group] +} + +# Data source to get API Key from secret manager secret-puller-secret +data "ibm_sm_iam_credentials_secret" "secret_puller_secret" { + instance_id = local.sm_guid + #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static type + secret_id = module.dynamic_serviceid_apikey1.secret_id +} + +# Deploying external secret as dockerconfigson type (from image pull IAM dynamic credential/secret) using new namespace store +module "eso_secretstore_create_externalsecret_iamcredentials_create" { + depends_on = [ + module.eso_operator_clusterstore_deployment, + kubernetes_namespace.cluster_namespaces + ] + source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git?ref=1.7.0" + es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "iam_credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure + sm_secret_id = module.image_pull.serviceid_apikey_secret_id + es_kubernetes_namespaces = [var.es_kubernetes_namespaces[3]] + eso_setup = false + eso_store_setup = true + eso_store_scope = "namespace" + es_container_registry_email = "terraform@ibm.com" + es_refresh_interval = var.es_refresh_interval + eso_generic_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key # pragma: allowlist secret tfsec:ignore:general-secrets-no-plaintext-exposure + eso_generic_secret_name = "generic-${var.es_kubernetes_namespaces[3]}-api-key" + eso_store_name = "${var.es_kubernetes_namespaces[3]}-store" + secrets_manager_guid = local.sm_guid + region = local.sm_region + es_kubernetes_secret_name = "dockerconfigjson-iam" #tfsec:ignore:general-secrets-no-plaintext-exposure #checkov:skip=CKV_SECRET_6 + es_helm_rls_name = "es-docker-iam" + es_store_helm_rls_name = "store" + eso_authentication = ["api_key"] +} diff --git a/docs/upgradeplanexamples/moved.tf.new b/docs/upgradeplanexamples/moved.tf.new new file mode 100644 index 00000000..e61a540b --- /dev/null +++ b/docs/upgradeplanexamples/moved.tf.new @@ -0,0 +1,54 @@ +moved { + from = module.eso_clusterstore_externalsecret_opaque_create.helm_release.kubernetes_secret[0] + to = module.external_secret_opaque_arbitrary_deployment.helm_release.kubernetes_secret[0] +} + +moved { + from = module.eso_secretstore_create_externalsecret_arbitrary_create.helm_release.external_secret_store[0] + to = module.eso_namespacedstore_apikeyauth_dockerconfigson_deployment.helm_release.external_secret_store_apikey[0] +} + +moved { + from = module.eso_operator_clusterstore_deployment.helm_release.external_clstr_secret_store[0] + to = module.eso_clusterstore_deployment.helm_release.cluster_secret_store_apikey[0] +} + +moved { + from = module.eso_operator_clusterstore_deployment.kubernetes_secret.eso_generic_secret[0] + to = module.eso_clusterstore_deployment.kubernetes_secret.eso_clusterstore_secret[0] +} + +moved { + from = module.eso_secretstore_create_externalsecret_arbitrary_create.kubernetes_secret.eso_generic_secret[0] + to = module.eso_namespacedstore_apikeyauth_dockerconfigson_deployment.kubernetes_secret.eso_secretsstore_secret[0] +} + +moved { + from = module.eso_secretstore_create_externalsecret_iamcredentials_create.kubernetes_secret.eso_generic_secret[0] + to = module.eso_namespacedstore_apikeyauth_iamcredentials_deployment.kubernetes_secret.eso_secretsstore_secret[0] +} + +moved { + from = module.eso_secretstore_create_externalsecret_iamcredentials_create.helm_release.external_secret_store[0] + to = module.eso_namespacedstore_apikeyauth_iamcredentials_deployment.helm_release.external_secret_store_apikey[0] +} + +moved { + from = module.eso_secretstore_create_externalsecret_iamcredentials_create.helm_release.kubernetes_secret[0] + to = module.external_secret_dockerconfigson_iamcredentials_deployment.helm_release.kubernetes_secret[0] +} + +moved { + from = module.eso_secretstore_create_externalsecret_arbitrary_create.helm_release.kubernetes_secret[0] + to = module.external_secret_dockerconfigson_arbitrary_deployment.helm_release.kubernetes_secret[0] +} + +moved { + from = module.eso_operator_clusterstore_deployment.helm_release.kubernetes_secret_user_pw[0] + to = module.external_secret_dockerconfigson_usr_pass_deployment.helm_release.kubernetes_secret_user_pw[0] +} + +moved { + from = module.eso_operator_clusterstore_deployment.helm_release.external_secrets_operator[0] + to = module.eso_operator_deployment.helm_release.external_secrets_operator +} diff --git a/docs/upgradeplanexamples/variables.tf.new b/docs/upgradeplanexamples/variables.tf.new new file mode 100644 index 00000000..1d75764e --- /dev/null +++ b/docs/upgradeplanexamples/variables.tf.new @@ -0,0 +1,98 @@ +####################################################################### +# Generic +####################################################################### + +variable "prefix" { + description = "Prefix for name of all resource created by this example" + type = string + default = "eso-example" +} + +variable "region" { + type = string + description = "Region where resources will be created" + default = "us-south" +} + +variable "ibmcloud_api_key" { + type = string + description = "APIkey that's associated with the account to use, set via environment variable TF_VAR_ibmcloud_api_key or .tfvars file." + sensitive = true +} + +variable "resource_group" { + type = string + description = "An existing resource group name to use for this example, if unset a new resource group will be created" + default = null +} + +# tflint-ignore: terraform_unused_declarations +variable "resource_tags" { + type = list(string) + description = "Optional list of tags to be added to created resources" + default = [] +} + +## Image-pull module +variable "sm_iam_secret_name" { + type = string + description = "Name of SM IAM secret (dynamic ServiceID API Key) to be created" + default = "sm-iam-secret-puller" #tfsec:ignore:general-secrets-no-plaintext-exposure +} + +variable "sm_service_plan" { + type = string + description = "Secrets-Manager trial plan" + default = "trial" +} +variable "cr_namespace_name" { + type = string + description = "Container registry namespace name to be configured in IAM policy." + default = "cr-namespace" +} + + +## ESO Module +variable "es_kubernetes_namespaces" { + type = list(string) + description = "Namespace(s) where Kubernetes secrets will be installed/required." + default = ["namespace-1", "namespace-2", "namespace-3", "namespace-4"] +} +variable "es_refresh_interval" { + description = "Specify interval for es secret synchronization" + default = "1h" + type = string +} + +variable "existing_sm_instance_guid" { + type = string + description = "Existing Secrets Manager GUID. If not provided a new instance will be provisioned" + default = null +} + +variable "existing_sm_instance_region" { + type = string + description = "Existing Secrets Manager Region. Required if value is passed into var.existing_instance_guid" + default = null +} + +### new variables + +# as now already exists +variable "existing_eso_namespace" { + type = string + description = "Namespace to deploy the External secrets Operator into" + default = "external-secrets-operator" +} + +variable "service_endpoints" { + type = string + description = "The service endpoint type to communicate with the provided secrets manager instance. Possible values are `public` or `private`. This also will set the iam endpoint for containerAuth when enabling Trusted Profile/CR based authentication." + default = "public" +} + +variable "eso_deployment_nodes_configuration" { + type = string + description = "Configuration to deploy ESO on specific cluster nodes. The value of this variable will be used for NodeSelector label value and tolerations configuration. If null standard ESO deployment is done." + default = "edge" +} diff --git a/docs/upgradeplanexamples/variables.tf.old b/docs/upgradeplanexamples/variables.tf.old new file mode 100644 index 00000000..a2032a70 --- /dev/null +++ b/docs/upgradeplanexamples/variables.tf.old @@ -0,0 +1,77 @@ +####################################################################### +# Generic +####################################################################### + +variable "prefix" { + description = "Prefix for name of all resource created by this example" + type = string + default = "eso-example" +} + +variable "region" { + type = string + description = "Region where resources will be created" + default = "us-south" +} + +variable "ibmcloud_api_key" { + type = string + description = "APIkey that's associated with the account to use, set via environment variable TF_VAR_ibmcloud_api_key or .tfvars file." + sensitive = true +} + +variable "resource_group" { + type = string + description = "An existing resource group name to use for this example, if unset a new resource group will be created" + default = null +} + +# tflint-ignore: terraform_unused_declarations +variable "resource_tags" { + type = list(string) + description = "Optional list of tags to be added to created resources" + default = [] +} + +## Image-pull module +variable "sm_iam_secret_name" { + type = string + description = "Name of SM IAM secret (dynamic ServiceID API Key) to be created" + default = "sm-iam-secret-puller" #tfsec:ignore:general-secrets-no-plaintext-exposure +} + +variable "sm_service_plan" { + type = string + description = "Secrets-Manager trial plan" + default = "trial" +} +variable "cr_namespace_name" { + type = string + description = "Container registry namespace name to be configured in IAM policy." + default = "cr-namespace" +} + + +## ESO Module +variable "es_kubernetes_namespaces" { + type = list(string) + description = "Namespace(s) where Kubernetes secrets will be installed/required." + default = ["namespace-1", "namespace-2", "namespace-3", "namespace-4"] +} +variable "es_refresh_interval" { + description = "Specify interval for es secret synchronization" + default = "1h" + type = string +} + +variable "existing_sm_instance_guid" { + type = string + description = "Existing Secrets Manager GUID. If not provided a new instance will be provisioned" + default = null +} + +variable "existing_sm_instance_region" { + type = string + description = "Existing Secrets Manager Region. Required if value is passed into var.existing_instance_guid" + default = null +} diff --git a/examples/all-combined/main.tf b/examples/all-combined/main.tf index f5f00f80..60b51872 100644 --- a/examples/all-combined/main.tf +++ b/examples/all-combined/main.tf @@ -123,7 +123,6 @@ module "public_gateways" { location = "${var.region}-${var.zones[count.index]}" name = "${var.prefix}-vpc-gateway-${var.zones[count.index]}" resource_group_id = module.resource_group.resource_group_id - tags = var.tags } module "security_group" { @@ -172,12 +171,11 @@ locals { } module "network_acl" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/network-acl" + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/network-acl?ref=v1.5.0" name = "${var.prefix}-vpc-acl" vpc_id = module.vpc.vpc.vpc_id resource_group_id = module.resource_group.resource_group_id rules = local.acl_rules - tags = var.tags } # OCP CLUSTER creation @@ -194,25 +192,10 @@ module "ocp_base" { tags = [] use_existing_cos = false # outbound required by cluster proxy - disable_outbound_traffic_protection = true + disable_outbound_traffic_protection = true + import_default_worker_pool_on_create = false } -# OCP CLUSTER creation -module "ocp_base" { - source = "terraform-ibm-modules/base-ocp-vpc/ibm" - version = "3.36.0" - cluster_name = "${var.prefix}-cluster" - resource_group_id = module.resource_group.resource_group_id - region = var.region - force_delete_storage = true - vpc_id = module.vpc.vpc_id - vpc_subnets = module.vpc.subnets - worker_pools = local.ocp_worker_pools - tags = [] - use_existing_cos = false - # outbound required by cluster proxy - disable_outbound_traffic_protection = true -} ############################################################################## # Init cluster config for helm and kubernetes providers @@ -249,9 +232,9 @@ module "vpes" { region = var.region prefix = "vpe" vpc_name = "${var.prefix}-vpc" - vpc_id = module.vpc.vpc_id + vpc_id = module.vpc.vpc.vpc_id subnet_zone_list = [ - for index, subnet in module.vpc.subnets.transit : { + for index, subnet in local.subnets.default : { name = "${local.sm_region}-${index}" zone = subnet.zone id = subnet.id diff --git a/examples/all-combined/outputs.tf b/examples/all-combined/outputs.tf index 547bb0b2..a06c9202 100644 --- a/examples/all-combined/outputs.tf +++ b/examples/all-combined/outputs.tf @@ -2,22 +2,13 @@ # Outputs ############################################################################## -# output "secret_manager_guid" { -# value = module.image_pull.secret_manager_guid -# description = "GUID of Secrets-Manager containing secret" -# } - -# output "serviceid_name" { -# description = "Name of the ServiceID created to access Container Registry" -# value = module.image_pull.serviceid_name -# } - -# output "serviceid_apikey_secret_id" { -# description = "ID of the Secret Manager Secret containing ServiceID API Key" -# value = module.image_pull.serviceid_apikey_secret_id -# } output "cluster_id" { description = "ID of the cluster deployed" value = module.ocp_base.cluster_id } + +output "subnets" { + description = "List of subnet" + value = local.subnets +} diff --git a/examples/all-combined/sdnlb-secret.tf b/examples/all-combined/sdnlb-secret.tf deleted file mode 100644 index feae005f..00000000 --- a/examples/all-combined/sdnlb-secret.tf +++ /dev/null @@ -1,37 +0,0 @@ -############################################################################## -# Load cluster and serviceID details -############################################################################## - -# data "ibm_iam_service_id" "existing_sdnlb_serviceid" { -# name = var.existing_sdnlb_serviceid_name -# } - -# creating a dynamic secret on SM to generate the serviceID API key -# module "dynamic_sdnlb_serviceid_apikey_by_sm_serviceid_apikey" { -# source = "terraform-ibm-modules/iam-serviceid-apikey-secrets-manager/ibm" -# version = "1.1.1" -# region = local.sm_region -# sm_iam_secret_name = "${var.prefix}-sdnlb-secret" -# sm_iam_secret_description = "sdnlb serviceID apikey secret" -# secrets_manager_guid = local.sm_guid -# serviceid_id = data.ibm_iam_service_id.existing_sdnlb_serviceid.service_ids[0].id -# secret_group_id = module.secrets_manager_group.secret_group_id -# providers = { -# ibm = ibm.ibm-sm -# } -# } - -# module "sdnlb_eso_secret" { -# depends_on = [module.external_secrets_operator] -# source = "git::https://github.ibm.com/GoldenEye/sdnlb-module.git//modules/sdnlb-eso-secret-module?ref=3.5.0" -# sdnlb_service_id = data.ibm_iam_service_id.existing_sdnlb_serviceid.service_ids[0].id -# sdnlb_api_key_sm_id = module.dynamic_sdnlb_serviceid_apikey_by_sm_serviceid_apikey.secret_id -# #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static type -# externalsecret_helm_release_new_namespace = "sdnlb-secret-helm-release-namespace" -# eso_store_name = "cluster-store" -# eso_store_scope = "cluster" - -# providers = { -# ibm = ibm.ibm-sdnlb -# } -# } diff --git a/examples/all-combined/secretsmanager.tf b/examples/all-combined/secretsmanager.tf index be004b72..ef72cd9e 100644 --- a/examples/all-combined/secretsmanager.tf +++ b/examples/all-combined/secretsmanager.tf @@ -30,7 +30,7 @@ locals { # if service_endpoints is not private the crn for SM is not needed because of VPE creation is not needed sm_crn = var.existing_sm_instance_crn == null ? (var.service_endpoints == "private" ? ibm_resource_instance.secrets_manager[0].crn : "") : var.existing_sm_instance_crn - # https://github.ibm.com/GoldenEye/issues/issues/5268 - deployment region will match to sm_region as workaround + sm_region = var.existing_sm_instance_region == null ? var.region : var.existing_sm_instance_region sm_acct_id = var.existing_sm_instance_guid == null ? module.iam_secrets_engine[0].acct_secret_group_id : module.secrets_manager_group_acct[0].secret_group_id } diff --git a/examples/all-combined/secretstore.tf b/examples/all-combined/secretstore.tf index ceb7c1dd..4d9e4716 100644 --- a/examples/all-combined/secretstore.tf +++ b/examples/all-combined/secretstore.tf @@ -83,119 +83,3 @@ module "external_secret_arbitrary_cr_registry" { es_kubernetes_secret_name = "dockerconfigjson-arb" #checkov:skip=CKV_SECRET_6 es_helm_rls_name = "es-docker-arb" } - -################################################################## -# Image pull API key secret using imagepull-apikey-secrets-manager-module -################################################################## - -# create image pull serviceID and secret and store in secrets manager -# module "image_pull" { -# source = "git::https://github.ibm.com/GoldenEye/imagepull-apikey-secrets-manager-module.git?ref=1.1.7" -# resource_group_id = module.resource_group.resource_group_id -# secrets_manager_guid = local.sm_guid -# cr_namespace_name = var.cr_namespace_name -# region = local.sm_region -# #tfsec:ignore:general-secrets-no-plaintext-exposure -# service_id_secret_name = "${var.prefix}-image-pull-service-id" -# service_id_secret_group_id = module.secrets_manager_group.secret_group_id -# depends_on = [module.iam_secrets_engine, module.secrets_manager_group] -# providers = { -# ibm = ibm.ibm-sm -# } -# } - -# # ESO external secret storing the secret in the cluster as dockerconfigson type (from image pull IAM dynamic credential/secret) using namespaced secretstore -# module "external_secret_secret_image_pull" { -# source = "../../modules/eso-external-secret" -# depends_on = [ -# module.eso_apikey_namespace_secretstore_2, -# ] -# eso_store_scope = "namespace" -# es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 -# sm_secret_type = "iam_credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure -# sm_secret_id = module.image_pull.serviceid_apikey_secret_id -# es_kubernetes_namespace = kubernetes_namespace.apikey_namespaces[3].metadata[0].name -# es_container_registry = "test.icr.com" -# es_container_registry_email = "terraform@ibm.com" -# es_refresh_interval = var.es_refresh_interval -# eso_store_name = "${var.es_namespaces_apikey[3]}-store" -# es_kubernetes_secret_name = "dockerconfigjson-iam" #tfsec:ignore:general-secrets-no-plaintext-exposure #checkov:skip=CKV_SECRET_6 -# es_helm_rls_name = "es-docker-iam" -# } - -# ################################################################## -# # Image pull API key secrets using imagepull-apikey-secrets-manager-module -# # to be configured in a single chain of secrets -# ################################################################## - -# # create image pull serviceID and secret and store in secrets manager -# module "image_pull_chain_secret_1" { -# source = "git::https://github.ibm.com/GoldenEye/imagepull-apikey-secrets-manager-module.git?ref=1.1.7" -# resource_group_id = module.resource_group.resource_group_id -# secrets_manager_guid = local.sm_guid -# cr_namespace_name = var.cr_namespace_name -# region = local.sm_region -# #tfsec:ignore:general-secrets-no-plaintext-exposure -# service_id_secret_name = "${var.prefix}-image-pull-service-id-chain-sec-1" -# service_id_secret_group_id = module.secrets_manager_group.secret_group_id -# depends_on = [module.iam_secrets_engine, module.secrets_manager_group] -# providers = { -# ibm = ibm.ibm-sm -# } -# } - -# # create image pull serviceID and secret and store in secrets manager -# module "image_pull_chain_secret_2" { -# source = "git::https://github.ibm.com/GoldenEye/imagepull-apikey-secrets-manager-module.git?ref=1.1.7" -# resource_group_id = module.resource_group.resource_group_id -# secrets_manager_guid = local.sm_guid -# cr_namespace_name = var.cr_namespace_name -# region = local.sm_region -# #tfsec:ignore:general-secrets-no-plaintext-exposure -# service_id_secret_name = "${var.prefix}-image-pull-service-id-chain-sec-2" -# service_id_secret_group_id = module.secrets_manager_group.secret_group_id -# depends_on = [module.iam_secrets_engine, module.secrets_manager_group] -# providers = { -# ibm = ibm.ibm-sm -# } -# } - -# # create image pull serviceID and secret and store in secrets manager -# module "image_pull_chain_secret_3" { -# source = "git::https://github.ibm.com/GoldenEye/imagepull-apikey-secrets-manager-module.git?ref=1.1.7" -# resource_group_id = module.resource_group.resource_group_id -# secrets_manager_guid = local.sm_guid -# cr_namespace_name = var.cr_namespace_name -# region = local.sm_region -# #tfsec:ignore:general-secrets-no-plaintext-exposure -# service_id_secret_name = "${var.prefix}-image-pull-service-id-chain-sec-3" -# service_id_secret_group_id = module.secrets_manager_group.secret_group_id -# depends_on = [module.iam_secrets_engine, module.secrets_manager_group] -# providers = { -# ibm = ibm.ibm-sm -# } -# } - -# module "external_secret_secret_image_pull_chain" { -# source = "../../modules/eso-external-secret" -# depends_on = [module.eso_apikey_namespace_secretstore_2, ] -# eso_store_scope = "namespace" -# es_kubernetes_secret_type = "dockerconfigjson" -# sm_secret_type = "iam_credentials" -# eso_store_name = "${var.es_namespaces_apikey[3]}-store" -# es_kubernetes_secret_name = "dockerconfigjson-chain" -# es_helm_rls_name = "es-docker-iam-chain" -# es_kubernetes_namespace = kubernetes_namespace.apikey_namespaces[3].metadata[0].name -# sm_secret_id = null # null is accepted only in the case of a dockerjsonconfig secret with secrets chain -# es_container_registry_secrets_chain = [ -# { -# "es_container_registry" : "test1.icr.com", "sm_secret_id" : module.image_pull_chain_secret_1.serviceid_apikey_secret_id, "es_container_registry_email" : "terraform1@ibm.com" -# }, -# { -# "es_container_registry" : "test2.icr.com", "sm_secret_id" : module.image_pull_chain_secret_2.serviceid_apikey_secret_id, "es_container_registry_email" : null -# }, -# { -# "es_container_registry" : "test3.icr.com", "sm_secret_id" : module.image_pull_chain_secret_3.serviceid_apikey_secret_id, "es_container_registry_email" : "" -# } -# ] -# } diff --git a/examples/all-combined/variables.tf b/examples/all-combined/variables.tf index ce4ff298..1286d6c1 100644 --- a/examples/all-combined/variables.tf +++ b/examples/all-combined/variables.tf @@ -45,12 +45,6 @@ variable "sm_service_plan" { description = "Secrets-Manager trial plan" default = "trial" } -variable "cr_namespace_name" { - type = string - description = "Container registry namespace name to be configured in IAM policy." - default = "cr-namespace" -} - ## ESO Module @@ -258,10 +252,6 @@ variable "sdnlb_ibmcloud_api_key" { default = null } -variable "existing_sdnlb_serviceid_name" { - type = string - description = "The service ID with access to provision the sDNLB. The example creates an API key for this service ID." -} variable "zones" { description = "List of zones" @@ -277,9 +267,32 @@ variable "cidr_bases" { } } + variable "acl_rules_list" { - description = "Access control list rule set per network zone" - type = list(object) + description = "List of rules that are to be attached to the Network ACL" + type = list(object({ + name = string + action = string + source = string + destination = string + direction = string + icmp = optional(object({ + code = number + type = number + })) + tcp = optional(object({ + port_max = number + port_min = number + source_port_max = number + source_port_min = number + })) + udp = optional(object({ + port_max = number + port_min = number + source_port_max = number + source_port_min = number + })) + })) default = [ { name = "iks-create-worker-nodes-inbound" diff --git a/examples/basic/README.md b/examples/basic/README.md index f77bef3c..504f852c 100644 --- a/examples/basic/README.md +++ b/examples/basic/README.md @@ -8,7 +8,7 @@ This module provides a basic example to deploy the External Secrets Operator alo - **VPC and Subnet Configuration**: Establishes a Virtual Private Cloud (VPC) with associated subnets, setting up network segmentation and ACL rules. -- **OpenShift Cluster Provisioning**: Deploys an OpenShift (OCP) cluster, tailored for a cloud-native architecture with worker pools. +- **OpenShift Cluster Provisioning**: Deploys an OpenShift (OCP) cluster, tailored for a cloud-native architecture with worker pools for private, transit, and edge network segments. - **Secrets Manager Integration**: - Either utilizes an existing Secrets Manager instance or creates a new one. diff --git a/examples/basic/main.tf b/examples/basic/main.tf index 9f1594ea..1cb5ca1c 100644 --- a/examples/basic/main.tf +++ b/examples/basic/main.tf @@ -16,7 +16,7 @@ locals { sm_guid = var.existing_sm_instance_guid == null ? ibm_resource_instance.secrets_manager[0].guid : var.existing_sm_instance_guid - # https://github.ibm.com/GoldenEye/issues/issues/5268 - deployment region will match to sm_region as workaround + sm_region = var.existing_sm_instance_region == null ? var.region : var.existing_sm_instance_region sm_acct_id = var.existing_sm_instance_guid == null ? module.iam_secrets_engine[0].acct_secret_group_id : module.secrets_manager_group_acct[0].secret_group_id es_namespace_apikey = "es-operator" # pragma: allowlist secret @@ -145,7 +145,6 @@ module "public_gateways" { location = "${var.region}-${var.zones[count.index]}" name = "${var.prefix}-vpc-gateway-${var.zones[count.index]}" resource_group_id = module.resource_group.resource_group_id - tags = var.tags } module "security_group" { @@ -194,15 +193,13 @@ locals { } module "network_acl" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/network-acl" + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/network-acl?ref=v1.5.0" name = "${var.prefix}-vpc-acl" vpc_id = module.vpc.vpc.vpc_id resource_group_id = module.resource_group.resource_group_id rules = local.acl_rules - tags = var.tags } - # OCP CLUSTER creation module "ocp_base" { source = "terraform-ibm-modules/base-ocp-vpc/ibm" @@ -217,12 +214,14 @@ module "ocp_base" { tags = [] use_existing_cos = false # outbound required by cluster proxy - disable_outbound_traffic_protection = true + disable_outbound_traffic_protection = true + import_default_worker_pool_on_create = false } -############################################################################# + +############################################################################## # Init cluster config for helm and kubernetes providers -############################################################################# +############################################################################## data "ibm_container_cluster_config" "cluster_config" { cluster_name_id = module.ocp_base.cluster_id @@ -335,19 +334,20 @@ module "external_secrets_operator" { source = "../../" eso_namespace = local.eso_namespace - eso_cluster_nodes_configuration = { + eso_cluster_nodes_configuration = var.eso_deployment_nodes_configuration == null ? null : { nodeSelector = { label = "dedicated" - value = "default" + value = var.eso_deployment_nodes_configuration } tolerations = { key = "dedicated" operator = "Equal" - value = "default" + value = var.eso_deployment_nodes_configuration effect = "NoExecute" } } + depends_on = [ kubernetes_namespace.apikey_namespace ] diff --git a/examples/basic/outputs.tf b/examples/basic/outputs.tf index 18de0faf..e124314b 100644 --- a/examples/basic/outputs.tf +++ b/examples/basic/outputs.tf @@ -1,7 +1,7 @@ ############################################################################## # Outputs -# ############################################################################## -# output "cluster_id" { -# description = "ID of the cluster deployed" -# value = module.ocp_base.cluster_id -# } +############################################################################## +output "cluster_id" { + description = "ID of the cluster deployed" + value = module.ocp_base.cluster_id +} diff --git a/examples/basic/variables.tf b/examples/basic/variables.tf index 7b1c1cad..79c0bc69 100644 --- a/examples/basic/variables.tf +++ b/examples/basic/variables.tf @@ -59,9 +59,9 @@ variable "existing_sm_instance_region" { default = null } -variable "tags" { - description = "List of Tags for the ACL" - type = list(string) +variable "eso_deployment_nodes_configuration" { + type = string + description = "Configuration to deploy ESO on specific cluster nodes. The value of this variable will be used for NodeSelector label value and tolerations configuration. If null standard ESO deployment is done on default workers pool." default = null } @@ -80,22 +80,30 @@ variable "cidr_bases" { } variable "acl_rules_list" { - description = "Access control list rule set per network zone" - type = list( - object({ - name = string - action = string - source = string - destination = string - direction = string - tcp = optional(object({ - source_port_min = number - source_port_max = number - port_min = number - port_max = number - })) - }) - ) + description = "List of rules that are to be attached to the Network ACL" + type = list(object({ + name = string + action = string + source = string + destination = string + direction = string + icmp = optional(object({ + code = number + type = number + })) + tcp = optional(object({ + port_max = number + port_min = number + source_port_max = number + source_port_min = number + })) + udp = optional(object({ + port_max = number + port_min = number + source_port_max = number + source_port_min = number + })) + })) default = [ { name = "iks-create-worker-nodes-inbound" diff --git a/examples/trusted-profiles-authentication/main.tf b/examples/trusted-profiles-authentication/main.tf index b2b74549..452f2808 100644 --- a/examples/trusted-profiles-authentication/main.tf +++ b/examples/trusted-profiles-authentication/main.tf @@ -90,7 +90,7 @@ resource "kubernetes_namespace" "examples" { module "sm_arbitrary_secrets" { count = length(kubernetes_namespace.examples) source = "terraform-ibm-modules/secrets-manager-secret/ibm" - version = "1.3.2" + version = "1.4.0" region = local.sm_region secrets_manager_guid = local.sm_guid secret_group_id = module.secrets_manager_groups[count.index].secret_group_id diff --git a/main.tf b/main.tf index 885884c3..6a7f601b 100644 --- a/main.tf +++ b/main.tf @@ -232,7 +232,6 @@ resource "helm_release" "pod_reloader" { depends_on = [module.eso_namespace, data.kubernetes_namespace.existing_eso_namespace] count = var.reloader_deployed == true ? 1 : 0 name = "reloader" - //chart = "oci://icr.io/ibm-iac-charts/reloader" chart = "reloader" namespace = local.eso_namespace repository = "https://stakater.github.io/stakater-charts" diff --git a/outputs.tf b/outputs.tf index bb6ea662..b16a1a35 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,8 +1,3 @@ -######################################################################################################################## +############################################################################## # Outputs -######################################################################################################################## - -#output "myoutput" { -# description = "Description of my output" -# value = "value" -#} +############################################################################## diff --git a/renovate.json b/renovate.json index 808f9f18..aba6bf47 100644 --- a/renovate.json +++ b/renovate.json @@ -5,7 +5,7 @@ { "fileMatch": ["\\.tf$"], "matchStrings": [ - "[\\w-]+_digest\\s*=\\s*\"(?[\\w.-]+)@(?sha256:[a-f0-9]+)\"" + "[\\w-]+_image_tag_digest\\s*=\\s*\"(?[\\w.-]+)@(?sha256:[a-f0-9]+)\"\\s*# datasource: (?[^\\s]+)" ], "datasourceTemplate": "docker" } @@ -13,9 +13,15 @@ "labels": ["renovate"], "packageRules": [ { - "matchManagers": ["regex"], - "groupName": "Image Digest Updates", - "commitMessageExtra": "to latest digest", + "matchManagers": ["helmv3"], + "groupName": "Charts and Images", + "commitMessageExtra": "to latest", + "group": true + }, + { + "matchDatasources": ["docker"], + "groupName": "Charts and Images", + "commitMessageExtra": "to latest", "group": true } ] diff --git a/tests/README.md b/tests/README.md index dfd68426..581aa046 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,5 +1,8 @@ + + # Tests For information about how to create and run tests, see [Validation tests](https://terraform-ibm-modules.github.io/documentation/#/tests) in the project documentation. + diff --git a/tests/go.mod b/tests/go.mod index ea7f7292..d4fd85c8 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -1,14 +1,15 @@ module github.com/terraform-ibm-modules/terraform-ibm-external-secrets-operator -go 1.22.4 +go 1.23.0 toolchain go1.23.4 require ( github.com/gruntwork-io/terratest v0.48.1 github.com/stretchr/testify v1.10.0 - github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper v1.42.8 - k8s.io/apimachinery v0.28.4 + github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper v1.42.10 + gopkg.in/yaml.v3 v3.0.1 + k8s.io/apimachinery v0.32.0 ) require ( @@ -17,8 +18,8 @@ require ( github.com/IBM-Cloud/bluemix-go v0.0.0-20240719075425-078fcb3a55be // indirect github.com/IBM-Cloud/power-go-client v1.9.0 // indirect github.com/IBM/cloud-databases-go-sdk v0.7.1 // indirect - github.com/IBM/go-sdk-core/v5 v5.18.3 // indirect - github.com/IBM/platform-services-go-sdk v0.72.0 // indirect + github.com/IBM/go-sdk-core/v5 v5.18.5 // indirect + github.com/IBM/platform-services-go-sdk v0.73.0 // indirect github.com/IBM/project-go-sdk v0.3.6 // indirect github.com/IBM/schematics-go-sdk v0.4.0 // indirect github.com/IBM/vpc-go-sdk v1.0.2 // indirect @@ -68,9 +69,10 @@ require ( github.com/cloudflare/circl v1.3.7 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/cyphar/filepath-securejoin v0.3.6 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 // indirect @@ -81,13 +83,13 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.21.5 // indirect github.com/go-openapi/errors v0.22.0 // indirect - github.com/go-openapi/jsonpointer v0.20.1 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.20.3 // indirect github.com/go-openapi/loads v0.21.3 // indirect github.com/go-openapi/runtime v0.26.0 // indirect github.com/go-openapi/spec v0.20.12 // indirect github.com/go-openapi/strfmt v0.23.0 // indirect - github.com/go-openapi/swag v0.22.5 // indirect + github.com/go-openapi/swag v0.23.0 // indirect github.com/go-openapi/validate v0.22.4 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect @@ -121,7 +123,7 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect - github.com/klauspost/compress v1.16.5 // indirect + github.com/klauspost/compress v1.16.6 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-zglob v0.0.4 // indirect @@ -129,14 +131,15 @@ require ( github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/moby/spdystream v0.2.0 // indirect + github.com/moby/spdystream v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pquerna/otp v1.4.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect @@ -145,33 +148,33 @@ require ( github.com/tmccombs/hcl2json v0.6.4 // indirect github.com/ulikunitz/xz v0.5.11 // indirect github.com/urfave/cli v1.22.16 // indirect + github.com/x448/float16 v0.8.4 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/zclconf/go-cty v1.15.1 // indirect go.mongodb.org/mongo-driver v1.14.0 // indirect go.opentelemetry.io/otel v1.29.0 // indirect go.opentelemetry.io/otel/metric v1.29.0 // indirect go.opentelemetry.io/otel/trace v1.29.0 // indirect - golang.org/x/crypto v0.31.0 // indirect - golang.org/x/mod v0.18.0 // indirect - golang.org/x/net v0.33.0 // indirect + golang.org/x/crypto v0.32.0 // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/net v0.34.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/term v0.27.0 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/term v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.8.0 // indirect - golang.org/x/tools v0.22.0 // indirect + golang.org/x/tools v0.26.0 // indirect google.golang.org/protobuf v1.35.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.28.4 // indirect - k8s.io/client-go v0.28.4 // indirect - k8s.io/klog/v2 v2.100.1 // indirect - k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect - k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect + k8s.io/api v0.29.2 // indirect + k8s.io/client-go v0.29.2 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect + k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect + sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/tests/go.sum b/tests/go.sum index c8940d02..f3722b61 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -11,10 +11,10 @@ github.com/IBM-Cloud/power-go-client v1.9.0/go.mod h1:UDyXeIKEp6r7yWUXYu3r0ZnFSl github.com/IBM/cloud-databases-go-sdk v0.7.1 h1:5kK4/3NUsGxZzmuUe+1ftajpOQbeDVh5VeemrPgROP4= github.com/IBM/cloud-databases-go-sdk v0.7.1/go.mod h1:JYucI1PdwqbAd8XGdDAchxzxRP7bxOh1zUnseovHKsc= github.com/IBM/go-sdk-core/v5 v5.9.2/go.mod h1:YlOwV9LeuclmT/qi/LAK2AsobbAP42veV0j68/rlZsE= -github.com/IBM/go-sdk-core/v5 v5.18.3 h1:q6IDU3N2bHGwijK9pMnzKC5gqdaRII56NzB4ZNdSFvY= -github.com/IBM/go-sdk-core/v5 v5.18.3/go.mod h1:5kILxqEWOrwMhoD2b7J6Xv9Z2M6YIdT/6Oy+XRSsCGQ= -github.com/IBM/platform-services-go-sdk v0.72.0 h1:AfJe6bgqmTQU4ff/2URu3wkRLZD0XIzojn7SLf2yIns= -github.com/IBM/platform-services-go-sdk v0.72.0/go.mod h1:ApFkvqw7NaluWJ5Uq+afdM/2jQqo5ILc0SzKSVobYNw= +github.com/IBM/go-sdk-core/v5 v5.18.5 h1:g0JRl3sYXJczB/yuDlrN6x22LJ6jIxhp0Sa4ARNW60c= +github.com/IBM/go-sdk-core/v5 v5.18.5/go.mod h1:KonTFRR+8ZSgw5cxBSYo6E4WZoY1+7n1kfHM82VcjFU= +github.com/IBM/platform-services-go-sdk v0.73.0 h1:CKs6qCM2U549gMn4ULfJB76DaDQpit/+0VmbKDqSpFU= +github.com/IBM/platform-services-go-sdk v0.73.0/go.mod h1:LSaXGGJUGGPMCCtG1/24r9LJEbF0hmpXtQOhABRk0PY= github.com/IBM/project-go-sdk v0.3.6 h1:DRiANKnAePevFsIKSvR89SUaMa2xsd7YKK71Ka1eqKI= github.com/IBM/project-go-sdk v0.3.6/go.mod h1:FOJM9ihQV3EEAY6YigcWiTNfVCThtdY8bLC/nhQHFvo= github.com/IBM/schematics-go-sdk v0.4.0 h1:x01f/tPquYJYLQzJLGuxWfCbV/EdSMXRikOceNy/JLM= @@ -128,12 +128,13 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM= github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/elazarl/goproxy v1.2.3 h1:xwIyKHbaP5yfT6O9KIeYJR5549MXRQkoQMRXGztz8YQ= github.com/elazarl/goproxy v1.2.3/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64= -github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= -github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= @@ -143,6 +144,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= @@ -160,7 +163,6 @@ github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMj github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= github.com/go-git/go-git/v5 v5.13.1 h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q+M= github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -175,8 +177,8 @@ github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpX github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE= -github.com/go-openapi/jsonpointer v0.20.1 h1:MkK4VEIEZMj4wT9PmjaUmGflVBr9nvud4Q4UVFbDoBE= -github.com/go-openapi/jsonpointer v0.20.1/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.20.3 h1:EjGcjTW8pD1mRis6+w/gmoBdqv5+RbE9B85D1NgDOVQ= github.com/go-openapi/jsonreference v0.20.3/go.mod h1:FviDZ46i9ivh810gqzFLl5NttD5q3tSlMLqLr6okedM= github.com/go-openapi/loads v0.21.3 h1:8sSH2FIm/SnbDUGv572md4YqVMFne/a9Eubvcd3anew= @@ -189,8 +191,8 @@ github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrC github.com/go-openapi/strfmt v0.21.7/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew= github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c= github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= -github.com/go-openapi/swag v0.22.5 h1:fVS63IE3M0lsuWRzuom3RLwUMVI2peDH01s6M70ugys= -github.com/go-openapi/swag v0.22.5/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-openapi/validate v0.22.4 h1:5v3jmMyIPKTR8Lv9syBAIRxG6lY0RqeBPB1LKEijzk8= github.com/go-openapi/validate v0.22.4/go.mod h1:qm6O8ZIcPVdSY5219468Jv7kBdGvkiZLPOmqnqTUZ2A= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= @@ -209,6 +211,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M= github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -243,13 +247,12 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gruntwork-io/go-commons v0.8.0 h1:k/yypwrPqSeYHevLlEDmvmgQzcyTwrlZGRaxEM6G0ro= github.com/gruntwork-io/go-commons v0.8.0/go.mod h1:gtp0yTtIBExIZp7vyIV9I0XQkVwiQZze678hvDXof78= github.com/gruntwork-io/terratest v0.48.1 h1:pnydDjkWbZCUYXvQkr24y21fBo8PfJC5hRGdwbl1eXM= @@ -307,8 +310,8 @@ github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= -github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk= +github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -341,8 +344,8 @@ github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTS github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= +github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -351,6 +354,8 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= @@ -378,8 +383,9 @@ github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3Ro github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= -github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= +github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= +github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= @@ -408,8 +414,9 @@ github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= @@ -445,8 +452,8 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper v1.42.8 h1:x0QXUGf7KLz7b8ZlhZ/sz5pb9zBzr09DEaHILMubJNY= -github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper v1.42.8/go.mod h1:5shqAmx3+jszLYJ88v0wB6JXY62fnTCdPT9BGihnAlg= +github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper v1.42.10 h1:nyPAuFwSJhp157NBJNZfdpVycOjJa/xGz6qX1V0532c= +github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper v1.42.10/go.mod h1:RpHvmlmqbmry1YvwWsx90rlirNe4KZ8o8GmntjKViJA= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmccombs/hcl2json v0.6.4 h1:/FWnzS9JCuyZ4MNwrG4vMrFrzRgsWEOVi+1AyYUVLGw= github.com/tmccombs/hcl2json v0.6.4/go.mod h1:+ppKlIW3H5nsAsZddXPy2iMyvld3SHxyjswOZhavRDk= @@ -455,6 +462,8 @@ github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0o github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ= github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= @@ -495,8 +504,8 @@ golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98y golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= @@ -508,8 +517,8 @@ golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= -golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -538,8 +547,8 @@ golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -592,8 +601,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -608,8 +617,8 @@ golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= +golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -647,8 +656,8 @@ golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= -golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= -golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= +golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= +golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -689,21 +698,21 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY= -k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0= -k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8= -k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg= -k8s.io/client-go v0.28.4 h1:Np5ocjlZcTrkyRJ3+T3PkXDpe4UpatQxj85+xjaD2wY= -k8s.io/client-go v0.28.4/go.mod h1:0VDZFpgoZfelyP5Wqu0/r/TRYcLYuJ2U1KEeoaPa1N4= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +k8s.io/api v0.29.2 h1:hBC7B9+MU+ptchxEqTNW2DkUosJpp1P+Wn6YncZ474A= +k8s.io/api v0.29.2/go.mod h1:sdIaaKuU7P44aoyyLlikSLayT6Vb7bvJNCX105xZXY0= +k8s.io/apimachinery v0.32.0 h1:cFSE7N3rmEEtv4ei5X6DaJPHHX0C+upp+v5lVPiEwpg= +k8s.io/apimachinery v0.32.0/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= +k8s.io/client-go v0.29.2 h1:FEg85el1TeZp+/vYJM7hkDlSTFZ+c5nnK44DJ4FyoRg= +k8s.io/client-go v0.29.2/go.mod h1:knlvFZE58VpqbQpJNbCbctTVXcd35mMyAAwBdpt4jrA= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= +k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= +sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= +sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/tests/pr_test.go b/tests/pr_test.go index 6e4ee3d9..e359c9a1 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -16,12 +16,11 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// Resource groups are maintained https://github.ibm.com/GoldenEye/ge-dev-account-management const resourceGroup = "geretain-test-ext-secrets-sync" const defaultExampleTerraformDir = "examples/all-combined" const basicExampleTerraformDir = "examples/basic" -// deploying eso on default node to have it able to connect to SM and IAM on public network +// deploying eso on edge node to have it able to connect to SM and IAM on public network const esoWorkersSelector = "default" // Define a struct with fields that match the structure of the YAML data @@ -45,9 +44,6 @@ type Config struct { AcmeLEPrivateKeySmGuid string `yaml:"acme_letsencrypt_private_key_sm_id"` AcmeLEPrivateKeySmRegion string `yaml:"acme_letsencrypt_private_key_sm_region"` AcmeLEPrivateKeySecretId string `yaml:"acme_letsencrypt_private_key_secret_id"` - - // sDNLB serviceID - SdnlbServiceidName string `yaml:"sdnlbServiceIdName"` } var smGuid string @@ -63,7 +59,6 @@ var impCertPrivateSecretID string var acmeLEPrivateKeySmGuid string var acmeLEPrivateKeySmRegion string var acmeLEPrivateKeySecretId string -var sdnlbServiceIdName string // terraform vars for all-combined test (including Upgrade one) var allCombinedTerraformVars map[string]interface{} @@ -98,12 +93,6 @@ func TestMain(m *testing.M) { impCertificateSmGuid = config.ImpCertificateSmGuid impCertificateSmRegion = config.ImpCertificateSmRegion - sdnlbServiceIdName = config.SdnlbServiceidName - err = log.Output(1, "TestMain using sdnlbServiceIdName "+sdnlbServiceIdName) - if err != nil { - log.Fatal(err) - } - allCombinedTerraformVars = map[string]interface{}{ "existing_cis_instance_name": cisName, "existing_cis_instance_resource_group_id": rgId, @@ -122,7 +111,6 @@ func TestMain(m *testing.M) { "eso_deployment_nodes_configuration": esoWorkersSelector, // setting skip_iam_authorization_policy to true because using the existing secrets manager instance and the policy already exists "skip_iam_authorization_policy": true, - "existing_sdnlb_serviceid_name": sdnlbServiceIdName, "service_endpoints": "public", } @@ -164,12 +152,6 @@ func setupOptions(t *testing.T, prefix string, terraformDir string, terraformVar IgnoreUpdates: testhelper.Exemptions{ List: ignoreUpdates, }, - ImplicitDestroy: []string{ - // workaround for the issue https://github.ibm.com/GoldenEye/issues/issues/10743 - // when the issue is fixed on IKS, so the destruction of default workers pool is correctly managed on provider/clusters service the next two entries should be removed - "'module.ocp_base.ibm_container_vpc_worker_pool.autoscaling_pool[\"default\"]'", - "'module.ocp_base.ibm_container_vpc_worker_pool.pool[\"default\"]'", - }, IgnoreDestroys: testhelper.Exemptions{ // Ignore for consistency check List: []string{ @@ -210,22 +192,16 @@ func TestRunDefaultExample(t *testing.T) { secretsMap := map[string]string{ "dockerconfigjson-uc": namespaces_for_apikey_login[0], // temporary disabled cloudant resource key secret test - // https://github.ibm.com/GoldenEye/issues/issues/7726 - // "cloudant-opaque-arb": namespaces_for_apikey_login[1], "dockerconfigjson-arb": namespaces_for_apikey_login[2], "pvtcertificate-tls": namespaces_for_apikey_login[2], "kv-single-key": namespaces_for_apikey_login[3], "kv-multiple-keys": namespaces_for_apikey_login[3], - "dockerconfigjson-iam": namespaces_for_apikey_login[3], - "dockerconfigjson-chain": namespaces_for_apikey_login[3], options.Prefix + "-arbitrary-arb-tp-0": namespaces_for_tp_login[0], options.Prefix + "-arbitrary-arb-tp-1": namespaces_for_tp_login[1], options.Prefix + "-arbitrary-arb-tp-multisg-1": "tpns-multisg", options.Prefix + "-arbitrary-arb-tp-multisg-2": "tpns-multisg", options.Prefix + "-arbitrary-arb-tp-nosg": "tpns-nosg", options.Prefix + "-arbitrary-arb-cstore-tp": "eso-cstore-tp-namespace", - // sdnlb secret - "sdnlb-config": "kube-system", } log.Printf("secretsMap %s", secretsMap) diff --git a/tests/samples/sample.yaml b/tests/samples/sample.yaml index dfcf1a92..50e1fd93 100644 --- a/tests/samples/sample.yaml +++ b/tests/samples/sample.yaml @@ -32,7 +32,7 @@ spec: app: example-busybox spec: nodeSelector: - dedicated: default + dedicated: edge containers: - name: busybox-container image: busybox From 6b338b8540457dd3279d283c0b9c70ba530574d1 Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Wed, 15 Jan 2025 13:40:31 +0530 Subject: [PATCH 11/40] updated the PR test --- .github/workflows/ci.yml | 14 ++++++++++++++ .github/workflows/release.yml | 12 ++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..14502e48 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,14 @@ +name: CI-Pipeline + +# Controls when the workflow will run, when comment is created +on: + issue_comment: + types: + - created +jobs: + call-terraform-ci-pipeline: + uses: terraform-ibm-modules/common-pipeline-assets/.github/workflows/common-terraform-module-ci-v2.yml@v1.22.5 + secrets: inherit + with: + craSCCv2: true + craConfigYamlFile: "cra-config.yaml" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..13edc440 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,12 @@ +name: Release-Pipeline + +# Trigger on push(merge) to main branch +on: + push: + branches: + - main + +jobs: + call-terraform-release-pipeline: + uses: terraform-ibm-modules/common-pipeline-assets/.github/workflows/common-release.yml@v1.22.5 + secrets: inherit From 0d8600c0828174d01a2b0dfd893bf31aa27b0591 Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Wed, 15 Jan 2025 14:54:45 +0530 Subject: [PATCH 12/40] resolve failure --- cra-config.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cra-config.yaml b/cra-config.yaml index bd320bfc..2af41e5d 100644 --- a/cra-config.yaml +++ b/cra-config.yaml @@ -4,8 +4,7 @@ CRA_TARGETS: CRA_IGNORE_RULES_FILE: "cra-tf-validate-ignore-rules.json" CRA_ENVIRONMENT_VARIABLES: # An optional map of environment variables for CRA, where the key is the variable name and value is the value. Useful for providing TF_VARs. TF_VAR_existing_cis_instance_name: "test_value_for_cis_instance_name" - TF_VAR_existing_cis_instance_resource_group_id: "test_value_for_cis_instance_rg_id" - TF_VAR_existing_sdnlb_serviceid_name: "test_value_for_existing_sdnlb_serviceid_name" + TF_VAR_existing_cis_instance_resource_group_id: "6deff3aad31a48b696cb1b173e54c41d" # pragma: allowlist secret # SCC_INSTANCE_ID: "" # The SCC instance ID to use to download profile for CRA scan. If not provided, a default global value will be used. # SCC_REGION: "" # The IBM Cloud region that the SCC instance is in. If not provided, a default global value will be used. # PROFILE_ID: "" # The Profile ID input for CRA SCC scan. Ensure to use a US-specific ID. If not provided, a default global value will be used. From 58f88865ff78ceb9871e55763ba16d2092180974 Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Wed, 15 Jan 2025 15:15:14 +0530 Subject: [PATCH 13/40] resolve failure --- cra-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cra-config.yaml b/cra-config.yaml index 2af41e5d..27499937 100644 --- a/cra-config.yaml +++ b/cra-config.yaml @@ -3,7 +3,7 @@ CRA_TARGETS: - CRA_TARGET: "examples/all-combined" CRA_IGNORE_RULES_FILE: "cra-tf-validate-ignore-rules.json" CRA_ENVIRONMENT_VARIABLES: # An optional map of environment variables for CRA, where the key is the variable name and value is the value. Useful for providing TF_VARs. - TF_VAR_existing_cis_instance_name: "test_value_for_cis_instance_name" + TF_VAR_existing_cis_instance_name: "geretain-permanent-cis" TF_VAR_existing_cis_instance_resource_group_id: "6deff3aad31a48b696cb1b173e54c41d" # pragma: allowlist secret # SCC_INSTANCE_ID: "" # The SCC instance ID to use to download profile for CRA scan. If not provided, a default global value will be used. # SCC_REGION: "" # The IBM Cloud region that the SCC instance is in. If not provided, a default global value will be used. From d8bfa479735fde59d961addce124b94d06f8ecfe Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Wed, 15 Jan 2025 23:09:30 +0530 Subject: [PATCH 14/40] resolve failure --- .github/CODEOWNERS | 2 +- README.md | 18 +++++++++--------- examples/all-combined/README.md | 7 +------ examples/basic/main.tf | 6 +++--- examples/basic/variables.tf | 6 ------ main.tf | 5 ++--- tests/samples/sample.yaml | 2 +- 7 files changed, 17 insertions(+), 29 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 9ca7a60c..5969395a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,2 @@ # Primary owner should be listed first in list of global owners, follwed by any secondary owners -* @valerio-bontempi @DANIELBU +* @valerio-bontempi @daniel-butler-irl diff --git a/README.md b/README.md index 5aa3ead9..eb8849d1 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -## External Secrets Operator module +## Terraform IBM External Secrets Operator module -[![Certified]()](https://github.ibm.com/GoldenEye/documentation/blob/master/status.md) -[![CI](https://img.shields.io/badge/CI-Toolchain%20Tekton%20Pipeline-3662FF?logo=ibm)](https://cloud.ibm.com/devops/toolchains/c3916535-165a-4275-9b1f-c58575839951?env_id=ibm:yp:us-south) -[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) +[![Graduated (Supported)](https://img.shields.io/badge/Status-Graduated%20(Supported)-brightgreen)](https://terraform-ibm-modules.github.io/documentation/#/badge-status) +[![latest release](https://img.shields.io/github/v/release/terraform-ibm-modules/terraform-ibm-external-secrets-operator?logo=GitHub&sort=semver)](https://github.com/terraform-ibm-modules/terraform-ibm-external-secrets-operator/releases/latest) [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) -[![latest release](https://shields-server.m03l6u0cqkx.eu-de.codeengine.appdomain.cloud/github/v/release/GoldenEye/external-secrets-operator-module?logo=GitHub)](https://github.ibm.com/GoldenEye/external-secrets-operator-module/releases/latest) +[![Renovate enabled](https://img.shields.io/badge/renovate-enabled-brightgreen.svg)](https://renovatebot.com/) +[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) This module automates the installation and configuration of the [External Secrets Operator](https://external-secrets.io/) in a cluster. @@ -227,7 +227,7 @@ To configure a set of tenants to be configured in their proper namespace (to ach ```hcl module "external_secrets_operator" { - source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git?ref=" + source = "https://github.com/terraform-ibm-modules/terraform-ibm-external-secrets-operator.git?ref=" eso_namespace = var.eso_namespace # namespace to deploy ESO service_endpoints = var.service_endpoints # use public or private endpoints for IAM and Secrets Manager eso_cluster_nodes_configuration = <> @@ -244,7 +244,7 @@ module "eso_namespace_secretstore_1" { depends_on = [ module.external_secrets_operator ] - source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git//modules/eso-secretstore?ref=master" + source = "https://github.com/terraform-ibm-modules/terraform-ibm-external-secrets-operator.git//modules/eso-secretstore?ref=master" eso_authentication = "api_key" region = local.sm_region # SM region sstore_namespace = var.es_kubernetes_namespaces[2] # namespace to create the secret store @@ -266,7 +266,7 @@ module "eso_namespace_secretstores" { depends_on = [ module.external_secrets_operator ] - source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git//modules/eso-secretstore?ref=master" + source = "https://github.com/terraform-ibm-modules/terraform-ibm-external-secrets-operator.git//modules/eso-secretstore?ref=master" eso_authentication = "trusted_profile" region = local.sm_region # SM region sstore_namespace = kubernetes_namespace.examples[count.index].metadata[0].name # namespace to create the secret store @@ -475,7 +475,7 @@ NIST controls do not apply to this module. ```hcl # Replace "master" with a GIT release version to lock into a specific release module "es_kubernetes_secret" { - source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git//modules/eso-external-secret?ref=master" + source = "https://github.com/terraform-ibm-modules/terraform-ibm-external-secrets-operator.git//modules/eso-external-secret?ref=master" es_kubernetes_secret_type = "dockerconfigjson" sm_secret_type = "iam_credentials" sm_secret_id = module.docker_config.serviceid_apikey_secret_id diff --git a/examples/all-combined/README.md b/examples/all-combined/README.md index d540f909..ff8821ff 100644 --- a/examples/all-combined/README.md +++ b/examples/all-combined/README.md @@ -32,13 +32,9 @@ This end-to-end example performs the following actions - Deploys external secrets in designated namespaces - Creates a SecretStore (using API key authentication) to access secrets from designated namespace - Deploys a dockerconfigjson secret from a dynamic IAM secret to authenticate in container registry - - Creates ServiceID (imagePull) with IAM policies to read from container registry namespace - - Creates IAM Secrets Manager secret and dynamic API key that is associated with a imagePull Service ID - Deploys external secrets in designated namespaces - Creates a SecretStore(using API key authentication) to access secrets from designated namespace - Deploys a dockerconfigjson secret from a set of dynamic IAM secrets to authenticate in a set of container registries - - Creates a set of ServiceIDs (imagePull) with IAM policies to read from container registry namespace for each secret to create (`${var.prefix}-image-pull-service-id-chain-sec-1/2/3`) - - Creates a set of IAM Secrets Manager secrets and dynamic API key that are associated with the imagePull ServiceIDs created at the step above - Deploys external secrets resource in designated namespaces for the dockerjsonconfig secret building the secrets chain and using an existing secrets store - Creates and deploys a set of arbitrary secrets to cover the different use-cases for namespaced SecretStores - Creates and deploys a public certificate through CIS integration and public certificate engine module @@ -46,7 +42,6 @@ This end-to-end example performs the following actions - Loads certificate components stored on Secrets Manager as arbitrary secrets and then use these to create and deploy an imported certificate with public and intermediate certificates and public certificate private key - Creates and deploys a key-value secret with single key-value couple - Creates and deploys a key-value secret with multiple key-value couples - - Creates a dynamic secret on Secrets Manager from the sDNLB entitled service ID and configures an ExternalSecret CRD on the cluster to create and synch the sDNLB secret with the expected format In order to create the intermediate certificate the following parameters are needed: @@ -70,7 +65,7 @@ In the case all the mentioned parameters are left with their default **null** va The example is split into separated templates related with their specific scope: - main.tf for the VPC, cluster, VPE, ESO operator deployment and namespaces preliminary creation - clusterstore.tf for ESO ClusterSecretsStore configuration with API key authentication, including two different externalsecrets and secret types configuration (username/password and arbitrary) -- secretstore.tf for ESO secretstore configuration with API key authentication and namespace isolation, including two different externalsecrets and secrets configuration (arbitrary and image pull API key secret using imagepull-apikey-secrets-manager-module) +- secretstore.tf for ESO secretstore configuration with API key authentication and namespace isolation. - secretsmanager.tf for Secrets Manager instance configuration, along with IAM serviceID and API keys and secrets groups - kv.tf for key-value (single and multiple keys) secrets - publiccertificate.tf for public certificate management diff --git a/examples/basic/main.tf b/examples/basic/main.tf index 1cb5ca1c..af8a683d 100644 --- a/examples/basic/main.tf +++ b/examples/basic/main.tf @@ -334,15 +334,15 @@ module "external_secrets_operator" { source = "../../" eso_namespace = local.eso_namespace - eso_cluster_nodes_configuration = var.eso_deployment_nodes_configuration == null ? null : { + eso_cluster_nodes_configuration = { nodeSelector = { label = "dedicated" - value = var.eso_deployment_nodes_configuration + value = "default" } tolerations = { key = "dedicated" operator = "Equal" - value = var.eso_deployment_nodes_configuration + value = "default" effect = "NoExecute" } } diff --git a/examples/basic/variables.tf b/examples/basic/variables.tf index 79c0bc69..e2c036cd 100644 --- a/examples/basic/variables.tf +++ b/examples/basic/variables.tf @@ -59,12 +59,6 @@ variable "existing_sm_instance_region" { default = null } -variable "eso_deployment_nodes_configuration" { - type = string - description = "Configuration to deploy ESO on specific cluster nodes. The value of this variable will be used for NodeSelector label value and tolerations configuration. If null standard ESO deployment is done on default workers pool." - default = null -} - variable "zones" { description = "List of zones" type = list(string) diff --git a/main.tf b/main.tf index 6a7f601b..fe806ad9 100644 --- a/main.tf +++ b/main.tf @@ -180,9 +180,8 @@ EOF resource "helm_release" "external_secrets_operator" { depends_on = [module.eso_namespace, data.kubernetes_namespace.existing_eso_namespace] - name = "external-secrets" - namespace = local.eso_namespace - # chart = "oci://icr.io/ibm-iac-charts/external-secrets" + name = "external-secrets" + namespace = local.eso_namespace chart = "external-secrets" version = "0.12.1" wait = true diff --git a/tests/samples/sample.yaml b/tests/samples/sample.yaml index 50e1fd93..dfcf1a92 100644 --- a/tests/samples/sample.yaml +++ b/tests/samples/sample.yaml @@ -32,7 +32,7 @@ spec: app: example-busybox spec: nodeSelector: - dedicated: edge + dedicated: default containers: - name: busybox-container image: busybox From 324d750045a0302bfd43fcad06a1a41e6c039a7b Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Wed, 15 Jan 2025 23:12:00 +0530 Subject: [PATCH 15/40] SKIP UPGRADE TEST --- .github/settings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/settings.yml b/.github/settings.yml index f1a90940..19dfb323 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -25,4 +25,4 @@ repository: description: "Synchronizes secrets between Secrets Manager and an IBM Cloud OpenShift cluster" # Use a comma-separated list of topics to set on the repo (ensure not to use any caps in the topic string). - topics: terraform, ibm-cloud, terraform-module, core-team + topics: terraform, ibm-cloud, terraform-module, core-team, external-secret, From 22a5e38f8e099406f33ff9e7b9687bb6f78d085d Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Wed, 22 Jan 2025 13:49:14 +0530 Subject: [PATCH 16/40] resolve review comments --- README.md | 5 + examples/all-combined/README.md | 7 +- examples/all-combined/main.tf | 17 +- examples/all-combined/provider.tf | 6 +- examples/all-combined/secretstore.tf | 116 ++++++++ examples/all-combined/variables.tf | 247 +++++++++--------- examples/basic/main.tf | 15 -- main.tf | 34 ++- .../README.md | 135 ++++++++++ .../main.tf | 57 ++++ .../outputs.tf | 18 ++ .../variables.tf | 62 +++++ .../version.tf | 14 + renovate.json | 8 + tests/pr_test.go | 2 + variables.tf | 24 ++ 16 files changed, 594 insertions(+), 173 deletions(-) create mode 100644 modules/imagepull-apikey-secrets-manager-module/README.md create mode 100644 modules/imagepull-apikey-secrets-manager-module/main.tf create mode 100644 modules/imagepull-apikey-secrets-manager-module/outputs.tf create mode 100644 modules/imagepull-apikey-secrets-manager-module/variables.tf create mode 100644 modules/imagepull-apikey-secrets-manager-module/version.tf diff --git a/README.md b/README.md index eb8849d1..d0627acb 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ This module automates the installation and configuration of the [External Secret * [eso-external-secret](./modules/eso-external-secret) * [eso-secretstore](./modules/eso-secretstore) * [eso-trusted-profile](./modules/eso-trusted-profile) + * [imagepull-apikey-secrets-manager-module](./modules/imagepull-apikey-secrets-manager-module) * [Examples](./examples) * [Basic Example](./examples/basic) * [Example that uses trusted profiles (container authentication)](./examples/trusted-profiles-authentication) @@ -531,6 +532,8 @@ module "es_kubernetes_secret" { |------|-------------|------|---------|:--------:| | [eso\_cluster\_nodes\_configuration](#input\_eso\_cluster\_nodes\_configuration) | Configuration to use to customise ESO deployment on specific cluster nodes. Setting appropriate values will result in customising ESO helm release. Default value is null to keep ESO standard deployment. |
object({
nodeSelector = object({
label = string
value = string
})
tolerations = object({
key = string
operator = string
value = string
effect = string
})
})
| `null` | no | | [eso\_enroll\_in\_servicemesh](#input\_eso\_enroll\_in\_servicemesh) | Flag to enroll ESO into istio servicemesh | `bool` | `false` | no | +| [eso\_image\_repo](#input\_eso\_image\_repo) | The container image repository for External Secrets Operator (ESO). By default, the image is pulled from `ghcr.io/external-secrets/external-secrets`. | `string` | `"ghcr.io/external-secrets/external-secrets"` | no | +| [eso\_image\_tag\_digest](#input\_eso\_image\_tag\_digest) | The tag digest of the ESO image to deploy. If not provided, a default value will be used. | `string` | `null` | no | | [eso\_namespace](#input\_eso\_namespace) | Namespace to create and be used to install ESO components including helm releases. If eso\_store\_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster\_store in it | `string` | `null` | no | | [eso\_pod\_configuration](#input\_eso\_pod\_configuration) | Configuration to use to customise ESO deployment on specific pods. Setting appropriate values will result in customising ESO helm release. Default value is {} to keep ESO standard deployment. Ignore the key if not required. |
object({
annotations = optional(object({
# The annotations for external secret controller pods.
external_secrets = optional(map(string), {})
# The annotations for external secret cert controller pods.
external_secrets_cert_controller = optional(map(string), {})
# The annotations for external secret controller pods.
external_secrets_webhook = optional(map(string), {})
}), {})

labels = optional(object({
# The labels for external secret controller pods.
external_secrets = optional(map(string), {})
# The labels for external secret cert controller pods.
external_secrets_cert_controller = optional(map(string), {})
# The labels for external secret controller pods.
external_secrets_webhook = optional(map(string), {})
}), {})
})
| `{}` | no | | [existing\_eso\_namespace](#input\_existing\_eso\_namespace) | Existing Namespace to be used to install ESO components including helm releases. If eso\_store\_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster\_store in it | `string` | `null` | no | @@ -538,6 +541,8 @@ module "es_kubernetes_secret" { | [reloader\_deployed](#input\_reloader\_deployed) | Whether to deploy reloader or not https://github.com/stakater/Reloader | `bool` | `true` | no | | [reloader\_ignore\_configmaps](#input\_reloader\_ignore\_configmaps) | Whether to ignore configmap changes or not | `bool` | `false` | no | | [reloader\_ignore\_secrets](#input\_reloader\_ignore\_secrets) | Whether to ignore secret changes or not | `bool` | `false` | no | +| [reloader\_image\_repo](#input\_reloader\_image\_repo) | The container image repository for Reloader. By default, the image is pulled from `ghcr.io/stakater/reloader`. | `string` | `"ghcr.io/stakater/reloader"` | no | +| [reloader\_image\_tag\_digest](#input\_reloader\_image\_tag\_digest) | The tag digest of the Reloader image to deploy. If not provided, a default value will be used. | `string` | `null` | no | | [reloader\_is\_argo\_rollouts](#input\_reloader\_is\_argo\_rollouts) | Enable Argo Rollouts | `bool` | `false` | no | | [reloader\_is\_openshift](#input\_reloader\_is\_openshift) | Enable OpenShift DeploymentConfigs | `bool` | `true` | no | | [reloader\_log\_format](#input\_reloader\_log\_format) | The log format to use for reloader. Possible values are `json` or `text`. Default value is `json` | `string` | `"text"` | no | diff --git a/examples/all-combined/README.md b/examples/all-combined/README.md index ff8821ff..d16cd119 100644 --- a/examples/all-combined/README.md +++ b/examples/all-combined/README.md @@ -32,9 +32,13 @@ This end-to-end example performs the following actions - Deploys external secrets in designated namespaces - Creates a SecretStore (using API key authentication) to access secrets from designated namespace - Deploys a dockerconfigjson secret from a dynamic IAM secret to authenticate in container registry + - Creates ServiceID (imagePull) with IAM policies to read from container registry namespace + - Creates IAM Secrets Manager secret and dynamic API key that is associated with a imagePull Service ID - Deploys external secrets in designated namespaces - Creates a SecretStore(using API key authentication) to access secrets from designated namespace - Deploys a dockerconfigjson secret from a set of dynamic IAM secrets to authenticate in a set of container registries + - Creates a set of ServiceIDs (imagePull) with IAM policies to read from container registry namespace for each secret to create (`${var.prefix}-image-pull-service-id-chain-sec-1/2/3`) + - Creates a set of IAM Secrets Manager secrets and dynamic API key that are associated with the imagePull ServiceIDs created at the step above - Deploys external secrets resource in designated namespaces for the dockerjsonconfig secret building the secrets chain and using an existing secrets store - Creates and deploys a set of arbitrary secrets to cover the different use-cases for namespaced SecretStores - Creates and deploys a public certificate through CIS integration and public certificate engine module @@ -44,6 +48,7 @@ This end-to-end example performs the following actions - Creates and deploys a key-value secret with multiple key-value couples + In order to create the intermediate certificate the following parameters are needed: - imported_certificate_sm_id: Secrets Manager ID where the componenents for the imported certificate are stored - imported_certificate_sm_region: region of the Secrets Manager instance where the componenents for the imported certificate are stored @@ -65,7 +70,7 @@ In the case all the mentioned parameters are left with their default **null** va The example is split into separated templates related with their specific scope: - main.tf for the VPC, cluster, VPE, ESO operator deployment and namespaces preliminary creation - clusterstore.tf for ESO ClusterSecretsStore configuration with API key authentication, including two different externalsecrets and secret types configuration (username/password and arbitrary) -- secretstore.tf for ESO secretstore configuration with API key authentication and namespace isolation. +- secretstore.tf for ESO secretstore configuration with API key authentication and namespace isolation, including two different externalsecrets and secrets configuration (arbitrary and image pull API key secret using imagepull-apikey-secrets-manager-module) - secretsmanager.tf for Secrets Manager instance configuration, along with IAM serviceID and API keys and secrets groups - kv.tf for key-value (single and multiple keys) secrets - publiccertificate.tf for public certificate management diff --git a/examples/all-combined/main.tf b/examples/all-combined/main.tf index 60b51872..d0ad4b34 100644 --- a/examples/all-combined/main.tf +++ b/examples/all-combined/main.tf @@ -16,8 +16,7 @@ module "resource_group" { locals { - # sDNLB entitled account API key - if null the ibmcloud_api_key will be used - sdnlb_ibmcloud_api_key = var.sdnlb_ibmcloud_api_key == null ? var.ibmcloud_api_key : var.sdnlb_ibmcloud_api_key + subnet_prefix = flatten([ for k, v in module.zone_subnet_addrs : [ @@ -265,20 +264,6 @@ module "vpes" { module "external_secrets_operator" { source = "../../" eso_namespace = var.eso_namespace - - eso_cluster_nodes_configuration = var.eso_deployment_nodes_configuration == null ? null : { - nodeSelector = { - label = "dedicated" - value = var.eso_deployment_nodes_configuration - } - tolerations = { - key = "dedicated" - operator = "Equal" - value = var.eso_deployment_nodes_configuration - effect = "NoExecute" - } - } - depends_on = [ kubernetes_namespace.apikey_namespaces, kubernetes_namespace.tp_namespaces ] diff --git a/examples/all-combined/provider.tf b/examples/all-combined/provider.tf index 1bee7827..6ffbf1e7 100644 --- a/examples/all-combined/provider.tf +++ b/examples/all-combined/provider.tf @@ -9,11 +9,7 @@ provider "ibm" { alias = "ibm-sm" } -provider "ibm" { - ibmcloud_api_key = local.sdnlb_ibmcloud_api_key - region = var.region - alias = "ibm-sdnlb" -} + provider "kubernetes" { host = data.ibm_container_cluster_config.cluster_config.host diff --git a/examples/all-combined/secretstore.tf b/examples/all-combined/secretstore.tf index 4d9e4716..dd6c0f2f 100644 --- a/examples/all-combined/secretstore.tf +++ b/examples/all-combined/secretstore.tf @@ -83,3 +83,119 @@ module "external_secret_arbitrary_cr_registry" { es_kubernetes_secret_name = "dockerconfigjson-arb" #checkov:skip=CKV_SECRET_6 es_helm_rls_name = "es-docker-arb" } + +################################################################## +# Image pull API key secret using imagepull-apikey-secrets-manager-module +################################################################## + +# create image pull serviceID and secret and store in secrets manager +module "image_pull" { + source = "git::https://github.ibm.com/GoldenEye/imagepull-apikey-secrets-manager-module.git?ref=1.1.7" + resource_group_id = module.resource_group.resource_group_id + secrets_manager_guid = local.sm_guid + cr_namespace_name = var.cr_namespace_name + region = local.sm_region + #tfsec:ignore:general-secrets-no-plaintext-exposure + service_id_secret_name = "${var.prefix}-image-pull-service-id" + service_id_secret_group_id = module.secrets_manager_group.secret_group_id + depends_on = [module.iam_secrets_engine, module.secrets_manager_group] + providers = { + ibm = ibm.ibm-sm + } +} + +# ESO external secret storing the secret in the cluster as dockerconfigson type (from image pull IAM dynamic credential/secret) using namespaced secretstore +module "external_secret_secret_image_pull" { + source = "../../modules/eso-external-secret" + depends_on = [ + module.eso_apikey_namespace_secretstore_2, + ] + eso_store_scope = "namespace" + es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 + sm_secret_type = "iam_credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure + sm_secret_id = module.image_pull.serviceid_apikey_secret_id + es_kubernetes_namespace = kubernetes_namespace.apikey_namespaces[3].metadata[0].name + es_container_registry = "test.icr.com" + es_container_registry_email = "terraform@ibm.com" + es_refresh_interval = var.es_refresh_interval + eso_store_name = "${var.es_namespaces_apikey[3]}-store" + es_kubernetes_secret_name = "dockerconfigjson-iam" #tfsec:ignore:general-secrets-no-plaintext-exposure #checkov:skip=CKV_SECRET_6 + es_helm_rls_name = "es-docker-iam" +} + +################################################################## +# Image pull API key secrets using imagepull-apikey-secrets-manager-module +# to be configured in a single chain of secrets +################################################################## + +# create image pull serviceID and secret and store in secrets manager +module "image_pull_chain_secret_1" { + source = "../../modules/imagepull-apikey-secrets-manager-module" + resource_group_id = module.resource_group.resource_group_id + secrets_manager_guid = local.sm_guid + cr_namespace_name = var.cr_namespace_name + region = local.sm_region + #tfsec:ignore:general-secrets-no-plaintext-exposure + service_id_secret_name = "${var.prefix}-image-pull-service-id-chain-sec-1" + service_id_secret_group_id = module.secrets_manager_group.secret_group_id + depends_on = [module.iam_secrets_engine, module.secrets_manager_group] + providers = { + ibm = ibm.ibm-sm + } +} + +# create image pull serviceID and secret and store in secrets manager +module "image_pull_chain_secret_2" { + source = "../../modules/imagepull-apikey-secrets-manager-module" + resource_group_id = module.resource_group.resource_group_id + secrets_manager_guid = local.sm_guid + cr_namespace_name = var.cr_namespace_name + region = local.sm_region + #tfsec:ignore:general-secrets-no-plaintext-exposure + service_id_secret_name = "${var.prefix}-image-pull-service-id-chain-sec-2" + service_id_secret_group_id = module.secrets_manager_group.secret_group_id + depends_on = [module.iam_secrets_engine, module.secrets_manager_group] + providers = { + ibm = ibm.ibm-sm + } +} + +# create image pull serviceID and secret and store in secrets manager +module "image_pull_chain_secret_3" { + source = "../../modules/imagepull-apikey-secrets-manager-module" + resource_group_id = module.resource_group.resource_group_id + secrets_manager_guid = local.sm_guid + cr_namespace_name = var.cr_namespace_name + region = local.sm_region + #tfsec:ignore:general-secrets-no-plaintext-exposure + service_id_secret_name = "${var.prefix}-image-pull-service-id-chain-sec-3" + service_id_secret_group_id = module.secrets_manager_group.secret_group_id + depends_on = [module.iam_secrets_engine, module.secrets_manager_group] + providers = { + ibm = ibm.ibm-sm + } +} + +module "external_secret_secret_image_pull_chain" { + source = "../../modules/eso-external-secret" + depends_on = [module.eso_apikey_namespace_secretstore_2, ] + eso_store_scope = "namespace" + es_kubernetes_secret_type = "dockerconfigjson" + sm_secret_type = "iam_credentials" + eso_store_name = "${var.es_namespaces_apikey[3]}-store" + es_kubernetes_secret_name = "dockerconfigjson-chain" + es_helm_rls_name = "es-docker-iam-chain" + es_kubernetes_namespace = kubernetes_namespace.apikey_namespaces[3].metadata[0].name + sm_secret_id = null # null is accepted only in the case of a dockerjsonconfig secret with secrets chain + es_container_registry_secrets_chain = [ + { + "es_container_registry" : "test1.icr.com", "sm_secret_id" : module.image_pull_chain_secret_1.serviceid_apikey_secret_id, "es_container_registry_email" : "terraform1@ibm.com" + }, + { + "es_container_registry" : "test2.icr.com", "sm_secret_id" : module.image_pull_chain_secret_2.serviceid_apikey_secret_id, "es_container_registry_email" : null + }, + { + "es_container_registry" : "test3.icr.com", "sm_secret_id" : module.image_pull_chain_secret_3.serviceid_apikey_secret_id, "es_container_registry_email" : "" + } + ] +} diff --git a/examples/all-combined/variables.tf b/examples/all-combined/variables.tf index 1286d6c1..37dd36c9 100644 --- a/examples/all-combined/variables.tf +++ b/examples/all-combined/variables.tf @@ -33,6 +33,119 @@ variable "resource_tags" { default = [] } +variable "zones" { + description = "List of zones" + type = list(string) + default = ["1", "2", "3"] +} + +variable "cidr_bases" { + description = "A list of base CIDR blocks for each network zone" + type = map(string) + default = { + default = "192.168.32.0/20" + } +} + + +variable "acl_rules_list" { + description = "List of rules that are to be attached to the Network ACL" + type = list(object({ + name = string + action = string + source = string + destination = string + direction = string + icmp = optional(object({ + code = number + type = number + })) + tcp = optional(object({ + port_max = number + port_min = number + source_port_max = number + source_port_min = number + })) + udp = optional(object({ + port_max = number + port_min = number + source_port_max = number + source_port_min = number + })) + })) + default = [ + { + name = "iks-create-worker-nodes-inbound" + action = "allow" + source = "161.26.0.0/16" + destination = "0.0.0.0/0" + direction = "inbound" + }, + { + name = "iks-nodes-to-master-inbound" + action = "allow" + source = "166.8.0.0/14" + destination = "0.0.0.0/0" + direction = "inbound" + }, + { + name = "iks-create-worker-nodes-outbound" + action = "allow" + source = "0.0.0.0/0" + destination = "161.26.0.0/16" + direction = "outbound" + }, + { + name = "iks-worker-to-master-outbound" + action = "allow" + source = "0.0.0.0/0" + destination = "166.8.0.0/14" + direction = "outbound" + }, + { + name = "allow-all-https-inbound" + source = "0.0.0.0/0" + action = "allow" + destination = "0.0.0.0/0" + direction = "inbound" + tcp = { + source_port_min = 443 + source_port_max = 443 + port_min = 1 + port_max = 65535 + } + }, + { + name = "allow-all-https-outbound" + source = "0.0.0.0/0" + action = "allow" + destination = "0.0.0.0/0" + direction = "outbound" + tcp = { + source_port_min = 1 + source_port_max = 65535 + port_min = 443 + port_max = 443 + } + }, + { + name = "deny-all-outbound" + action = "deny" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "outbound" + }, + { + name = "deny-all-inbound" + action = "deny" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "inbound" + } + ] +} + + ## Image-pull module variable "sm_iam_secret_name" { type = string @@ -46,6 +159,12 @@ variable "sm_service_plan" { default = "trial" } +variable "cr_namespace_name" { + type = string + description = "Container registry namespace name to be configured in IAM policy." + default = "cr-namespace" +} + ## ESO Module variable "eso_namespace" { @@ -108,12 +227,6 @@ variable "service_endpoints" { default = "public" } -variable "eso_deployment_nodes_configuration" { - type = string - description = "Configuration to deploy ESO on specific cluster nodes. The value of this variable will be used for NodeSelector label value and tolerations configuration. If null standard ESO deployment is done on default workers pool." - default = null -} - ## public certificate secret configuration variable "skip_iam_authorization_policy" { type = bool @@ -242,125 +355,3 @@ variable "pvt_certificate_template_name" { description = "Template name for the private certificate to create" default = null } - -### sDNLB secret management - -variable "sdnlb_ibmcloud_api_key" { - type = string - description = "APIkey that's associated with the account owning the sDNLB entitled serviceID. If null the ibmcloud_api_key will be used." - sensitive = true - default = null -} - - -variable "zones" { - description = "List of zones" - type = list(string) - default = ["1", "2", "3"] -} - -variable "cidr_bases" { - description = "A list of base CIDR blocks for each network zone" - type = map(string) - default = { - default = "192.168.32.0/20" - } -} - - -variable "acl_rules_list" { - description = "List of rules that are to be attached to the Network ACL" - type = list(object({ - name = string - action = string - source = string - destination = string - direction = string - icmp = optional(object({ - code = number - type = number - })) - tcp = optional(object({ - port_max = number - port_min = number - source_port_max = number - source_port_min = number - })) - udp = optional(object({ - port_max = number - port_min = number - source_port_max = number - source_port_min = number - })) - })) - default = [ - { - name = "iks-create-worker-nodes-inbound" - action = "allow" - source = "161.26.0.0/16" - destination = "0.0.0.0/0" - direction = "inbound" - }, - { - name = "iks-nodes-to-master-inbound" - action = "allow" - source = "166.8.0.0/14" - destination = "0.0.0.0/0" - direction = "inbound" - }, - { - name = "iks-create-worker-nodes-outbound" - action = "allow" - source = "0.0.0.0/0" - destination = "161.26.0.0/16" - direction = "outbound" - }, - { - name = "iks-worker-to-master-outbound" - action = "allow" - source = "0.0.0.0/0" - destination = "166.8.0.0/14" - direction = "outbound" - }, - { - name = "allow-all-https-inbound" - source = "0.0.0.0/0" - action = "allow" - destination = "0.0.0.0/0" - direction = "inbound" - tcp = { - source_port_min = 443 - source_port_max = 443 - port_min = 1 - port_max = 65535 - } - }, - { - name = "allow-all-https-outbound" - source = "0.0.0.0/0" - action = "allow" - destination = "0.0.0.0/0" - direction = "outbound" - tcp = { - source_port_min = 1 - source_port_max = 65535 - port_min = 443 - port_max = 443 - } - }, - { - name = "deny-all-outbound" - action = "deny" - source = "0.0.0.0/0" - destination = "0.0.0.0/0" - direction = "outbound" - }, - { - name = "deny-all-inbound" - action = "deny" - source = "0.0.0.0/0" - destination = "0.0.0.0/0" - direction = "inbound" - } - ] -} diff --git a/examples/basic/main.tf b/examples/basic/main.tf index af8a683d..3c4aa319 100644 --- a/examples/basic/main.tf +++ b/examples/basic/main.tf @@ -333,21 +333,6 @@ resource "ibm_iam_service_policy" "secret_puller_policy" { module "external_secrets_operator" { source = "../../" eso_namespace = local.eso_namespace - - eso_cluster_nodes_configuration = { - nodeSelector = { - label = "dedicated" - value = "default" - } - tolerations = { - key = "dedicated" - operator = "Equal" - value = "default" - effect = "NoExecute" - } - } - - depends_on = [ kubernetes_namespace.apikey_namespace ] diff --git a/main.tf b/main.tf index fe806ad9..6a2401c5 100644 --- a/main.tf +++ b/main.tf @@ -7,11 +7,21 @@ ## Install ESO locals { - eso_image_tag_digest = "v0.12.1-ubi@sha256:d38834043de0a4e4feeac8a08d0bc96b71ddd7fe1d4c8583ee3751badeaeb01d" - eso_image_repo = "ghcr.io/external-secrets/external-secrets" - reloader_image_tag_digest = "v1.2.1-ubi@sha256:80a557100c6835c7e3c9842194250c9c4ca78f43200bc3a93a32e5b105ad11bb" - reloader_image_repo = "ghcr.io/stakater/reloader" + default_eso_image_repo = "ghcr.io/external-secrets/external-secrets" + default_eso_image_tag_digest = "v0.12.1-ubi@sha256:d38834043de0a4e4feeac8a08d0bc96b71ddd7fe1d4c8583ee3751badeaeb01d" # datasource: ghcr.io/external-secrets/external-secrets + + + default_reloader_image_repo = "ghcr.io/stakater/reloader" + default_reloader_image_tag_digest = "v1.2.1-ubi@sha256:80a557100c6835c7e3c9842194250c9c4ca78f43200bc3a93a32e5b105ad11bb" # datasource: ghcr.io/stakater/reloader + + # Repo and digest for ESO + eso_image_repo = var.eso_image_repo != null ? var.eso_image_repo : local.default_eso_image_repo + eso_image_tag_digest = var.eso_image_tag_digest != null ? var.eso_image_tag_digest : local.default_eso_image_tag_digest + + # Repo and digest for Reloader + reloader_image_repo = var.reloader_image_repo != null ? var.reloader_image_repo : local.default_reloader_image_repo + reloader_image_tag_digest = var.reloader_image_tag_digest != null ? var.reloader_image_tag_digest : local.default_reloader_image_tag_digest } # creating namespace to deploy ESO into RedHat ServiceMesh @@ -177,15 +187,23 @@ certController: EOF } +locals { + eso_chart_location = "https://charts.external-secrets.io" + eso_chart_version = "0.12.1" # datasource: https://charts.external-secrets.io + + reloader_chart_location = "https://stakater.github.io/stakater-charts" + reloader_chart_version = "1.2.0" # datasource: https://stakater.github.io/stakater-charts +} + resource "helm_release" "external_secrets_operator" { depends_on = [module.eso_namespace, data.kubernetes_namespace.existing_eso_namespace] name = "external-secrets" namespace = local.eso_namespace chart = "external-secrets" - version = "0.12.1" + version = local.eso_chart_version wait = true - repository = "https://charts.external-secrets.io" + repository = local.eso_chart_location set { name = "image.repository" @@ -233,8 +251,8 @@ resource "helm_release" "pod_reloader" { name = "reloader" chart = "reloader" namespace = local.eso_namespace - repository = "https://stakater.github.io/stakater-charts" - version = "1.2.0" + repository = local.reloader_chart_location + version = local.reloader_chart_version wait = true # Set the deployment image name and tag diff --git a/modules/imagepull-apikey-secrets-manager-module/README.md b/modules/imagepull-apikey-secrets-manager-module/README.md new file mode 100644 index 00000000..91e62d98 --- /dev/null +++ b/modules/imagepull-apikey-secrets-manager-module/README.md @@ -0,0 +1,135 @@ +# ImagePull API key Secrets Manager module + +[![Certified]()](https://github.ibm.com/GoldenEye/documentation/blob/master/status.md) [![CI](https://img.shields.io/badge/CI-Toolchain%20Tekton%20Pipeline-3662FF?logo=ibm)](https://cloud.ibm.com/devops/toolchains/c3916535-165a-4275-9b1f-c58575839951?env_id=ibm:yp:us-south) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) [![latest release](https://shields-server.m03l6u0cqkx.eu-de.codeengine.appdomain.cloud/github/v/release/GoldenEye/imagepull-apikey-secrets-manager-module?logo=GitHub)](https://github.ibm.com/GoldenEye/imagepull-apikey-secrets-manager-module/releases/latest) + + + +## Overview +* [imagepull-apikey-secrets-manager-module](#imagepull-apikey-secrets-manager-module) +* [Examples](./examples) + * [Example creating ImagePull serviceID and storing its API key in a Secrets-Manager instance](./examples/complete) +* [Contributing](#contributing) + + +## Compliance and security +This module implements the following NIST controls on the network layer. For more information about how this module implements the controls in the following list, see [NIST controls](docs/controls.md). + +|Profile|Category|ID|Description| +|---|---|---|---| +| NIST | AC-3 | AC-3 | The information system enforces approved authorizations for logical access to information and system resources in accordance with applicable access control policies.| +|NIST|IA-5| IA-5(g)| Protect authenticator content from unauthorized disclosure and modification. | + + + +## imagepull-apikey-secrets-manager-module + +A module to generate and store a service ID API key in IBM Cloud Secrets Manager that can be used in an `imagePullSecret` for pulling images from an IBM Container Registry. +For more information about image pull secrets, see [Creating an image pull secret](https://cloud.ibm.com/docs/containers?topic=containers-registry#other_registry_accounts) in "Setting up an image registry" in Cloud docs. + + :exclamation: Important: To use and generate dynamic secrets, Secrets Manager requires a properly configured [IAM credentials engine](https://cloud.ibm.com/docs/secrets-manager?topic=secrets-manager-configure-iam-engine&interface=ui). Use the [Secrets Manager module](https://github.ibm.com/GoldenEye/secrets-manager-module) for the configuration. + + +### Usage + +```hcl +############################################################################## +# Config providers +############################################################################## +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key # pragma: allowlist secret + region = var.region +} + +################################################################## +## Dynamic Service ID API Key / SM secret for image-pull +################################################################## + +# Replace "master" with a GIT release version to lock into a specific release + +module "image_pull" { + source = "git::https://github.ibm.com/GoldenEye/imagepull-apikey-secrets-manager-module.git?ref=master" + resource_group_id = module.resource_group.resource_group_id + secrets_manager_guid = module.secrets_manager_iam_configuration.secrets_manager_guid + cr_namespace_name = "cr-namespace" + service_id_secret_group_id = module.secrets_manager_iam_configuration.acct_secret_group_id + region = var.region + #tfsec:ignore:general-secrets-no-plaintext-exposure + service_id_secret_name = "image-pull-service-id" + depends_on = [module.secrets_manager_iam_configuration] +} +``` +### Required IAM access policies +You need the following permissions to run this module. + + + +- Account Management + - **IAM Identity** service + - `Operator` platform access + - `Administrator` platform access +- IAM services + - **Secrets Manager** service + - `Writer` service access + - **No service access** + - **Resource Group** \ + - `Viewer` resource group access + +For more information about the access you need to run all the GoldenEye modules, see [GoldenEye IAM permissions](https://github.ibm.com/GoldenEye/documentation/blob/master/goldeneye-iam-permissions.md). + + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= v1.0.0 | +| [ibm](#requirement\_ibm) | >= 1.51.0, < 2.0.0 | +| [time](#requirement\_time) | >= 0.9.1, < 1.0.0 | + +### Modules + +| Name | Source | Version | +|------|--------|---------| +| [dynamic\_serviceid\_apikey](#module\_dynamic\_serviceid\_apikey) | terraform-ibm-modules/iam-serviceid-apikey-secrets-manager/ibm | 1.1.1 | + +### Resources + +| Name | Type | +|------|------| +| [ibm_iam_service_id.image_secret_pull_service_id](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_service_id) | resource | +| [ibm_iam_service_policy.cr_policy](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_service_policy) | resource | +| [time_sleep.wait_30_seconds_for_creation](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | +| [time_sleep.wait_30_seconds_for_destruction](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cr\_namespace\_name](#input\_cr\_namespace\_name) | Container registry namespace name to be configured in IAM policy. | `string` | n/a | yes | +| [region](#input\_region) | Region where resources will be sourced / created | `string` | n/a | yes | +| [resource\_group\_id](#input\_resource\_group\_id) | The resource group ID in which the container registry namespace exists (used in IAM policy configuration). | `string` | n/a | yes | +| [secrets\_manager\_guid](#input\_secrets\_manager\_guid) | Secrets manager instance GUID where secrets will be stored or fetched from | `string` | n/a | yes | +| [service\_id\_description](#input\_service\_id\_description) | Description to be used for ServiceID. | `string` | `"ServiceId used to access container registry"` | no | +| [service\_id\_name](#input\_service\_id\_name) | Name to be used for ServiceID. | `string` | `"sid:0.0.1:image-secret-pull:automated:simple-service:container-registry:"` | no | +| [service\_id\_secret\_description](#input\_service\_id\_secret\_description) | Description to be used for ServiceID API Key. | `string` | `"API Key associated with image pull serviceid"` | no | +| [service\_id\_secret\_group\_id](#input\_service\_id\_secret\_group\_id) | Secret Group ID of SM IAM secret where Service ID apikey will be stored. Leave default (null) to add in default secret-group. | `string` | `null` | no | +| [service\_id\_secret\_name](#input\_service\_id\_secret\_name) | Name of SM IAM secret (dynamic ServiceID API Key) to be created. | `string` | `"image-pull-iam-secret"` | no | + +### Outputs + +| Name | Description | +|------|-------------| +| [secret\_manager\_guid](#output\_secret\_manager\_guid) | GUI of Secrets-Manager containing secret | +| [serviceid\_apikey\_secret\_id](#output\_serviceid\_apikey\_secret\_id) | ID of the Secret Manager Secret containing ServiceID API Key | +| [serviceid\_name](#output\_serviceid\_name) | Name of the ServiceID created to access Container Registry | + + + +## Contributing + +You can report issues and request features for this module in the GoldenEye [issues](https://github.ibm.com/GoldenEye/issues) repo.See [Report a Bug or Create Enhancement Request](https://github.ibm.com/GoldenEye/documentation/blob/master/issues.md). + +To set up your local development environment, see [Local development setup](https://github.ibm.com/GoldenEye/documentation/blob/master/local-dev-setup.md) in the project documentation. diff --git a/modules/imagepull-apikey-secrets-manager-module/main.tf b/modules/imagepull-apikey-secrets-manager-module/main.tf new file mode 100644 index 00000000..9c622707 --- /dev/null +++ b/modules/imagepull-apikey-secrets-manager-module/main.tf @@ -0,0 +1,57 @@ +############################################################################## +# Create ServiceID +############################################################################## + +resource "ibm_iam_service_id" "image_secret_pull_service_id" { + name = var.service_id_name + description = var.service_id_description +} + +############################################################################## +# Create IAM policy +############################################################################## + +resource "ibm_iam_service_policy" "cr_policy" { + + + iam_service_id = ibm_iam_service_id.image_secret_pull_service_id.id + roles = ["Reader"] + + resources { + service = "container-registry" + resource_type = "namespace" + resource = var.cr_namespace_name + resource_group_id = var.resource_group_id + } +} + +# wait time to acknowledge / finish serviceID creation +resource "time_sleep" "wait_30_seconds_for_creation" { + depends_on = [ibm_iam_service_policy.cr_policy] + create_duration = "30s" +} + + +############################################################################## +# Create Secrets-Manager IAM secret/API key +############################################################################## + +module "dynamic_serviceid_apikey" { + source = "terraform-ibm-modules/iam-serviceid-apikey-secrets-manager/ibm" + version = "1.1.1" + region = var.region + #tfsec:ignore:general-secrets-no-plaintext-exposure + sm_iam_secret_name = var.service_id_secret_name + sm_iam_secret_description = var.service_id_secret_description #tfsec:ignore:general-secrets-no-plaintext-exposure + serviceid_id = ibm_iam_service_id.image_secret_pull_service_id.id + secrets_manager_guid = var.secrets_manager_guid + sm_iam_secret_api_key_persistence = true + secret_group_id = var.service_id_secret_group_id + depends_on = [time_sleep.wait_30_seconds_for_creation] +} + +## Wait 30 sec after APIKey is deleted to ensure proper processing (https://github.ibm.com/GoldenEye/issues/issues/2200) +resource "time_sleep" "wait_30_seconds_for_destruction" { + depends_on = [module.dynamic_serviceid_apikey] + destroy_duration = "30s" +} diff --git a/modules/imagepull-apikey-secrets-manager-module/outputs.tf b/modules/imagepull-apikey-secrets-manager-module/outputs.tf new file mode 100644 index 00000000..cce7ead2 --- /dev/null +++ b/modules/imagepull-apikey-secrets-manager-module/outputs.tf @@ -0,0 +1,18 @@ +############################################################################## +# Outputs +############################################################################## + +output "secret_manager_guid" { + value = var.secrets_manager_guid + description = "GUI of Secrets-Manager containing secret" +} + +output "serviceid_name" { + description = "Name of the ServiceID created to access Container Registry" + value = ibm_iam_service_id.image_secret_pull_service_id.name +} + +output "serviceid_apikey_secret_id" { + description = "ID of the Secret Manager Secret containing ServiceID API Key" + value = module.dynamic_serviceid_apikey.secret_id +} diff --git a/modules/imagepull-apikey-secrets-manager-module/variables.tf b/modules/imagepull-apikey-secrets-manager-module/variables.tf new file mode 100644 index 00000000..eac10c0d --- /dev/null +++ b/modules/imagepull-apikey-secrets-manager-module/variables.tf @@ -0,0 +1,62 @@ +############################################################################## +# Input Variables for module +############################################################################## + +############################################################################## +# Common vars +############################################################################## +variable "region" { + description = "Region where resources will be sourced / created" + type = string +} + +variable "secrets_manager_guid" { + type = string + description = "Secrets manager instance GUID where secrets will be stored or fetched from" +} + +############################################################################## +# Service ID setup vars +############################################################################## +variable "cr_namespace_name" { + type = string + description = "Container registry namespace name to be configured in IAM policy." +} + +variable "resource_group_id" { + type = string + description = "The resource group ID in which the container registry namespace exists (used in IAM policy configuration)." +} + +variable "service_id_name" { + type = string + default = "sid:0.0.1:image-secret-pull:automated:simple-service:container-registry:" + description = "Name to be used for ServiceID." +} + +variable "service_id_description" { + type = string + default = "ServiceId used to access container registry" + description = "Description to be used for ServiceID." +} + +############################################################################## +# Service ID SM secret setup vars +############################################################################## +variable "service_id_secret_group_id" { + type = string + description = "Secret Group ID of SM IAM secret where Service ID apikey will be stored. Leave default (null) to add in default secret-group." + default = null +} + +variable "service_id_secret_name" { + type = string + description = "Name of SM IAM secret (dynamic ServiceID API Key) to be created." + default = "image-pull-iam-secret" #tfsec:ignore:general-secrets-no-plaintext-exposure +} + +variable "service_id_secret_description" { + type = string + default = "API Key associated with image pull serviceid" #tfsec:ignore:general-secrets-no-plaintext-exposure + description = "Description to be used for ServiceID API Key." +} diff --git a/modules/imagepull-apikey-secrets-manager-module/version.tf b/modules/imagepull-apikey-secrets-manager-module/version.tf new file mode 100644 index 00000000..4f2be558 --- /dev/null +++ b/modules/imagepull-apikey-secrets-manager-module/version.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">= v1.0.0" + required_providers { + # Use "greater than or equal to" range in modules + ibm = { + source = "IBM-Cloud/ibm" + version = ">= 1.51.0, < 2.0.0" + } + time = { + source = "hashicorp/time" + version = ">= 0.9.1, < 1.0.0" + } + } +} diff --git a/renovate.json b/renovate.json index aba6bf47..4a3b1242 100644 --- a/renovate.json +++ b/renovate.json @@ -8,6 +8,14 @@ "[\\w-]+_image_tag_digest\\s*=\\s*\"(?[\\w.-]+)@(?sha256:[a-f0-9]+)\"\\s*# datasource: (?[^\\s]+)" ], "datasourceTemplate": "docker" + }, + { + "fileMatch": ["\\.tf$"], + "matchStrings": [ + "[\\w-]+_chart_version\\s*=\\s*\"(?[\\w.-]+)\"\\s*# datasource: (?[^\\s]+)\\s*( versioning=(?.*?))?\\s.*?" + ], + "datasourceTemplate": "docker", + "versioningTemplate": "{{#if versioning}}{{{versioning}}}{{else}}semver{{/if}}" } ], "labels": ["renovate"], diff --git a/tests/pr_test.go b/tests/pr_test.go index e359c9a1..f2d52949 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -196,6 +196,8 @@ func TestRunDefaultExample(t *testing.T) { "pvtcertificate-tls": namespaces_for_apikey_login[2], "kv-single-key": namespaces_for_apikey_login[3], "kv-multiple-keys": namespaces_for_apikey_login[3], + "dockerconfigjson-iam": namespaces_for_apikey_login[3], + "dockerconfigjson-chain": namespaces_for_apikey_login[3], options.Prefix + "-arbitrary-arb-tp-0": namespaces_for_tp_login[0], options.Prefix + "-arbitrary-arb-tp-1": namespaces_for_tp_login[1], options.Prefix + "-arbitrary-arb-tp-multisg-1": "tpns-multisg", diff --git a/variables.tf b/variables.tf index 20b5f463..0c3c8994 100644 --- a/variables.tf +++ b/variables.tf @@ -150,3 +150,27 @@ variable "reloader_custom_values" { type = string default = null } + +variable "eso_image_repo" { + type = string + description = "The container image repository for External Secrets Operator (ESO). By default, the image is pulled from `ghcr.io/external-secrets/external-secrets`." + default = "ghcr.io/external-secrets/external-secrets" +} + +variable "eso_image_tag_digest" { + type = string + description = "The tag digest of the ESO image to deploy. If not provided, a default value will be used." + default = null +} + +variable "reloader_image_repo" { + type = string + description = "The container image repository for Reloader. By default, the image is pulled from `ghcr.io/stakater/reloader`." + default = "ghcr.io/stakater/reloader" +} + +variable "reloader_image_tag_digest" { + type = string + description = "The tag digest of the Reloader image to deploy. If not provided, a default value will be used." + default = null +} From d991e55f821ee85251c4e42e31f9c498955f8310 Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Wed, 22 Jan 2025 14:18:06 +0530 Subject: [PATCH 17/40] fix pre-commit --- .../README.md | 87 +------------------ 1 file changed, 1 insertion(+), 86 deletions(-) diff --git a/modules/imagepull-apikey-secrets-manager-module/README.md b/modules/imagepull-apikey-secrets-manager-module/README.md index 91e62d98..bc94dc2e 100644 --- a/modules/imagepull-apikey-secrets-manager-module/README.md +++ b/modules/imagepull-apikey-secrets-manager-module/README.md @@ -1,84 +1,6 @@ # ImagePull API key Secrets Manager module -[![Certified]()](https://github.ibm.com/GoldenEye/documentation/blob/master/status.md) [![CI](https://img.shields.io/badge/CI-Toolchain%20Tekton%20Pipeline-3662FF?logo=ibm)](https://cloud.ibm.com/devops/toolchains/c3916535-165a-4275-9b1f-c58575839951?env_id=ibm:yp:us-south) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) [![latest release](https://shields-server.m03l6u0cqkx.eu-de.codeengine.appdomain.cloud/github/v/release/GoldenEye/imagepull-apikey-secrets-manager-module?logo=GitHub)](https://github.ibm.com/GoldenEye/imagepull-apikey-secrets-manager-module/releases/latest) - - - -## Overview -* [imagepull-apikey-secrets-manager-module](#imagepull-apikey-secrets-manager-module) -* [Examples](./examples) - * [Example creating ImagePull serviceID and storing its API key in a Secrets-Manager instance](./examples/complete) -* [Contributing](#contributing) - - -## Compliance and security -This module implements the following NIST controls on the network layer. For more information about how this module implements the controls in the following list, see [NIST controls](docs/controls.md). - -|Profile|Category|ID|Description| -|---|---|---|---| -| NIST | AC-3 | AC-3 | The information system enforces approved authorizations for logical access to information and system resources in accordance with applicable access control policies.| -|NIST|IA-5| IA-5(g)| Protect authenticator content from unauthorized disclosure and modification. | - - - -## imagepull-apikey-secrets-manager-module - -A module to generate and store a service ID API key in IBM Cloud Secrets Manager that can be used in an `imagePullSecret` for pulling images from an IBM Container Registry. -For more information about image pull secrets, see [Creating an image pull secret](https://cloud.ibm.com/docs/containers?topic=containers-registry#other_registry_accounts) in "Setting up an image registry" in Cloud docs. - - :exclamation: Important: To use and generate dynamic secrets, Secrets Manager requires a properly configured [IAM credentials engine](https://cloud.ibm.com/docs/secrets-manager?topic=secrets-manager-configure-iam-engine&interface=ui). Use the [Secrets Manager module](https://github.ibm.com/GoldenEye/secrets-manager-module) for the configuration. - - -### Usage - -```hcl -############################################################################## -# Config providers -############################################################################## -provider "ibm" { - ibmcloud_api_key = var.ibmcloud_api_key # pragma: allowlist secret - region = var.region -} - -################################################################## -## Dynamic Service ID API Key / SM secret for image-pull -################################################################## - -# Replace "master" with a GIT release version to lock into a specific release - -module "image_pull" { - source = "git::https://github.ibm.com/GoldenEye/imagepull-apikey-secrets-manager-module.git?ref=master" - resource_group_id = module.resource_group.resource_group_id - secrets_manager_guid = module.secrets_manager_iam_configuration.secrets_manager_guid - cr_namespace_name = "cr-namespace" - service_id_secret_group_id = module.secrets_manager_iam_configuration.acct_secret_group_id - region = var.region - #tfsec:ignore:general-secrets-no-plaintext-exposure - service_id_secret_name = "image-pull-service-id" - depends_on = [module.secrets_manager_iam_configuration] -} -``` -### Required IAM access policies -You need the following permissions to run this module. - - - -- Account Management - - **IAM Identity** service - - `Operator` platform access - - `Administrator` platform access -- IAM services - - **Secrets Manager** service - - `Writer` service access - - **No service access** - - **Resource Group** \ - - `Viewer` resource group access - -For more information about the access you need to run all the GoldenEye modules, see [GoldenEye IAM permissions](https://github.ibm.com/GoldenEye/documentation/blob/master/goldeneye-iam-permissions.md). +This module generate and store a service ID API key in IBM Cloud Secrets Manager that can be used in an imagePullSecret for pulling images from an IBM Container Registry. For more information about image pull secrets, see Creating an image pull secret in "Setting up an image registry" in Cloud docs. ### Requirements @@ -126,10 +48,3 @@ For more information about the access you need to run all the GoldenEye modules, | [serviceid\_apikey\_secret\_id](#output\_serviceid\_apikey\_secret\_id) | ID of the Secret Manager Secret containing ServiceID API Key | | [serviceid\_name](#output\_serviceid\_name) | Name of the ServiceID created to access Container Registry | - - -## Contributing - -You can report issues and request features for this module in the GoldenEye [issues](https://github.ibm.com/GoldenEye/issues) repo.See [Report a Bug or Create Enhancement Request](https://github.ibm.com/GoldenEye/documentation/blob/master/issues.md). - -To set up your local development environment, see [Local development setup](https://github.ibm.com/GoldenEye/documentation/blob/master/local-dev-setup.md) in the project documentation. From 36ef82129fd91598176a619e1508e68698a2f480 Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Wed, 22 Jan 2025 14:38:13 +0530 Subject: [PATCH 18/40] fix pipeline failure --- examples/all-combined/provider.tf | 1 - examples/all-combined/secretstore.tf | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/all-combined/provider.tf b/examples/all-combined/provider.tf index 6ffbf1e7..97dc8d6c 100644 --- a/examples/all-combined/provider.tf +++ b/examples/all-combined/provider.tf @@ -10,7 +10,6 @@ provider "ibm" { } - provider "kubernetes" { host = data.ibm_container_cluster_config.cluster_config.host token = data.ibm_container_cluster_config.cluster_config.token diff --git a/examples/all-combined/secretstore.tf b/examples/all-combined/secretstore.tf index dd6c0f2f..4ada5091 100644 --- a/examples/all-combined/secretstore.tf +++ b/examples/all-combined/secretstore.tf @@ -90,7 +90,7 @@ module "external_secret_arbitrary_cr_registry" { # create image pull serviceID and secret and store in secrets manager module "image_pull" { - source = "git::https://github.ibm.com/GoldenEye/imagepull-apikey-secrets-manager-module.git?ref=1.1.7" + source = "../../modules/imagepull-apikey-secrets-manager-module" resource_group_id = module.resource_group.resource_group_id secrets_manager_guid = local.sm_guid cr_namespace_name = var.cr_namespace_name From aff7739a4dff62e026b088a85510611834e108b5 Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Wed, 22 Jan 2025 22:15:50 +0530 Subject: [PATCH 19/40] added imagepull-apikey-sm-manager to all-combined ex --- README.md | 3 ++- .../imagepull-apikey-secrets-manager}/README.md | 2 +- .../imagepull-apikey-secrets-manager}/main.tf | 0 .../imagepull-apikey-secrets-manager}/outputs.tf | 0 .../imagepull-apikey-secrets-manager}/variables.tf | 0 .../imagepull-apikey-secrets-manager}/version.tf | 0 examples/all-combined/secretstore.tf | 8 ++++---- 7 files changed, 7 insertions(+), 6 deletions(-) rename {modules/imagepull-apikey-secrets-manager-module => examples/all-combined/imagepull-apikey-secrets-manager}/README.md (98%) rename {modules/imagepull-apikey-secrets-manager-module => examples/all-combined/imagepull-apikey-secrets-manager}/main.tf (100%) rename {modules/imagepull-apikey-secrets-manager-module => examples/all-combined/imagepull-apikey-secrets-manager}/outputs.tf (100%) rename {modules/imagepull-apikey-secrets-manager-module => examples/all-combined/imagepull-apikey-secrets-manager}/variables.tf (100%) rename {modules/imagepull-apikey-secrets-manager-module => examples/all-combined/imagepull-apikey-secrets-manager}/version.tf (100%) diff --git a/README.md b/README.md index d0627acb..7defc268 100644 --- a/README.md +++ b/README.md @@ -17,11 +17,11 @@ This module automates the installation and configuration of the [External Secret * [eso-external-secret](./modules/eso-external-secret) * [eso-secretstore](./modules/eso-secretstore) * [eso-trusted-profile](./modules/eso-trusted-profile) - * [imagepull-apikey-secrets-manager-module](./modules/imagepull-apikey-secrets-manager-module) * [Examples](./examples) * [Basic Example](./examples/basic) * [Example that uses trusted profiles (container authentication)](./examples/trusted-profiles-authentication) * [Example to deploy the External Secret Operator and to create a different set of resources in terms of secrets, secret groups, stores and auth configurations](./examples/all-combined) + * [ImagePull API key Secrets Manager](./examples/all-combined/imagepull-apikey-secrets-manager) * [Contributing](#contributing) @@ -499,6 +499,7 @@ module "es_kubernetes_secret" { ## Examples - [ Example to deploy the External Secret Operator and to create a different set of resources in terms of secrets, secret groups, stores and auth configurations](examples/all-combined) +- [ ImagePull API key Secrets Manager](examples/all-combined/imagepull-apikey-secrets-manager) - [ Basic Example](examples/basic) - [ Example that uses trusted profiles (container authentication)](examples/trusted-profiles-authentication) diff --git a/modules/imagepull-apikey-secrets-manager-module/README.md b/examples/all-combined/imagepull-apikey-secrets-manager/README.md similarity index 98% rename from modules/imagepull-apikey-secrets-manager-module/README.md rename to examples/all-combined/imagepull-apikey-secrets-manager/README.md index bc94dc2e..1a901128 100644 --- a/modules/imagepull-apikey-secrets-manager-module/README.md +++ b/examples/all-combined/imagepull-apikey-secrets-manager/README.md @@ -1,4 +1,4 @@ -# ImagePull API key Secrets Manager module +# ImagePull API key Secrets Manager This module generate and store a service ID API key in IBM Cloud Secrets Manager that can be used in an imagePullSecret for pulling images from an IBM Container Registry. For more information about image pull secrets, see Creating an image pull secret in "Setting up an image registry" in Cloud docs. diff --git a/modules/imagepull-apikey-secrets-manager-module/main.tf b/examples/all-combined/imagepull-apikey-secrets-manager/main.tf similarity index 100% rename from modules/imagepull-apikey-secrets-manager-module/main.tf rename to examples/all-combined/imagepull-apikey-secrets-manager/main.tf diff --git a/modules/imagepull-apikey-secrets-manager-module/outputs.tf b/examples/all-combined/imagepull-apikey-secrets-manager/outputs.tf similarity index 100% rename from modules/imagepull-apikey-secrets-manager-module/outputs.tf rename to examples/all-combined/imagepull-apikey-secrets-manager/outputs.tf diff --git a/modules/imagepull-apikey-secrets-manager-module/variables.tf b/examples/all-combined/imagepull-apikey-secrets-manager/variables.tf similarity index 100% rename from modules/imagepull-apikey-secrets-manager-module/variables.tf rename to examples/all-combined/imagepull-apikey-secrets-manager/variables.tf diff --git a/modules/imagepull-apikey-secrets-manager-module/version.tf b/examples/all-combined/imagepull-apikey-secrets-manager/version.tf similarity index 100% rename from modules/imagepull-apikey-secrets-manager-module/version.tf rename to examples/all-combined/imagepull-apikey-secrets-manager/version.tf diff --git a/examples/all-combined/secretstore.tf b/examples/all-combined/secretstore.tf index 4ada5091..bdc20697 100644 --- a/examples/all-combined/secretstore.tf +++ b/examples/all-combined/secretstore.tf @@ -90,7 +90,7 @@ module "external_secret_arbitrary_cr_registry" { # create image pull serviceID and secret and store in secrets manager module "image_pull" { - source = "../../modules/imagepull-apikey-secrets-manager-module" + source = "./imagepull-apikey-secrets-manager" resource_group_id = module.resource_group.resource_group_id secrets_manager_guid = local.sm_guid cr_namespace_name = var.cr_namespace_name @@ -130,7 +130,7 @@ module "external_secret_secret_image_pull" { # create image pull serviceID and secret and store in secrets manager module "image_pull_chain_secret_1" { - source = "../../modules/imagepull-apikey-secrets-manager-module" + source = "./imagepull-apikey-secrets-manager" resource_group_id = module.resource_group.resource_group_id secrets_manager_guid = local.sm_guid cr_namespace_name = var.cr_namespace_name @@ -146,7 +146,7 @@ module "image_pull_chain_secret_1" { # create image pull serviceID and secret and store in secrets manager module "image_pull_chain_secret_2" { - source = "../../modules/imagepull-apikey-secrets-manager-module" + source = "./imagepull-apikey-secrets-manager" resource_group_id = module.resource_group.resource_group_id secrets_manager_guid = local.sm_guid cr_namespace_name = var.cr_namespace_name @@ -162,7 +162,7 @@ module "image_pull_chain_secret_2" { # create image pull serviceID and secret and store in secrets manager module "image_pull_chain_secret_3" { - source = "../../modules/imagepull-apikey-secrets-manager-module" + source = "./imagepull-apikey-secrets-manager" resource_group_id = module.resource_group.resource_group_id secrets_manager_guid = local.sm_guid cr_namespace_name = var.cr_namespace_name From 568d6836457c03e6f0f502893e8696e53e096d38 Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Wed, 22 Jan 2025 23:27:38 +0530 Subject: [PATCH 20/40] fix pipeline failure --- tests/pr_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/pr_test.go b/tests/pr_test.go index f2d52949..65e5c311 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -20,9 +20,6 @@ const resourceGroup = "geretain-test-ext-secrets-sync" const defaultExampleTerraformDir = "examples/all-combined" const basicExampleTerraformDir = "examples/basic" -// deploying eso on edge node to have it able to connect to SM and IAM on public network -const esoWorkersSelector = "default" - // Define a struct with fields that match the structure of the YAML data const yamlLocation = "../common-dev-assets/common-go-assets/common-permanent-resources.yaml" @@ -108,7 +105,6 @@ func TestMain(m *testing.M) { "acme_letsencrypt_private_key_secret_id": acmeLEPrivateKeySecretId, "acme_letsencrypt_private_key_sm_id": acmeLEPrivateKeySmGuid, "acme_letsencrypt_private_key_sm_region": acmeLEPrivateKeySmRegion, - "eso_deployment_nodes_configuration": esoWorkersSelector, // setting skip_iam_authorization_policy to true because using the existing secrets manager instance and the policy already exists "skip_iam_authorization_policy": true, "service_endpoints": "public", From f7d41414152dc5901f075a7c1fbb12b67ff3c209 Mon Sep 17 00:00:00 2001 From: Khuzaima Shakeel <56439894+Khuzaima05@users.noreply.github.com> Date: Wed, 29 Jan 2025 18:10:16 +0530 Subject: [PATCH 21/40] Update variables.tf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Conall Ó Cofaigh --- variables.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variables.tf b/variables.tf index 0c3c8994..2b9cd7bd 100644 --- a/variables.tf +++ b/variables.tf @@ -153,7 +153,7 @@ variable "reloader_custom_values" { variable "eso_image_repo" { type = string - description = "The container image repository for External Secrets Operator (ESO). By default, the image is pulled from `ghcr.io/external-secrets/external-secrets`." + description = "The External Secrets Operator image reference in the format of `[registry-url]/[namespace]/[image]`." default = "ghcr.io/external-secrets/external-secrets" } From 27e661f36c45eabe79eeed14e935160f28f90303 Mon Sep 17 00:00:00 2001 From: Khuzaima Shakeel <56439894+Khuzaima05@users.noreply.github.com> Date: Wed, 29 Jan 2025 18:10:25 +0530 Subject: [PATCH 22/40] Update variables.tf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Conall Ó Cofaigh --- variables.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variables.tf b/variables.tf index 2b9cd7bd..f95de0d7 100644 --- a/variables.tf +++ b/variables.tf @@ -163,7 +163,7 @@ variable "eso_image_tag_digest" { default = null } -variable "reloader_image_repo" { +variable "reloader_registry_namespace_image" { type = string description = "The container image repository for Reloader. By default, the image is pulled from `ghcr.io/stakater/reloader`." default = "ghcr.io/stakater/reloader" From 9c3187c9e1dfb3ff68d88510525d3c74b9cf256a Mon Sep 17 00:00:00 2001 From: Khuzaima Shakeel <56439894+Khuzaima05@users.noreply.github.com> Date: Wed, 29 Jan 2025 18:10:35 +0530 Subject: [PATCH 23/40] Update variables.tf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Conall Ó Cofaigh --- variables.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variables.tf b/variables.tf index f95de0d7..13f1d7d2 100644 --- a/variables.tf +++ b/variables.tf @@ -165,7 +165,7 @@ variable "eso_image_tag_digest" { variable "reloader_registry_namespace_image" { type = string - description = "The container image repository for Reloader. By default, the image is pulled from `ghcr.io/stakater/reloader`." + description = "The Reloader image reference in the format of `[registry-url]/[namespace]/[image]`." default = "ghcr.io/stakater/reloader" } From 4167f9d665e2bed84dd7c93da77262919c3133a9 Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Thu, 30 Jan 2025 13:48:42 +0530 Subject: [PATCH 24/40] resolve review comments --- .github/CODEOWNERS | 4 +- README.md | 18 +- docs/upgradeplan.md | 29 - docs/upgradeplanexamples/main.tf.new | 618 ------------------ docs/upgradeplanexamples/main.tf.old | 457 ------------- docs/upgradeplanexamples/moved.tf.new | 54 -- docs/upgradeplanexamples/variables.tf.new | 98 --- docs/upgradeplanexamples/variables.tf.old | 77 --- examples/all-combined/README.md | 11 +- examples/all-combined/clusterstore.tf | 77 --- examples/all-combined/main.tf | 18 +- examples/all-combined/privatecertificate.tf | 8 +- examples/all-combined/publiccertificate.tf | 10 +- .../all-combined/tpauth_cluster_sstore.tf | 2 +- .../all-combined/tpauth_namespaced_sstore.tf | 8 +- examples/all-combined/variables.tf | 12 +- examples/basic/README.md | 2 +- examples/basic/main.tf | 20 +- .../trusted-profiles-authentication/main.tf | 2 +- main.tf | 51 +- renovate.json | 2 +- variables.tf | 50 +- 22 files changed, 119 insertions(+), 1509 deletions(-) delete mode 100644 docs/upgradeplan.md delete mode 100644 docs/upgradeplanexamples/main.tf.new delete mode 100644 docs/upgradeplanexamples/main.tf.old delete mode 100644 docs/upgradeplanexamples/moved.tf.new delete mode 100644 docs/upgradeplanexamples/variables.tf.new delete mode 100644 docs/upgradeplanexamples/variables.tf.old diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5969395a..aeac75fd 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,2 @@ -# Primary owner should be listed first in list of global owners, follwed by any secondary owners -* @valerio-bontempi @daniel-butler-irl +# Primary owner should be listed first in list of global owners, followed by any secondary owners +* @vbontempi @daniel-butler-irl diff --git a/README.md b/README.md index 7defc268..b6b35696 100644 --- a/README.md +++ b/README.md @@ -364,7 +364,7 @@ Events: Warning UpdateFailed 119s (x13 over 28m) external-secrets An error occurred while performing the 'authenticate' step: Post "https://iam.cloud.ibm.com/identity/token": context deadline exceeded (Client.Timeout exceeded while awaiting headers) ``` -In the output above there is a problem with reaching IAM endpoint (as the ESO pods were deployed on private network and it was trying to reach IAM on public endpoint) +In the output above there is a problem with reaching IAM endpoint (verify that the pods where ESO is running are able to reach that endpoint) ### _Important note_ @@ -423,8 +423,8 @@ Base64 Decoded `.dockerconfigson` > ``` { "auths": { - "xx.artifactory.swg-devops.com": { - "username": "artifactoryuser@ibm.com", + "xx.artifactory.xyz-devops.com": { + "username": "artifactoryuser@org.com", "password": "APIKEYVALUE" # pragma: allowlist secret } } @@ -531,25 +531,29 @@ module "es_kubernetes_secret" { | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| +| [eso\_chart\_location](#input\_eso\_chart\_location) | The location of the External Secrets Operator Helm chart. | `string` | `"https://charts.external-secrets.io"` | no | +| [eso\_chart\_version](#input\_eso\_chart\_version) | The version of the External Secrets Operator Helm chart. | `string` | `"0.12.1"` | no | | [eso\_cluster\_nodes\_configuration](#input\_eso\_cluster\_nodes\_configuration) | Configuration to use to customise ESO deployment on specific cluster nodes. Setting appropriate values will result in customising ESO helm release. Default value is null to keep ESO standard deployment. |
object({
nodeSelector = object({
label = string
value = string
})
tolerations = object({
key = string
operator = string
value = string
effect = string
})
})
| `null` | no | | [eso\_enroll\_in\_servicemesh](#input\_eso\_enroll\_in\_servicemesh) | Flag to enroll ESO into istio servicemesh | `bool` | `false` | no | -| [eso\_image\_repo](#input\_eso\_image\_repo) | The container image repository for External Secrets Operator (ESO). By default, the image is pulled from `ghcr.io/external-secrets/external-secrets`. | `string` | `"ghcr.io/external-secrets/external-secrets"` | no | -| [eso\_image\_tag\_digest](#input\_eso\_image\_tag\_digest) | The tag digest of the ESO image to deploy. If not provided, a default value will be used. | `string` | `null` | no | +| [eso\_image\_digest](#input\_eso\_image\_digest) | The image digest in the format sha256:xxxxx... for ESO image to deploy. If not provided, a default value will be used. | `string` | `"sha256:d38834043de0a4e4feeac8a08d0bc96b71ddd7fe1d4c8583ee3751badeaeb01d"` | no | | [eso\_namespace](#input\_eso\_namespace) | Namespace to create and be used to install ESO components including helm releases. If eso\_store\_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster\_store in it | `string` | `null` | no | | [eso\_pod\_configuration](#input\_eso\_pod\_configuration) | Configuration to use to customise ESO deployment on specific pods. Setting appropriate values will result in customising ESO helm release. Default value is {} to keep ESO standard deployment. Ignore the key if not required. |
object({
annotations = optional(object({
# The annotations for external secret controller pods.
external_secrets = optional(map(string), {})
# The annotations for external secret cert controller pods.
external_secrets_cert_controller = optional(map(string), {})
# The annotations for external secret controller pods.
external_secrets_webhook = optional(map(string), {})
}), {})

labels = optional(object({
# The labels for external secret controller pods.
external_secrets = optional(map(string), {})
# The labels for external secret cert controller pods.
external_secrets_cert_controller = optional(map(string), {})
# The labels for external secret controller pods.
external_secrets_webhook = optional(map(string), {})
}), {})
})
| `{}` | no | +| [eso\_registry\_namespace\_image](#input\_eso\_registry\_namespace\_image) | The External Secrets Operator image reference in the format of `[registry-url]/[namespace]/[image]`. | `string` | `"ghcr.io/external-secrets/external-secrets"` | no | | [existing\_eso\_namespace](#input\_existing\_eso\_namespace) | Existing Namespace to be used to install ESO components including helm releases. If eso\_store\_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster\_store in it | `string` | `null` | no | +| [reloader\_chart\_location](#input\_reloader\_chart\_location) | The location of the Reloader Helm chart. | `string` | `"https://stakater.github.io/stakater-charts"` | no | +| [reloader\_chart\_version](#input\_reloader\_chart\_version) | The version of the Reloader Helm chart. | `string` | `"1.2.0"` | no | | [reloader\_custom\_values](#input\_reloader\_custom\_values) | String containing custom values to be used for reloader helm chart. See https://github.com/stakater/Reloader/blob/master/deployments/kubernetes/chart/reloader/values.yaml | `string` | `null` | no | | [reloader\_deployed](#input\_reloader\_deployed) | Whether to deploy reloader or not https://github.com/stakater/Reloader | `bool` | `true` | no | | [reloader\_ignore\_configmaps](#input\_reloader\_ignore\_configmaps) | Whether to ignore configmap changes or not | `bool` | `false` | no | | [reloader\_ignore\_secrets](#input\_reloader\_ignore\_secrets) | Whether to ignore secret changes or not | `bool` | `false` | no | -| [reloader\_image\_repo](#input\_reloader\_image\_repo) | The container image repository for Reloader. By default, the image is pulled from `ghcr.io/stakater/reloader`. | `string` | `"ghcr.io/stakater/reloader"` | no | -| [reloader\_image\_tag\_digest](#input\_reloader\_image\_tag\_digest) | The tag digest of the Reloader image to deploy. If not provided, a default value will be used. | `string` | `null` | no | +| [reloader\_image\_digest](#input\_reloader\_image\_digest) | The image digest in the format sha256:xxxxx... the reloader image to deploy. If not provided, a default value will be used. | `string` | `"sha256:80a557100c6835c7e3c9842194250c9c4ca78f43200bc3a93a32e5b105ad11bb"` | no | | [reloader\_is\_argo\_rollouts](#input\_reloader\_is\_argo\_rollouts) | Enable Argo Rollouts | `bool` | `false` | no | | [reloader\_is\_openshift](#input\_reloader\_is\_openshift) | Enable OpenShift DeploymentConfigs | `bool` | `true` | no | | [reloader\_log\_format](#input\_reloader\_log\_format) | The log format to use for reloader. Possible values are `json` or `text`. Default value is `json` | `string` | `"text"` | no | | [reloader\_namespaces\_selector](#input\_reloader\_namespaces\_selector) | List of comma separated label selectors, if multiple are provided they are combined with the AND operator | `string` | `null` | no | | [reloader\_namespaces\_to\_ignore](#input\_reloader\_namespaces\_to\_ignore) | List of comma separated namespaces to ignore for reloader. If multiple are provided they are combined with the AND operator | `string` | `null` | no | | [reloader\_pod\_monitor\_metrics](#input\_reloader\_pod\_monitor\_metrics) | Enable to scrape Reloader's Prometheus metrics | `bool` | `false` | no | +| [reloader\_registry\_namespace\_image](#input\_reloader\_registry\_namespace\_image) | The Reloader image reference in the format of `[registry-url]/[namespace]/[image]`. | `string` | `"ghcr.io/stakater/reloader"` | no | | [reloader\_reload\_on\_create](#input\_reloader\_reload\_on\_create) | Enable reload on create events | `bool` | `true` | no | | [reloader\_reload\_strategy](#input\_reloader\_reload\_strategy) | The reload strategy to use for reloader. Possible values are `env-vars` or `annotations`. Default value is `annotations` | `string` | `"annotations"` | no | | [reloader\_resource\_label\_selector](#input\_reloader\_resource\_label\_selector) | List of comma separated label selectors, if multiple are provided they are combined with the AND operator | `string` | `null` | no | diff --git a/docs/upgradeplan.md b/docs/upgradeplan.md deleted file mode 100644 index 0544da84..00000000 --- a/docs/upgradeplan.md +++ /dev/null @@ -1,29 +0,0 @@ -# Updating from version 1.7.0 or earlier - -The External Secrets Operator module was redesigned with new features and to allow easier configurations of instances. The last version before the redesign was [1.7.0](https://github.ibm.com/GoldenEye/external-secrets-operator-module/releases/tag/1.7.0). - -:exclamation: **Important:** Pay attention to how you update from version 1.7.0 or earlier to the redesigned module. If you update directly, you might cause issues with your deployment. - -The following lists outlines some of the changes the prevent a direct update: - -- Version 1.7.0 and earlier creates some resources implicitly (for example, `stores` and `externalsecrets`). In later versions, you must define these resources explicitly in the Terraform. - - For example, in version 1.7.0 and earlier, the default value of the `eso_store_setup` input variable is `true`. This value causes the module to create a `ClusterStore` by default (or a `SecretStore` if the value of `eso_store_scope` is `namespace`). In versions after 1.7.0, you instantiate an `eso-clusterstore` or an `eso-secretstore` submodule. - - Likewise, for `externalsecret` resources, version 1.7.0 creates an `externalsecret` resource when it sets up secrets. In later versions, you create `externalsecret` resources through the `eso-external-secret` submodule. -- Some resources have different names in the redesigned version. -- The direct update destroys resources. Secrets that are controlled through the `externalsecrets` resource will also be destroyed, and this will cause disruption. - -For more information about the redesign, see GoldenEye issue [4758](https://github.ibm.com/GoldenEye/issues/issues/4758). - -## Example of using Terraform move to update with minimal disruption - -To update your existing deployments, you can use the Terraform `move` configuration block. For more information about the `move` block, see [Use configuration to move resources](https://developer.hashicorp.com/terraform/tutorials/configuration-language/move-config). - -The `docs/upgradeplanexamples` directory in this module contains a set of files to help you with your update, by providing an example of the same terraform template for the `1.7.0` module version and for the redesigned one. - -The `.old` files ([variables.tf.old](upgradeplanexamples/variables.tf.old) and [main.tf.old](upgradeplanexamples/main.tf.old)) describe the terraform template to deploy external-secrets-operator module with version 1.7.0. - -The `.new` files ([variables.tf.new](upgradeplanexamples/variables.tf.new) and [main.tf.new](upgradeplanexamples/main.tf.new)) describe how to upgrade then to the redesigned version. - -The [moved.tf.new](upgradeplanexamples/moved.tf.new) file defines how resources deployed with `1.7.0` template ("old" files) are renamed and moved when the updating with the redesigned version. By adding this file to your template, terraform will update the resources instead of destroying and re-creating them. diff --git a/docs/upgradeplanexamples/main.tf.new b/docs/upgradeplanexamples/main.tf.new deleted file mode 100644 index 909c47c5..00000000 --- a/docs/upgradeplanexamples/main.tf.new +++ /dev/null @@ -1,618 +0,0 @@ -############################################################################## -# Locals -############################################################################## - -locals { - # general - validate_sm_region_cnd = var.existing_sm_instance_guid != null && var.existing_sm_instance_region == null - validate_sm_region_msg = "existing_sm_instance_region must also be set when value given for existing_sm_instance_guid." - # tflint-ignore: terraform_unused_declarations - validate_sm_region_chk = regex( - "^${local.validate_sm_region_msg}$", - (!local.validate_sm_region_cnd - ? local.validate_sm_region_msg - : "")) - - sm_guid = var.existing_sm_instance_guid == null ? ibm_resource_instance.secrets_manager[0].guid : var.existing_sm_instance_guid - sm_region = var.existing_sm_instance_region == null ? var.region : var.existing_sm_instance_region - sm_acct_id = var.existing_sm_instance_guid == null ? module.iam_secrets_engine[0].acct_secret_group_id : module.secrets_manager_group_acct[0].secret_group_id - - # artifactory-registry-secret - artifactory_apikey = sensitive("artifactory-payload-example") - - # cr-registry-arbitrary-secret - imagepull_apikey = sensitive("imagepull-payload-example") -} - -################################################################## -# Resource Group -################################################################## - -module "resource_group" { - source = "terraform-ibm-modules/resource-group/ibm" - version = "1.1.5" - # if an existing resource group is not set (null) create a new one using prefix - resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null - existing_resource_group_name = var.resource_group -} - -################################################################## -# Create VPC, public gateway and subnets -################################################################## - -locals { - - # VPC Configuration - acl_rules_map = { - private = concat( - module.acl_profile.base_acl, - module.acl_profile.https_acl, - module.acl_profile.deny_all_acl - ) - } - vpc_cidr_bases = { - private = "192.168.0.0/20", - transit = "192.168.16.0/20", - edge = "192.168.32.0/20" - } - - # OCP Configuration - ocp_worker_pools = [ - { - subnet_prefix = "private" - pool_name = "default" - machine_type = "bx2.4x16" - workers_per_zone = 1 - labels = { "dedicated" : "private" } - }, - { - subnet_prefix = "edge" - pool_name = "edge" - machine_type = "bx2.4x16" - workers_per_zone = 1 - labels = { "dedicated" : "edge" } - }, - { - subnet_prefix = "transit" - pool_name = "transit" - machine_type = "bx2.4x16" - workers_per_zone = 1 - labels = { "dedicated" : "transit" } - } - ] -} - -# VPC ACLs -module "acl_profile" { - source = "git::https://github.ibm.com/GoldenEye/acl-profile-ocp.git?ref=1.3.1" -} - - -# VPC creation -module "vpc" { - source = "git::https://github.ibm.com/GoldenEye/vpc-module.git?ref=6.3.3" - unique_name = "${var.prefix}-vpc" - ibm_region = local.sm_region - resource_group_id = module.resource_group.resource_group_id - cidr_bases = local.vpc_cidr_bases - acl_rules_map = local.acl_rules_map - virtual_private_endpoints = {} - vpc_tags = [] -} - -# OCP CLUSTER creation -module "ocp_base" { - source = "terraform-ibm-modules/base-ocp-vpc/ibm" - version = "3.18.1" - ibmcloud_api_key = var.ibmcloud_api_key # pragma: allowlist secret - cluster_name = "${var.prefix}-vpc" - resource_group_id = module.resource_group.resource_group_id - region = local.sm_region - force_delete_storage = true - vpc_id = module.vpc.vpc_id - vpc_subnets = module.vpc.subnets - worker_pools = local.ocp_worker_pools - tags = [] - use_existing_cos = false -} - -############################################################################## -# Init cluster config for helm and kubernetes providers -############################################################################## - -data "ibm_container_cluster_config" "cluster_config" { - cluster_name_id = module.ocp_base.cluster_id - resource_group_id = module.resource_group.resource_group_id -} - -# Wait time to allow cluster refreshes components after provisioning -resource "time_sleep" "wait_45_seconds" { - depends_on = [data.ibm_container_cluster_config.cluster_config] - create_duration = "45s" -} - -# Create namespace -resource "kubernetes_namespace" "cluster_namespaces" { - for_each = toset(var.es_kubernetes_namespaces) - metadata { - name = each.value - } - lifecycle { - ignore_changes = [ - metadata[0].annotations, - metadata[0].labels - ] - } - depends_on = [ - time_sleep.wait_45_seconds - ] -} - -######################################## -# Secrets-Manager and IAM configuration -######################################## - -# IAM user policy, Secret Manager instance, Service ID for IAM engine, IAM service ID policies, associated Service ID API key stored in a secret object in account level secret-group and IAM engine configuration -resource "ibm_resource_instance" "secrets_manager" { - count = var.existing_sm_instance_guid == null ? 1 : 0 - name = "${var.prefix}-sm" - service = "secrets-manager" - plan = var.sm_service_plan - location = local.sm_region - tags = var.resource_tags - resource_group_id = module.resource_group.resource_group_id - timeouts { - create = "30m" # Extending provisioning time to 30 minutes - } -} - -# Configure instance with IAM engine -module "iam_secrets_engine" { - # providers = { - # restapi.nocontent = restapi.nocontent - # } - count = var.existing_sm_instance_guid == null ? 1 : 0 - source = "git::https://github.ibm.com/GoldenEye/secrets-manager-iam-engine-module.git?ref=2.0.6" - region = local.sm_region - secrets_manager_guid = ibm_resource_instance.secrets_manager[0].guid - create_iam_user_policy = false - iam_secret_generator_service_id_name = "${var.prefix}-sid:0.0.1:${ibm_resource_instance.secrets_manager[0].name}-iam-secret-generator:automated:simple-service:secret-manager:" - iam_secret_generator_apikey_name = "${var.prefix}-iam-secret-generator-apikey" - new_secret_group_name = "${var.prefix}-account-secret-group" - iam_secret_generator_apikey_secret_name = "${var.prefix}-iam-secret-generator-apikey-secret" - iam_engine_name = "iam-engine" -} - -# Creates secret group to place secrets -module "secrets_manager_group" { - source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" - version = "1.1.4" - # source = "git::https://github.ibm.com/GoldenEye/secrets-manager-secret-group-module.git?ref=2.0.1" - region = local.sm_region - secrets_manager_guid = local.sm_guid - secret_group_name = "${var.prefix}-secret-group" #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value - secret_group_description = "Secret-Group for storing account credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure -} - -# Additional Secrets-Manager Secret-Group for SERVICE level secrets -module "secrets_manager_group_acct" { - source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" - version = "1.1.4" - count = var.existing_sm_instance_guid == null ? 0 : 1 - # source = "git::https://github.ibm.com/GoldenEye/secrets-manager-secret-group-module.git?ref=2.0.1" - region = local.sm_region - secrets_manager_guid = local.sm_guid - #tfsec:ignore:general-secrets-no-plaintext-exposure - secret_group_name = "${var.prefix}-account-secret-group" #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value - secret_group_description = "Secret-Group for storing account credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure - depends_on = [module.iam_secrets_engine] -} - -################################################################## -# Create service-id, policy to pull secrets from secret manager -################################################################## - -# Create service-id -resource "ibm_iam_service_id" "secret_puller" { - name = "sid:0.0.1:${var.prefix}-secret-puller:automated:simple-service:secret-manager:" - description = "ServiceID that can pull secrets from Secret Manager" -} -# Create policy to allow new service id to pull secrets from secrets manager -resource "ibm_iam_service_policy" "secret_puller_policy" { - iam_service_id = ibm_iam_service_id.secret_puller.id - roles = ["Viewer", "SecretsReader"] - - resources { - service = "secrets-manager" - resource_instance_id = local.sm_guid - resource_type = "secret-group" - resource = module.secrets_manager_group.secret_group_id - } -} - -################################################################## -# Artifactory-registry -################################################################## - -# Creates username_password secrets and stores in secret manager -module "sm_up_artifactory_secret" { - source = "git::https://github.ibm.com/GoldenEye/secrets-manager-secret-module.git?ref=3.1.1" - region = local.sm_region - secrets_manager_guid = local.sm_guid - secret_group_id = module.secrets_manager_group.secret_group_id - #tfsec:ignore:general-secrets-no-plaintext-exposure - secret_name = "${var.prefix}-artifactory-up-secret" # checkov:skip=CKV_SECRET_6 - secret_description = "example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure # checkov:skip=CKV_SECRET_6 - secret_payload_password = local.artifactory_apikey # pragma: allowlist secret - secret_type = "username_password" #checkov:skip=CKV_SECRET_6 - #tfsec:ignore:general-secrets-no-plaintext-exposure - secret_username = "artifactory-user" # checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value - secret_user_pass_auto_rotation = false -} - -# # Installing external secrets operator(ESO), cluster store and deploying external secret as dockerconfigson type -# module "eso_operator_clusterstore_deployment" { -# source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git?ref=1.7.0" -# depends_on = [ -# kubernetes_namespace.cluster_namespaces -# ] -# es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 -> externalsecret -# sm_secret_type = "username_password" #checkov:skip=CKV_SECRET_6 -> externalsecret -# sm_secret_id = module.sm_up_artifactory_secret.secret_id # -> externalsecret -# eso_setup = true -# es_kubernetes_namespaces = [var.es_kubernetes_namespaces[0]] # -> value to use in externalsecret -# secrets_manager_guid = local.sm_guid # -> cluster store -# eso_generic_secret_name = "generic-cluster-api-key" #checkov:skip=CKV_SECRET_6 # -> cluster store -# eso_store_name = "cluster-store" # -> cluster store -# es_container_registry = "wcp-my-team-docker-local.artifactory.swg-devops.com" # -> value to use in externalsecret -# region = local.sm_region # -> cluster store -# es_kubernetes_secret_name = "dockerconfigjson-uc" #checkov:skip=CKV_SECRET_6 # -> value to use in externalsecret -# es_helm_rls_name = "es-docker-uc" # -> value to use in externalsecret -# es_store_helm_rls_name = "cluster-store" # -> value to use in cluster store -# eso_authentication = ["api_key"] # -> value to use in cluster store -# } - -### from previous single to three modules (ESO + clusterstore + externalsecret) - -################################################################## -# ESO deployment -################################################################## - -module "eso_operator_deployment" { - depends_on = [ - kubernetes_namespace.cluster_namespaces - ] - source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git?ref=task_4882_5006_5196" - existing_eso_namespace = "external-secrets-operator" # default of previous module version while now it is not defaulted - service_endpoints = "public" # default of previous module version default - - eso_cluster_nodes_configuration = var.eso_deployment_nodes_configuration == null ? null : { - nodeSelector = { - label = "dedicated" - value = var.eso_deployment_nodes_configuration - } - tolerations = { - key = "dedicated" - operator = "Equal" - value = var.eso_deployment_nodes_configuration - effect = "NoExecute" - } - } - -} - -################################################################## -# ESO ClusterStore creation with apikey authentication -################################################################## - -module "eso_clusterstore_deployment" { - source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git//eso-clusterstore?ref=task_4882_5006_5196" - eso_authentication = "api_key" - clusterstore_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key # pragma: allowlist secret - region = local.sm_region - clusterstore_helm_rls_name = "cluster-store" - clusterstore_secret_name = "generic-cluster-api-key" #checkov:skip=CKV_SECRET_6 - clusterstore_name = "cluster-store" - clusterstore_secrets_manager_guid = local.sm_guid - eso_namespace = var.existing_eso_namespace - service_endpoints = var.service_endpoints - depends_on = [ - module.eso_operator_deployment - ] -} - -################################################################## -# ExternalSecret for ESO in cluster scope and apikey auth -################################################################## - -# Creation of ExternalSecret for cluster scope and deploying external secret as dockerconfigson type -module "external_secret_dockerconfigson_usr_pass_deployment" { - depends_on = [module.eso_clusterstore_deployment] - source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git//eso-external-secret?ref=task_4882_5006_5196" - es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 - sm_secret_type = "username_password" #checkov:skip=CKV_SECRET_6 - sm_secret_id = module.sm_up_artifactory_secret.secret_id - # es_kubernetes_namespace = var.es_kubernetes_namespaces[0] - es_kubernetes_namespace = kubernetes_namespace.cluster_namespaces[var.es_kubernetes_namespaces[0]].metadata[0].name # to create explicit dependency - eso_store_name = "cluster-store" - eso_store_scope = "cluster" - es_container_registry = "wcp-my-team-docker-local.artifactory.swg-devops.com" - es_kubernetes_secret_name = "dockerconfigjson-uc" #checkov:skip=CKV_SECRET_6 - es_helm_rls_name = "es-docker-uc" - es_helm_rls_namespace = var.existing_eso_namespace # to keep backward compatibility with previous version installing it in eso operator namespace -} - -################################################################## -# Cloudant-arbitrary-secret -################################################################## - -############################################################################## -# Basic cloudant instance + database -############################################################################## - -module "cloudant" { - source = "terraform-ibm-modules/cloudant/ibm" - version = "1.1.7" - resource_group_id = module.resource_group.resource_group_id - instance_name = "${var.prefix}-cloudant" - access_tags = [] - region = var.region - tags = var.resource_tags - database_config = [{ - db = "cloudant-db" - partitioned = false - shards = 3 - }] -} - -data "ibm_cloudant" "instance" { - name = module.cloudant.name - resource_group_id = module.resource_group.resource_group_id -} - -resource "ibm_resource_key" "resource_key" { - name = "cd-resource-key" - role = "Manager" - resource_instance_id = data.ibm_cloudant.instance.id - timeouts { - create = "15m" - delete = "15m" - } -} - -# Creates arbitrary secret and stores in secret manager -module "sm_arbitrary_cloudant_secret" { - source = "git::https://github.ibm.com/GoldenEye/secrets-manager-secret-module.git?ref=3.1.1" - region = local.sm_region - secrets_manager_guid = local.sm_guid - secret_group_id = module.secrets_manager_group.secret_group_id - secret_type = "arbitrary" - #tfsec:ignore:general-secrets-no-plaintext-exposure - secret_name = "${var.prefix}-cloudant-rk-secret" #checkov:skip=CKV_SECRET_6 - secret_description = "example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure - secret_payload_password = ibm_resource_key.resource_key.credentials["apikey"] -} - -# # Deploying external secret as Opaque type using existing cluster store -# module "eso_clusterstore_externalsecret_opaque_create" { -# depends_on = [ -# module.eso_operator_clusterstore_deployment, -# kubernetes_namespace.cluster_namespaces -# ] -# source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git?ref=1.7.0" -# es_kubernetes_secret_type = "opaque" # -> externalsecret -# sm_secret_type = "arbitrary" # -> externalsecret -# sm_secret_id = module.sm_arbitrary_cloudant_secret.secret_id # -> externalsecret -# eso_setup = false -# eso_store_setup = false -# es_kubernetes_namespaces = [var.es_kubernetes_namespaces[1]] # -> value to use in externalsecret -# eso_store_name = "cluster-store" # -> value to use in externalsecret -# secrets_manager_guid = local.sm_guid # -> cluster store -# region = local.sm_region # -> cluster store -# es_kubernetes_secret_data_key = "apikey" # -> value to use in externalsecret -# es_kubernetes_secret_name = "cloudant-opaque-arb" #checkov:skip=CKV_SECRET_6 # -> value to use in externalsecret -# es_helm_rls_name = "es-cloudant-arb" # -> value to use in externalsecret -# eso_authentication = ["api_key"] # -> cluster store -# } - -### from previous single to singe module eso-external-secret - -################################################################## -# ExternalSecret for ESO in cluster scope and apikey auth -################################################################## - -# Creates externalsecret using existing cluster store and configure the secret as Opaque type -module "external_secret_opaque_arbitrary_deployment" { - depends_on = [module.eso_clusterstore_deployment] - source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git//eso-external-secret?ref=task_4882_5006_5196" - es_kubernetes_secret_type = "opaque" #checkov:skip=CKV_SECRET_6 - sm_secret_type = "arbitrary" #checkov:skip=CKV_SECRET_6 - sm_secret_id = module.sm_arbitrary_cloudant_secret.secret_id - # es_kubernetes_namespace = var.es_kubernetes_namespaces[1] - es_kubernetes_namespace = kubernetes_namespace.cluster_namespaces[var.es_kubernetes_namespaces[1]].metadata[0].name # to create explicit dependency - eso_store_name = "cluster-store" - eso_store_scope = "cluster" - es_kubernetes_secret_data_key = "apikey" - es_kubernetes_secret_name = "cloudant-opaque-arb" #checkov:skip=CKV_SECRET_6 - es_helm_rls_name = "es-cloudant-arb" - es_helm_rls_namespace = var.existing_eso_namespace # to keep backward compatibility with previous version installing it in eso operator namespace -} - -################################################################## -# cr-registry-arbitrary-secret -################################################################## - -# Creates arbitrary secret and stores in secret manager -module "sm_arbitrary_imagepull_secret" { - source = "git::https://github.ibm.com/GoldenEye/secrets-manager-secret-module.git?ref=3.1.1" - region = local.sm_region - secrets_manager_guid = local.sm_guid - secret_group_id = module.secrets_manager_group.secret_group_id - secret_type = "arbitrary" - #tfsec:ignore:general-secrets-no-plaintext-exposure - secret_name = "${var.prefix}-imagepull-apikey-secret" #checkov:skip=CKV_SECRET_6 - secret_description = "example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure - secret_payload_password = local.imagepull_apikey # pragma: allowlist secret -} - -# # Deploying external secret as dockerconfigson type using new namespace store -# module "eso_secretstore_create_externalsecret_arbitrary_create" { -# depends_on = [ -# module.eso_operator_clusterstore_deployment, -# kubernetes_namespace.cluster_namespaces -# ] -# source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git?ref=1.7.0" -# es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 # -> externalsecret -# sm_secret_type = "arbitrary" # -> externalsecret -# sm_secret_id = module.sm_arbitrary_imagepull_secret.secret_id # -> externalsecret -# eso_setup = false -# eso_store_setup = true -# eso_store_scope = "namespace" # -> secretstore -# es_kubernetes_namespaces = [var.es_kubernetes_namespaces[2]] # -> value to use in externalsecret -# es_container_registry_email = "terraform@ibm.com" # -> value to use in externalsecret -# eso_generic_secret_name = "generic-${var.es_kubernetes_namespaces[2]}-api-key" # -> secretstore -# eso_store_name = "${var.es_kubernetes_namespaces[2]}-store" # -> secretstore -# secrets_manager_guid = local.sm_guid # -> secretstore -# region = local.sm_region # -> secretstore -# es_kubernetes_secret_name = "dockerconfigjson-arb" #checkov:skip=CKV_SECRET_6 # -> value to use in externalsecret -# es_helm_rls_name = "es-docker-arb" # -> value to use in externalsecret -# es_store_helm_rls_name = "store" # -> value to use in externalsecret -# eso_authentication = ["api_key"] # -> secretstore - -# } - -### from previous single to two modules eso-secretstore + eso-external-secret - -# Deploying external secret as dockerconfigson type using new namespace store -# creation of Namespaced SecretStores with apikey authentication -module "eso_namespacedstore_apikeyauth_dockerconfigson_deployment" { - depends_on = [module.eso_clusterstore_deployment] - source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git//eso-secretstore?ref=task_4882_5006_5196" - eso_authentication = "api_key" - region = local.sm_region - sstore_namespace = kubernetes_namespace.cluster_namespaces[var.es_kubernetes_namespaces[2]].metadata[0].name - sstore_secrets_manager_guid = local.sm_guid - sstore_store_name = "${var.es_kubernetes_namespaces[2]}-store" - sstore_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key # pragma: allowlist secret - service_endpoints = var.service_endpoints - sstore_helm_rls_name = "store" - sstore_secret_name = "generic-${var.es_kubernetes_namespaces[2]}-api-key" -} - -# Deploying external secret as dockerconfigson type using new namespace store -# Creates externalsecret using previously created namespaced store and configure the secret as arbitrary type -module "external_secret_dockerconfigson_arbitrary_deployment" { - depends_on = [module.eso_clusterstore_deployment] - source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git//eso-external-secret?ref=task_4882_5006_5196" - es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 - sm_secret_type = "arbitrary" #checkov:skip=CKV_SECRET_6 - sm_secret_id = module.sm_arbitrary_imagepull_secret.secret_id - # es_kubernetes_namespace = var.es_kubernetes_namespaces[2] - es_kubernetes_namespace = kubernetes_namespace.cluster_namespaces[var.es_kubernetes_namespaces[2]].metadata[0].name # to create explicit dependency - eso_store_name = "${var.es_kubernetes_namespaces[2]}-store" - eso_store_scope = "namespace" - es_kubernetes_secret_name = "dockerconfigjson-arb" #checkov:skip=CKV_SECRET_6 - es_container_registry_email = "terraform@ibm.com" # -> value to use in externalsecret - es_helm_rls_name = "es-docker-arb" - es_helm_rls_namespace = var.existing_eso_namespace # to keep backward compatibility with previous version installing it in eso operator namespace -} - -################################################################## -# cr-registry-same-account -################################################################## - -# Create dynamic Service ID API key and add to secret manager -module "dynamic_serviceid_apikey1" { - source = "git::https://github.ibm.com/GoldenEye/iam-serviceid-apikey-secrets-manager-module.git?ref=2.0.2" - region = local.sm_region - #tfsec:ignore:general-secrets-no-plaintext-exposure - sm_iam_secret_name = "${var.prefix}-${var.sm_iam_secret_name}" - sm_iam_secret_description = "Example of dynamic IAM secret / apikey" #tfsec:ignore:general-secrets-no-plaintext-exposure - serviceid_id = ibm_iam_service_id.secret_puller.id - secrets_manager_guid = local.sm_guid - secret_group_id = local.sm_acct_id - depends_on = [module.iam_secrets_engine, ibm_iam_service_policy.secret_puller_policy, ibm_iam_service_id.secret_puller] -} - -# Creates image pull secrets and stores in secret manager -module "image_pull" { - source = "git::https://github.ibm.com/GoldenEye/imagepull-apikey-secrets-manager-module.git?ref=1.1.2" - resource_group_id = module.resource_group.resource_group_id - secrets_manager_guid = local.sm_guid - cr_namespace_name = var.cr_namespace_name - region = local.sm_region - #tfsec:ignore:general-secrets-no-plaintext-exposure - service_id_secret_name = "${var.prefix}-image-pull-service-id" - service_id_secret_group_id = module.secrets_manager_group.secret_group_id - depends_on = [module.iam_secrets_engine, module.secrets_manager_group] -} - -# Data source to get API Key from secret manager secret-puller-secret -data "ibm_sm_iam_credentials_secret" "secret_puller_secret" { - instance_id = local.sm_guid - #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static type - secret_id = module.dynamic_serviceid_apikey1.secret_id -} - -# # Deploying external secret as dockerconfigson type (from image pull IAM dynamic credential/secret) using new namespace store -# module "eso_secretstore_create_externalsecret_iamcredentials_create" { -# depends_on = [ -# module.eso_operator_clusterstore_deployment, -# kubernetes_namespace.cluster_namespaces -# ] -# source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git?ref=1.7.0" -# es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 -> externalsecret -# sm_secret_type = "iam_credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure -> externalsecret -# sm_secret_id = module.image_pull.serviceid_apikey_secret_id # -> externalsecret -# es_kubernetes_namespaces = [var.es_kubernetes_namespaces[3]] # -> externalsecret -# eso_setup = false -# eso_store_setup = true -# eso_store_scope = "namespace" # -> secret store -# es_container_registry_email = "terraform@ibm.com" # -> externalsecret -# es_refresh_interval = var.es_refresh_interval # -> externalsecret -# eso_generic_secret_name = "generic-${var.es_kubernetes_namespaces[3]}-api-key" # -> secret store -# eso_store_name = "${var.es_kubernetes_namespaces[3]}-store" # -> secret store -# secrets_manager_guid = local.sm_guid # -> secret store -# region = local.sm_region # -> secret store -# es_kubernetes_secret_name = "dockerconfigjson-iam" #tfsec:ignore:general-secrets-no-plaintext-exposure #checkov:skip=CKV_SECRET_6 # -> externalsecret -# es_helm_rls_name = "es-docker-iam" # -> externalsecret -# es_store_helm_rls_name = "store" # -> value to use in secret store -# eso_authentication = ["api_key"] # -> value to use in secret store -# } - -### from previous single to two modules eso-secretstore + eso-external-secret - -# Deploying external secret as dockerconfigson type (from image pull IAM dynamic credential/secret) using new namespace store -# creation of Namespaced SecretStores with apikey authentication -module "eso_namespacedstore_apikeyauth_iamcredentials_deployment" { - depends_on = [module.eso_clusterstore_deployment] - source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git//eso-secretstore?ref=task_4882_5006_5196" - eso_authentication = "api_key" - region = local.sm_region - sstore_namespace = kubernetes_namespace.cluster_namespaces[var.es_kubernetes_namespaces[3]].metadata[0].name - sstore_secrets_manager_guid = local.sm_guid - sstore_store_name = "${var.es_kubernetes_namespaces[3]}-store" - sstore_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key #tfsec:ignore:general-secrets-no-plaintext-exposure # pragma: allowlist secret -> secret store - service_endpoints = var.service_endpoints - sstore_helm_rls_name = "store" - sstore_secret_name = "generic-${var.es_kubernetes_namespaces[3]}-api-key" -} - -# Deploying external secret as dockerconfigson type using new namespace store -# Creates externalsecret using previously created namespaced store and configure the secret as iam_credentials type -module "external_secret_dockerconfigson_iamcredentials_deployment" { - depends_on = [module.eso_clusterstore_deployment] - source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git//eso-external-secret?ref=task_4882_5006_5196" - es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 - sm_secret_type = "iam_credentials" #checkov:skip=CKV_SECRET_6 - sm_secret_id = module.image_pull.serviceid_apikey_secret_id - # es_kubernetes_namespace = var.es_kubernetes_namespaces[3] - es_kubernetes_namespace = kubernetes_namespace.cluster_namespaces[var.es_kubernetes_namespaces[3]].metadata[0].name # to create explicit dependency - eso_store_name = "${var.es_kubernetes_namespaces[3]}-store" - eso_store_scope = "namespace" - es_kubernetes_secret_name = "dockerconfigjson-iam" #checkov:skip=CKV_SECRET_6 - es_helm_rls_name = "es-docker-iam" - es_container_registry_email = "terraform@ibm.com" - es_refresh_interval = var.es_refresh_interval - es_helm_rls_namespace = var.existing_eso_namespace # to keep backward compatibility with previous version installing it in eso operator namespace -} diff --git a/docs/upgradeplanexamples/main.tf.old b/docs/upgradeplanexamples/main.tf.old deleted file mode 100644 index 2f6f934d..00000000 --- a/docs/upgradeplanexamples/main.tf.old +++ /dev/null @@ -1,457 +0,0 @@ -############################################################################## -# Locals -############################################################################## - -locals { - # general - validate_sm_region_cnd = var.existing_sm_instance_guid != null && var.existing_sm_instance_region == null - validate_sm_region_msg = "existing_sm_instance_region must also be set when value given for existing_sm_instance_guid." - # tflint-ignore: terraform_unused_declarations - validate_sm_region_chk = regex( - "^${local.validate_sm_region_msg}$", - (!local.validate_sm_region_cnd - ? local.validate_sm_region_msg - : "")) - - sm_guid = var.existing_sm_instance_guid == null ? ibm_resource_instance.secrets_manager[0].guid : var.existing_sm_instance_guid - sm_region = var.existing_sm_instance_region == null ? var.region : var.existing_sm_instance_region - sm_acct_id = var.existing_sm_instance_guid == null ? module.iam_secrets_engine[0].acct_secret_group_id : module.secrets_manager_group_acct[0].secret_group_id - - # artifactory-registry-secret - artifactory_apikey = sensitive("artifactory-payload-example") - - # cr-registry-arbitrary-secret - imagepull_apikey = sensitive("imagepull-payload-example") -} - -################################################################## -# Resource Group -################################################################## - -module "resource_group" { - source = "terraform-ibm-modules/resource-group/ibm" - version = "1.1.5" - # if an existing resource group is not set (null) create a new one using prefix - resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null - existing_resource_group_name = var.resource_group -} - -################################################################## -# Create VPC, public gateway and subnets -################################################################## - -locals { - - # VPC Configuration - acl_rules_map = { - private = concat( - module.acl_profile.base_acl, - module.acl_profile.https_acl, - module.acl_profile.deny_all_acl - ) - } - vpc_cidr_bases = { - private = "192.168.0.0/20", - transit = "192.168.16.0/20", - edge = "192.168.32.0/20" - } - - # OCP Configuration - ocp_worker_pools = [ - { - subnet_prefix = "private" - pool_name = "default" - machine_type = "bx2.4x16" - workers_per_zone = 1 - labels = { "dedicated" : "private" } - }, - { - subnet_prefix = "edge" - pool_name = "edge" - machine_type = "bx2.4x16" - workers_per_zone = 1 - labels = { "dedicated" : "edge" } - }, - { - subnet_prefix = "transit" - pool_name = "transit" - machine_type = "bx2.4x16" - workers_per_zone = 1 - labels = { "dedicated" : "transit" } - } - ] -} - -# VPC ACLs -module "acl_profile" { - source = "git::https://github.ibm.com/GoldenEye/acl-profile-ocp.git?ref=1.3.1" -} - - -# VPC creation -module "vpc" { - source = "git::https://github.ibm.com/GoldenEye/vpc-module.git?ref=6.3.3" - unique_name = "${var.prefix}-vpc" - ibm_region = local.sm_region - resource_group_id = module.resource_group.resource_group_id - cidr_bases = local.vpc_cidr_bases - acl_rules_map = local.acl_rules_map - virtual_private_endpoints = {} - vpc_tags = [] -} - -# OCP CLUSTER creation -module "ocp_base" { - source = "terraform-ibm-modules/base-ocp-vpc/ibm" - version = "3.18.1" - ibmcloud_api_key = var.ibmcloud_api_key # pragma: allowlist secret - cluster_name = "${var.prefix}-vpc" - resource_group_id = module.resource_group.resource_group_id - region = local.sm_region - force_delete_storage = true - vpc_id = module.vpc.vpc_id - vpc_subnets = module.vpc.subnets - worker_pools = local.ocp_worker_pools - tags = [] - use_existing_cos = false -} - -############################################################################## -# Init cluster config for helm and kubernetes providers -############################################################################## - -data "ibm_container_cluster_config" "cluster_config" { - cluster_name_id = module.ocp_base.cluster_id - resource_group_id = module.resource_group.resource_group_id -} - -# Wait time to allow cluster refreshes components after provisioning -resource "time_sleep" "wait_45_seconds" { - depends_on = [data.ibm_container_cluster_config.cluster_config] - create_duration = "45s" -} - -# Create namespace -resource "kubernetes_namespace" "cluster_namespaces" { - for_each = toset(var.es_kubernetes_namespaces) - metadata { - name = each.value - } - lifecycle { - ignore_changes = [ - metadata[0].annotations, - metadata[0].labels - ] - } - depends_on = [ - time_sleep.wait_45_seconds - ] -} - -######################################## -# Secrets-Manager and IAM configuration -######################################## - -# IAM user policy, Secret Manager instance, Service ID for IAM engine, IAM service ID policies, associated Service ID API key stored in a secret object in account level secret-group and IAM engine configuration -resource "ibm_resource_instance" "secrets_manager" { - count = var.existing_sm_instance_guid == null ? 1 : 0 - name = "${var.prefix}-sm" - service = "secrets-manager" - plan = var.sm_service_plan - location = local.sm_region - tags = var.resource_tags - resource_group_id = module.resource_group.resource_group_id - timeouts { - create = "30m" # Extending provisioning time to 30 minutes - } -} - -# Configure instance with IAM engine -module "iam_secrets_engine" { - # providers = { - # restapi.nocontent = restapi.nocontent - # } - count = var.existing_sm_instance_guid == null ? 1 : 0 - source = "git::https://github.ibm.com/GoldenEye/secrets-manager-iam-engine-module.git?ref=2.0.6" - region = local.sm_region - secrets_manager_guid = ibm_resource_instance.secrets_manager[0].guid - create_iam_user_policy = false - iam_secret_generator_service_id_name = "${var.prefix}-sid:0.0.1:${ibm_resource_instance.secrets_manager[0].name}-iam-secret-generator:automated:simple-service:secret-manager:" - iam_secret_generator_apikey_name = "${var.prefix}-iam-secret-generator-apikey" - new_secret_group_name = "${var.prefix}-account-secret-group" - iam_secret_generator_apikey_secret_name = "${var.prefix}-iam-secret-generator-apikey-secret" - iam_engine_name = "iam-engine" -} - -# Creates secret group to place secrets -module "secrets_manager_group" { - source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" - version = "1.1.4" - # source = "git::https://github.ibm.com/GoldenEye/secrets-manager-secret-group-module.git?ref=2.0.1" - region = local.sm_region - secrets_manager_guid = local.sm_guid - secret_group_name = "${var.prefix}-secret-group" #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value - secret_group_description = "Secret-Group for storing account credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure -} - -# Additional Secrets-Manager Secret-Group for SERVICE level secrets -module "secrets_manager_group_acct" { - source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" - version = "1.1.4" - count = var.existing_sm_instance_guid == null ? 0 : 1 - # source = "git::https://github.ibm.com/GoldenEye/secrets-manager-secret-group-module.git?ref=2.0.1" - region = local.sm_region - secrets_manager_guid = local.sm_guid - #tfsec:ignore:general-secrets-no-plaintext-exposure - secret_group_name = "${var.prefix}-account-secret-group" #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value - secret_group_description = "Secret-Group for storing account credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure - depends_on = [module.iam_secrets_engine] -} - -################################################################## -# Create service-id, policy to pull secrets from secret manager -################################################################## - -# Create service-id -resource "ibm_iam_service_id" "secret_puller" { - name = "sid:0.0.1:${var.prefix}-secret-puller:automated:simple-service:secret-manager:" - description = "ServiceID that can pull secrets from Secret Manager" -} -# Create policy to allow new service id to pull secrets from secrets manager -resource "ibm_iam_service_policy" "secret_puller_policy" { - iam_service_id = ibm_iam_service_id.secret_puller.id - roles = ["Viewer", "SecretsReader"] - - resources { - service = "secrets-manager" - resource_instance_id = local.sm_guid - resource_type = "secret-group" - resource = module.secrets_manager_group.secret_group_id - } -} - -################################################################## -# Artifactory-registry -################################################################## - -# Creates username_password secrets and stores in secret manager -module "sm_up_artifactory_secret" { - source = "git::https://github.ibm.com/GoldenEye/secrets-manager-secret-module.git?ref=3.1.1" - region = local.sm_region - secrets_manager_guid = local.sm_guid - secret_group_id = module.secrets_manager_group.secret_group_id - #tfsec:ignore:general-secrets-no-plaintext-exposure - secret_name = "${var.prefix}-artifactory-up-secret" # checkov:skip=CKV_SECRET_6 - secret_description = "example secret in existing secret manager instance" # tfsec:ignore:general-secrets-no-plaintext-exposure # checkov:skip=CKV_SECRET_6 - secret_payload_password = local.artifactory_apikey # pragma: allowlist secret - secret_type = "username_password" #checkov:skip=CKV_SECRET_6 - #tfsec:ignore:general-secrets-no-plaintext-exposure - secret_username = "artifactory-user" # checkov:skip=CKV_SECRET_6: does not require high entropy string as is static value - secret_user_pass_auto_rotation = false -} - -# Installing external secrets operator(ESO), cluster store and deploying external secret as dockerconfigson type -module "eso_operator_clusterstore_deployment" { - source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git?ref=1.7.0" - depends_on = [ - kubernetes_namespace.cluster_namespaces - ] - es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 - sm_secret_type = "username_password" #checkov:skip=CKV_SECRET_6 - sm_secret_id = module.sm_up_artifactory_secret.secret_id - eso_setup = true - es_kubernetes_namespaces = [var.es_kubernetes_namespaces[0]] - eso_generic_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key # pragma: allowlist secret - secrets_manager_guid = local.sm_guid - eso_generic_secret_name = "generic-cluster-api-key" #checkov:skip=CKV_SECRET_6 - eso_store_name = "cluster-store" - es_container_registry = "wcp-my-team-docker-local.artifactory.swg-devops.com" - region = local.sm_region - es_kubernetes_secret_name = "dockerconfigjson-uc" #checkov:skip=CKV_SECRET_6 - es_helm_rls_name = "es-docker-uc" - es_store_helm_rls_name = "cluster-store" - eso_authentication = ["api_key"] - -} - -################################################################## -# Cloudant-arbitrary-secret -################################################################## - -############################################################################## -# Basic cloudant instance + database -############################################################################## - -module "cloudant" { - source = "terraform-ibm-modules/cloudant/ibm" - version = "1.1.7" - resource_group_id = module.resource_group.resource_group_id - instance_name = "${var.prefix}-cloudant" - access_tags = [] - region = var.region - tags = var.resource_tags - database_config = [{ - db = "cloudant-db" - partitioned = false - shards = 3 - }] -} - -data "ibm_cloudant" "instance" { - name = module.cloudant.name - resource_group_id = module.resource_group.resource_group_id -} - -resource "ibm_resource_key" "resource_key" { - name = "cd-resource-key" - role = "Manager" - resource_instance_id = data.ibm_cloudant.instance.id - timeouts { - create = "15m" - delete = "15m" - } -} - -# Creates arbitrary secret and stores in secret manager -module "sm_arbitrary_cloudant_secret" { - source = "git::https://github.ibm.com/GoldenEye/secrets-manager-secret-module.git?ref=3.1.1" - region = local.sm_region - secrets_manager_guid = local.sm_guid - secret_group_id = module.secrets_manager_group.secret_group_id - secret_type = "arbitrary" - #tfsec:ignore:general-secrets-no-plaintext-exposure - secret_name = "${var.prefix}-cloudant-rk-secret" #checkov:skip=CKV_SECRET_6 - secret_description = "example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure - secret_payload_password = ibm_resource_key.resource_key.credentials["apikey"] -} - -# Deploying external secret as Opaque type using existing cluster store -module "eso_clusterstore_externalsecret_opaque_create" { - depends_on = [ - module.eso_operator_clusterstore_deployment, - kubernetes_namespace.cluster_namespaces - ] - source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git?ref=1.7.0" - es_kubernetes_secret_type = "opaque" - sm_secret_type = "arbitrary" - sm_secret_id = module.sm_arbitrary_cloudant_secret.secret_id - eso_setup = false - eso_store_setup = false - es_kubernetes_namespaces = [var.es_kubernetes_namespaces[1]] - eso_generic_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key # pragma: allowlist secret - eso_store_name = "cluster-store" - secrets_manager_guid = local.sm_guid - region = local.sm_region - es_kubernetes_secret_data_key = "apikey" - es_kubernetes_secret_name = "cloudant-opaque-arb" #checkov:skip=CKV_SECRET_6 - es_helm_rls_name = "es-cloudant-arb" - eso_authentication = ["api_key"] -} - -################################################################## -# cr-registry-arbitrary-secret -################################################################## - -# Creates arbitrary secret and stores in secret manager -module "sm_arbitrary_imagepull_secret" { - source = "git::https://github.ibm.com/GoldenEye/secrets-manager-secret-module.git?ref=3.1.1" - region = local.sm_region - secrets_manager_guid = local.sm_guid - secret_group_id = module.secrets_manager_group.secret_group_id - secret_type = "arbitrary" - #tfsec:ignore:general-secrets-no-plaintext-exposure - secret_name = "${var.prefix}-imagepull-apikey-secret" #checkov:skip=CKV_SECRET_6 - secret_description = "example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure - secret_payload_password = local.imagepull_apikey # pragma: allowlist secret -} - -# Deploying external secret as dockerconfigson type using new namespace store -module "eso_secretstore_create_externalsecret_arbitrary_create" { - depends_on = [ - module.eso_operator_clusterstore_deployment, - kubernetes_namespace.cluster_namespaces - ] - source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git?ref=1.7.0" - es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 - sm_secret_type = "arbitrary" - sm_secret_id = module.sm_arbitrary_imagepull_secret.secret_id - eso_setup = false - eso_store_setup = true - eso_store_scope = "namespace" - es_kubernetes_namespaces = [var.es_kubernetes_namespaces[2]] - es_container_registry_email = "terraform@ibm.com" - eso_generic_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key # pragma: allowlist secret - eso_generic_secret_name = "generic-${var.es_kubernetes_namespaces[2]}-api-key" - eso_store_name = "${var.es_kubernetes_namespaces[2]}-store" - secrets_manager_guid = local.sm_guid - region = local.sm_region - es_kubernetes_secret_name = "dockerconfigjson-arb" #checkov:skip=CKV_SECRET_6 - es_helm_rls_name = "es-docker-arb" - es_store_helm_rls_name = "store" - eso_authentication = ["api_key"] - -} - -################################################################## -# cr-registry-same-account -################################################################## - -# Create dynamic Service ID API key and add to secret manager -module "dynamic_serviceid_apikey1" { - source = "git::https://github.ibm.com/GoldenEye/iam-serviceid-apikey-secrets-manager-module.git?ref=2.0.2" - region = local.sm_region - #tfsec:ignore:general-secrets-no-plaintext-exposure - sm_iam_secret_name = "${var.prefix}-${var.sm_iam_secret_name}" - sm_iam_secret_description = "Example of dynamic IAM secret / apikey" #tfsec:ignore:general-secrets-no-plaintext-exposure - serviceid_id = ibm_iam_service_id.secret_puller.id - secrets_manager_guid = local.sm_guid - secret_group_id = local.sm_acct_id - depends_on = [module.iam_secrets_engine, ibm_iam_service_policy.secret_puller_policy, ibm_iam_service_id.secret_puller] -} - -# Creates image pull secrets and stores in secret manager -module "image_pull" { - source = "git::https://github.ibm.com/GoldenEye/imagepull-apikey-secrets-manager-module.git?ref=1.1.2" - resource_group_id = module.resource_group.resource_group_id - secrets_manager_guid = local.sm_guid - cr_namespace_name = var.cr_namespace_name - region = local.sm_region - #tfsec:ignore:general-secrets-no-plaintext-exposure - service_id_secret_name = "${var.prefix}-image-pull-service-id" - service_id_secret_group_id = module.secrets_manager_group.secret_group_id - depends_on = [module.iam_secrets_engine, module.secrets_manager_group] -} - -# Data source to get API Key from secret manager secret-puller-secret -data "ibm_sm_iam_credentials_secret" "secret_puller_secret" { - instance_id = local.sm_guid - #checkov:skip=CKV_SECRET_6: does not require high entropy string as is static type - secret_id = module.dynamic_serviceid_apikey1.secret_id -} - -# Deploying external secret as dockerconfigson type (from image pull IAM dynamic credential/secret) using new namespace store -module "eso_secretstore_create_externalsecret_iamcredentials_create" { - depends_on = [ - module.eso_operator_clusterstore_deployment, - kubernetes_namespace.cluster_namespaces - ] - source = "git::https://github.ibm.com/GoldenEye/external-secrets-operator-module.git?ref=1.7.0" - es_kubernetes_secret_type = "dockerconfigjson" #checkov:skip=CKV_SECRET_6 - sm_secret_type = "iam_credentials" #tfsec:ignore:general-secrets-no-plaintext-exposure - sm_secret_id = module.image_pull.serviceid_apikey_secret_id - es_kubernetes_namespaces = [var.es_kubernetes_namespaces[3]] - eso_setup = false - eso_store_setup = true - eso_store_scope = "namespace" - es_container_registry_email = "terraform@ibm.com" - es_refresh_interval = var.es_refresh_interval - eso_generic_secret_apikey = data.ibm_sm_iam_credentials_secret.secret_puller_secret.api_key # pragma: allowlist secret tfsec:ignore:general-secrets-no-plaintext-exposure - eso_generic_secret_name = "generic-${var.es_kubernetes_namespaces[3]}-api-key" - eso_store_name = "${var.es_kubernetes_namespaces[3]}-store" - secrets_manager_guid = local.sm_guid - region = local.sm_region - es_kubernetes_secret_name = "dockerconfigjson-iam" #tfsec:ignore:general-secrets-no-plaintext-exposure #checkov:skip=CKV_SECRET_6 - es_helm_rls_name = "es-docker-iam" - es_store_helm_rls_name = "store" - eso_authentication = ["api_key"] -} diff --git a/docs/upgradeplanexamples/moved.tf.new b/docs/upgradeplanexamples/moved.tf.new deleted file mode 100644 index e61a540b..00000000 --- a/docs/upgradeplanexamples/moved.tf.new +++ /dev/null @@ -1,54 +0,0 @@ -moved { - from = module.eso_clusterstore_externalsecret_opaque_create.helm_release.kubernetes_secret[0] - to = module.external_secret_opaque_arbitrary_deployment.helm_release.kubernetes_secret[0] -} - -moved { - from = module.eso_secretstore_create_externalsecret_arbitrary_create.helm_release.external_secret_store[0] - to = module.eso_namespacedstore_apikeyauth_dockerconfigson_deployment.helm_release.external_secret_store_apikey[0] -} - -moved { - from = module.eso_operator_clusterstore_deployment.helm_release.external_clstr_secret_store[0] - to = module.eso_clusterstore_deployment.helm_release.cluster_secret_store_apikey[0] -} - -moved { - from = module.eso_operator_clusterstore_deployment.kubernetes_secret.eso_generic_secret[0] - to = module.eso_clusterstore_deployment.kubernetes_secret.eso_clusterstore_secret[0] -} - -moved { - from = module.eso_secretstore_create_externalsecret_arbitrary_create.kubernetes_secret.eso_generic_secret[0] - to = module.eso_namespacedstore_apikeyauth_dockerconfigson_deployment.kubernetes_secret.eso_secretsstore_secret[0] -} - -moved { - from = module.eso_secretstore_create_externalsecret_iamcredentials_create.kubernetes_secret.eso_generic_secret[0] - to = module.eso_namespacedstore_apikeyauth_iamcredentials_deployment.kubernetes_secret.eso_secretsstore_secret[0] -} - -moved { - from = module.eso_secretstore_create_externalsecret_iamcredentials_create.helm_release.external_secret_store[0] - to = module.eso_namespacedstore_apikeyauth_iamcredentials_deployment.helm_release.external_secret_store_apikey[0] -} - -moved { - from = module.eso_secretstore_create_externalsecret_iamcredentials_create.helm_release.kubernetes_secret[0] - to = module.external_secret_dockerconfigson_iamcredentials_deployment.helm_release.kubernetes_secret[0] -} - -moved { - from = module.eso_secretstore_create_externalsecret_arbitrary_create.helm_release.kubernetes_secret[0] - to = module.external_secret_dockerconfigson_arbitrary_deployment.helm_release.kubernetes_secret[0] -} - -moved { - from = module.eso_operator_clusterstore_deployment.helm_release.kubernetes_secret_user_pw[0] - to = module.external_secret_dockerconfigson_usr_pass_deployment.helm_release.kubernetes_secret_user_pw[0] -} - -moved { - from = module.eso_operator_clusterstore_deployment.helm_release.external_secrets_operator[0] - to = module.eso_operator_deployment.helm_release.external_secrets_operator -} diff --git a/docs/upgradeplanexamples/variables.tf.new b/docs/upgradeplanexamples/variables.tf.new deleted file mode 100644 index 1d75764e..00000000 --- a/docs/upgradeplanexamples/variables.tf.new +++ /dev/null @@ -1,98 +0,0 @@ -####################################################################### -# Generic -####################################################################### - -variable "prefix" { - description = "Prefix for name of all resource created by this example" - type = string - default = "eso-example" -} - -variable "region" { - type = string - description = "Region where resources will be created" - default = "us-south" -} - -variable "ibmcloud_api_key" { - type = string - description = "APIkey that's associated with the account to use, set via environment variable TF_VAR_ibmcloud_api_key or .tfvars file." - sensitive = true -} - -variable "resource_group" { - type = string - description = "An existing resource group name to use for this example, if unset a new resource group will be created" - default = null -} - -# tflint-ignore: terraform_unused_declarations -variable "resource_tags" { - type = list(string) - description = "Optional list of tags to be added to created resources" - default = [] -} - -## Image-pull module -variable "sm_iam_secret_name" { - type = string - description = "Name of SM IAM secret (dynamic ServiceID API Key) to be created" - default = "sm-iam-secret-puller" #tfsec:ignore:general-secrets-no-plaintext-exposure -} - -variable "sm_service_plan" { - type = string - description = "Secrets-Manager trial plan" - default = "trial" -} -variable "cr_namespace_name" { - type = string - description = "Container registry namespace name to be configured in IAM policy." - default = "cr-namespace" -} - - -## ESO Module -variable "es_kubernetes_namespaces" { - type = list(string) - description = "Namespace(s) where Kubernetes secrets will be installed/required." - default = ["namespace-1", "namespace-2", "namespace-3", "namespace-4"] -} -variable "es_refresh_interval" { - description = "Specify interval for es secret synchronization" - default = "1h" - type = string -} - -variable "existing_sm_instance_guid" { - type = string - description = "Existing Secrets Manager GUID. If not provided a new instance will be provisioned" - default = null -} - -variable "existing_sm_instance_region" { - type = string - description = "Existing Secrets Manager Region. Required if value is passed into var.existing_instance_guid" - default = null -} - -### new variables - -# as now already exists -variable "existing_eso_namespace" { - type = string - description = "Namespace to deploy the External secrets Operator into" - default = "external-secrets-operator" -} - -variable "service_endpoints" { - type = string - description = "The service endpoint type to communicate with the provided secrets manager instance. Possible values are `public` or `private`. This also will set the iam endpoint for containerAuth when enabling Trusted Profile/CR based authentication." - default = "public" -} - -variable "eso_deployment_nodes_configuration" { - type = string - description = "Configuration to deploy ESO on specific cluster nodes. The value of this variable will be used for NodeSelector label value and tolerations configuration. If null standard ESO deployment is done." - default = "edge" -} diff --git a/docs/upgradeplanexamples/variables.tf.old b/docs/upgradeplanexamples/variables.tf.old deleted file mode 100644 index a2032a70..00000000 --- a/docs/upgradeplanexamples/variables.tf.old +++ /dev/null @@ -1,77 +0,0 @@ -####################################################################### -# Generic -####################################################################### - -variable "prefix" { - description = "Prefix for name of all resource created by this example" - type = string - default = "eso-example" -} - -variable "region" { - type = string - description = "Region where resources will be created" - default = "us-south" -} - -variable "ibmcloud_api_key" { - type = string - description = "APIkey that's associated with the account to use, set via environment variable TF_VAR_ibmcloud_api_key or .tfvars file." - sensitive = true -} - -variable "resource_group" { - type = string - description = "An existing resource group name to use for this example, if unset a new resource group will be created" - default = null -} - -# tflint-ignore: terraform_unused_declarations -variable "resource_tags" { - type = list(string) - description = "Optional list of tags to be added to created resources" - default = [] -} - -## Image-pull module -variable "sm_iam_secret_name" { - type = string - description = "Name of SM IAM secret (dynamic ServiceID API Key) to be created" - default = "sm-iam-secret-puller" #tfsec:ignore:general-secrets-no-plaintext-exposure -} - -variable "sm_service_plan" { - type = string - description = "Secrets-Manager trial plan" - default = "trial" -} -variable "cr_namespace_name" { - type = string - description = "Container registry namespace name to be configured in IAM policy." - default = "cr-namespace" -} - - -## ESO Module -variable "es_kubernetes_namespaces" { - type = list(string) - description = "Namespace(s) where Kubernetes secrets will be installed/required." - default = ["namespace-1", "namespace-2", "namespace-3", "namespace-4"] -} -variable "es_refresh_interval" { - description = "Specify interval for es secret synchronization" - default = "1h" - type = string -} - -variable "existing_sm_instance_guid" { - type = string - description = "Existing Secrets Manager GUID. If not provided a new instance will be provisioned" - default = null -} - -variable "existing_sm_instance_region" { - type = string - description = "Existing Secrets Manager Region. Required if value is passed into var.existing_instance_guid" - default = null -} diff --git a/examples/all-combined/README.md b/examples/all-combined/README.md index d16cd119..8b914d13 100644 --- a/examples/all-combined/README.md +++ b/examples/all-combined/README.md @@ -2,7 +2,7 @@ This end-to-end example performs the following actions - Loads an existing resource group or creates a new one -- Provisions a standard GoldenEye OCP infrastructure with VPC, COS instance and an OpenShift cluster +- Provisions a OCP infrastructure with VPC, COS instance and an OpenShift cluster - Configures an hybrid ESO configuration with a set of different stores to cover use-cases - a ClusterSecretStore with API key authentication - a ClusterSecretStore with Trusted profile authentication @@ -22,11 +22,6 @@ This end-to-end example performs the following actions - Deploys another dockerconfigjson secret for an artifactory registry - Deploys external secrets in designated namespace - Creates a ClusterSecretStore using Trusted Profile authentication to access secrets from designated namespace - - Deploys an opaque secret for Cloudant credentials (temporary disabled due to issue https://github.ibm.com/GoldenEye/issues/issues/7726) - - Creates Cloudant instance and resource key - - Creates arbitrary Secrets Manager secret to store resource key - - Deploys external secrets in designated namespace - - Uses existing ClusterSecretStore to access secrets from designated namespace - Deploys a dockerconfigjson secret from an arbitrary secret to authenticate in container registry - Creates arbitrary Secrets Manager secret to store existing API key - Deploys external secrets in designated namespaces @@ -70,7 +65,7 @@ In the case all the mentioned parameters are left with their default **null** va The example is split into separated templates related with their specific scope: - main.tf for the VPC, cluster, VPE, ESO operator deployment and namespaces preliminary creation - clusterstore.tf for ESO ClusterSecretsStore configuration with API key authentication, including two different externalsecrets and secret types configuration (username/password and arbitrary) -- secretstore.tf for ESO secretstore configuration with API key authentication and namespace isolation, including two different externalsecrets and secrets configuration (arbitrary and image pull API key secret using imagepull-apikey-secrets-manager-module) +- secretstore.tf for ESO secretstore configuration with API key authentication and namespace isolation, including two different externalsecrets and secrets configuration (arbitrary and image pull API key secret using imagepull-apikey-secrets-manager) - secretsmanager.tf for Secrets Manager instance configuration, along with IAM serviceID and API keys and secrets groups - kv.tf for key-value (single and multiple keys) secrets - publiccertificate.tf for public certificate management @@ -82,6 +77,6 @@ The example is split into separated templates related with their specific scope: ## Important note about input region and existing SecretManager region parameters -Due to the https://github.ibm.com/GoldenEye/issues/issues/5268 the test is currently using the existing SecretManager region to deploy the VPC and the cluster if this value is not null. Instead if null it follows what set through `var.region` +The test is currently using the existing SecretManager region to deploy the VPC and the cluster if this value is not null. Instead if null it follows what set through `var.region` This logic is achieved through the local `sm_region` variable that is then used to create resources. diff --git a/examples/all-combined/clusterstore.tf b/examples/all-combined/clusterstore.tf index 07b2367c..93ec421e 100644 --- a/examples/all-combined/clusterstore.tf +++ b/examples/all-combined/clusterstore.tf @@ -75,80 +75,3 @@ module "external_secret_usr_pass" { es_kubernetes_secret_name = "dockerconfigjson-uc" #checkov:skip=CKV_SECRET_6 es_helm_rls_name = "es-docker-uc" } - -### temporary disabled the test on the Cloudant resource key blocking the tests because of potential issue with Cloudant instance creation -### https://github.ibm.com/GoldenEye/issues/issues/7726 - -################################################################## -# creation of arbitrary secret to store Cloudant resource key -# A Cloudant instance is created in advance to create its resource key -################################################################## - -############################################################################## -# Basic cloudant instance + database -############################################################################## - -# module "cloudant" { -# source = "terraform-ibm-modules/cloudant/ibm" -# version = "1.1.7" -# resource_group_id = module.resource_group.resource_group_id -# instance_name = "${var.prefix}-cloudant" -# access_tags = [] -# region = var.region -# tags = var.resource_tags -# plan = "lite" -# database_config = [] -# } - -# # load cloudant instance details when ready -# data "ibm_cloudant" "instance" { -# # forcing on depend instead of id because it triggers a validation error -# depends_on = [module.cloudant] -# # id = module.cloudant.instance_id -# name = module.cloudant.instance_name -# resource_group_id = module.resource_group.resource_group_id -# } - -# # create resource key for cloudant instance -# resource "ibm_resource_key" "resource_key" { -# name = "cd-resource-key" -# role = "Manager" -# resource_instance_id = data.ibm_cloudant.instance.id -# timeouts { -# create = "15m" -# delete = "15m" -# } -# } - -# # Creates the arbitrary secret to store the cloudant resource key in secrets manager -# module "sm_arbitrary_cloudant_secret" { -# source = "terraform-ibm-modules/secrets-manager-secret/ibm" -# version = "1.1.1" -# region = local.sm_region -# secrets_manager_guid = local.sm_guid -# secret_group_id = module.secrets_manager_group.secret_group_id -# secret_type = "arbitrary" -# #tfsec:ignore:general-secrets-no-plaintext-exposure -# secret_name = "${var.prefix}-cloudant-rk-secret" #checkov:skip=CKV_SECRET_6 -# secret_description = "example secret in existing secret manager instance" #tfsec:ignore:general-secrets-no-plaintext-exposure -# secret_payload_password = ibm_resource_key.resource_key.credentials["apikey"] -# providers = { -# ibm = ibm.ibm-sm -# } -# } - -# # ESO externalsecret with cluster scope creating opaque type secret -# module "external_secret_arbitrary_cloudant" { -# depends_on = [module.eso_clusterstore] -# source = "../../modules/eso-external-secret" -# eso_store_scope = "cluster" -# es_kubernetes_secret_type = "opaque" -# sm_secret_type = "arbitrary" -# sm_secret_id = module.sm_arbitrary_cloudant_secret.secret_id -# es_kubernetes_namespace = kubernetes_namespace.apikey_namespaces[1].metadata[0].name -# eso_store_name = "cluster-store" -# es_refresh_interval = "5m" -# es_kubernetes_secret_data_key = "apikey" -# es_kubernetes_secret_name = "cloudant-opaque-arb" #checkov:skip=CKV_SECRET_6 -# es_helm_rls_name = "es-cloudant-arb" -# } diff --git a/examples/all-combined/main.tf b/examples/all-combined/main.tf index d0ad4b34..2b4c7cbc 100644 --- a/examples/all-combined/main.tf +++ b/examples/all-combined/main.tf @@ -78,7 +78,8 @@ module "zone_subnet_addrs" { } module "vpc" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git?ref=v1.5.0" + source = "terraform-ibm-modules/vpc/ibm" + version = "1.5.0" vpc_name = "${var.prefix}-vpc" resource_group_id = module.resource_group.resource_group_id locations = [] @@ -94,7 +95,8 @@ module "vpc" { } module "subnet_prefix" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/vpc-address-prefix?ref=v1.5.0" + source = "terraform-ibm-modules/vpc/ibm//modules/vpc-address-prefix" + version = "1.5.0" count = length(local.subnet_prefix) name = "${var.prefix}-z-${local.subnet_prefix[count.index].label}-${split("-", local.subnet_prefix[count.index].zone)[2]}" location = local.subnet_prefix[count.index].zone @@ -105,7 +107,8 @@ module "subnet_prefix" { module "subnets" { depends_on = [module.subnet_prefix] - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/subnet?ref=v1.5.0" + source = "terraform-ibm-modules/vpc/ibm//modules/subnet" + version = "1.5.0" count = length(local.subnet_prefix) location = local.subnet_prefix[count.index].zone vpc_id = module.vpc.vpc.vpc_id @@ -116,7 +119,8 @@ module "subnets" { } module "public_gateways" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/public-gateway?ref=v1.5.0" + source = "terraform-ibm-modules/vpc/ibm//modules/public-gateway" + version = "1.5.0" count = length(var.zones) vpc_id = module.vpc.vpc.vpc_id location = "${var.region}-${var.zones[count.index]}" @@ -125,7 +129,8 @@ module "public_gateways" { } module "security_group" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/security-group?ref=v1.5.0" + source = "terraform-ibm-modules/vpc/ibm//modules/security-group" + version = "1.5.0" depends_on = [module.vpc] create_security_group = false resource_group_id = module.resource_group.resource_group_id @@ -170,7 +175,8 @@ locals { } module "network_acl" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/network-acl?ref=v1.5.0" + source = "terraform-ibm-modules/vpc/ibm//modules/network-acl" + version = "1.5.0" name = "${var.prefix}-vpc-acl" vpc_id = module.vpc.vpc.vpc_id resource_group_id = module.resource_group.resource_group_id diff --git a/examples/all-combined/privatecertificate.tf b/examples/all-combined/privatecertificate.tf index e092408d..47bbad6f 100644 --- a/examples/all-combined/privatecertificate.tf +++ b/examples/all-combined/privatecertificate.tf @@ -4,8 +4,8 @@ # private certificate common name, Certificate Authority common name and certificate template name definition locals { - pvt_cert_common_name = var.pvt_cert_common_name == null ? "pvt-${var.prefix}.goldeneye.dev.cloud.ibm.com" : var.pvt_cert_common_name - pvt_root_ca_common_name = var.pvt_root_ca_common_name == null ? "pvt-${var.prefix}.goldeneye.dev.cloud.ibm.com" : var.pvt_root_ca_common_name + pvt_cert_common_name = var.pvt_cert_common_name == null ? "pvt-${var.prefix}.example.dev.cloud.cloud_provider.com" : var.pvt_cert_common_name + pvt_root_ca_common_name = var.pvt_root_ca_common_name == null ? "pvt-${var.prefix}.example.dev.cloud.cloud_provider.com" : var.pvt_root_ca_common_name pvt_certificate_template_name = var.pvt_certificate_template_name != null ? var.pvt_certificate_template_name : "pvt-${var.prefix}-cert-template" } @@ -15,10 +15,10 @@ module "secrets_manager_private_secret_engine" { version = "1.3.5" secrets_manager_guid = local.sm_guid region = local.sm_region - root_ca_name = var.pvt_ca_name != null ? var.pvt_ca_name : "pvt-${var.prefix}-goldeneye-root-ca" + root_ca_name = var.pvt_ca_name != null ? var.pvt_ca_name : "pvt-${var.prefix}-project-root-ca" root_ca_common_name = local.pvt_root_ca_common_name root_ca_max_ttl = var.pvt_ca_max_ttl - intermediate_ca_name = "pvt-${var.prefix}-goldeneye-intermediate-ca" + intermediate_ca_name = "pvt-${var.prefix}-project-intermediate-ca" certificate_template_name = local.pvt_certificate_template_name providers = { ibm = ibm.ibm-sm diff --git a/examples/all-combined/publiccertificate.tf b/examples/all-combined/publiccertificate.tf index 789289c3..217e47b4 100644 --- a/examples/all-combined/publiccertificate.tf +++ b/examples/all-combined/publiccertificate.tf @@ -12,8 +12,8 @@ module "secrets_manager_public_cert_engine" { secrets_manager_guid = local.sm_guid region = local.sm_region internet_services_crn = data.ibm_cis.cis_instance.id - ca_config_name = var.ca_name != null ? var.ca_name : "${var.prefix}-goldeneye-ca" - dns_config_name = var.dns_provider_name != null ? var.dns_provider_name : "${var.prefix}-goldeneye-dns" + ca_config_name = var.ca_name != null ? var.ca_name : "${var.prefix}-project-ca" + dns_config_name = var.dns_provider_name != null ? var.dns_provider_name : "${var.prefix}-project-dns" private_key_secrets_manager_instance_guid = var.acme_letsencrypt_private_key_sm_id private_key_secrets_manager_secret_id = var.acme_letsencrypt_private_key_secret_id private_key_secrets_manager_region = var.acme_letsencrypt_private_key_sm_region @@ -27,7 +27,7 @@ module "secrets_manager_public_cert_engine" { # public certificate common name definition locals { - cert_common_name = var.cert_common_name == null ? "${var.prefix}-2.goldeneye.dev.cloud.ibm.com" : var.cert_common_name + cert_common_name = var.cert_common_name == null ? "${var.prefix}-2.project.dev.cloud.ibm.com" : var.cert_common_name } # public certificate creation @@ -40,8 +40,8 @@ module "secrets_manager_public_certificate" { cert_description = "Certificate for ${local.cert_common_name}" cert_name = "${var.prefix}-sm-public-cert" cert_secrets_group_id = module.secrets_manager_group.secret_group_id - secrets_manager_ca_name = var.ca_name != null ? var.ca_name : "${var.prefix}-goldeneye-ca" - secrets_manager_dns_provider_name = var.dns_provider_name != null ? var.dns_provider_name : "${var.prefix}-goldeneye-dns" + secrets_manager_ca_name = var.ca_name != null ? var.ca_name : "${var.prefix}-project-ca" + secrets_manager_dns_provider_name = var.dns_provider_name != null ? var.dns_provider_name : "${var.prefix}-project-dns" secrets_manager_guid = local.sm_guid secrets_manager_region = local.sm_region bundle_certs = var.public_certificate_bundle diff --git a/examples/all-combined/tpauth_cluster_sstore.tf b/examples/all-combined/tpauth_cluster_sstore.tf index 1b46373d..51b003f9 100644 --- a/examples/all-combined/tpauth_cluster_sstore.tf +++ b/examples/all-combined/tpauth_cluster_sstore.tf @@ -97,6 +97,6 @@ module "cstore_external_secret_tp" { es_refresh_interval = "5m" eso_store_name = local.cstore_store_name # each store created with the name of the namespace with "-store" as suffix es_container_registry = "us.icr.io" - es_container_registry_email = "goldeneye@us.ibm.com" + es_container_registry_email = "user@company.com" es_helm_rls_name = "es-tp" } diff --git a/examples/all-combined/tpauth_namespaced_sstore.tf b/examples/all-combined/tpauth_namespaced_sstore.tf index 7d95ccc2..0f52f9aa 100644 --- a/examples/all-combined/tpauth_namespaced_sstore.tf +++ b/examples/all-combined/tpauth_namespaced_sstore.tf @@ -98,7 +98,7 @@ module "external_secret_tp" { es_refresh_interval = "5m" eso_store_name = "${var.es_namespaces_tp[count.index]}-store" # each store created with the name of the namespace with "-store" as suffix es_container_registry = "us.icr.io" - es_container_registry_email = "goldeneye@us.ibm.com" + es_container_registry_email = "user@company.com" es_helm_rls_name = "es-tp" } @@ -223,7 +223,7 @@ module "external_secret_tp_multisg_1" { es_refresh_interval = "5m" eso_store_name = "${var.es_namespace_tp_multi_sg}-store" # each store created with the name of the namespace with "-store" as suffix es_container_registry = "us.icr.io" - es_container_registry_email = "goldeneye@us.ibm.com" + es_container_registry_email = "user@company.com" es_helm_rls_name = "es-tp-multisg-1" } @@ -243,7 +243,7 @@ module "external_secret_tp_multisg_2" { es_refresh_interval = "5m" eso_store_name = "${var.es_namespace_tp_multi_sg}-store" # each store created with the name of the namespace with "-store" as suffix es_container_registry = "us.icr.io" - es_container_registry_email = "goldeneye@us.ibm.com" + es_container_registry_email = "user@company.com" es_helm_rls_name = "es-tp-multisg-2" } @@ -339,6 +339,6 @@ module "external_secret_tp_nosg" { es_refresh_interval = "5m" eso_store_name = "${var.es_namespace_tp_no_sg}-store" # each store created with the name of the namespace with "-store" as suffix es_container_registry = "us.icr.io" - es_container_registry_email = "goldeneye@us.ibm.com" + es_container_registry_email = "user@company.com" es_helm_rls_name = "es-tp-nosg" } diff --git a/examples/all-combined/variables.tf b/examples/all-combined/variables.tf index 37dd36c9..80bf64f2 100644 --- a/examples/all-combined/variables.tf +++ b/examples/all-combined/variables.tf @@ -235,20 +235,20 @@ variable "skip_iam_authorization_policy" { } variable "cert_common_name" { - description = "Public certificate common name. If null it will be set to [prefix value].goldeneye.dev.cloud.ibm.com" + description = "Public certificate common name. If null it will be set to [prefix value].project.dev.cloud.ibm.com" type = string default = null } variable "ca_name" { type = string - description = "Secret Managers certificate authority name. If null it will be set to [prefix value]-goldeneye-ca" + description = "Secret Managers certificate authority name. If null it will be set to [prefix value]-project-ca" default = null } variable "dns_provider_name" { type = string - description = "Secret Managers DNS provider name. If null it will be set to [prefix value]-goldeneye-dns" + description = "Secret Managers DNS provider name. If null it will be set to [prefix value]-project-dns" default = null } @@ -327,20 +327,20 @@ variable "existing_cis_instance_resource_group_id" { ### private certificate secret configuration variable "pvt_cert_common_name" { - description = "Private certificate common name. If null it will be set to pvt-[prefix value].goldeneye.dev.cloud.ibm.com" + description = "Private certificate common name. If null it will be set to pvt-[prefix value].project.dev.cloud.ibm.com" type = string default = null } variable "pvt_ca_name" { type = string - description = "Secret Managers certificate authority name. If null it will be set to pvt-[prefix value]-goldeneye-ca" + description = "Secret Managers certificate authority name. If null it will be set to pvt-[prefix value]-project-ca" default = null } variable "pvt_root_ca_common_name" { type = string - description = "Root CA common name for the private certificate. If null it will be set to pvt-[prefix value].goldeneye.dev.cloud.ibm.com" + description = "Root CA common name for the private certificate. If null it will be set to pvt-[prefix value].project.dev.cloud.ibm.com" default = null } diff --git a/examples/basic/README.md b/examples/basic/README.md index 504f852c..23cd7bec 100644 --- a/examples/basic/README.md +++ b/examples/basic/README.md @@ -8,7 +8,7 @@ This module provides a basic example to deploy the External Secrets Operator alo - **VPC and Subnet Configuration**: Establishes a Virtual Private Cloud (VPC) with associated subnets, setting up network segmentation and ACL rules. -- **OpenShift Cluster Provisioning**: Deploys an OpenShift (OCP) cluster, tailored for a cloud-native architecture with worker pools for private, transit, and edge network segments. +- **OpenShift Cluster Provisioning**: Deploys an OpenShift (OCP) cluster, tailored for a cloud-native architecture with default worker pools . - **Secrets Manager Integration**: - Either utilizes an existing Secrets Manager instance or creates a new one. diff --git a/examples/basic/main.tf b/examples/basic/main.tf index 3c4aa319..6f6e4cf7 100644 --- a/examples/basic/main.tf +++ b/examples/basic/main.tf @@ -101,7 +101,8 @@ module "zone_subnet_addrs" { } module "vpc" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git?ref=v1.5.0" + source = "terraform-ibm-modules/vpc/ibm" + version = "1.5.0" vpc_name = "${var.prefix}-vpc" resource_group_id = module.resource_group.resource_group_id locations = [] @@ -117,7 +118,8 @@ module "vpc" { } module "subnet_prefix" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/vpc-address-prefix?ref=v1.5.0" + source = "terraform-ibm-modules/vpc/ibm//modules/vpc-address-prefix" + version = "1.5.0" count = length(local.subnet_prefix) name = "${var.prefix}-z-${local.subnet_prefix[count.index].label}-${split("-", local.subnet_prefix[count.index].zone)[2]}" location = local.subnet_prefix[count.index].zone @@ -128,7 +130,8 @@ module "subnet_prefix" { module "subnets" { depends_on = [module.subnet_prefix] - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/subnet?ref=v1.5.0" + source = "terraform-ibm-modules/vpc/ibm//modules/subnet" + version = "1.5.0" count = length(local.subnet_prefix) location = local.subnet_prefix[count.index].zone vpc_id = module.vpc.vpc.vpc_id @@ -139,7 +142,8 @@ module "subnets" { } module "public_gateways" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/public-gateway?ref=v1.5.0" + source = "terraform-ibm-modules/vpc/ibm//modules/public-gateway" + version = "1.5.0" count = length(var.zones) vpc_id = module.vpc.vpc.vpc_id location = "${var.region}-${var.zones[count.index]}" @@ -148,7 +152,8 @@ module "public_gateways" { } module "security_group" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/security-group?ref=v1.5.0" + source = "terraform-ibm-modules/vpc/ibm//modules/security-group" + version = "1.5.0" depends_on = [module.vpc] create_security_group = false resource_group_id = module.resource_group.resource_group_id @@ -193,7 +198,8 @@ locals { } module "network_acl" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-vpc.git//modules/network-acl?ref=v1.5.0" + source = "terraform-ibm-modules/vpc/ibm//modules/network-acl" + version = "1.5.0" name = "${var.prefix}-vpc-acl" vpc_id = module.vpc.vpc.vpc_id resource_group_id = module.resource_group.resource_group_id @@ -427,7 +433,7 @@ module "external_secret_usr_pass" { sm_secret_id = module.sm_userpass_secret.secret_id es_kubernetes_namespace = kubernetes_namespace.apikey_namespace.metadata[0].name eso_store_name = "cluster-store" - es_container_registry = "wcp-my-team-docker-local.artifactory.swg-devops.com" + es_container_registry = "example-registry-local.artifactory.com" es_kubernetes_secret_name = "dockerconfigjson-uc" #checkov:skip=CKV_SECRET_6 es_helm_rls_name = "es-docker-uc" reloader_watching = true diff --git a/examples/trusted-profiles-authentication/main.tf b/examples/trusted-profiles-authentication/main.tf index 452f2808..347c4554 100644 --- a/examples/trusted-profiles-authentication/main.tf +++ b/examples/trusted-profiles-authentication/main.tf @@ -175,7 +175,7 @@ module "external_secrets" { es_refresh_interval = "5m" eso_store_name = "${kubernetes_namespace.examples[count.index].metadata[0].name}-store" # each store created with the name of the namespace with "-store" as suffix es_container_registry = "us.icr.io" - es_container_registry_email = "goldeneye@us.ibm.com" + es_container_registry_email = "user@company.com" es_helm_rls_name = "es-${count.index}" } diff --git a/main.tf b/main.tf index 6a2401c5..fb7c561f 100644 --- a/main.tf +++ b/main.tf @@ -4,25 +4,6 @@ # Module for deploying External Secret Operator (ESO) and use it to create and synchronize Kubernetes secrets into clusters based on Secrets-Manager secrets. ############################################################################## -## Install ESO - -locals { - - default_eso_image_repo = "ghcr.io/external-secrets/external-secrets" - default_eso_image_tag_digest = "v0.12.1-ubi@sha256:d38834043de0a4e4feeac8a08d0bc96b71ddd7fe1d4c8583ee3751badeaeb01d" # datasource: ghcr.io/external-secrets/external-secrets - - - default_reloader_image_repo = "ghcr.io/stakater/reloader" - default_reloader_image_tag_digest = "v1.2.1-ubi@sha256:80a557100c6835c7e3c9842194250c9c4ca78f43200bc3a93a32e5b105ad11bb" # datasource: ghcr.io/stakater/reloader - - # Repo and digest for ESO - eso_image_repo = var.eso_image_repo != null ? var.eso_image_repo : local.default_eso_image_repo - eso_image_tag_digest = var.eso_image_tag_digest != null ? var.eso_image_tag_digest : local.default_eso_image_tag_digest - - # Repo and digest for Reloader - reloader_image_repo = var.reloader_image_repo != null ? var.reloader_image_repo : local.default_reloader_image_repo - reloader_image_tag_digest = var.reloader_image_tag_digest != null ? var.reloader_image_tag_digest : local.default_reloader_image_tag_digest -} # creating namespace to deploy ESO into RedHat ServiceMesh module "eso_namespace" { @@ -187,58 +168,50 @@ certController: EOF } -locals { - eso_chart_location = "https://charts.external-secrets.io" - eso_chart_version = "0.12.1" # datasource: https://charts.external-secrets.io - - reloader_chart_location = "https://stakater.github.io/stakater-charts" - reloader_chart_version = "1.2.0" # datasource: https://stakater.github.io/stakater-charts -} - resource "helm_release" "external_secrets_operator" { depends_on = [module.eso_namespace, data.kubernetes_namespace.existing_eso_namespace] name = "external-secrets" namespace = local.eso_namespace chart = "external-secrets" - version = local.eso_chart_version + version = var.eso_chart_version wait = true - repository = local.eso_chart_location + repository = var.eso_chart_location set { name = "image.repository" type = "string" - value = local.eso_image_repo + value = var.eso_registry_namespace_image } set { name = "image.tag" type = "string" - value = local.eso_image_tag_digest + value = var.eso_image_digest } set { name = "webhook.image.repository" type = "string" - value = local.eso_image_repo + value = var.eso_registry_namespace_image } set { name = "webhook.image.tag" type = "string" - value = local.eso_image_tag_digest + value = var.eso_image_digest } set { name = "certController.image.repository" type = "string" - value = local.eso_image_repo + value = var.eso_registry_namespace_image } set { name = "certController.image.tag" type = "string" - value = local.eso_image_tag_digest + value = var.eso_image_digest } # The following mounts are needed for the CRI based authentication with Trusted Profiles @@ -251,21 +224,21 @@ resource "helm_release" "pod_reloader" { name = "reloader" chart = "reloader" namespace = local.eso_namespace - repository = local.reloader_chart_location - version = local.reloader_chart_version + repository = var.reloader_chart_location + version = var.reloader_chart_version wait = true # Set the deployment image name and tag set { name = "reloader.deployment.image.name" type = "string" - value = local.reloader_image_repo + value = var.reloader_registry_namespace_image } set { name = "reloader.deployment.image.tag" type = "string" - value = local.reloader_image_tag_digest + value = var.reloader_image_digest } # Set reload strategy diff --git a/renovate.json b/renovate.json index 4a3b1242..4eda1200 100644 --- a/renovate.json +++ b/renovate.json @@ -5,7 +5,7 @@ { "fileMatch": ["\\.tf$"], "matchStrings": [ - "[\\w-]+_image_tag_digest\\s*=\\s*\"(?[\\w.-]+)@(?sha256:[a-f0-9]+)\"\\s*# datasource: (?[^\\s]+)" + "[\\w-]+_image_digest\\s*=\\s*\"(?[\\w.-]+)@(?sha256:[a-f0-9]+)\"\\s*# datasource: (?[^\\s]+)" ], "datasourceTemplate": "docker" }, diff --git a/variables.tf b/variables.tf index 13f1d7d2..9547fd72 100644 --- a/variables.tf +++ b/variables.tf @@ -151,16 +151,22 @@ variable "reloader_custom_values" { default = null } -variable "eso_image_repo" { +# image registry and digest + +variable "eso_registry_namespace_image" { type = string description = "The External Secrets Operator image reference in the format of `[registry-url]/[namespace]/[image]`." default = "ghcr.io/external-secrets/external-secrets" } -variable "eso_image_tag_digest" { +variable "eso_image_digest" { type = string - description = "The tag digest of the ESO image to deploy. If not provided, a default value will be used." - default = null + description = "The image digest in the format sha256:xxxxx... for ESO image to deploy. If not provided, a default value will be used." + default = "sha256:d38834043de0a4e4feeac8a08d0bc96b71ddd7fe1d4c8583ee3751badeaeb01d" # datasource: ghcr.io/external-secrets/external-secrets + validation { + condition = var.eso_image_digest == null || can(regex("^sha256:", var.eso_image_digest)) + error_message = "If provided, the value of eso_image_digest must start with 'sha256:'." + } } variable "reloader_registry_namespace_image" { @@ -169,8 +175,38 @@ variable "reloader_registry_namespace_image" { default = "ghcr.io/stakater/reloader" } -variable "reloader_image_tag_digest" { +variable "reloader_image_digest" { type = string - description = "The tag digest of the Reloader image to deploy. If not provided, a default value will be used." - default = null + description = "The image digest in the format sha256:xxxxx... the reloader image to deploy. If not provided, a default value will be used." + default = "sha256:80a557100c6835c7e3c9842194250c9c4ca78f43200bc3a93a32e5b105ad11bb" # datasource: ghcr.io/stakater/reloader + validation { + condition = var.reloader_image_digest == null || can(regex("^sha256:", var.reloader_image_digest)) + error_message = "If provided, the value of reloader_image_digest must start with 'sha256:'." + } +} + +# helms repo and charts + +variable "eso_chart_location" { + type = string + description = "The location of the External Secrets Operator Helm chart." + default = "https://charts.external-secrets.io" +} + +variable "eso_chart_version" { + type = string + description = "The version of the External Secrets Operator Helm chart." + default = "0.12.1" # datasource: https://charts.external-secrets.io +} + +variable "reloader_chart_location" { + type = string + description = "The location of the Reloader Helm chart." + default = "https://stakater.github.io/stakater-charts" +} + +variable "reloader_chart_version" { + type = string + description = "The version of the Reloader Helm chart." + default = "1.2.0" # datasource: https://stakater.github.io/stakater-charts } From 9542709afa892cc15d81fc168c46817413fde02f Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Tue, 4 Feb 2025 11:47:55 +0530 Subject: [PATCH 25/40] resolve review comments --- examples/all-combined/privatecertificate.tf | 4 ++-- examples/all-combined/publiccertificate.tf | 2 +- examples/all-combined/variables.tf | 6 +++--- main.tf | 16 ++++++++++++---- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/examples/all-combined/privatecertificate.tf b/examples/all-combined/privatecertificate.tf index 47bbad6f..25d44e49 100644 --- a/examples/all-combined/privatecertificate.tf +++ b/examples/all-combined/privatecertificate.tf @@ -4,8 +4,8 @@ # private certificate common name, Certificate Authority common name and certificate template name definition locals { - pvt_cert_common_name = var.pvt_cert_common_name == null ? "pvt-${var.prefix}.example.dev.cloud.cloud_provider.com" : var.pvt_cert_common_name - pvt_root_ca_common_name = var.pvt_root_ca_common_name == null ? "pvt-${var.prefix}.example.dev.cloud.cloud_provider.com" : var.pvt_root_ca_common_name + pvt_cert_common_name = var.pvt_cert_common_name == null ? "pvt-${var.prefix}.goldeneye.dev.cloud.ibm.com" : var.pvt_cert_common_name + pvt_root_ca_common_name = var.pvt_root_ca_common_name == null ? "pvt-${var.prefix}.goldeneye.dev.cloud.ibm.com" : var.pvt_root_ca_common_name pvt_certificate_template_name = var.pvt_certificate_template_name != null ? var.pvt_certificate_template_name : "pvt-${var.prefix}-cert-template" } diff --git a/examples/all-combined/publiccertificate.tf b/examples/all-combined/publiccertificate.tf index 217e47b4..44b02f51 100644 --- a/examples/all-combined/publiccertificate.tf +++ b/examples/all-combined/publiccertificate.tf @@ -27,7 +27,7 @@ module "secrets_manager_public_cert_engine" { # public certificate common name definition locals { - cert_common_name = var.cert_common_name == null ? "${var.prefix}-2.project.dev.cloud.ibm.com" : var.cert_common_name + cert_common_name = var.cert_common_name == null ? "${var.prefix}-2.goldeneye.dev.cloud.ibm.com" : var.cert_common_name } # public certificate creation diff --git a/examples/all-combined/variables.tf b/examples/all-combined/variables.tf index 80bf64f2..c59844ed 100644 --- a/examples/all-combined/variables.tf +++ b/examples/all-combined/variables.tf @@ -327,20 +327,20 @@ variable "existing_cis_instance_resource_group_id" { ### private certificate secret configuration variable "pvt_cert_common_name" { - description = "Private certificate common name. If null it will be set to pvt-[prefix value].project.dev.cloud.ibm.com" + description = "Private certificate common name. If null it will be set to pvt-[prefix value].goldeneye.dev.cloud.ibm.com" type = string default = null } variable "pvt_ca_name" { type = string - description = "Secret Managers certificate authority name. If null it will be set to pvt-[prefix value]-project-ca" + description = "Secret Managers certificate authority name. If null it will be set to pvt-[prefix value]-goldeneye-ca" default = null } variable "pvt_root_ca_common_name" { type = string - description = "Root CA common name for the private certificate. If null it will be set to pvt-[prefix value].project.dev.cloud.ibm.com" + description = "Root CA common name for the private certificate. If null it will be set to pvt-[prefix value].goldeneye.dev.cloud.ibm.com" default = null } diff --git a/main.tf b/main.tf index fb7c561f..1636bf4b 100644 --- a/main.tf +++ b/main.tf @@ -168,6 +168,10 @@ certController: EOF } +locals { + eso_image_tag_digest = "v${var.eso_chart_version}-ubi@${var.eso_image_digest}" +} + resource "helm_release" "external_secrets_operator" { depends_on = [module.eso_namespace, data.kubernetes_namespace.existing_eso_namespace] @@ -187,7 +191,7 @@ resource "helm_release" "external_secrets_operator" { set { name = "image.tag" type = "string" - value = var.eso_image_digest + value = local.eso_image_tag_digest } set { @@ -199,7 +203,7 @@ resource "helm_release" "external_secrets_operator" { set { name = "webhook.image.tag" type = "string" - value = var.eso_image_digest + value = local.eso_image_tag_digest } set { @@ -211,13 +215,17 @@ resource "helm_release" "external_secrets_operator" { set { name = "certController.image.tag" type = "string" - value = var.eso_image_digest + value = local.eso_image_tag_digest } # The following mounts are needed for the CRI based authentication with Trusted Profiles values = [local.eso_helm_release_values_cri, local.eso_helm_release_values_workerselector] } +locals { + reloader_image_tag_digest = "v${var.reloader_chart_version}-ubi@${var.reloader_image_digest}" +} + resource "helm_release" "pod_reloader" { depends_on = [module.eso_namespace, data.kubernetes_namespace.existing_eso_namespace] count = var.reloader_deployed == true ? 1 : 0 @@ -238,7 +246,7 @@ resource "helm_release" "pod_reloader" { set { name = "reloader.deployment.image.tag" type = "string" - value = var.reloader_image_digest + value = local.reloader_image_tag_digest } # Set reload strategy From 2e876c9991c675f030513a50ef33e5eac352cf12 Mon Sep 17 00:00:00 2001 From: Khuzaima Shakeel <56439894+Khuzaima05@users.noreply.github.com> Date: Thu, 6 Feb 2025 13:50:51 +0530 Subject: [PATCH 26/40] Update variables.tf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Conall Ó Cofaigh --- variables.tf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/variables.tf b/variables.tf index 9547fd72..3ea5df7c 100644 --- a/variables.tf +++ b/variables.tf @@ -208,5 +208,6 @@ variable "reloader_chart_location" { variable "reloader_chart_version" { type = string description = "The version of the Reloader Helm chart." - default = "1.2.0" # datasource: https://stakater.github.io/stakater-charts + # renovate: datasource=github-releases depName=stakater/Reloader + default = "1.2.0" } From 001329611d1751cbe3e75fb97af4ff61a47c5499 Mon Sep 17 00:00:00 2001 From: Khuzaima Shakeel <56439894+Khuzaima05@users.noreply.github.com> Date: Thu, 6 Feb 2025 13:51:03 +0530 Subject: [PATCH 27/40] Update variables.tf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Conall Ó Cofaigh --- variables.tf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/variables.tf b/variables.tf index 3ea5df7c..d9f492c5 100644 --- a/variables.tf +++ b/variables.tf @@ -196,7 +196,8 @@ variable "eso_chart_location" { variable "eso_chart_version" { type = string description = "The version of the External Secrets Operator Helm chart." - default = "0.12.1" # datasource: https://charts.external-secrets.io + # renovate: datasource=github-tags depName=external-secrets/external-secrets versioning="regex:^helm-chart-(?\\d+)\\.(?\\d+)\\.(?\\d+)$" + default = "0.12.1" } variable "reloader_chart_location" { From 08fc57c0b19577b9ad35527df435ba38ba8dfdd1 Mon Sep 17 00:00:00 2001 From: valerio-bontempi Date: Thu, 6 Feb 2025 19:51:57 +0100 Subject: [PATCH 28/40] fix: addressed PR comments --- .cra/.fileignore | 3 --- .github/settings.yml | 2 +- .mdlrc | 2 -- .whitesource | 3 --- README.md | 41 ++++++++++-------------------- variables.tf | 60 +++++++++++++++++++++++++------------------- 6 files changed, 48 insertions(+), 63 deletions(-) delete mode 100644 .cra/.fileignore delete mode 100644 .mdlrc delete mode 100644 .whitesource diff --git a/.cra/.fileignore b/.cra/.fileignore deleted file mode 100644 index 098e3a44..00000000 --- a/.cra/.fileignore +++ /dev/null @@ -1,3 +0,0 @@ -**/.terraform/* -common-dev-assets/* -tests/* diff --git a/.github/settings.yml b/.github/settings.yml index 19dfb323..6dbad9cf 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -25,4 +25,4 @@ repository: description: "Synchronizes secrets between Secrets Manager and an IBM Cloud OpenShift cluster" # Use a comma-separated list of topics to set on the repo (ensure not to use any caps in the topic string). - topics: terraform, ibm-cloud, terraform-module, core-team, external-secret, + topics: terraform, ibm-cloud, terraform-module, core-team, external-secret diff --git a/.mdlrc b/.mdlrc deleted file mode 100644 index c32df301..00000000 --- a/.mdlrc +++ /dev/null @@ -1,2 +0,0 @@ -all -rule 'MD013', :tables => false diff --git a/.whitesource b/.whitesource deleted file mode 100644 index df373213..00000000 --- a/.whitesource +++ /dev/null @@ -1,3 +0,0 @@ -{ - "settingsInheritedFrom": "GoldenEye/whitesource-config@master" -} diff --git a/README.md b/README.md index b6b35696..255e13a3 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,6 @@ This module automates the installation and configuration of the [External Secret * [Contributing](#contributing) -## Compliance and security - -NIST controls do not apply to this module. - ## external-secrets-operator-module @@ -125,7 +121,7 @@ The resulting helm release configuration, according to the `terraform plan` outp # module.external_secrets_operator.helm_release.external_secrets_operator[0] will be created + resource "helm_release" "external_secrets_operator" { + atomic = false - + chart = "oci://icr.io/goldeneye_images/external-secrets" + + chart = "external-secrets" + cleanup_on_fail = false + create_namespace = false + dependency_update = false @@ -144,6 +140,7 @@ The resulting helm release configuration, according to the `terraform plan` outp + recreate_pods = false + render_subchart_notes = true + replace = false + + repository = "https://charts.external-secrets.io" + reset_values = false + reuse_values = false + skip_crds = false @@ -228,7 +225,8 @@ To configure a set of tenants to be configured in their proper namespace (to ach ```hcl module "external_secrets_operator" { - source = "https://github.com/terraform-ibm-modules/terraform-ibm-external-secrets-operator.git?ref=" + source = "terraform-ibm-modules/external-secrets-operator/ibm" + version = "1.0.0" eso_namespace = var.eso_namespace # namespace to deploy ESO service_endpoints = var.service_endpoints # use public or private endpoints for IAM and Secrets Manager eso_cluster_nodes_configuration = <> @@ -245,7 +243,7 @@ module "eso_namespace_secretstore_1" { depends_on = [ module.external_secrets_operator ] - source = "https://github.com/terraform-ibm-modules/terraform-ibm-external-secrets-operator.git//modules/eso-secretstore?ref=master" + source = "../modules/eso-secretstore" eso_authentication = "api_key" region = local.sm_region # SM region sstore_namespace = var.es_kubernetes_namespaces[2] # namespace to create the secret store @@ -267,7 +265,7 @@ module "eso_namespace_secretstores" { depends_on = [ module.external_secrets_operator ] - source = "https://github.com/terraform-ibm-modules/terraform-ibm-external-secrets-operator.git//modules/eso-secretstore?ref=master" + source = "../modules/eso-secretstore" eso_authentication = "trusted_profile" region = local.sm_region # SM region sstore_namespace = kubernetes_namespace.examples[count.index].metadata[0].name # namespace to create the secret store @@ -468,15 +466,11 @@ data: - -NIST controls do not apply to this module. - ## Usage ```hcl -# Replace "master" with a GIT release version to lock into a specific release module "es_kubernetes_secret" { - source = "https://github.com/terraform-ibm-modules/terraform-ibm-external-secrets-operator.git//modules/eso-external-secret?ref=master" + source = "../modules/eso-external-secret" es_kubernetes_secret_type = "dockerconfigjson" sm_secret_type = "iam_credentials" sm_secret_id = module.docker_config.serviceid_apikey_secret_id @@ -495,15 +489,6 @@ module "es_kubernetes_secret" { } ``` - -## Examples - -- [ Example to deploy the External Secret Operator and to create a different set of resources in terms of secrets, secret groups, stores and auth configurations](examples/all-combined) -- [ ImagePull API key Secrets Manager](examples/all-combined/imagepull-apikey-secrets-manager) -- [ Basic Example](examples/basic) -- [ Example that uses trusted profiles (container authentication)](examples/trusted-profiles-authentication) - - ### Requirements @@ -532,28 +517,28 @@ module "es_kubernetes_secret" { | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | [eso\_chart\_location](#input\_eso\_chart\_location) | The location of the External Secrets Operator Helm chart. | `string` | `"https://charts.external-secrets.io"` | no | -| [eso\_chart\_version](#input\_eso\_chart\_version) | The version of the External Secrets Operator Helm chart. | `string` | `"0.12.1"` | no | +| [eso\_chart\_version](#input\_eso\_chart\_version) | The version of the External Secrets Operator Helm chart. Ensure that the chart version is compatible with the image version specified in eso\_image\_digest. | `string` | `"0.12.1"` | no | | [eso\_cluster\_nodes\_configuration](#input\_eso\_cluster\_nodes\_configuration) | Configuration to use to customise ESO deployment on specific cluster nodes. Setting appropriate values will result in customising ESO helm release. Default value is null to keep ESO standard deployment. |
object({
nodeSelector = object({
label = string
value = string
})
tolerations = object({
key = string
operator = string
value = string
effect = string
})
})
| `null` | no | | [eso\_enroll\_in\_servicemesh](#input\_eso\_enroll\_in\_servicemesh) | Flag to enroll ESO into istio servicemesh | `bool` | `false` | no | -| [eso\_image\_digest](#input\_eso\_image\_digest) | The image digest in the format sha256:xxxxx... for ESO image to deploy. If not provided, a default value will be used. | `string` | `"sha256:d38834043de0a4e4feeac8a08d0bc96b71ddd7fe1d4c8583ee3751badeaeb01d"` | no | +| [eso\_image\_digest](#input\_eso\_image\_digest) | The image sha256 digest for the external secrets image to deploy. If not provided, a default value will be used. | `string` | `"v0.12.1-ubi@sha256:e78b56f81db033bbb724cc06a07880ad4ee8390e08dca0f763dbed08ae411671"` | no | | [eso\_namespace](#input\_eso\_namespace) | Namespace to create and be used to install ESO components including helm releases. If eso\_store\_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster\_store in it | `string` | `null` | no | | [eso\_pod\_configuration](#input\_eso\_pod\_configuration) | Configuration to use to customise ESO deployment on specific pods. Setting appropriate values will result in customising ESO helm release. Default value is {} to keep ESO standard deployment. Ignore the key if not required. |
object({
annotations = optional(object({
# The annotations for external secret controller pods.
external_secrets = optional(map(string), {})
# The annotations for external secret cert controller pods.
external_secrets_cert_controller = optional(map(string), {})
# The annotations for external secret controller pods.
external_secrets_webhook = optional(map(string), {})
}), {})

labels = optional(object({
# The labels for external secret controller pods.
external_secrets = optional(map(string), {})
# The labels for external secret cert controller pods.
external_secrets_cert_controller = optional(map(string), {})
# The labels for external secret controller pods.
external_secrets_webhook = optional(map(string), {})
}), {})
})
| `{}` | no | -| [eso\_registry\_namespace\_image](#input\_eso\_registry\_namespace\_image) | The External Secrets Operator image reference in the format of `[registry-url]/[namespace]/[image]`. | `string` | `"ghcr.io/external-secrets/external-secrets"` | no | +| [eso\_registry\_namespace\_image](#input\_eso\_registry\_namespace\_image) | The External Secrets Operator image registry in the format of `[registry-url]/[namespace]/[image]`. | `string` | `"ghcr.io/external-secrets/external-secrets"` | no | | [existing\_eso\_namespace](#input\_existing\_eso\_namespace) | Existing Namespace to be used to install ESO components including helm releases. If eso\_store\_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster\_store in it | `string` | `null` | no | | [reloader\_chart\_location](#input\_reloader\_chart\_location) | The location of the Reloader Helm chart. | `string` | `"https://stakater.github.io/stakater-charts"` | no | -| [reloader\_chart\_version](#input\_reloader\_chart\_version) | The version of the Reloader Helm chart. | `string` | `"1.2.0"` | no | +| [reloader\_chart\_version](#input\_reloader\_chart\_version) | The version of the Reloader Helm chart. Ensure that the chart version is compatible with the image version specified in reloader\_image\_digest. | `string` | `"1.2.0"` | no | | [reloader\_custom\_values](#input\_reloader\_custom\_values) | String containing custom values to be used for reloader helm chart. See https://github.com/stakater/Reloader/blob/master/deployments/kubernetes/chart/reloader/values.yaml | `string` | `null` | no | | [reloader\_deployed](#input\_reloader\_deployed) | Whether to deploy reloader or not https://github.com/stakater/Reloader | `bool` | `true` | no | | [reloader\_ignore\_configmaps](#input\_reloader\_ignore\_configmaps) | Whether to ignore configmap changes or not | `bool` | `false` | no | | [reloader\_ignore\_secrets](#input\_reloader\_ignore\_secrets) | Whether to ignore secret changes or not | `bool` | `false` | no | -| [reloader\_image\_digest](#input\_reloader\_image\_digest) | The image digest in the format sha256:xxxxx... the reloader image to deploy. If not provided, a default value will be used. | `string` | `"sha256:80a557100c6835c7e3c9842194250c9c4ca78f43200bc3a93a32e5b105ad11bb"` | no | +| [reloader\_image\_digest](#input\_reloader\_image\_digest) | The image sha256 digest for the reloader image to deploy. | `string` | `"v1.2.1-ubi@sha256:20e42fdc757d91309aa8caad0fce97f2dc67be85f17e6fb3642844e583f7bc97"` | no | | [reloader\_is\_argo\_rollouts](#input\_reloader\_is\_argo\_rollouts) | Enable Argo Rollouts | `bool` | `false` | no | | [reloader\_is\_openshift](#input\_reloader\_is\_openshift) | Enable OpenShift DeploymentConfigs | `bool` | `true` | no | | [reloader\_log\_format](#input\_reloader\_log\_format) | The log format to use for reloader. Possible values are `json` or `text`. Default value is `json` | `string` | `"text"` | no | | [reloader\_namespaces\_selector](#input\_reloader\_namespaces\_selector) | List of comma separated label selectors, if multiple are provided they are combined with the AND operator | `string` | `null` | no | | [reloader\_namespaces\_to\_ignore](#input\_reloader\_namespaces\_to\_ignore) | List of comma separated namespaces to ignore for reloader. If multiple are provided they are combined with the AND operator | `string` | `null` | no | | [reloader\_pod\_monitor\_metrics](#input\_reloader\_pod\_monitor\_metrics) | Enable to scrape Reloader's Prometheus metrics | `bool` | `false` | no | -| [reloader\_registry\_namespace\_image](#input\_reloader\_registry\_namespace\_image) | The Reloader image reference in the format of `[registry-url]/[namespace]/[image]`. | `string` | `"ghcr.io/stakater/reloader"` | no | +| [reloader\_registry\_namespace\_image](#input\_reloader\_registry\_namespace\_image) | The reloader image registry in the format of `[registry-url]/[namespace]/[image]`. | `string` | `"ghcr.io/stakater/reloader"` | no | | [reloader\_reload\_on\_create](#input\_reloader\_reload\_on\_create) | Enable reload on create events | `bool` | `true` | no | | [reloader\_reload\_strategy](#input\_reloader\_reload\_strategy) | The reload strategy to use for reloader. Possible values are `env-vars` or `annotations`. Default value is `annotations` | `string` | `"annotations"` | no | | [reloader\_resource\_label\_selector](#input\_reloader\_resource\_label\_selector) | List of comma separated label selectors, if multiple are provided they are combined with the AND operator | `string` | `null` | no | diff --git a/variables.tf b/variables.tf index d9f492c5..2cb9006e 100644 --- a/variables.tf +++ b/variables.tf @@ -151,64 +151,72 @@ variable "reloader_custom_values" { default = null } -# image registry and digest +# external secrets image and helm charts references variable "eso_registry_namespace_image" { type = string - description = "The External Secrets Operator image reference in the format of `[registry-url]/[namespace]/[image]`." + description = "The External Secrets Operator image registry in the format of `[registry-url]/[namespace]/[image]`." default = "ghcr.io/external-secrets/external-secrets" + nullable = false } variable "eso_image_digest" { type = string - description = "The image digest in the format sha256:xxxxx... for ESO image to deploy. If not provided, a default value will be used." - default = "sha256:d38834043de0a4e4feeac8a08d0bc96b71ddd7fe1d4c8583ee3751badeaeb01d" # datasource: ghcr.io/external-secrets/external-secrets + description = "The image sha256 digest for the external secrets image to deploy. If not provided, a default value will be used." + default = "v0.12.1-ubi@sha256:e78b56f81db033bbb724cc06a07880ad4ee8390e08dca0f763dbed08ae411671" # datasource: ghcr.io/external-secrets/external-secrets + nullable = false validation { - condition = var.eso_image_digest == null || can(regex("^sha256:", var.eso_image_digest)) - error_message = "If provided, the value of eso_image_digest must start with 'sha256:'." + condition = can(regex("^v\\d+\\.\\d+.\\d+\\-\\w+\\@sha256:\\w+", var.eso_image_digest)) + error_message = "The value of eso_image_digest must start with 'sha256:'." } } -variable "reloader_registry_namespace_image" { +variable "eso_chart_location" { type = string - description = "The Reloader image reference in the format of `[registry-url]/[namespace]/[image]`." - default = "ghcr.io/stakater/reloader" + description = "The location of the External Secrets Operator Helm chart." + default = "https://charts.external-secrets.io" + nullable = false } -variable "reloader_image_digest" { +variable "eso_chart_version" { type = string - description = "The image digest in the format sha256:xxxxx... the reloader image to deploy. If not provided, a default value will be used." - default = "sha256:80a557100c6835c7e3c9842194250c9c4ca78f43200bc3a93a32e5b105ad11bb" # datasource: ghcr.io/stakater/reloader - validation { - condition = var.reloader_image_digest == null || can(regex("^sha256:", var.reloader_image_digest)) - error_message = "If provided, the value of reloader_image_digest must start with 'sha256:'." - } + description = "The version of the External Secrets Operator Helm chart. Ensure that the chart version is compatible with the image version specified in eso_image_digest." + # renovate: datasource=github-tags depName=external-secrets/external-secrets versioning="regex:^helm-chart-(?\\d+)\\.(?\\d+)\\.(?\\d+)$" + default = "0.12.1" + nullable = false } -# helms repo and charts +# reloader image and helm charts references -variable "eso_chart_location" { +variable "reloader_registry_namespace_image" { type = string - description = "The location of the External Secrets Operator Helm chart." - default = "https://charts.external-secrets.io" + description = "The reloader image registry in the format of `[registry-url]/[namespace]/[image]`." + default = "ghcr.io/stakater/reloader" + nullable = false } -variable "eso_chart_version" { +variable "reloader_image_digest" { type = string - description = "The version of the External Secrets Operator Helm chart." - # renovate: datasource=github-tags depName=external-secrets/external-secrets versioning="regex:^helm-chart-(?\\d+)\\.(?\\d+)\\.(?\\d+)$" - default = "0.12.1" + description = "The image sha256 digest for the reloader image to deploy." + default = "v1.2.1-ubi@sha256:20e42fdc757d91309aa8caad0fce97f2dc67be85f17e6fb3642844e583f7bc97" # datasource: ghcr.io/stakater/reloader + nullable = false + validation { + condition = can(regex("^v\\d+\\.\\d+.\\d+\\-\\w+\\@sha256:\\w+", var.reloader_image_digest)) + error_message = "The value of reloader_image_digest must start with 'sha256:'." + } } variable "reloader_chart_location" { type = string description = "The location of the Reloader Helm chart." default = "https://stakater.github.io/stakater-charts" + nullable = false } variable "reloader_chart_version" { type = string - description = "The version of the Reloader Helm chart." + description = "The version of the Reloader Helm chart. Ensure that the chart version is compatible with the image version specified in reloader_image_digest." # renovate: datasource=github-releases depName=stakater/Reloader - default = "1.2.0" + default = "1.2.0" + nullable = false } From bda792d799896bce9e88a03bdf218d0ac63ca9b8 Mon Sep 17 00:00:00 2001 From: valerio-bontempi Date: Thu, 6 Feb 2025 20:04:08 +0100 Subject: [PATCH 29/40] Update submodule to latest commit --- common-dev-assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-dev-assets b/common-dev-assets index 66d1c66f..d904c5d3 160000 --- a/common-dev-assets +++ b/common-dev-assets @@ -1 +1 @@ -Subproject commit 66d1c66f5e189696eb8769f8f10a8cc80816172f +Subproject commit d904c5d3d2d499d980d179ff028574ef6b49f10f From d1d2c0c90f7bb069849f426f192f81d1568808a6 Mon Sep 17 00:00:00 2001 From: valerio-bontempi Date: Thu, 6 Feb 2025 20:28:55 +0100 Subject: [PATCH 30/40] Revert "Update submodule to latest commit" This reverts commit bda792d799896bce9e88a03bdf218d0ac63ca9b8. --- common-dev-assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-dev-assets b/common-dev-assets index d904c5d3..66d1c66f 160000 --- a/common-dev-assets +++ b/common-dev-assets @@ -1 +1 @@ -Subproject commit d904c5d3d2d499d980d179ff028574ef6b49f10f +Subproject commit 66d1c66f5e189696eb8769f8f10a8cc80816172f From 2a0db7cafe7456c4bfc9c9e6d8803c5a8dce14d1 Mon Sep 17 00:00:00 2001 From: valerio-bontempi Date: Thu, 6 Feb 2025 22:23:54 +0100 Subject: [PATCH 31/40] fix: reviewed images and versions configurations --- README.md | 12 +++---- main.tf | 24 +++++--------- variables.tf | 92 ++++++++++++++++++++++++++++------------------------ 3 files changed, 63 insertions(+), 65 deletions(-) diff --git a/README.md b/README.md index 255e13a3..0b0749ab 100644 --- a/README.md +++ b/README.md @@ -517,28 +517,28 @@ module "es_kubernetes_secret" { | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | [eso\_chart\_location](#input\_eso\_chart\_location) | The location of the External Secrets Operator Helm chart. | `string` | `"https://charts.external-secrets.io"` | no | -| [eso\_chart\_version](#input\_eso\_chart\_version) | The version of the External Secrets Operator Helm chart. Ensure that the chart version is compatible with the image version specified in eso\_image\_digest. | `string` | `"0.12.1"` | no | +| [eso\_chart\_version](#input\_eso\_chart\_version) | The version of the External Secrets Operator Helm chart. Ensure that the chart version is compatible with the image version specified in eso\_image\_version. | `string` | `"0.12.1"` | no | | [eso\_cluster\_nodes\_configuration](#input\_eso\_cluster\_nodes\_configuration) | Configuration to use to customise ESO deployment on specific cluster nodes. Setting appropriate values will result in customising ESO helm release. Default value is null to keep ESO standard deployment. |
object({
nodeSelector = object({
label = string
value = string
})
tolerations = object({
key = string
operator = string
value = string
effect = string
})
})
| `null` | no | | [eso\_enroll\_in\_servicemesh](#input\_eso\_enroll\_in\_servicemesh) | Flag to enroll ESO into istio servicemesh | `bool` | `false` | no | -| [eso\_image\_digest](#input\_eso\_image\_digest) | The image sha256 digest for the external secrets image to deploy. If not provided, a default value will be used. | `string` | `"v0.12.1-ubi@sha256:e78b56f81db033bbb724cc06a07880ad4ee8390e08dca0f763dbed08ae411671"` | no | +| [eso\_image](#input\_eso\_image) | The External Secrets Operator image in the format of `[registry-url]/[namespace]/[image]`. | `string` | `"ghcr.io/external-secrets/external-secrets"` | no | +| [eso\_image\_version](#input\_eso\_image\_version) | The version or digest for the external secrets image to deploy. | `string` | `"v0.12.1-ubi@sha256:e78b56f81db033bbb724cc06a07880ad4ee8390e08dca0f763dbed08ae411671"` | no | | [eso\_namespace](#input\_eso\_namespace) | Namespace to create and be used to install ESO components including helm releases. If eso\_store\_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster\_store in it | `string` | `null` | no | | [eso\_pod\_configuration](#input\_eso\_pod\_configuration) | Configuration to use to customise ESO deployment on specific pods. Setting appropriate values will result in customising ESO helm release. Default value is {} to keep ESO standard deployment. Ignore the key if not required. |
object({
annotations = optional(object({
# The annotations for external secret controller pods.
external_secrets = optional(map(string), {})
# The annotations for external secret cert controller pods.
external_secrets_cert_controller = optional(map(string), {})
# The annotations for external secret controller pods.
external_secrets_webhook = optional(map(string), {})
}), {})

labels = optional(object({
# The labels for external secret controller pods.
external_secrets = optional(map(string), {})
# The labels for external secret cert controller pods.
external_secrets_cert_controller = optional(map(string), {})
# The labels for external secret controller pods.
external_secrets_webhook = optional(map(string), {})
}), {})
})
| `{}` | no | -| [eso\_registry\_namespace\_image](#input\_eso\_registry\_namespace\_image) | The External Secrets Operator image registry in the format of `[registry-url]/[namespace]/[image]`. | `string` | `"ghcr.io/external-secrets/external-secrets"` | no | | [existing\_eso\_namespace](#input\_existing\_eso\_namespace) | Existing Namespace to be used to install ESO components including helm releases. If eso\_store\_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster\_store in it | `string` | `null` | no | | [reloader\_chart\_location](#input\_reloader\_chart\_location) | The location of the Reloader Helm chart. | `string` | `"https://stakater.github.io/stakater-charts"` | no | -| [reloader\_chart\_version](#input\_reloader\_chart\_version) | The version of the Reloader Helm chart. Ensure that the chart version is compatible with the image version specified in reloader\_image\_digest. | `string` | `"1.2.0"` | no | +| [reloader\_chart\_version](#input\_reloader\_chart\_version) | The version of the Reloader Helm chart. Ensure that the chart version is compatible with the image version specified in reloader\_image\_version. | `string` | `"1.2.0"` | no | | [reloader\_custom\_values](#input\_reloader\_custom\_values) | String containing custom values to be used for reloader helm chart. See https://github.com/stakater/Reloader/blob/master/deployments/kubernetes/chart/reloader/values.yaml | `string` | `null` | no | | [reloader\_deployed](#input\_reloader\_deployed) | Whether to deploy reloader or not https://github.com/stakater/Reloader | `bool` | `true` | no | | [reloader\_ignore\_configmaps](#input\_reloader\_ignore\_configmaps) | Whether to ignore configmap changes or not | `bool` | `false` | no | | [reloader\_ignore\_secrets](#input\_reloader\_ignore\_secrets) | Whether to ignore secret changes or not | `bool` | `false` | no | -| [reloader\_image\_digest](#input\_reloader\_image\_digest) | The image sha256 digest for the reloader image to deploy. | `string` | `"v1.2.1-ubi@sha256:20e42fdc757d91309aa8caad0fce97f2dc67be85f17e6fb3642844e583f7bc97"` | no | +| [reloader\_image](#input\_reloader\_image) | The reloader image in the format of `[registry-url]/[namespace]/[image]`. | `string` | `"ghcr.io/stakater/reloader"` | no | +| [reloader\_image\_version](#input\_reloader\_image\_version) | The version or digest for the reloader image to deploy. | `string` | `"v1.2.1-ubi@sha256:20e42fdc757d91309aa8caad0fce97f2dc67be85f17e6fb3642844e583f7bc97"` | no | | [reloader\_is\_argo\_rollouts](#input\_reloader\_is\_argo\_rollouts) | Enable Argo Rollouts | `bool` | `false` | no | | [reloader\_is\_openshift](#input\_reloader\_is\_openshift) | Enable OpenShift DeploymentConfigs | `bool` | `true` | no | | [reloader\_log\_format](#input\_reloader\_log\_format) | The log format to use for reloader. Possible values are `json` or `text`. Default value is `json` | `string` | `"text"` | no | | [reloader\_namespaces\_selector](#input\_reloader\_namespaces\_selector) | List of comma separated label selectors, if multiple are provided they are combined with the AND operator | `string` | `null` | no | | [reloader\_namespaces\_to\_ignore](#input\_reloader\_namespaces\_to\_ignore) | List of comma separated namespaces to ignore for reloader. If multiple are provided they are combined with the AND operator | `string` | `null` | no | | [reloader\_pod\_monitor\_metrics](#input\_reloader\_pod\_monitor\_metrics) | Enable to scrape Reloader's Prometheus metrics | `bool` | `false` | no | -| [reloader\_registry\_namespace\_image](#input\_reloader\_registry\_namespace\_image) | The reloader image registry in the format of `[registry-url]/[namespace]/[image]`. | `string` | `"ghcr.io/stakater/reloader"` | no | | [reloader\_reload\_on\_create](#input\_reloader\_reload\_on\_create) | Enable reload on create events | `bool` | `true` | no | | [reloader\_reload\_strategy](#input\_reloader\_reload\_strategy) | The reload strategy to use for reloader. Possible values are `env-vars` or `annotations`. Default value is `annotations` | `string` | `"annotations"` | no | | [reloader\_resource\_label\_selector](#input\_reloader\_resource\_label\_selector) | List of comma separated label selectors, if multiple are provided they are combined with the AND operator | `string` | `null` | no | diff --git a/main.tf b/main.tf index 1636bf4b..d2ae022a 100644 --- a/main.tf +++ b/main.tf @@ -168,10 +168,6 @@ certController: EOF } -locals { - eso_image_tag_digest = "v${var.eso_chart_version}-ubi@${var.eso_image_digest}" -} - resource "helm_release" "external_secrets_operator" { depends_on = [module.eso_namespace, data.kubernetes_namespace.existing_eso_namespace] @@ -185,47 +181,43 @@ resource "helm_release" "external_secrets_operator" { set { name = "image.repository" type = "string" - value = var.eso_registry_namespace_image + value = var.eso_image } set { name = "image.tag" type = "string" - value = local.eso_image_tag_digest + value = var.eso_image_version } set { name = "webhook.image.repository" type = "string" - value = var.eso_registry_namespace_image + value = var.eso_image } set { name = "webhook.image.tag" type = "string" - value = local.eso_image_tag_digest + value = var.eso_image_version } set { name = "certController.image.repository" type = "string" - value = var.eso_registry_namespace_image + value = var.eso_image } set { name = "certController.image.tag" type = "string" - value = local.eso_image_tag_digest + value = var.eso_image_version } # The following mounts are needed for the CRI based authentication with Trusted Profiles values = [local.eso_helm_release_values_cri, local.eso_helm_release_values_workerselector] } -locals { - reloader_image_tag_digest = "v${var.reloader_chart_version}-ubi@${var.reloader_image_digest}" -} - resource "helm_release" "pod_reloader" { depends_on = [module.eso_namespace, data.kubernetes_namespace.existing_eso_namespace] count = var.reloader_deployed == true ? 1 : 0 @@ -240,13 +232,13 @@ resource "helm_release" "pod_reloader" { set { name = "reloader.deployment.image.name" type = "string" - value = var.reloader_registry_namespace_image + value = var.reloader_image } set { name = "reloader.deployment.image.tag" type = "string" - value = local.reloader_image_tag_digest + value = var.reloader_image_version } # Set reload strategy diff --git a/variables.tf b/variables.tf index 2cb9006e..b9162389 100644 --- a/variables.tf +++ b/variables.tf @@ -1,4 +1,6 @@ -######## eso generic configurations +############################################################################################################ +# EXTERNAL SECRETS CONFIGURATIONS +############################################################################################################ variable "eso_namespace" { description = "Namespace to create and be used to install ESO components including helm releases. If eso_store_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster_store in it" @@ -63,6 +65,45 @@ variable "eso_enroll_in_servicemesh" { default = false } +# external secrets image and helm charts references + +variable "eso_image" { + type = string + description = "The External Secrets Operator image in the format of `[registry-url]/[namespace]/[image]`." + default = "ghcr.io/external-secrets/external-secrets" + nullable = false +} + +variable "eso_image_version" { + type = string + description = "The version or digest for the external secrets image to deploy." + default = "v0.12.1-ubi@sha256:e78b56f81db033bbb724cc06a07880ad4ee8390e08dca0f763dbed08ae411671" # datasource: ghcr.io/external-secrets/external-secrets + nullable = false + validation { + condition = can(regex("(^v\\d+\\.\\d+.\\d+(\\-\\w+)?(\\@sha256\\:\\w+){0,1})$", var.eso_image_version)) + error_message = "The value of the external secrets image version must match classic version or the tag and sha256 image digest format" + } +} + +variable "eso_chart_location" { + type = string + description = "The location of the External Secrets Operator Helm chart." + default = "https://charts.external-secrets.io" + nullable = false +} + +variable "eso_chart_version" { + type = string + description = "The version of the External Secrets Operator Helm chart. Ensure that the chart version is compatible with the image version specified in eso_image_version." + # renovate: datasource=github-tags depName=external-secrets/external-secrets versioning="regex:^helm-chart-(?\\d+)\\.(?\\d+)\\.(?\\d+)$" + default = "0.12.1" + nullable = false +} + +############################################################################################################ +# RELOADER CONFIGURATIONS +############################################################################################################ + # Reloader variables full documentation https://github.com/stakater/Reloader/tree/master#helm-charts variable "reloader_deployed" { description = "Whether to deploy reloader or not https://github.com/stakater/Reloader" @@ -151,58 +192,23 @@ variable "reloader_custom_values" { default = null } -# external secrets image and helm charts references - -variable "eso_registry_namespace_image" { - type = string - description = "The External Secrets Operator image registry in the format of `[registry-url]/[namespace]/[image]`." - default = "ghcr.io/external-secrets/external-secrets" - nullable = false -} - -variable "eso_image_digest" { - type = string - description = "The image sha256 digest for the external secrets image to deploy. If not provided, a default value will be used." - default = "v0.12.1-ubi@sha256:e78b56f81db033bbb724cc06a07880ad4ee8390e08dca0f763dbed08ae411671" # datasource: ghcr.io/external-secrets/external-secrets - nullable = false - validation { - condition = can(regex("^v\\d+\\.\\d+.\\d+\\-\\w+\\@sha256:\\w+", var.eso_image_digest)) - error_message = "The value of eso_image_digest must start with 'sha256:'." - } -} - -variable "eso_chart_location" { - type = string - description = "The location of the External Secrets Operator Helm chart." - default = "https://charts.external-secrets.io" - nullable = false -} - -variable "eso_chart_version" { - type = string - description = "The version of the External Secrets Operator Helm chart. Ensure that the chart version is compatible with the image version specified in eso_image_digest." - # renovate: datasource=github-tags depName=external-secrets/external-secrets versioning="regex:^helm-chart-(?\\d+)\\.(?\\d+)\\.(?\\d+)$" - default = "0.12.1" - nullable = false -} - # reloader image and helm charts references -variable "reloader_registry_namespace_image" { +variable "reloader_image" { type = string - description = "The reloader image registry in the format of `[registry-url]/[namespace]/[image]`." + description = "The reloader image in the format of `[registry-url]/[namespace]/[image]`." default = "ghcr.io/stakater/reloader" nullable = false } -variable "reloader_image_digest" { +variable "reloader_image_version" { type = string - description = "The image sha256 digest for the reloader image to deploy." + description = "The version or digest for the reloader image to deploy." default = "v1.2.1-ubi@sha256:20e42fdc757d91309aa8caad0fce97f2dc67be85f17e6fb3642844e583f7bc97" # datasource: ghcr.io/stakater/reloader nullable = false validation { - condition = can(regex("^v\\d+\\.\\d+.\\d+\\-\\w+\\@sha256:\\w+", var.reloader_image_digest)) - error_message = "The value of reloader_image_digest must start with 'sha256:'." + condition = can(regex("(^v\\d+\\.\\d+.\\d+(\\-\\w+)?(\\@sha256\\:\\w+){0,1})$", var.reloader_image_version)) + error_message = "The value of the reloader image version must match classic version or the tag and sha256 image digest format" } } @@ -215,7 +221,7 @@ variable "reloader_chart_location" { variable "reloader_chart_version" { type = string - description = "The version of the Reloader Helm chart. Ensure that the chart version is compatible with the image version specified in reloader_image_digest." + description = "The version of the Reloader Helm chart. Ensure that the chart version is compatible with the image version specified in reloader_image_version." # renovate: datasource=github-releases depName=stakater/Reloader default = "1.2.0" nullable = false From 706753499f4a80d8096fd925683b23628a4566f4 Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Fri, 7 Feb 2025 15:46:18 +0530 Subject: [PATCH 32/40] fix image and charts --- README.md | 4 ++-- renovate.json | 23 +++++++++++++---------- variables.tf | 4 ++-- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 0b0749ab..dade8b5d 100644 --- a/README.md +++ b/README.md @@ -521,7 +521,7 @@ module "es_kubernetes_secret" { | [eso\_cluster\_nodes\_configuration](#input\_eso\_cluster\_nodes\_configuration) | Configuration to use to customise ESO deployment on specific cluster nodes. Setting appropriate values will result in customising ESO helm release. Default value is null to keep ESO standard deployment. |
object({
nodeSelector = object({
label = string
value = string
})
tolerations = object({
key = string
operator = string
value = string
effect = string
})
})
| `null` | no | | [eso\_enroll\_in\_servicemesh](#input\_eso\_enroll\_in\_servicemesh) | Flag to enroll ESO into istio servicemesh | `bool` | `false` | no | | [eso\_image](#input\_eso\_image) | The External Secrets Operator image in the format of `[registry-url]/[namespace]/[image]`. | `string` | `"ghcr.io/external-secrets/external-secrets"` | no | -| [eso\_image\_version](#input\_eso\_image\_version) | The version or digest for the external secrets image to deploy. | `string` | `"v0.12.1-ubi@sha256:e78b56f81db033bbb724cc06a07880ad4ee8390e08dca0f763dbed08ae411671"` | no | +| [eso\_image\_version](#input\_eso\_image\_version) | The version or digest for the external secrets image to deploy. | `string` | `"v0.12.1-ubi@sha256:d38834043de0a4e4feeac8a08d0bc96b71ddd7fe1d4c8583ee3751badeaeb01d"` | no | | [eso\_namespace](#input\_eso\_namespace) | Namespace to create and be used to install ESO components including helm releases. If eso\_store\_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster\_store in it | `string` | `null` | no | | [eso\_pod\_configuration](#input\_eso\_pod\_configuration) | Configuration to use to customise ESO deployment on specific pods. Setting appropriate values will result in customising ESO helm release. Default value is {} to keep ESO standard deployment. Ignore the key if not required. |
object({
annotations = optional(object({
# The annotations for external secret controller pods.
external_secrets = optional(map(string), {})
# The annotations for external secret cert controller pods.
external_secrets_cert_controller = optional(map(string), {})
# The annotations for external secret controller pods.
external_secrets_webhook = optional(map(string), {})
}), {})

labels = optional(object({
# The labels for external secret controller pods.
external_secrets = optional(map(string), {})
# The labels for external secret cert controller pods.
external_secrets_cert_controller = optional(map(string), {})
# The labels for external secret controller pods.
external_secrets_webhook = optional(map(string), {})
}), {})
})
| `{}` | no | | [existing\_eso\_namespace](#input\_existing\_eso\_namespace) | Existing Namespace to be used to install ESO components including helm releases. If eso\_store\_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster\_store in it | `string` | `null` | no | @@ -532,7 +532,7 @@ module "es_kubernetes_secret" { | [reloader\_ignore\_configmaps](#input\_reloader\_ignore\_configmaps) | Whether to ignore configmap changes or not | `bool` | `false` | no | | [reloader\_ignore\_secrets](#input\_reloader\_ignore\_secrets) | Whether to ignore secret changes or not | `bool` | `false` | no | | [reloader\_image](#input\_reloader\_image) | The reloader image in the format of `[registry-url]/[namespace]/[image]`. | `string` | `"ghcr.io/stakater/reloader"` | no | -| [reloader\_image\_version](#input\_reloader\_image\_version) | The version or digest for the reloader image to deploy. | `string` | `"v1.2.1-ubi@sha256:20e42fdc757d91309aa8caad0fce97f2dc67be85f17e6fb3642844e583f7bc97"` | no | +| [reloader\_image\_version](#input\_reloader\_image\_version) | The version or digest for the reloader image to deploy. | `string` | `"v1.2.1-ubi@sha256:80a557100c6835c7e3c9842194250c9c4ca78f43200bc3a93a32e5b105ad11bb"` | no | | [reloader\_is\_argo\_rollouts](#input\_reloader\_is\_argo\_rollouts) | Enable Argo Rollouts | `bool` | `false` | no | | [reloader\_is\_openshift](#input\_reloader\_is\_openshift) | Enable OpenShift DeploymentConfigs | `bool` | `true` | no | | [reloader\_log\_format](#input\_reloader\_log\_format) | The log format to use for reloader. Possible values are `json` or `text`. Default value is `json` | `string` | `"text"` | no | diff --git a/renovate.json b/renovate.json index 4eda1200..e7b77bef 100644 --- a/renovate.json +++ b/renovate.json @@ -1,27 +1,30 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": ["github>terraform-ibm-modules/common-dev-assets:commonRenovateConfig"], - "regexManagers": [ + "customManagers": [ { - "fileMatch": ["\\.tf$"], + "customType": "regex", + "description": "Update docker image digest to latest in variables.tf", + "fileMatch": ["variables.tf$"], + "datasourceTemplate": "docker", "matchStrings": [ - "[\\w-]+_image_digest\\s*=\\s*\"(?[\\w.-]+)@(?sha256:[a-f0-9]+)\"\\s*# datasource: (?[^\\s]+)" - ], - "datasourceTemplate": "docker" + "default\\s*=\\s*\"(?[\\w.-]+)@(?sha256:[a-f0-9]+)\"\\s*# datasource: (?[^\\s]+)" + ] }, { - "fileMatch": ["\\.tf$"], + "customType": "regex", + "description": "Update helm chart version to latest in variables.tf", + "fileMatch": ["variables.tf$"], "matchStrings": [ - "[\\w-]+_chart_version\\s*=\\s*\"(?[\\w.-]+)\"\\s*# datasource: (?[^\\s]+)\\s*( versioning=(?.*?))?\\s.*?" + "datasource=(?.*?) depName=(?.*?)( versioning=(?.*?))?\\s.*?default = \"(?.*)\"\\s" ], - "datasourceTemplate": "docker", "versioningTemplate": "{{#if versioning}}{{{versioning}}}{{else}}semver{{/if}}" } ], "labels": ["renovate"], "packageRules": [ { - "matchManagers": ["helmv3"], + "matchPackageNames": ["external-secrets/external-secrets", "stakater/Reloader"], "groupName": "Charts and Images", "commitMessageExtra": "to latest", "group": true @@ -33,4 +36,4 @@ "group": true } ] -} +} \ No newline at end of file diff --git a/variables.tf b/variables.tf index b9162389..7589bbb2 100644 --- a/variables.tf +++ b/variables.tf @@ -77,7 +77,7 @@ variable "eso_image" { variable "eso_image_version" { type = string description = "The version or digest for the external secrets image to deploy." - default = "v0.12.1-ubi@sha256:e78b56f81db033bbb724cc06a07880ad4ee8390e08dca0f763dbed08ae411671" # datasource: ghcr.io/external-secrets/external-secrets + default = "v0.12.1-ubi@sha256:d38834043de0a4e4feeac8a08d0bc96b71ddd7fe1d4c8583ee3751badeaeb01d" # datasource: ghcr.io/external-secrets/external-secrets nullable = false validation { condition = can(regex("(^v\\d+\\.\\d+.\\d+(\\-\\w+)?(\\@sha256\\:\\w+){0,1})$", var.eso_image_version)) @@ -204,7 +204,7 @@ variable "reloader_image" { variable "reloader_image_version" { type = string description = "The version or digest for the reloader image to deploy." - default = "v1.2.1-ubi@sha256:20e42fdc757d91309aa8caad0fce97f2dc67be85f17e6fb3642844e583f7bc97" # datasource: ghcr.io/stakater/reloader + default = "v1.2.1-ubi@sha256:80a557100c6835c7e3c9842194250c9c4ca78f43200bc3a93a32e5b105ad11bb" # datasource: ghcr.io/stakater/reloader nullable = false validation { condition = can(regex("(^v\\d+\\.\\d+.\\d+(\\-\\w+)?(\\@sha256\\:\\w+){0,1})$", var.reloader_image_version)) From 0b30610ab138e3947135e7650748e7a2c74d6bd4 Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Fri, 7 Feb 2025 15:54:15 +0530 Subject: [PATCH 33/40] updated es_container_registry --- examples/all-combined/clusterstore.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/all-combined/clusterstore.tf b/examples/all-combined/clusterstore.tf index 93ec421e..23218c75 100644 --- a/examples/all-combined/clusterstore.tf +++ b/examples/all-combined/clusterstore.tf @@ -71,7 +71,7 @@ module "external_secret_usr_pass" { sm_secret_id = module.sm_userpass_secret.secret_id es_kubernetes_namespace = kubernetes_namespace.apikey_namespaces[0].metadata[0].name eso_store_name = "cluster-store" - es_container_registry = "wcp-my-team-docker-local.artifactory.swg-devops.com" + es_container_registry = "example-registry-local.artifactory.com" es_kubernetes_secret_name = "dockerconfigjson-uc" #checkov:skip=CKV_SECRET_6 es_helm_rls_name = "es-docker-uc" } From 59da3b5c1b7fad2de2958d6d34a13ab91e770fbf Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Fri, 7 Feb 2025 16:11:06 +0530 Subject: [PATCH 34/40] fix pre-commit --- renovate.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index e7b77bef..0da57df4 100644 --- a/renovate.json +++ b/renovate.json @@ -36,4 +36,4 @@ "group": true } ] -} \ No newline at end of file +} From b09cb8de7ba75ee37475bfb3df442353e3aacd90 Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Fri, 7 Feb 2025 19:45:56 +0530 Subject: [PATCH 35/40] update common-dev-asset --- common-dev-assets | 2 +- examples/all-combined/secretstore.tf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common-dev-assets b/common-dev-assets index 66d1c66f..d904c5d3 160000 --- a/common-dev-assets +++ b/common-dev-assets @@ -1 +1 @@ -Subproject commit 66d1c66f5e189696eb8769f8f10a8cc80816172f +Subproject commit d904c5d3d2d499d980d179ff028574ef6b49f10f diff --git a/examples/all-combined/secretstore.tf b/examples/all-combined/secretstore.tf index bdc20697..e744721e 100644 --- a/examples/all-combined/secretstore.tf +++ b/examples/all-combined/secretstore.tf @@ -180,7 +180,7 @@ module "external_secret_secret_image_pull_chain" { source = "../../modules/eso-external-secret" depends_on = [module.eso_apikey_namespace_secretstore_2, ] eso_store_scope = "namespace" - es_kubernetes_secret_type = "dockerconfigjson" + es_kubernetes_secret_type = "dockerconfigjson" # checkov:skip=CKV_SECRET_6 sm_secret_type = "iam_credentials" eso_store_name = "${var.es_namespaces_apikey[3]}-store" es_kubernetes_secret_name = "dockerconfigjson-chain" From 68aab490d9bbc387553cdeb9897c9b575aed9444 Mon Sep 17 00:00:00 2001 From: valerio-bontempi Date: Mon, 10 Feb 2025 11:14:55 +0100 Subject: [PATCH 36/40] fix: committed common-dev-assets to fix issue --- common-dev-assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-dev-assets b/common-dev-assets index d904c5d3..a82b82a5 160000 --- a/common-dev-assets +++ b/common-dev-assets @@ -1 +1 @@ -Subproject commit d904c5d3d2d499d980d179ff028574ef6b49f10f +Subproject commit a82b82a515e442958a736cae705b72891d6a60f4 From c07fd610406fa66878569c6323960de1b42f55c0 Mon Sep 17 00:00:00 2001 From: Khuzaima-Shakeel Date: Mon, 10 Feb 2025 16:00:30 +0530 Subject: [PATCH 37/40] fix go file --- tests/go.mod | 37 ++++++++++++------------ tests/go.sum | 80 +++++++++++++++++++++++++--------------------------- 2 files changed, 56 insertions(+), 61 deletions(-) diff --git a/tests/go.mod b/tests/go.mod index 625d76ce..82f452f9 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -1,6 +1,6 @@ module github.com/terraform-ibm-modules/terraform-ibm-external-secrets-operator -go 1.23.0 +go 1.22.4 toolchain go1.23.6 @@ -9,7 +9,7 @@ require ( github.com/stretchr/testify v1.10.0 github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper v1.45.2 gopkg.in/yaml.v3 v3.0.1 - k8s.io/apimachinery v0.29.2 + k8s.io/apimachinery v0.28.4 ) require ( @@ -69,8 +69,8 @@ require ( github.com/cloudflare/circl v1.3.7 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/cyphar/filepath-securejoin v0.3.6 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/ghodss/yaml v1.0.0 // indirect @@ -82,13 +82,13 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.21.5 // indirect github.com/go-openapi/errors v0.22.0 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonpointer v0.20.1 // indirect github.com/go-openapi/jsonreference v0.20.3 // indirect github.com/go-openapi/loads v0.21.3 // indirect github.com/go-openapi/runtime v0.26.0 // indirect github.com/go-openapi/spec v0.20.12 // indirect github.com/go-openapi/strfmt v0.23.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/swag v0.22.5 // indirect github.com/go-openapi/validate v0.22.4 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect @@ -122,7 +122,7 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect - github.com/klauspost/compress v1.16.6 // indirect + github.com/klauspost/compress v1.16.5 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-zglob v0.0.4 // indirect @@ -130,11 +130,10 @@ require ( github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/moby/spdystream v0.5.0 // indirect + github.com/moby/spdystream v0.2.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pjbgf/sha1cd v0.3.2 // indirect @@ -154,7 +153,7 @@ require ( go.opentelemetry.io/otel/metric v1.29.0 // indirect go.opentelemetry.io/otel/trace v1.29.0 // indirect golang.org/x/crypto v0.33.0 // indirect - golang.org/x/mod v0.20.0 // indirect + golang.org/x/mod v0.18.0 // indirect golang.org/x/net v0.34.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect golang.org/x/sync v0.11.0 // indirect @@ -162,17 +161,17 @@ require ( golang.org/x/term v0.29.0 // indirect golang.org/x/text v0.22.0 // indirect golang.org/x/time v0.8.0 // indirect - golang.org/x/tools v0.24.0 // indirect + golang.org/x/tools v0.22.0 // indirect google.golang.org/protobuf v1.35.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/api v0.29.2 // indirect - k8s.io/client-go v0.29.2 // indirect - k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect - k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect - sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect + k8s.io/api v0.28.4 // indirect + k8s.io/client-go v0.28.4 // indirect + k8s.io/klog/v2 v2.100.1 // indirect + k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect + k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/tests/go.sum b/tests/go.sum index 2b06f299..4cdd5173 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -128,13 +128,12 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM= github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/elazarl/goproxy v1.4.0 h1:4GyuSbFa+s26+3rmYNSuUVsx+HgPrV1bk1jXI0l9wjM= github.com/elazarl/goproxy v1.4.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= +github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= @@ -161,6 +160,7 @@ github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMj github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= github.com/go-git/go-git/v5 v5.13.2 h1:7O7xvsK7K+rZPKW6AQR1YyNhfywkv7B8/FsP3ki6Zv0= github.com/go-git/go-git/v5 v5.13.2/go.mod h1:hWdW5P4YZRjmpGHwRH2v3zkWcNl6HeXaXQEMGb3NJ9A= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -175,8 +175,8 @@ github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpX github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonpointer v0.20.1 h1:MkK4VEIEZMj4wT9PmjaUmGflVBr9nvud4Q4UVFbDoBE= +github.com/go-openapi/jsonpointer v0.20.1/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= github.com/go-openapi/jsonreference v0.20.3 h1:EjGcjTW8pD1mRis6+w/gmoBdqv5+RbE9B85D1NgDOVQ= github.com/go-openapi/jsonreference v0.20.3/go.mod h1:FviDZ46i9ivh810gqzFLl5NttD5q3tSlMLqLr6okedM= github.com/go-openapi/loads v0.21.3 h1:8sSH2FIm/SnbDUGv572md4YqVMFne/a9Eubvcd3anew= @@ -189,8 +189,8 @@ github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrC github.com/go-openapi/strfmt v0.21.7/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew= github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c= github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-openapi/swag v0.22.5 h1:fVS63IE3M0lsuWRzuom3RLwUMVI2peDH01s6M70ugys= +github.com/go-openapi/swag v0.22.5/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0= github.com/go-openapi/validate v0.22.4 h1:5v3jmMyIPKTR8Lv9syBAIRxG6lY0RqeBPB1LKEijzk8= github.com/go-openapi/validate v0.22.4/go.mod h1:qm6O8ZIcPVdSY5219468Jv7kBdGvkiZLPOmqnqTUZ2A= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= @@ -209,8 +209,6 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= -github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M= github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -245,12 +243,13 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= -github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gruntwork-io/go-commons v0.8.0 h1:k/yypwrPqSeYHevLlEDmvmgQzcyTwrlZGRaxEM6G0ro= github.com/gruntwork-io/go-commons v0.8.0/go.mod h1:gtp0yTtIBExIZp7vyIV9I0XQkVwiQZze678hvDXof78= github.com/gruntwork-io/terratest v0.48.2 h1:+VwfODchq8jxZZWD+s8gBlhD1z6/C4bFLNrhpm9ONrs= @@ -308,8 +307,8 @@ github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk= -github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -342,8 +341,8 @@ github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTS github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= -github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -352,8 +351,6 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= @@ -381,9 +378,8 @@ github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3Ro github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= +github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= -github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= -github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= @@ -512,8 +508,8 @@ golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -651,8 +647,8 @@ golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= -golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -693,21 +689,21 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.29.2 h1:hBC7B9+MU+ptchxEqTNW2DkUosJpp1P+Wn6YncZ474A= -k8s.io/api v0.29.2/go.mod h1:sdIaaKuU7P44aoyyLlikSLayT6Vb7bvJNCX105xZXY0= -k8s.io/apimachinery v0.29.2 h1:EWGpfJ856oj11C52NRCHuU7rFDwxev48z+6DSlGNsV8= -k8s.io/apimachinery v0.29.2/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= -k8s.io/client-go v0.29.2 h1:FEg85el1TeZp+/vYJM7hkDlSTFZ+c5nnK44DJ4FyoRg= -k8s.io/client-go v0.29.2/go.mod h1:knlvFZE58VpqbQpJNbCbctTVXcd35mMyAAwBdpt4jrA= -k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= -k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= -k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= -k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= -sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= -sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY= +k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0= +k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8= +k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg= +k8s.io/client-go v0.28.4 h1:Np5ocjlZcTrkyRJ3+T3PkXDpe4UpatQxj85+xjaD2wY= +k8s.io/client-go v0.28.4/go.mod h1:0VDZFpgoZfelyP5Wqu0/r/TRYcLYuJ2U1KEeoaPa1N4= +k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= +k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= From 6df799080badf13551c356621b618ecc97fca1a2 Mon Sep 17 00:00:00 2001 From: valerio-bontempi Date: Mon, 10 Feb 2025 16:27:56 +0100 Subject: [PATCH 38/40] feat: moved certs common name setting into test code --- .../imagepull-apikey-secrets-manager/main.tf | 2 +- examples/all-combined/privatecertificate.tf | 5 +++-- examples/all-combined/publiccertificate.tf | 3 ++- examples/all-combined/variables.tf | 11 ++++------- tests/pr_test.go | 4 ++++ 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/examples/all-combined/imagepull-apikey-secrets-manager/main.tf b/examples/all-combined/imagepull-apikey-secrets-manager/main.tf index 9c622707..c5d52542 100644 --- a/examples/all-combined/imagepull-apikey-secrets-manager/main.tf +++ b/examples/all-combined/imagepull-apikey-secrets-manager/main.tf @@ -50,7 +50,7 @@ module "dynamic_serviceid_apikey" { depends_on = [time_sleep.wait_30_seconds_for_creation] } -## Wait 30 sec after APIKey is deleted to ensure proper processing (https://github.ibm.com/GoldenEye/issues/issues/2200) +## Wait 30 sec after APIKey is deleted to ensure proper processing resource "time_sleep" "wait_30_seconds_for_destruction" { depends_on = [module.dynamic_serviceid_apikey] destroy_duration = "30s" diff --git a/examples/all-combined/privatecertificate.tf b/examples/all-combined/privatecertificate.tf index 25d44e49..d9d039c7 100644 --- a/examples/all-combined/privatecertificate.tf +++ b/examples/all-combined/privatecertificate.tf @@ -4,8 +4,9 @@ # private certificate common name, Certificate Authority common name and certificate template name definition locals { - pvt_cert_common_name = var.pvt_cert_common_name == null ? "pvt-${var.prefix}.goldeneye.dev.cloud.ibm.com" : var.pvt_cert_common_name - pvt_root_ca_common_name = var.pvt_root_ca_common_name == null ? "pvt-${var.prefix}.goldeneye.dev.cloud.ibm.com" : var.pvt_root_ca_common_name + # generating certificate common name + pvt_cert_common_name = "pvt-${var.prefix}.${var.pvt_cert_common_name}" + pvt_root_ca_common_name = "pvt-${var.prefix}.${var.pvt_root_ca_common_name}" pvt_certificate_template_name = var.pvt_certificate_template_name != null ? var.pvt_certificate_template_name : "pvt-${var.prefix}-cert-template" } diff --git a/examples/all-combined/publiccertificate.tf b/examples/all-combined/publiccertificate.tf index 44b02f51..52a1ccaa 100644 --- a/examples/all-combined/publiccertificate.tf +++ b/examples/all-combined/publiccertificate.tf @@ -27,7 +27,8 @@ module "secrets_manager_public_cert_engine" { # public certificate common name definition locals { - cert_common_name = var.cert_common_name == null ? "${var.prefix}-2.goldeneye.dev.cloud.ibm.com" : var.cert_common_name + # generating certificate common name + cert_common_name = "pub-${var.prefix}.${var.cert_common_name}" } # public certificate creation diff --git a/examples/all-combined/variables.tf b/examples/all-combined/variables.tf index c59844ed..f173c455 100644 --- a/examples/all-combined/variables.tf +++ b/examples/all-combined/variables.tf @@ -235,9 +235,8 @@ variable "skip_iam_authorization_policy" { } variable "cert_common_name" { - description = "Public certificate common name. If null it will be set to [prefix value].project.dev.cloud.ibm.com" + description = "Public certificate common name" type = string - default = null } variable "ca_name" { @@ -327,21 +326,19 @@ variable "existing_cis_instance_resource_group_id" { ### private certificate secret configuration variable "pvt_cert_common_name" { - description = "Private certificate common name. If null it will be set to pvt-[prefix value].goldeneye.dev.cloud.ibm.com" + description = "Private certificate common name" type = string - default = null } variable "pvt_ca_name" { type = string - description = "Secret Managers certificate authority name. If null it will be set to pvt-[prefix value]-goldeneye-ca" + description = "Secret Managers certificate authority name. If null it will be set to pvt-[prefix]-project-root-ca" default = null } variable "pvt_root_ca_common_name" { type = string - description = "Root CA common name for the private certificate. If null it will be set to pvt-[prefix value].goldeneye.dev.cloud.ibm.com" - default = null + description = "Root CA common name for the private certificate" } variable "pvt_ca_max_ttl" { diff --git a/tests/pr_test.go b/tests/pr_test.go index 65e5c311..c867f9af 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -108,6 +108,10 @@ func TestMain(m *testing.M) { // setting skip_iam_authorization_policy to true because using the existing secrets manager instance and the policy already exists "skip_iam_authorization_policy": true, "service_endpoints": "public", + // setting CIS domain to be used in the test + "pvt_cert_common_name": "goldeneye.dev.cloud.ibm.com", + "pvt_root_ca_common_name": "goldeneye.dev.cloud.ibm.com", + "cert_common_name": "goldeneye.dev.cloud.ibm.com", } os.Exit(m.Run()) From 716988a37cfb323c23c3e177e86d2080aa9e3a63 Mon Sep 17 00:00:00 2001 From: valerio-bontempi Date: Mon, 10 Feb 2025 17:05:04 +0100 Subject: [PATCH 39/40] feat: added default values --- examples/all-combined/variables.tf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/all-combined/variables.tf b/examples/all-combined/variables.tf index f173c455..f9449a8a 100644 --- a/examples/all-combined/variables.tf +++ b/examples/all-combined/variables.tf @@ -237,6 +237,7 @@ variable "skip_iam_authorization_policy" { variable "cert_common_name" { description = "Public certificate common name" type = string + default = "example.com" } variable "ca_name" { @@ -328,6 +329,7 @@ variable "existing_cis_instance_resource_group_id" { variable "pvt_cert_common_name" { description = "Private certificate common name" type = string + default = "example.com" } variable "pvt_ca_name" { @@ -339,6 +341,7 @@ variable "pvt_ca_name" { variable "pvt_root_ca_common_name" { type = string description = "Root CA common name for the private certificate" + default = "example.com" } variable "pvt_ca_max_ttl" { From 06cd3f598bd15aae5fcb770b7cb2e6ab6f4203bc Mon Sep 17 00:00:00 2001 From: valerio-bontempi Date: Mon, 10 Feb 2025 18:57:50 +0100 Subject: [PATCH 40/40] fix: fixed vars descriptions and reloader chart version --- README.md | 6 +++--- variables.tf | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index dade8b5d..40a3efa7 100644 --- a/README.md +++ b/README.md @@ -521,18 +521,18 @@ module "es_kubernetes_secret" { | [eso\_cluster\_nodes\_configuration](#input\_eso\_cluster\_nodes\_configuration) | Configuration to use to customise ESO deployment on specific cluster nodes. Setting appropriate values will result in customising ESO helm release. Default value is null to keep ESO standard deployment. |
object({
nodeSelector = object({
label = string
value = string
})
tolerations = object({
key = string
operator = string
value = string
effect = string
})
})
| `null` | no | | [eso\_enroll\_in\_servicemesh](#input\_eso\_enroll\_in\_servicemesh) | Flag to enroll ESO into istio servicemesh | `bool` | `false` | no | | [eso\_image](#input\_eso\_image) | The External Secrets Operator image in the format of `[registry-url]/[namespace]/[image]`. | `string` | `"ghcr.io/external-secrets/external-secrets"` | no | -| [eso\_image\_version](#input\_eso\_image\_version) | The version or digest for the external secrets image to deploy. | `string` | `"v0.12.1-ubi@sha256:d38834043de0a4e4feeac8a08d0bc96b71ddd7fe1d4c8583ee3751badeaeb01d"` | no | +| [eso\_image\_version](#input\_eso\_image\_version) | The version or digest for the external secrets image to deploy. If changing the value, ensure it is compatible with the chart version set in eso\_chart\_version. | `string` | `"v0.12.1-ubi@sha256:d38834043de0a4e4feeac8a08d0bc96b71ddd7fe1d4c8583ee3751badeaeb01d"` | no | | [eso\_namespace](#input\_eso\_namespace) | Namespace to create and be used to install ESO components including helm releases. If eso\_store\_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster\_store in it | `string` | `null` | no | | [eso\_pod\_configuration](#input\_eso\_pod\_configuration) | Configuration to use to customise ESO deployment on specific pods. Setting appropriate values will result in customising ESO helm release. Default value is {} to keep ESO standard deployment. Ignore the key if not required. |
object({
annotations = optional(object({
# The annotations for external secret controller pods.
external_secrets = optional(map(string), {})
# The annotations for external secret cert controller pods.
external_secrets_cert_controller = optional(map(string), {})
# The annotations for external secret controller pods.
external_secrets_webhook = optional(map(string), {})
}), {})

labels = optional(object({
# The labels for external secret controller pods.
external_secrets = optional(map(string), {})
# The labels for external secret cert controller pods.
external_secrets_cert_controller = optional(map(string), {})
# The labels for external secret controller pods.
external_secrets_webhook = optional(map(string), {})
}), {})
})
| `{}` | no | | [existing\_eso\_namespace](#input\_existing\_eso\_namespace) | Existing Namespace to be used to install ESO components including helm releases. If eso\_store\_scope == cluster, this will also be used to deploy ClusterSecretStore/cluster\_store in it | `string` | `null` | no | | [reloader\_chart\_location](#input\_reloader\_chart\_location) | The location of the Reloader Helm chart. | `string` | `"https://stakater.github.io/stakater-charts"` | no | -| [reloader\_chart\_version](#input\_reloader\_chart\_version) | The version of the Reloader Helm chart. Ensure that the chart version is compatible with the image version specified in reloader\_image\_version. | `string` | `"1.2.0"` | no | +| [reloader\_chart\_version](#input\_reloader\_chart\_version) | The version of the Reloader Helm chart. Ensure that the chart version is compatible with the image version specified in reloader\_image\_version. | `string` | `"1.2.1"` | no | | [reloader\_custom\_values](#input\_reloader\_custom\_values) | String containing custom values to be used for reloader helm chart. See https://github.com/stakater/Reloader/blob/master/deployments/kubernetes/chart/reloader/values.yaml | `string` | `null` | no | | [reloader\_deployed](#input\_reloader\_deployed) | Whether to deploy reloader or not https://github.com/stakater/Reloader | `bool` | `true` | no | | [reloader\_ignore\_configmaps](#input\_reloader\_ignore\_configmaps) | Whether to ignore configmap changes or not | `bool` | `false` | no | | [reloader\_ignore\_secrets](#input\_reloader\_ignore\_secrets) | Whether to ignore secret changes or not | `bool` | `false` | no | | [reloader\_image](#input\_reloader\_image) | The reloader image in the format of `[registry-url]/[namespace]/[image]`. | `string` | `"ghcr.io/stakater/reloader"` | no | -| [reloader\_image\_version](#input\_reloader\_image\_version) | The version or digest for the reloader image to deploy. | `string` | `"v1.2.1-ubi@sha256:80a557100c6835c7e3c9842194250c9c4ca78f43200bc3a93a32e5b105ad11bb"` | no | +| [reloader\_image\_version](#input\_reloader\_image\_version) | The version or digest for the reloader image to deploy. If changing the value, ensure it is compatible with the chart version set in reloader\_chart\_version. | `string` | `"v1.2.1-ubi@sha256:80a557100c6835c7e3c9842194250c9c4ca78f43200bc3a93a32e5b105ad11bb"` | no | | [reloader\_is\_argo\_rollouts](#input\_reloader\_is\_argo\_rollouts) | Enable Argo Rollouts | `bool` | `false` | no | | [reloader\_is\_openshift](#input\_reloader\_is\_openshift) | Enable OpenShift DeploymentConfigs | `bool` | `true` | no | | [reloader\_log\_format](#input\_reloader\_log\_format) | The log format to use for reloader. Possible values are `json` or `text`. Default value is `json` | `string` | `"text"` | no | diff --git a/variables.tf b/variables.tf index 7589bbb2..40b13534 100644 --- a/variables.tf +++ b/variables.tf @@ -76,7 +76,7 @@ variable "eso_image" { variable "eso_image_version" { type = string - description = "The version or digest for the external secrets image to deploy." + description = "The version or digest for the external secrets image to deploy. If changing the value, ensure it is compatible with the chart version set in eso_chart_version." default = "v0.12.1-ubi@sha256:d38834043de0a4e4feeac8a08d0bc96b71ddd7fe1d4c8583ee3751badeaeb01d" # datasource: ghcr.io/external-secrets/external-secrets nullable = false validation { @@ -203,7 +203,7 @@ variable "reloader_image" { variable "reloader_image_version" { type = string - description = "The version or digest for the reloader image to deploy." + description = "The version or digest for the reloader image to deploy. If changing the value, ensure it is compatible with the chart version set in reloader_chart_version." default = "v1.2.1-ubi@sha256:80a557100c6835c7e3c9842194250c9c4ca78f43200bc3a93a32e5b105ad11bb" # datasource: ghcr.io/stakater/reloader nullable = false validation { @@ -223,6 +223,6 @@ variable "reloader_chart_version" { type = string description = "The version of the Reloader Helm chart. Ensure that the chart version is compatible with the image version specified in reloader_image_version." # renovate: datasource=github-releases depName=stakater/Reloader - default = "1.2.0" + default = "1.2.1" nullable = false }