hackforla / hackforla/incubator
Ship a downloadable terraform.tfvars backed by a read-only Postgres role
- Dominant language
- HCL
- Stars
- 6
- Forks
- 18
- Avg merge
- 1h 9m
- Merged PRs (30d)
- 42
Description
### Overview
We need a contributor to be able to run `terraform plan` locally without being handed the master password for the production database. Today a plan has to reach the database to refresh 18 `postgresql_role` and `postgresql_grant` resources, and the only credential that works is the `postgres` superuser — so a read-only operation currently requires the most privileged account we have.
### Action Items
**1. Make the connecting user configurable — this blocks everything else**
The Postgres provider hardcodes the user, so a read-only role cannot be used at all until this changes.
- [ ] In `terraform/variables.tf`, add a `pguser` variable with `default = "postgres"`. The default is what keeps CI working unchanged — CI passes `TF_VAR_pghost` and `TF_VAR_pgpassword` and knows nothing about a user.
- [ ] In `terraform/backend.tf`, change the `postgresql` provider's `username = "postgres"` (line 21 when written; find it inside the `provider "postgresql"` block) to `username = var.pguser`.
**2. Create the read-only role and find out whether it is actually sufficient**
This is the open technical question and the reason this ticket is not smaller. It may turn out that a genuinely read-only role cannot refresh everything, in which case the role grows and the trade-off has to be re-examined.
- [ ] Create a read-only role on `incubator-prod-database`. Reading roles hits `pg_roles`; reading grants hits catalog ACLs. Start from the least privilege that can see both and add only what the refresh demands.
- [ ] **Acceptance criterion:** run a full `terraform plan` authenticated as that role and confirm it still reports **no changes**. A plan that errors, or that reports spurious changes because it cannot see something, means the role is not sufficient — record what it could not read on this issue before widening it.
- [ ] If the role has to be widened beyond read-only to pass, stop and raise it here rather than proceeding. The whole point of the ticket is that contributors get something weaker than the master credential; a role that ends up close to superuser does not deliver that.
**3. Ship the file**
- [ ] Add `terraform/terraform.tfvars.example` to the repo, with placeholder values and a comment per variable saying what it is and where to get it. This one is committed — it holds no secrets.
- [ ] Store the real `terraform.tfvars` as a **Document** in the DevOps 1Password vault so a contributor can download it directly rather than assembling it by hand.
- [ ] Document the workflow in the repo README: download the file from 1Password, drop it in `terraform/`, run `terraform plan`. Terraform auto-loads `terraform.tfvars` from the working directory, so there is no flag to pass and no shell export — which is the reason for this shape rather than environment variables.
- [ ] State plainly in that documentation that this credential is for `plan` only and that `apply` is not available to contributors.
- [ ] After the PR merges, have someone who has not done the setup before follow the README from scratch and confirm they get a clean plan. The point of the ticket is the first-time experience, and the author is the worst person to judge it.
### Resources/Instructions
- Files to change: [terraform/variables.tf](https://github.com/hackforla/incubator/blob/main/terraform/variables.tf), [terraform/backend.tf](https://github.com/hackforla/incubator/blob/main/terraform/backend.tf), the repo README, plus the new `terraform/terraform.tfvars.example`.
- `terraform.tfvars` is **already gitignored** (`.gitignore:15`), so there is no new ignore rule to add and no accidental-commit path to guard.
- Do not confuse this with the committed `terraform/prod.backend.tfvars`, which is `-backend-config` for `init` and is not secret.
- Only the password is actually secret. `var.pghost` is the RDS endpoint and is readable from `aws rds describe-db-instances`.
- Environment variables (`TF_VAR_pguser` and friends) were considered and rejected for contributors: they need a `source`/`export` step that differs between PowerShell and bash. CI keeps using them; contributors get a file.
- Encouraging sign for the read-only question: the provider already sets `superuser = false`, so it is not taking superuser-only code paths today.
- **Dependency worth knowing:** this works only because the database is reachable from a contributor's machine. That exposure is currently accepted, but if `publicly_accessible` is ever turned off, local `terraform plan` stops working for everyone and this ticket's premise goes with it.
- **Out of scope:** AWS credentials. Contributors get AWS access through their IAM user or Identity Center, not through a downloaded file — that belongs to #139. `devops-security` is also out of scope; it has no Postgres provider and no equivalent need.
Contributor guide
Research direction
Start with terraform/variables.tf and terraform/backend.tf to trace the provider credentials, then inspect how the 18 postgresql_role and postgresql_grant resources are refreshed. Run a full terraform plan with the proposed read-only role and record any catalog access failures. Done means a no-change plan succeeds, terraform/terraform.tfvars.example and the README describe the plan-only workflow, and the real file is stored in the DevOps 1Password vault.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- postgresql, terraform
- Domain
- databases, devops, documentation
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100