From 90a9b9252f2764119555458d67ebed2e35ce5571 Mon Sep 17 00:00:00 2001 From: khatrivarun Date: Tue, 17 Mar 2026 11:56:54 +0530 Subject: [PATCH 1/4] feat(ferret): configure secrets and references to be pushed to openbao --- infrastructure/main.tf | 2 +- modules/ferretdb/cluster.tf | 2 +- modules/ferretdb/locals.tf | 8 +- modules/ferretdb/mongo-express.tf | 8 +- modules/ferretdb/secrets.tf | 264 ++++++++++++++++++++++-------- 5 files changed, 210 insertions(+), 74 deletions(-) diff --git a/infrastructure/main.tf b/infrastructure/main.tf index e4b8e3a..1c58a1e 100644 --- a/infrastructure/main.tf +++ b/infrastructure/main.tf @@ -132,7 +132,7 @@ module "cnpg" { # FerretDB Deployment for MongoDB Database Solution module "ferretdb" { - source = "git::https://github.com/necro-cloud/modules//modules/ferretdb?ref=main" + source = "git::https://github.com/necro-cloud/modules//modules/ferretdb?ref=task/118/ferret-secrets" // Cluster Secret Store Details cluster_secret_store_name = module.openbao.cluster_secret_store_name diff --git a/modules/ferretdb/cluster.tf b/modules/ferretdb/cluster.tf index 629d22b..9b97310 100644 --- a/modules/ferretdb/cluster.tf +++ b/modules/ferretdb/cluster.tf @@ -82,7 +82,7 @@ resource "kubernetes_manifest" "cluster" { "login" = true "name" = "ferret" "passwordSecret" = { - "name" = kubernetes_secret.ferret_database_credentials.metadata[0].name + "name" = kubernetes_manifest.ferret_database_credentials_sync.object.spec.target.name } "replication" = false "superuser" = false diff --git a/modules/ferretdb/locals.tf b/modules/ferretdb/locals.tf index 560de2b..23416a2 100644 --- a/modules/ferretdb/locals.tf +++ b/modules/ferretdb/locals.tf @@ -1,17 +1,17 @@ locals { access_namespaces = [for config in var.clients : config.namespace] - managed_roles = [for secret in kubernetes_secret.client_database_credentials : { + managed_roles = [for index, client in var.clients : { "bypassrls" = false - "comment" = "${secret.data.username} user for postgresql" + "comment" = "${client.user} user for postgresql" "connectionLimit" = -1 "createdb" = true "createrole" = true "ensure" = "present" "inherit" = true "login" = true - "name" = secret.data.username + "name" = client.user "passwordSecret" = { - "name" = secret.metadata[0].name + "name" = kubernetes_manifest.client_database_credentials_sync[index].object.spec.target.name } "replication" = false "superuser" = false diff --git a/modules/ferretdb/mongo-express.tf b/modules/ferretdb/mongo-express.tf index 75e0301..f374e28 100644 --- a/modules/ferretdb/mongo-express.tf +++ b/modules/ferretdb/mongo-express.tf @@ -63,7 +63,7 @@ resource "kubernetes_deployment" "mongo_express" { name = "DB_USERNAME" value_from { secret_key_ref { - name = kubernetes_secret.ferret_database_credentials.metadata[0].name + name = kubernetes_manifest.ferret_database_credentials_sync.object.spec.target.name key = "username" } } @@ -73,7 +73,7 @@ resource "kubernetes_deployment" "mongo_express" { name = "DB_PASSWORD" value_from { secret_key_ref { - name = kubernetes_secret.ferret_database_credentials.metadata[0].name + name = kubernetes_manifest.ferret_database_credentials_sync.object.spec.target.name key = "password" } } @@ -99,7 +99,7 @@ resource "kubernetes_deployment" "mongo_express" { name = "ME_CONFIG_BASICAUTH_USERNAME" value_from { secret_key_ref { - name = kubernetes_secret.ui_credentials.metadata[0].name + name = kubernetes_manifest.client_database_credentials_sync[count.index].object.spec.target.name key = "username" } } @@ -109,7 +109,7 @@ resource "kubernetes_deployment" "mongo_express" { name = "ME_CONFIG_BASICAUTH_PASSWORD" value_from { secret_key_ref { - name = kubernetes_secret.ui_credentials.metadata[0].name + name = kubernetes_manifest.client_database_credentials_sync[count.index].object.spec.target.name key = "password" } } diff --git a/modules/ferretdb/secrets.tf b/modules/ferretdb/secrets.tf index 1b81ab1..2f5a29f 100644 --- a/modules/ferretdb/secrets.tf +++ b/modules/ferretdb/secrets.tf @@ -38,90 +38,226 @@ resource "kubernetes_manifest" "garage_configuration_sync" { } } -// Database credentials configuration for Ferret -resource "random_password" "ferret_password" { - length = 20 - lower = true - numeric = true - special = false +// Password Generator for generating random passwords +resource "kubernetes_manifest" "password_generator" { + manifest = { + apiVersion = "generators.external-secrets.io/v1alpha1" + kind = "Password" + metadata = { + name = "password-generator" + namespace = kubernetes_namespace.namespace.metadata[0].name + } + spec = { + length = 20 + digits = 5 + symbols = 0 + noUpper = true + } + } } -resource "kubernetes_secret" "ferret_database_credentials" { - metadata { - name = "credentials-ferret" - namespace = kubernetes_namespace.namespace.metadata[0].name - - labels = { - app = var.app_name - component = "secret" +// Database credentials configuration for Ferret +resource "kubernetes_manifest" "ferret_database_credentials_sync" { + manifest = { + apiVersion = "external-secrets.io/v1" + kind = "ExternalSecret" + metadata = { + name = "credentials-ferret" + namespace = kubernetes_namespace.namespace.metadata[0].name + } + spec = { + refreshInterval = "0" + target = { + name = "credentials-ferret" + template = { + type = "kubernetes.io/basic-auth" + data = { + username = "ferret" + password = "{{ .password }}" + } + } + } + dataFrom = [{ + sourceRef = { + generatorRef = { + apiVersion = "generators.external-secrets.io/v1alpha1" + kind = "Password" + name = kubernetes_manifest.password_generator.object.metadata.name + } + } + }] } } +} - data = { - "username" = "ferret" - "password" = random_password.ferret_password.result +resource "kubernetes_manifest" "push_ferret_database_credentials" { + manifest = { + apiVersion = "external-secrets.io/v1alpha1" + kind = "PushSecret" + metadata = { + name = "push-${kubernetes_manifest.keycloak_database_credentials_sync.object.spec.target.name}" + namespace = kubernetes_namespace.namespace.metadata[0].name + } + spec = { + refreshInterval = "1h" + deletionPolicy = "None" + secretStoreRefs = [{ + name = var.cluster_secret_store_name + kind = "ClusterSecretStore" + }] + selector = { + secret = { + name = kubernetes_manifest.keycloak_database_credentials_sync.object.spec.target.name + } + } + data = [ + { + match = { + remoteRef = { + remoteKey = "${kubernetes_namespace.namespace.metadata[0].name}/credentials/${kubernetes_manifest.ferret_database_credentials_sync.object.spec.target.name}" + } + } + } + ] + } } - - type = "kubernetes.io/basic-auth" + depends_on = [kubernetes_manifest.ferret_database_credentials_sync] } + // Database credentials configuration for all clients -resource "random_password" "client_password" { +resource "kubernetes_manifest" "client_database_credentials_sync" { count = length(var.clients) - length = 20 - lower = true - numeric = true - special = false -} - -resource "kubernetes_secret" "client_database_credentials" { - count = length(var.clients) - metadata { - name = "credentials-${var.clients[count.index].user}" - namespace = kubernetes_namespace.namespace.metadata[0].name - - labels = { - app = var.app_name - component = "secret" + manifest = { + apiVersion = "external-secrets.io/v1" + kind = "ExternalSecret" + metadata = { + name = "credentials-${var.clients[count.index].user}" + namespace = kubernetes_namespace.namespace.metadata[0].name } - - annotations = { - "reflector.v1.k8s.emberstack.com/reflection-allowed" = "true" - "reflector.v1.k8s.emberstack.com/reflection-allowed-namespaces" = var.clients[count.index].namespace + spec = { + refreshInterval = "0" + target = { + name = "credentials-${var.clients[count.index].user}" + template = { + type = "kubernetes.io/basic-auth" + data = { + username = var.clients[count.index].user + password = "{{ .password }}" + } + } + } + dataFrom = [{ + sourceRef = { + generatorRef = { + apiVersion = "generators.external-secrets.io/v1alpha1" + kind = "Password" + name = kubernetes_manifest.password_generator.object.metadata.name + } + } + }] } } +} - data = { - "username" = var.clients[count.index].user - "password" = random_password.client_password[count.index].result +resource "kubernetes_manifest" "push_client_database_credentials" { + count = length(var.clients) + manifest = { + apiVersion = "external-secrets.io/v1alpha1" + kind = "PushSecret" + metadata = { + name = "push-${kubernetes_manifest.client_database_credentials_sync[count.index].object.spec.target.name}" + namespace = kubernetes_namespace.namespace.metadata[0].name + } + spec = { + refreshInterval = "1h" + deletionPolicy = "None" + secretStoreRefs = [{ + name = var.cluster_secret_store_name + kind = "ClusterSecretStore" + }] + selector = { + secret = { + name = kubernetes_manifest.client_database_credentials_sync[count.index].object.spec.target.name + } + } + data = [ + { + match = { + remoteRef = { + remoteKey = "${kubernetes_namespace.namespace.metadata[0].name}/credentials/${kubernetes_manifest.client_database_credentials_sync[count.index].object.spec.target.name}" + } + } + } + ] + } } - - type = "kubernetes.io/basic-auth" + depends_on = [kubernetes_manifest.client_database_credentials_sync] } // UI credentials configuration for MongoExpress -resource "random_password" "ui_password" { - length = 20 - lower = true - numeric = true - special = false -} - -resource "kubernetes_secret" "ui_credentials" { - metadata { - name = "ui-ferret" - namespace = kubernetes_namespace.namespace.metadata[0].name - - labels = { - app = var.app_name - component = "secret" +resource "kubernetes_manifest" "mongo_express_credentials_sync" { + manifest = { + apiVersion = "external-secrets.io/v1" + kind = "ExternalSecret" + metadata = { + name = "mongo-express-credentials" + namespace = kubernetes_namespace.namespace.metadata[0].name + } + spec = { + refreshInterval = "0" + target = { + name = "mongo-express-credentials" + template = { + data = { + username = "ferret" + password = "{{ .password }}" + } + } + } + dataFrom = [{ + sourceRef = { + generatorRef = { + apiVersion = "generators.external-secrets.io/v1alpha1" + kind = "Password" + name = kubernetes_manifest.password_generator.object.metadata.name + } + } + }] } } +} - data = { - "username" = "ferret" - "password" = random_password.ferret_password.result +resource "kubernetes_manifest" "push_mongo_express_credentials" { + manifest = { + apiVersion = "external-secrets.io/v1alpha1" + kind = "PushSecret" + metadata = { + name = "push-${kubernetes_manifest.mongo_express_credentials_sync.object.spec.target.name}" + namespace = kubernetes_namespace.namespace.metadata[0].name + } + spec = { + refreshInterval = "1h" + deletionPolicy = "None" + secretStoreRefs = [{ + name = var.cluster_secret_store_name + kind = "ClusterSecretStore" + }] + selector = { + secret = { + name = kubernetes_manifest.mongo_express_credentials_sync.object.spec.target.name + } + } + data = [ + { + match = { + remoteRef = { + remoteKey = "${kubernetes_namespace.namespace.metadata[0].name}/credentials/ui/${kubernetes_manifest.mongo_express_credentials_sync.object.spec.target.name}" + } + } + } + ] + } } - - type = "kubernetes.io/basic-auth" + depends_on = [kubernetes_manifest.mongo_express_credentials_sync] } From 8eadfd053a6c3858e7d964dac1d5d1cb391c1760 Mon Sep 17 00:00:00 2001 From: khatrivarun Date: Tue, 17 Mar 2026 12:00:27 +0530 Subject: [PATCH 2/4] fix(ferret): resource linkages fixes --- modules/ferretdb/mongo-express.tf | 4 ++-- modules/ferretdb/secrets.tf | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/ferretdb/mongo-express.tf b/modules/ferretdb/mongo-express.tf index f374e28..9d678c9 100644 --- a/modules/ferretdb/mongo-express.tf +++ b/modules/ferretdb/mongo-express.tf @@ -99,7 +99,7 @@ resource "kubernetes_deployment" "mongo_express" { name = "ME_CONFIG_BASICAUTH_USERNAME" value_from { secret_key_ref { - name = kubernetes_manifest.client_database_credentials_sync[count.index].object.spec.target.name + name = kubernetes_manifest.mongo_express_credentials_sync.object.spec.target.name key = "username" } } @@ -109,7 +109,7 @@ resource "kubernetes_deployment" "mongo_express" { name = "ME_CONFIG_BASICAUTH_PASSWORD" value_from { secret_key_ref { - name = kubernetes_manifest.client_database_credentials_sync[count.index].object.spec.target.name + name = kubernetes_manifest.mongo_express_credentials_sync.object.spec.target.name key = "password" } } diff --git a/modules/ferretdb/secrets.tf b/modules/ferretdb/secrets.tf index 2f5a29f..6eb7b40 100644 --- a/modules/ferretdb/secrets.tf +++ b/modules/ferretdb/secrets.tf @@ -95,7 +95,7 @@ resource "kubernetes_manifest" "push_ferret_database_credentials" { apiVersion = "external-secrets.io/v1alpha1" kind = "PushSecret" metadata = { - name = "push-${kubernetes_manifest.keycloak_database_credentials_sync.object.spec.target.name}" + name = "push-${kubernetes_manifest.ferret_database_credentials_sync.object.spec.target.name}" namespace = kubernetes_namespace.namespace.metadata[0].name } spec = { @@ -107,7 +107,7 @@ resource "kubernetes_manifest" "push_ferret_database_credentials" { }] selector = { secret = { - name = kubernetes_manifest.keycloak_database_credentials_sync.object.spec.target.name + name = kubernetes_manifest.ferret_database_credentials_sync.object.spec.target.name } } data = [ From 9ed1c13d3b53b8eae5b627abe4779b00190bb724 Mon Sep 17 00:00:00 2001 From: khatrivarun Date: Tue, 17 Mar 2026 12:32:05 +0530 Subject: [PATCH 3/4] fix(openbao): resource timeouts due to bad internet --- infrastructure/main.tf | 2 +- modules/openbao/job.tf | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/infrastructure/main.tf b/infrastructure/main.tf index 1c58a1e..7cb3cfe 100644 --- a/infrastructure/main.tf +++ b/infrastructure/main.tf @@ -35,7 +35,7 @@ module "observability" { # OpenBao Secrets Management Solution deployment module "openbao" { - source = "git::https://github.com/necro-cloud/modules//modules/openbao?ref=main" + source = "git::https://github.com/necro-cloud/modules//modules/openbao?ref=task/118/ferret-secrets" // Certificates Details cluster_issuer_name = module.cluster-issuer.cluster-issuer-name diff --git a/modules/openbao/job.tf b/modules/openbao/job.tf index c41a6ac..93e116b 100644 --- a/modules/openbao/job.tf +++ b/modules/openbao/job.tf @@ -65,4 +65,10 @@ resource "kubernetes_job" "configurator" { # Ensure OpenBao is fully up before running depends_on = [helm_release.openbao, kubernetes_manifest.internal_certificate] + + timeouts { + create = "10m" + update = "10m" + delete = "10m" + } } From 1fdb3ebb926a989815306d82d793317aaf7cd953 Mon Sep 17 00:00:00 2001 From: khatrivarun Date: Tue, 17 Mar 2026 13:03:00 +0530 Subject: [PATCH 4/4] docs(openbao): README updates --- modules/ferretdb/README.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/modules/ferretdb/README.md b/modules/ferretdb/README.md index 79e77c8..c7d904f 100644 --- a/modules/ferretdb/README.md +++ b/modules/ferretdb/README.md @@ -7,6 +7,7 @@ Required Modules to deploy FerretDB Database: 2. [Cluster Issuer](../cluster-issuer) 3. [Garage](../garage) 4. [Observability](../observability) +5. [OpenBao](../openbao) ## Providers @@ -24,13 +25,22 @@ Required Modules to deploy FerretDB Database: | [kubernetes_ingress_v1.mongo_express_ingress](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/ingress_v1) | resource | | [kubernetes_manifest.barman_object_store](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | | [kubernetes_manifest.client_certificate_authority](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | +| [kubernetes_manifest.client_database_credentials_sync](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | | [kubernetes_manifest.client_issuer](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | | [kubernetes_manifest.client_streaming_replica_certificate](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | | [kubernetes_manifest.cluster](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | | [kubernetes_manifest.ferret_cluster_image_catalog](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | +| [kubernetes_manifest.ferret_database_credentials_sync](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | +| [kubernetes_manifest.garage_certificate_authority_sync](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | +| [kubernetes_manifest.garage_configuration_sync](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | | [kubernetes_manifest.ingress_certificate](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | +| [kubernetes_manifest.mongo_express_credentials_sync](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | | [kubernetes_manifest.mongo_express_internal_certificate](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | +| [kubernetes_manifest.password_generator](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | | [kubernetes_manifest.public_issuer](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | +| [kubernetes_manifest.push_client_database_credentials](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | +| [kubernetes_manifest.push_ferret_database_credentials](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | +| [kubernetes_manifest.push_mongo_express_credentials](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | | [kubernetes_manifest.server_certificate](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | | [kubernetes_manifest.server_certificate_authority](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | | [kubernetes_manifest.server_issuer](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | @@ -39,17 +49,9 @@ Required Modules to deploy FerretDB Database: | [kubernetes_network_policy.ferret_network_policy](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/network_policy) | resource | | [kubernetes_pod_disruption_budget_v1.cnpg_pdb](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/pod_disruption_budget_v1) | resource | | [kubernetes_pod_disruption_budget_v1.ferret_pdb](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/pod_disruption_budget_v1) | resource | -| [kubernetes_secret.client_database_credentials](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret) | resource | | [kubernetes_secret.cloudflare_token](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret) | resource | -| [kubernetes_secret.ferret_database_credentials](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret) | resource | -| [kubernetes_secret.garage_certificate_authority](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret) | resource | -| [kubernetes_secret.garage_configuration](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret) | resource | -| [kubernetes_secret.ui_credentials](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret) | resource | | [kubernetes_service.ferret_service](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service) | resource | | [kubernetes_service.mongo_express](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service) | resource | -| [random_password.client_password](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource | -| [random_password.ferret_password](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource | -| [random_password.ui_password](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource | ## Inputs @@ -68,6 +70,7 @@ Required Modules to deploy FerretDB Database: | [cluster\_issuer\_name](#input\_cluster\_issuer\_name) | Name for the Cluster Issuer to be used to generate internal self signed certificates | `string` | n/a | yes | | [cluster\_name](#input\_cluster\_name) | Name of the Ferret Database Cluster to be created | `string` | `"ferret-postgresql-cluster"` | no | | [cluster\_postgresql\_version](#input\_cluster\_postgresql\_version) | Version of Ferret Database to use and deploy | `number` | `17` | no | +| [cluster\_secret\_store\_name](#input\_cluster\_secret\_store\_name) | Name of the cluster secret store to be used for pulling and pushing secrets to OpenBao | `string` | n/a | yes | | [cluster\_size](#input\_cluster\_size) | Number of pods to deploy for the Ferret Cluster | `number` | `2` | no | | [country\_name](#input\_country\_name) | Country name for deploying Ferret Database | `string` | `"India"` | no | | [domain](#input\_domain) | Domain for which Ingress Certificate is to be generated for | `string` | n/a | yes |