4-node: safe
A 3+1 node template with hardened security, delayed cluster, following high-standard security best practices.
Categories:
The safe
is a specialized configuration template for security hardening, based on the full
template.
Overview
- Conf Name :
safe
- Node Count : 4-node,
pigsty/vagrant/spec/full.rb
- Description : A 3+1 node template with hardened security, delayed cluster, following high-standard security best practices.
- Content :
pigsty/conf/safe.yml
- OS Distro :
el7
,el8
,el9
,u20
,u22
,u24
- OS Arch :
x86_64
- Related :
full
To enable: Use the -c safe
parameter during the configure
process:
./configure -c safe
This is a 4-node template, you need to modify the IP address of the other 3 nodes after configure
Content
Source: pigsty/conf/safe.yml
#==============================================================#
# File : safe.yml
# Desc : Pigsty 3-node security enhance template
# Ctime : 2020-05-22
# Mtime : 2024-11-12
# Docs : https://pigsty.io/docs/conf/safe
# Author : Ruohang Feng (rh@vonng.com)
# License : AGPLv3
#==============================================================#
#===== SECURITY ENHANCEMENT CONFIG TEMPLATE WITH 3 NODES ======#
# * 3 infra nodes, 3 etcd nodes, single minio node
# * 3-instance pgsql cluster with an extra delayed instance
# * crit.yml templates, no data loss, checksum enforced
# * enforce ssl on postgres & pgbouncer, use postgres by default
# * enforce an expiration date for all users (20 years by default)
# * enforce strong password policy with passwordcheck extension
# * enforce changing default password for all users
# * log connections and disconnections
# * restrict listen ip address for postgres/patroni/pgbouncer
all:
children:
infra: # infra cluster for proxy, monitor, alert, etc
hosts: # 1 for common usage, 3 nodes for production
10.10.10.10: { infra_seq: 1 } # identity required
10.10.10.11: { infra_seq: 2, repo_enabled: false }
10.10.10.12: { infra_seq: 3, repo_enabled: false }
vars: { patroni_watchdog_mode: off }
minio: # minio cluster, s3 compatible object storage
hosts: { 10.10.10.10: { minio_seq: 1 } }
vars: { minio_cluster: minio }
etcd: # dcs service for postgres/patroni ha consensus
hosts: # 1 node for testing, 3 or 5 for production
10.10.10.10: { etcd_seq: 1 } # etcd_seq required
10.10.10.11: { etcd_seq: 2 } # assign from 1 ~ n
10.10.10.12: { etcd_seq: 3 } # odd number please
vars: # cluster level parameter override roles/etcd
etcd_cluster: etcd # mark etcd cluster name etcd
etcd_safeguard: false # safeguard against purging
etcd_clean: true # purge etcd during init process
pg-meta: # 3 instance postgres cluster `pg-meta`
hosts:
10.10.10.10: { pg_seq: 1, pg_role: primary }
10.10.10.11: { pg_seq: 2, pg_role: replica }
10.10.10.12: { pg_seq: 3, pg_role: replica , pg_offline_query: true }
vars:
pg_cluster: pg-meta
pg_conf: crit.yml
pg_users:
- { name: dbuser_meta , password: Pleas3-ChangeThisPwd ,expire_in: 7300 ,pgbouncer: true ,roles: [ dbrole_admin ] ,comment: pigsty admin user }
- { name: dbuser_view , password: Make.3ure-Compl1ance ,expire_in: 7300 ,pgbouncer: true ,roles: [ dbrole_readonly ] ,comment: read-only viewer for meta database }
pg_databases:
- { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [ pigsty ] ,extensions: [ { name: vector } ] }
pg_services:
- { name: standby , ip: "*" ,port: 5435 , dest: default ,selector: "[]" , backup: "[? pg_role == `primary`]" }
pg_listen: '${ip},${vip},${lo}'
pg_vip_enabled: true
pg_vip_address: 10.10.10.2/24
pg_vip_interface: eth1
# OPTIONAL delayed cluster for pg-meta
pg-meta-delay: # delayed instance for pg-meta (1 hour ago)
hosts: { 10.10.10.13: { pg_seq: 1, pg_role: primary, pg_upstream: 10.10.10.10, pg_delay: 1h } }
vars: { pg_cluster: pg-meta-delay }
####################################################################
# Parameters #
####################################################################
vars: # global variables
version: v3.1.0 # pigsty version string
admin_ip: 10.10.10.10 # admin node ip address
region: default # upstream mirror region: default|china|europe
node_tune: oltp # node tuning specs: oltp,olap,tiny,crit
pg_conf: oltp.yml # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
patroni_ssl_enabled: true # secure patroni RestAPI communications with SSL?
pgbouncer_sslmode: require # pgbouncer client ssl mode: disable|allow|prefer|require|verify-ca|verify-full, disable by default
pg_default_service_dest: postgres # default service destination to postgres instead of pgbouncer
pgbackrest_method: minio # pgbackrest repo method: local,minio,[user-defined...]
#----------------------------------#
# Credentials
#----------------------------------#
#grafana_admin_username: admin
grafana_admin_password: You.Have2Use-A_VeryStrongPassword
#pg_admin_username: dbuser_dba
pg_admin_password: PessWorb.Should8eStrong-eNough
#pg_monitor_username: dbuser_monitor
pg_monitor_password: MekeSuerYour.PassWordI5secured
#pg_replication_username: replicator
pg_replication_password: doNotUseThis-PasswordFor.AnythingElse
#patroni_username: postgres
patroni_password: don.t-forget-to-change-thEs3-password
#haproxy_admin_username: admin
haproxy_admin_password: GneratePasswordWith-pwgen-s-16-1
#----------------------------------#
# MinIO Related Options
#----------------------------------#
minio_users: # and configure `pgbackrest_repo` & `minio_users` accordingly
- { access_key: dba , secret_key: S3User.DBA.Strong.Password, policy: consoleAdmin }
- { access_key: pgbackrest , secret_key: Min10.bAckup ,policy: readwrite }
pgbackrest_repo: # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
local: # default pgbackrest repo with local posix fs
path: /pg/backup # local backup directory, `/pg/backup` by default
retention_full_type: count # retention full backups by count
retention_full: 2 # keep 2, at most 3 full backup when using local fs repo
minio: # optional minio repo for pgbackrest
s3_key: pgbackrest # <-------- CHANGE THIS, SAME AS `minio_users` access_key
s3_key_secret: Min10.bAckup # <-------- CHANGE THIS, SAME AS `minio_users` secret_key
cipher_pass: 'pgBR.${pg_cluster}' # <-------- CHANGE THIS, you can use cluster name as part of password
type: s3 # minio is s3-compatible, so s3 is used
s3_endpoint: sss.pigsty # minio endpoint domain name, `sss.pigsty` by default
s3_region: us-east-1 # minio region, us-east-1 by default, useless for minio
s3_bucket: pgsql # minio bucket name, `pgsql` by default
s3_uri_style: path # use path style uri for minio rather than host style
path: /pgbackrest # minio backup path, default is `/pgbackrest`
storage_port: 9000 # minio port, 9000 by default
storage_ca_file: /etc/pki/ca.crt # minio ca file path, `/etc/pki/ca.crt` by default
bundle: y # bundle small files into a single file
cipher_type: aes-256-cbc # enable AES encryption for remote backup repo
retention_full_type: time # retention full backup by time on minio repo
retention_full: 14 # keep full backup for last 14 days
#----------------------------------#
# Access Control
#----------------------------------#
# add passwordcheck extension to enforce strong password policy
pg_libs: '$libdir/passwordcheck, pg_stat_statements, auto_explain'
pg_extensions:
- passwordcheck, supautils, pgsodium, pg_vault, pg_session_jwt, anonymizer, pgsmcrypto, pgauditlogtofile, pgaudit #, pgaudit17, pgaudit16, pgaudit15, pgaudit14
- pg_auth_mon, credcheck, pgcryptokey, pg_jobmon, logerrors, login_hook, set_user, pgextwlist, pg_auditor, sslutils, noset #pg_tde #pg_snakeoil
pg_default_roles: # default roles and users in postgres cluster
- { name: dbrole_readonly ,login: false ,comment: role for global read-only access }
- { name: dbrole_offline ,login: false ,comment: role for restricted read-only access }
- { name: dbrole_readwrite ,login: false ,roles: [ dbrole_readonly ] ,comment: role for global read-write access }
- { name: dbrole_admin ,login: false ,roles: [ pg_monitor, dbrole_readwrite ] ,comment: role for object creation }
- { name: postgres ,superuser: true ,expire_in: 7300 ,comment: system superuser }
- { name: replicator ,replication: true ,expire_in: 7300 ,roles: [ pg_monitor, dbrole_readonly ] ,comment: system replicator }
- { name: dbuser_dba ,superuser: true ,expire_in: 7300 ,roles: [ dbrole_admin ] ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 , comment: pgsql admin user }
- { name: dbuser_monitor ,roles: [ pg_monitor ] ,expire_in: 7300 ,pgbouncer: true ,parameters: { log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }
pg_default_hba_rules: # postgres host-based auth rules by default
- { user: '${dbsu}' ,db: all ,addr: local ,auth: ident ,title: 'dbsu access via local os user ident' }
- { user: '${dbsu}' ,db: replication ,addr: local ,auth: ident ,title: 'dbsu replication from local os ident' }
- { user: '${repl}' ,db: replication ,addr: localhost ,auth: ssl ,title: 'replicator replication from localhost' }
- { user: '${repl}' ,db: replication ,addr: intra ,auth: ssl ,title: 'replicator replication from intranet' }
- { user: '${repl}' ,db: postgres ,addr: intra ,auth: ssl ,title: 'replicator postgres db from intranet' }
- { user: '${monitor}' ,db: all ,addr: localhost ,auth: pwd ,title: 'monitor from localhost with password' }
- { user: '${monitor}' ,db: all ,addr: infra ,auth: ssl ,title: 'monitor from infra host with password' }
- { user: '${admin}' ,db: all ,addr: infra ,auth: ssl ,title: 'admin @ infra nodes with pwd & ssl' }
- { user: '${admin}' ,db: all ,addr: world ,auth: cert ,title: 'admin @ everywhere with ssl & cert' }
- { user: '+dbrole_readonly',db: all ,addr: localhost ,auth: ssl ,title: 'pgbouncer read/write via local socket' }
- { user: '+dbrole_readonly',db: all ,addr: intra ,auth: ssl ,title: 'read/write biz user via password' }
- { user: '+dbrole_offline' ,db: all ,addr: intra ,auth: ssl ,title: 'allow etl offline tasks from intranet' }
pgb_default_hba_rules: # pgbouncer host-based authentication rules
- { user: '${dbsu}' ,db: pgbouncer ,addr: local ,auth: peer ,title: 'dbsu local admin access with os ident' }
- { user: 'all' ,db: all ,addr: localhost ,auth: pwd ,title: 'allow all user local access with pwd' }
- { user: '${monitor}' ,db: pgbouncer ,addr: intra ,auth: ssl ,title: 'monitor access via intranet with pwd' }
- { user: '${monitor}' ,db: all ,addr: world ,auth: deny ,title: 'reject all other monitor access addr' }
- { user: '${admin}' ,db: all ,addr: intra ,auth: ssl ,title: 'admin access via intranet with pwd' }
- { user: '${admin}' ,db: all ,addr: world ,auth: deny ,title: 'reject all other admin access addr' }
- { user: 'all' ,db: all ,addr: intra ,auth: ssl ,title: 'allow all user intra access with pwd' }
#----------------------------------#
# Repo, Node, Packages
#----------------------------------#
# if you wish to customize your own repo, change these settings:
repo_modules: infra,node,pgsql # install upstream repo during repo bootstrap
repo_remove: true # remove existing repo on admin node during repo bootstrap
node_repo_modules: local # install the local module in repo_upstream for all nodes
node_repo_remove: true # remove existing node repo for node managed by pigsty
repo_packages: [ # default packages to be downloaded (if `repo_packages` is not explicitly set)
node-bootstrap, infra-package, infra-addons, node-package1, node-package2, pgsql-common #,docker
]
repo_extra_packages: [ # default postgres packages to be downloaded
pgsql-main, pgsql-sec,
passwordcheck, supautils, pgsodium, pg_vault, pg_session_jwt, anonymizer, pgsmcrypto, pgauditlogtofile, pgaudit, #, pgaudit17, pgaudit16, pgaudit15, pgaudit14
pg_auth_mon, credcheck, pgcryptokey, pg_jobmon, logerrors, login_hook, set_user, pgextwlist, pg_auditor, sslutils, noset #pg_tde #pg_snakeoil
#,pgsql-core,pgsql-time,pgsql-gis,pgsql-rag,pgsql-fts,pgsql-olap,pgsql-feat,pgsql-lang,pgsql-type,pgsql-func,pgsql-admin,pgsql-stat,pgsql-sec,pgsql-fdw,pgsql-sim,pgsql-etl,
#,pg17-core,pg17-time,pg17-gis,pg17-rag,pg17-fts,pg17-olap,pg17-feat,pg17-lang,pg17-type,pg17-func,pg17-admin,pg17-stat,pg17-sec,pg17-fdw,pg17-sim,pg17-etl,
#,pg16-core,pg16-time,pg16-gis,pg16-rag,pg16-fts,pg16-olap,pg16-feat,pg16-lang,pg16-type,pg16-func,pg16-admin,pg16-stat,pg16-sec,pg16-fdw,pg16-sim,pg16-etl,
]
Caveat
Beware that not all security-related extensions are available in ARM64 environments, ARM system users should enable extensions at their discretion.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.