Skip to content

Commit d2d089d

Browse files
westonplatterCopilotcoderabbitai[bot]
authored
feat(INT-60): write up knowledge base example for standard DBs + Roles (#5)
## what - providers an example that pairs with https://www.notion.so/masterpoint/Databases-in-IaC-1c8859758a568015b3d6da59c1ce1685 - Example that creates admin, writer, and reader roles. ## why ## references - [INT-60](https://www.notion.so/masterpoint/Write-up-approach-in-Knowledge-Base-1d1859758a568067be11cbd552989384) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Documentation** - Corrected a Markdown syntax error in the main README to fix the banner image link. - Added a comprehensive README for the web app example, detailing PostgreSQL setup using Terraform, role descriptions, and authentication notes. - **New Features** - Introduced a complete example for a production-ready PostgreSQL setup using Terraform, including configuration files for variables, providers, outputs, and version constraints. - Added sample Terraform configuration and variable files to define database roles, privileges, and connection settings for a web application environment. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent eb94576 commit d2d089d

File tree

8 files changed

+421
-1
lines changed

8 files changed

+421
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
![Banner][banner-image]](https://masterpoint.io/)
1+
[![Banner][banner-image]](https://masterpoint.io/)
22

33
# terraform-postgres-automation
44

examples/web_app/README.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Example: Web (FastAPI) App setup
2+
3+
This example shows how to create roles for a FastAPI web application with thoughtful permission boundaries intended for a production setup.
4+
5+
## Prerequisites
6+
7+
- Terraform installed on your local machine.
8+
- Access to a PostgreSQL instance where you can apply these configurations.
9+
10+
## Usage
11+
12+
1. Clone the repository and navigate to the `examples/web_app` directory.
13+
2. Review and update the `fixtures.tfvars` file with your specific configuration details.
14+
3. Run the following Terraform commands to apply the configuration:
15+
16+
```bash
17+
terraform init
18+
19+
# cat out the databases and roles
20+
cat fixtures.auto.vars
21+
22+
terraform plan
23+
terraform apply
24+
```
25+
26+
## Roles and Permissions
27+
28+
There are 3 roles in this example,
29+
30+
- **fastapi_app_owner**: owner of the `web_app` database.
31+
32+
- This DB role is only used and accessed in the CI/CD
33+
- This role applies migrations (makes changes to the DB structure) prior to the application booting up
34+
35+
- **fastapi_app_writer**: writer role for the `web_app` database
36+
37+
- This DB role is the primary role for the FastAPI application
38+
- This role has full Create, Read, Update, Delete abilities
39+
40+
- **fastapi_app_reader**: reader role for the `web_app` database.
41+
- This DB role is a secondary role for the FastAPI application
42+
- This role can only Read from the DB. For example, we'd use this role for `GET` http endpoints.
43+
- For production setups, we'd have this role connect to a Postgres Read-Replica Server to minimize the amount of DB traffic on Postgres Write-DB instance.
44+
45+
## NOTE about authentication on Mac with default settings
46+
47+
Some default `pg_hba.conf` Postgres settings will allow you to log into the
48+
Postgres server without ensuring a valid password. We ran into this when
49+
we installed `postgresql@17` via [Homebrew](https://brew.sh/)
50+
51+
Example `pg_hba.conf` settings that don't check for a valid password
52+
53+
```bash
54+
$ PG_PASSWORD=doesNotMatter psql web_app -U fastapi_app_owner
55+
psql (17.4 (Homebrew), server 17.2 (Homebrew))
56+
Type "help" for help.
57+
web_app=>
58+
```
59+
60+
```bash
61+
# TYPE DATABASE USER ADDRESS METHOD
62+
63+
# "local" is for Unix domain socket connections only
64+
local all all trust
65+
# IPv4 local connections:
66+
host all all 127.0.0.1/32 trust
67+
# IPv6 local connections:
68+
host all all ::1/128 trust
69+
# Allow replication connections from localhost, by a user with the
70+
# replication privilege.
71+
local replication all trust
72+
host replication all 127.0.0.1/32 trust
73+
host replication all ::1/128 trust
74+
```
75+
76+
If you want Postgres to check the password values, swap in these `pg_hba.conf` changes,
77+
78+
Example `pg_hba.conf` settings that require valid password values,
79+
80+
```bash
81+
# Allow only "my_user" to connect without a password (local + IPv4 localhost)
82+
local all my_user trust
83+
host all my_user 127.0.0.1/32 trust
84+
# All other users must use a password (local + IPv4 localhost + IPv6 localhost + other hosts)
85+
local all all md5
86+
host all all 127.0.0.1/32 md5
87+
host all all ::1/128 md5
88+
# Replication rules (if needed, otherwise you can remove them or secure similarly)
89+
local replication all md5
90+
host replication all 127.0.0.1/32 md5
91+
host replication all ::1/128 md5
92+
```
93+
94+
```bash
95+
$ PG_PASSWORD=insecure-pass-for-demo-fastapi-app-owner psql web_app -U fastapi_app_owner
96+
psql (17.4 (Homebrew), server 17.2 (Homebrew))
97+
Type "help" for help.
98+
web_app=>
99+
```

examples/web_app/fixtures.auto.tfvars

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# complete/fixtures.tfvars
2+
3+
# postgres shell command to create this user:
4+
# CREATE ROLE admin_user LOGIN CREATEDB PASSWORD 'insecure-pass-for-demo-admin-user';
5+
db_username = "admin_user"
6+
7+
db_password = "insecure-pass-for-demo-admin-user"
8+
db_scheme = "postgres"
9+
db_hostname = "localhost"
10+
db_port = 5432
11+
db_superuser = false
12+
db_sslmode = "disable"
13+
14+
databases = [
15+
{
16+
name = "web_app"
17+
connection_limit = 10
18+
}
19+
]
20+
21+
roles = [
22+
{
23+
role = {
24+
name = "fastapi_app_admin"
25+
login = true
26+
superuser = false
27+
password = "insecure-pass-for-demo-fastapi-app-admin"
28+
}
29+
table_grants = {
30+
role = "fastapi_app_admin"
31+
database = "web_app"
32+
schema = "public"
33+
object_type = "table"
34+
objects = [] # empty list to grant all tables
35+
privileges = ["ALL"]
36+
}
37+
38+
schema_grants = {
39+
role = "fastapi_app_admin"
40+
database = "web_app"
41+
schema = "public"
42+
object_type = "schema"
43+
privileges = ["USAGE", "CREATE"]
44+
}
45+
46+
sequence_grants = {
47+
role = "fastapi_app_admin"
48+
database = "web_app"
49+
schema = "public"
50+
object_type = "sequence"
51+
objects = [] # empty list to grant all sequences
52+
privileges = ["ALL"]
53+
}
54+
},
55+
{
56+
role = {
57+
name = "fastapi_app_writer"
58+
login = true
59+
superuser = false
60+
password = "insecure-pass-for-demo-fastapi-app-writer"
61+
}
62+
63+
table_grants = {
64+
role = "fastapi_app_writer"
65+
database = "web_app"
66+
schema = "public"
67+
object_type = "table"
68+
objects = [] # empty list to grant all tables
69+
privileges = ["ALL"] # grant all privileges on tables to the writer role
70+
}
71+
72+
schema_grants = {
73+
role = "fastapi_app_writer"
74+
database = "web_app"
75+
schema = "public"
76+
object_type = "schema"
77+
privileges = ["USAGE"] # write does not have create privileges
78+
}
79+
80+
sequence_grants = {
81+
role = "fastapi_app_writer"
82+
database = "web_app"
83+
schema = "public"
84+
object_type = "sequence"
85+
objects = [] # empty list to grant all sequences
86+
privileges = ["ALL"]
87+
}
88+
89+
default_privileges = [
90+
{
91+
role = "fastapi_app_writer"
92+
database = "web_app"
93+
schema = "public"
94+
owner = "fastapi_app_admin"
95+
object_type = "table"
96+
objects = [] # empty list to grant all tables
97+
privileges = ["ALL"]
98+
},
99+
{
100+
role = "fastapi_app_writer"
101+
database = "web_app"
102+
schema = "public"
103+
owner = "fastapi_app_admin"
104+
object_type = "sequence"
105+
objects = [] # empty list to grant all sequences
106+
privileges = ["ALL"]
107+
},
108+
]
109+
},
110+
{
111+
role = {
112+
name = "fastapi_app_reader"
113+
login = true
114+
password = "insecure-pass-for-demo-fastapi-app-reader"
115+
superuser = false
116+
}
117+
118+
table_grants = {
119+
role = "fastapi_app_reader"
120+
database = "web_app"
121+
schema = "public"
122+
object_type = "table"
123+
objects = [] # empty list to grant all tables
124+
privileges = ["SELECT"]
125+
}
126+
127+
sequence_grants = {
128+
role = "fastapi_app_reader"
129+
database = "web_app"
130+
schema = "public"
131+
object_type = "sequence"
132+
objects = [] # empty list to grant all sequences
133+
privileges = ["USAGE", "SELECT"]
134+
}
135+
136+
default_privileges = [
137+
{
138+
role = "fastapi_app_reader"
139+
database = "web_app"
140+
schema = "public"
141+
owner = "fastapi_app_admin"
142+
object_type = "table"
143+
objects = [] # empty list to grant all tables
144+
privileges = ["SELECT"]
145+
},
146+
{
147+
role = "fastapi_app_reader"
148+
database = "web_app"
149+
schema = "public"
150+
owner = "fastapi_app_admin"
151+
object_type = "sequence"
152+
objects = [] # empty list to grant all sequences
153+
privileges = ["USAGE", "SELECT"]
154+
},
155+
]
156+
}
157+
]

examples/web_app/main.tf

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# complete/main.tf
2+
3+
module "postgres_automation" {
4+
source = "../../"
5+
6+
databases = var.databases
7+
roles = var.roles
8+
}

examples/web_app/outputs.tf

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
output "databases" {
2+
value = module.postgres_automation.databases
3+
}
4+
5+
output "database_access" {
6+
value = module.postgres_automation.database_access
7+
}
8+
9+
output "default_privileges" {
10+
value = module.postgres_automation.default_privileges
11+
}
12+
13+
output "schema_access" {
14+
value = module.postgres_automation.schema_access
15+
}
16+
17+
output "table_access" {
18+
value = module.postgres_automation.table_access
19+
}

examples/web_app/providers.tf

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# complete/providers.tf
2+
3+
provider "postgresql" {
4+
scheme = var.db_scheme
5+
host = var.db_hostname
6+
username = var.db_username
7+
port = var.db_port
8+
password = var.db_password
9+
superuser = var.db_superuser
10+
sslmode = var.db_sslmode
11+
}

0 commit comments

Comments
 (0)