Repository navigation
Conversation
Add community/modules/database/cloudsql, which creates a MySQL or PostgreSQL instance, database and user reachable only over Private Service Access or Private Service Connect, or adopts an existing instance. The generated password is written through write-only arguments to a Secret Manager secret and the database user, so it is never stored in Terraform state, and consumers get per-secret read access. Production defaults include deletion protection with a destroy guard, automated backups with point-in-time recovery, encrypted-only connections and a random root password. CMEK is supported for the instance and the secret replica. Also add an example blueprint, three validate_configs test configs and a scheduled daily integration test covering adoption, PostgreSQL over PSC, password rotation and a protected destroy.
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a robust, production-ready Cloud SQL module designed for secure database deployments within the HPC Toolkit. By leveraging Secret Manager for ephemeral credential handling and enforcing private networking, the module minimizes security risks. It supports both new instance creation and the adoption of existing instances, with extensive documentation and automated daily testing to ensure reliability across various configurations. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a new community module cloudsql for creating private Cloud SQL instances (MySQL or PostgreSQL) with credentials managed securely via Secret Manager, along with corresponding examples, integration tests, and documentation updates. The review feedback highlights two key improvement opportunities: first, removing an overly restrictive validation on disk_size_gb that unnecessarily forces disk_autoresize to false; and second, updating the regex validator for network_id in metadata.yaml to allow empty strings, preventing validation failures when using Private Service Connect or adopting existing instances.
The disk_size_gb validation required disk_autoresize = false whenever a size was set. The google provider (>= 7.13.0) already handles autoresize: when the disk has grown past the configured size, it clears the diff instead of shrinking or recreating the instance. Forcing autoresize off was also the riskier choice, since on 7.13.0 lowering the configured size then forces the instance to be recreated. Remove the validation and document the behaviour on disk_size_gb.
|
this PR has been inactive for 2 days and has no unresolved comments. @ishitachail, @vikramvs-gg, please review. |
What this does
Adds
community/modules/database/cloudsql, a general-purpose Cloud SQL module (MySQL or PostgreSQL) usable by any deployment. It creates an instance, database and user reachable only over private networking, and delivers the generated password through a Secret Manager secret. The password is never stored in Terraform state, plan files, outputs or startup scripts.slurm-cloudsql-federationis unchanged. Moving Slurm accounting onto this module is left to a later PR, once this module has run in production.use_psc_connection). There is never a public IP (ipv4_enabled = falseunconditionally).network_idis required only for a created instance over Private Service Access.password_secret_accessors, oruseofmodules/project/service-account(theservice_account_iam_emailinput), grantsroles/secretmanager.secretAccessoron that one secret only, never project-wide. A user-suppliedsql_passwordis supported but documented as landing in the deployment folder and the saved plan.password_version. The module replaces the secret version and updates the user in the same apply. The old version is disabled rather than deleted, so a failed apply can be recovered by re-enabling it. The README explains how to destroy disabled versions, which are still billed.existing_instance_namethe module creates only the database, user and secret on an existing instance. The instance must have a private IP (a plan-time postcondition), and adoption cannot be combined with PSC. To adopt an instance created in the same apply, pass the creating module'sinstance_nameoutput. The adopted instance's database is abandoned on destroy, so its data stays.encryption_key_nameencrypts the instance, anduser_managed_replication[].kms_key_nameencrypts the secret's replica. Both take keys from the existingkms-keyandkms-key-iammodules:use: [kms_key_iam]fillsencryption_key_nameand orders the instance after the IAM grant to the Cloud SQL service agent. The module contains no key-management resources.Production defaults (created instance)
deletion_protection = trueandapi_deletion_protection = true. Both checks run only when the instance itself is deleted, by which point Terraform has already removed the database, user, secret and PSC endpoint. So while either is on, aterraform_datadestroy guard that depends on all of them fails the destroy before anything is removed. The database and user also default toABANDONwhile protected. Teardown: set both tofalse, apply, then destroy.enable_backups = trueandpoint_in_time_recovery = true(binary logging on MySQL), withretain_backups_on_delete = true.backup_start_time,retained_backups(at least 7, matching the 7-day transaction log retention) andfinal_backup_retention_daystune them.ssl_mode = "ENCRYPTED_ONLY".TRUSTED_CLIENT_CERTIFICATE_REQUIREDis accepted; the module does not issue client certificates.set_root_password = true: the built-inroot/postgresuser gets a random password that is never stored. It is set only at creation, so turning the flag off later cannot blank it.availability_type = "ZONAL".REGIONALMySQL is rejected at plan time unless backups and binary logging are on, as Cloud SQL requires.ABANDON, because a user that owns objects cannot be dropped.Files
community/modules/database/cloudsql/(main.tf,variables.tf,outputs.tf,versions.tf,metadata.yaml,README.md). Outputs:instance_name,connection_name,self_link,private_ip_address,database_name,username,password_secret_id,password_secret_version.community/examples/cloudsql-database.yaml, Private Service Access with a workload service account granted read on the secret throughuse.cloudsql-psc.yaml: PSC with the production settings (backups, retention, final backup, both protections,REGIONAL,ssl_mode, consumer projects, maintenance window).cloudsql-postgres.yaml: PostgreSQL with database flags and query insights, plus an adopting module.cloudsql-cmek.yaml: CMEK on the instance and the secret replica throughkms-keyandkms-key-iam.cloudsql-database(build, test definition, blueprint,test-validation/test-cloudsql.yml) and its Kueue lock entries. It is not inTO_SKIP, solist_tests.pyis unchanged from develop.modules/README.mdandexamples/README.mdlist the module and example.tools/validate_configs/test_configs/README.mddescribes the three configs. Thekms-key-iamoutput description and README namecloudsqlas a consumer ofencryption_key_name(documentation only).Daily test coverage
One run deploys:
It checks:
password_version, then version 1 is DISABLED, version 2 is ENABLED, the new password works and the old one is refused;The MySQL instance name gets a per-attempt suffix, because a Kueue requeue reuses the build ID and Cloud SQL reserves a deleted instance's name for up to a week.
How the minimal Secret Manager role was derived
I deployed a real instance and impersonated a consumer service account that held nothing but a binding on that one secret:
roles/secretmanager.secretAccessor, the consumer could read the password.secretmanager.versions.access.So that role is both sufficient and necessary; no project-level or admin role is needed. Every live test since has used a VM whose only access is this per-secret binding.
The identity running Terraform also needs
secretmanager.secrets.setIamPolicyon the secret, plussecretmanager.versions.access, because the module reads the version back on every plan. The first could not be verified independently, because the test identity holdsroles/owner.What's been tested
Local (current head):
make testspasses: Go unit tests, golden copies, andvalidate_configsacross 99 blueprints, including the four cloudsql blueprints.network_id;tier; PSC with adoption;REGIONALMySQL without backups or binary logging;retained_backupsbelow 7;MYSQL_5_6).>= 7.13.0(the first release withroot_password_wo); validation fails on 7.12.0. random>= 3.7.1(3.7.0 was never published).Live (project
ellenp-personal-project; each environment torn down afterwards, then the whole project swept):failed=0. Earlier versions of the test also passed on 2026-10-12 and twice on 2026-10-13.set_root_passwordoff applied an innocent-looking update that leftroot@%with no password.Error 400 ... binary logging enabled); the module now rejects it at plan time.The instance is protected) until set to false and applied.pg_hba.conf ... no encryption).terraform destroysucceeds throughABANDON(2026-10-12).kms-keykey, and rotation works in that setup (2026-10-07).kms-keyandkms-key-iam(2026-10-06).deletion_policy: ABANDONonprivate-service-access(repeated).Gaps, maintainer decisions and future work
Gaps
REGIONALare not in the daily test. CMEK was last verified live on an earlier revision;REGIONALhas only been tested as a rejection.mysql --ssl).Maintainer decisions
community/modules/database/cloudsql/(community, experimental), alongsideslurm-cloudsql-federation, rather than coremodules/database/.db-f1-microinstances and ane2-smallVM for about 45 minutes.local-exec, so the machine running Terraform needssh(true for gcluster and the Open Front End). There is precedent, for example incommunity/modules/scripts/gcloud.deletion_policy: ABANDONrather thanREMOVE_PEERINGonprivate-service-accessin the example and tests.REMOVE_PEERINGneeds google >= 8.1.0, which no repo module requires.ABANDONis the existing convention and was verified to tear down cleanly.metadata.yamllists sqladmin, servicenetworking, secretmanager and compute. Thetest_apis_enabledvalidator requires all four, even for PSC-only or adoption-only deployments; this is documented in the README.sql_passwordis not an ephemeral variable. gcluster writes blueprint values into the deployment folder, so marking it ephemeral would not keep it off disk. The README says to leave it unset.Deferred work
None of the following is implemented in this PR, and nothing in this PR depends on them.
slurm-cloudsql-federationat it, with an unchanged interface and a zero-diff plan for existing deployments, once this module has run in production.makemigrations.CLOUD_IAM_SERVICE_ACCOUNT, thecloudsql.iam_authenticationflag, androles/cloudsql.instanceUser(plusroles/cloudsql.clientthrough the Auth Proxy). Whether to add this is a maintainer call.password_secret_accessorsor its ownsecret_bindings; neither PR depends on the other.pre-existing-cloudsqlmodule, following the toolkit'spre-existing-*convention.