-
Notifications
You must be signed in to change notification settings - Fork 225
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
doc(postgres): revamp with current best-known practices, separate ser…
…ver and client info
- Loading branch information
Showing
1 changed file
with
214 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,11 @@ install: | |
~/.config/envman/PATH.env | ||
~/.local/opt/postgres/ | ||
~/.local/share/postgres/var/postgresql.conf | ||
# for psql (postgres client) | ||
~/.pgpass | ||
~/.psqlrc | ||
~/.config/psql/ | ||
``` | ||
|
||
## Cheat Sheet | ||
|
@@ -25,116 +30,261 @@ install: | |
> handles SQL, 'NoSQL', JSON, HSTORE, Full-Text Search, Messages Queues and | ||
> more. Best bang for buck. | ||
### Start the postgres server | ||
To enable Postgres as a Linux Service with [serviceman](../serviceman/): \ | ||
(see macOS below) | ||
|
||
Run just once (for development): | ||
```sh | ||
sudo env PATH="$PATH" \ | ||
serviceman add --system --username "$(whoami)" --name 'postgres' -- \ | ||
postgres -D ~/.local/share/postgres/var -p 5432 | ||
|
||
sudo systemctl restart systemd-journald | ||
``` | ||
|
||
To login: \ | ||
(see creating remote app users below) | ||
|
||
```sh | ||
postgres -D $HOME/.local/share/postgres/var -p 5432 | ||
# as Postgres admin | ||
psql "postgres://postgres:postgres@localhost:5432/postgres" | ||
|
||
# as remote user | ||
psql "postgres://[email protected]:5432/db-xxxx?sslmode=require&sslnegotiation=direct" | ||
``` | ||
|
||
Run as a system service on Linux: | ||
## Table of Contents | ||
|
||
- Server vs Client & PG Essentials | ||
- Initialize a database with a password | ||
- Start the Postgres Server | ||
- development | ||
- systemd (most Linuxes) | ||
- OpenRC (container Linuxes) | ||
- macOS | ||
- Enable Secure Remote Access | ||
- Create Secure Remote App (User/DB) | ||
- Change an User's (App's) password | ||
|
||
### Where to Find the Postgres Client Cheat Sheet | ||
|
||
This is exclusively a server-side cheat sheet. | ||
|
||
For the client-side cheat sheet, see [The PSQL (Client) Cheat Sheet](../psql/). | ||
|
||
For a collection of other helpful scripts, see | ||
[PG Essentials](https://github.com/bnnanet/pg-essentials): | ||
|
||
- pg-register-service | ||
- pg-addgroup | ||
- pg-adduser | ||
- pg-passwd | ||
|
||
### How to Initialize the Postgres Database (with password) | ||
|
||
1. Create a database directory, paired to the Postgres version | ||
```sh | ||
mkdir -p ~/.local/share/postgres-17/var/ | ||
``` | ||
2. Use a password file and `initdb` to create a new DB directory | ||
```sh | ||
echo 'postgres' > /tmp/pwfile && \ | ||
initdb -D ~/.local/share/postgres/var/ \ | ||
--username 'postgres' --pwfile /tmp/pwfile \ | ||
--auth-local=password --auth-host=password \ && | ||
rm /tmp/pwfile | ||
``` | ||
3. Test that the server starts | ||
```sh | ||
postgres -D ~/.local/share/postgres/var -p 5432 | ||
``` | ||
(kill with `ctrl+c`) | ||
|
||
### How to run the Postgres server (daemon or foreground) | ||
|
||
- foreground (development) | ||
- systemd (Debian, Ubuntu, Redhat, etc) | ||
- OpenRC (Alpine, Arch, Gentoo, etc) | ||
- macOS (launchd) | ||
|
||
#### To run in the foreground (for development): | ||
|
||
```sh | ||
postgres -D ~/.local/share/postgres/var -p 5432 | ||
``` | ||
|
||
#### Debian / Systemd | ||
|
||
```sh | ||
curl https://webi.sh/serviceman | sh | ||
``` | ||
|
||
```sh | ||
sudo env PATH="$PATH" \ | ||
serviceman add --system --username "$(whoami)" --name postgres -- \ | ||
postgres -D "$HOME/.local/share/postgres/var" -p 5432 | ||
serviceman add --system --username "$(whoami)" --name 'postgres' -- \ | ||
postgres -D ~/.local/share/postgres/var -p 5432 | ||
|
||
# Restart the logging service | ||
sudo systemctl restart systemd-journald | ||
sudo journalctl -xefu postgres | ||
``` | ||
|
||
### Connect with the psql client | ||
#### Alpine / OpenRC | ||
|
||
`/etc/init.d/postgres`: | ||
|
||
```sh | ||
psql 'postgres://postgres:postgres@localhost:5432/postgres' | ||
#!/sbin/openrc-run | ||
|
||
name="postgres" | ||
description="postgres daemon" | ||
command="/home/app/.local/opt/postgres/bin/postgres" | ||
command_args="-D /home/app/.local/share/postgres/var -p 5432" | ||
command_user="app:app" | ||
|
||
supervisor="supervise-daemon" | ||
output_log="/var/log/postgres" | ||
error_log="/var/log/postgres" | ||
|
||
depend() { | ||
need net | ||
} | ||
|
||
start_pre() { | ||
checkpath --directory --owner root /var/log/ | ||
checkpath --file --owner ${command_user} ${output_log} ${error_log} | ||
} | ||
|
||
start() { | ||
ebegin "Starting ${name}" | ||
supervise-daemon ${name} --start \ | ||
--stdout ${output_log} \ | ||
--stderr ${error_log} \ | ||
--pidfile /run/${RC_SVCNAME}.pid \ | ||
--respawn-delay 5 \ | ||
--respawn-max 10 \ | ||
-- \ | ||
${command} \ | ||
${command_args} \ | ||
eend $? | ||
} | ||
|
||
stop() { | ||
ebegin "Stopping ${name}" | ||
supervise-daemon ${name} --stop \ | ||
--pidfile /run/${RC_SVCNAME}.pid | ||
eend $? | ||
} | ||
``` | ||
|
||
### Initialize a database with a password | ||
|
||
```sh | ||
echo "postgres" > /tmp/pwfile | ||
mkdir -p $HOME/.local/share/postgres/var/ | ||
sudo rc-update add postgres | ||
sudo rc-service postgres restart | ||
|
||
sudo tail -f /var/log/postgres | ||
``` | ||
|
||
initdb -D $HOME/.local/share/postgres/var/ \ | ||
--username postgres --pwfile "/tmp/pwfile" \ | ||
--auth-local=password --auth-host=password | ||
#### macOS | ||
|
||
```sh | ||
serviceman add --name 'postgres' -- \ | ||
postgres -D ~/.local/share/postgres/var -p 5432 | ||
|
||
rm /tmp/pwfile | ||
tail -f ~/.local/share/postgres/var/log/postgres.log | ||
``` | ||
|
||
### Add and secure remote users | ||
### How to Enable Secure Remote Postgres Access | ||
|
||
1. Create the `my_remote_users` group: | ||
|
||
1. Set your server name or IP address | ||
```sh | ||
PG_HOST=pg-1.example.com | ||
echo 'CREATE ROLE "my_remote_users" NOLOGIN;' | | ||
psql "postgres://postgres:postgres@localhost:5432/postgres" -f - | ||
``` | ||
2. Generate a 10-year self-signed TLS certificate | ||
|
||
```sh | ||
openssl req -new -x509 -days 3650 -nodes -text \ | ||
-out server.crt \ | ||
-keyout server.key \ | ||
-subj "/CN=$PG_HOST" | ||
2. Update the hba permissions to enable App users (`sameuser`): \ | ||
`~/.local/share/postgres/var/pg_hba.conf`: | ||
|
||
chmod og-rwx server.key server.crt | ||
mv server.key server.crt ~/.local/share/postgres/var/ | ||
```ini | ||
# Allow 'my_remote_users' to connect remotely directly over the internet | ||
hostssl sameuser +my_remote_users 0.0.0.0/0 scram-sha-256 | ||
hostssl sameuser +my_remote_users ::0/0 scram-sha-256 | ||
|
||
# Allow 'my_remote_users' group to connect through a local TLS-terminating proxy | ||
hostnossl sameuser +my_remote_users 127.0.0.1/8 scram-sha-256 | ||
hostnossl sameuser +my_remote_users ::1/128 scram-sha-256 | ||
host sameuser +my_remote_users 10.0.0.0/8 scram-sha-256 | ||
host sameuser +my_remote_users 172.16.0.0/12 scram-sha-256 | ||
host sameuser +my_remote_users 192.168.0.0/16 scram-sha-256 | ||
host sameuser +my_remote_users fc00::/7 scram-sha-256 | ||
``` | ||
|
||
3. Enable SSL (TLS) | ||
3. Create a 10-year Self-signed cert for your server name or IP | ||
|
||
```sh | ||
vim ~/.local/share/postgres/var/postgresql.conf | ||
my_host=pg-1.example.com | ||
|
||
openssl req -new -x509 -days 3650 -nodes -text \ | ||
-out ./server.crt -keyout ./server.key -subj "/CN=$my_host" | ||
|
||
chmod 0600 ./server.key ./server.crt | ||
mv ./server.key ./server.crt ~/.local/share/postgres/var/ | ||
``` | ||
|
||
4. Update the main postgres config to allow secure connections: \ | ||
`~/.local/share/postgres/var/postgresql.conf`: | ||
|
||
```ini | ||
ssl = on | ||
password_encryption = scram-sha-256 | ||
listen_addresses = '*' | ||
``` | ||
4. Generate a user with a random token password | ||
|
||
```sh | ||
MY_USER='my_user' | ||
MY_PASSWORD="$(xxd -l16 -ps /dev/urandom)" | ||
5. Restart Postgres for the change to take effect | ||
|
||
echo "CREATE ROLE \"$MY_USER\" LOGIN ENCRYPTED PASSWORD '$MY_PASSWORD';" | | ||
psql 'postgres://postgres:postgres@localhost:5432/postgres' -f - | ||
``` | ||
|
||
5. Show the token password and save it somewhere | ||
```sh | ||
echo "$MY_PASSWORD" | ||
``` | ||
6. Allow the user to connect via IPv4 and IPv6 | ||
```sh | ||
echo "# Allow $MY_USER to connect remotely over the internet | ||
hostssl all $MY_USER 0.0.0.0/0 scram-sha-256 | ||
hostssl all $MY_USER ::0/0 scram-sha-256" \ | ||
>> ~/.local/share/postgres/var/pg_hba.conf | ||
``` | ||
7. Restart postgres | ||
```sh | ||
# all unixes | ||
killall postgres | ||
|
||
# systemd (Debian, Ubunut, RedHat, Suse, etc) | ||
sudo systemctl restart postgres | ||
``` | ||
8. Test the connection from a remote system | ||
|
||
```sh | ||
PG_HOST="pg-1.example.com" | ||
PG_USER="my_user" | ||
# openrc (Alpine, Gentoo, Arch) | ||
rc-service postgres restart | ||
|
||
psql "postgres://$PG_USER@$PG_HOST/postgres?sslmode=require" << EOF | ||
SELECT CURRENT_USER; | ||
EOF | ||
# macos | ||
launchctl unload ~/Library/LaunchAgents/postgres.plist | ||
launchctl load ~/Library/LaunchAgents/postgres.plist | ||
``` | ||
|
||
(you will be prompted for your password / token) | ||
### How to Create Secure Remote Users | ||
|
||
The `sameuser` database directive REQUIRES the user and db name to be the same. | ||
|
||
```sh | ||
my_app="foobar_xxxx" | ||
|
||
# e.g. generate password / token with 'xxd -l16 -ps /dev/urandom' | ||
my_token="db-token-for-the-app" | ||
|
||
echo " | ||
CREATE DATABASE \"$my_app\"; | ||
CREATE ROLE \"$my_app\" LOGIN INHERIT | ||
IN ROLE \"my_remote_users\" ENCRYPTED PASSWORD '$my_token'; | ||
GRANT ALL PRIVILEGES ON DATABASE \"$my_app\" to \"$my_app\"; | ||
" | psql "postgres://postgres:postgres@localhost:5432/postgres" -f - | ||
``` | ||
|
||
Notes: | ||
|
||
- quote style matters: | ||
- double quotes `"` for identifiers (users, tables, groups, roles) | ||
- single quotes `'` for values (password) | ||
|
||
### Add or update a user's password | ||
### How to Change a DB's Password | ||
|
||
```sh | ||
MY_USER='my_user' | ||
MY_NEW_PASSWORD="$(xxd -l16 -ps /dev/urandom)" | ||
my_app='foobar_xxxx' | ||
my_token="$(xxd -l16 -ps /dev/urandom)" | ||
|
||
# Update existing user with new password using new hash | ||
echo "ALTER USER \"$MY_USER\" PASSWORD '$MY_NEW_PASSWORD';" | | ||
echo "ALTER USER \"$my_app\" PASSWORD '$my_token';" | | ||
psql 'postgres://postgres:postgres@localhost:5432/postgres' -f - | ||
``` |