1 # An entry in pg_hba and the corresponding firewall rule if necessary
3 # This currently only supports a limited number of entry types. Only
4 # what we need at the moment.
6 # See the upstream documentation at https://www.postgresql.org/docs/11/auth-pg-hba-conf.html
9 # @param pg_port port of the postgres cluster
10 # @param pg_cluster cluster name
11 # @param pg_version pg version of the cluster
12 # @param connection_type connection type
13 # @param database database (or all, sameuser, replication, etc.)
14 # @param user user (or all, etc.)
15 # @param address hosts that match
16 # @param method auth method
17 # @param order ordering of this entry in pg_hba.conf
18 define postgres::cluster::hba_entry (
19 Optional[Integer] $pg_port = undef,
20 Optional[String] $pg_cluster = undef,
21 Optional[String] $pg_version = undef,
22 Enum['local', 'hostssl'] $connection_type = 'hostssl',
23 Variant[String,Array[String]] $database = 'sameuser',
24 Variant[String,Array[String]] $user = 'all',
25 Optional[Variant[Stdlib::IP::Address, Array[Stdlib::IP::Address]]] $address = undef,
26 Enum['md5', 'trust'] $method = 'md5',
29 $address_methods = ['md5']
30 if $method in $address_methods {
32 fail("Authentication method ${method} needs an address")
35 if !($method in $address_methods) {
36 fail("Authentication method ${method} needs no address")
40 $clusters = $facts['postgresql_clusters']
42 $filtered = $clusters.filter |$cluster| { $cluster['port'] == $pg_port }
43 if $filtered.length != 1 {
44 fail("Did not find exactly one cluster with port ${pg_port}")
46 } elsif $pg_cluster and $pg_version {
47 $filtered = $clusters.filter |$cluster| { $cluster['version'] == $pg_version and $cluster['cluster'] == $pg_cluster}
48 if $filtered.length != 1 {
49 fail("Did not find exactly one cluster ${pg_version}/${pg_cluster}")
52 fail('postgres::cluster::hba_entry needs either the port of both a pg version and cluster name')
54 $real_port = $filtered['port']
55 $real_version = $filtered['version']
56 $real_cluster = $filtered['cluster']
57 if $pg_version and $pg_version != $real_version {
58 fail("Inconsisten cluster version information: ${pg_version} != ${real_version}")
60 if $pg_cluster and $pg_cluster != $real_cluster {
61 fail("Inconsisten cluster name information: ${pg_cluster} != ${real_cluster}")
65 ferm::rule::simple { "postgres::cluster::hba_entry::${name}":
66 description => "allow access to pg${real_version}/${real_cluster}: ${name}",
68 chain => "pg-${real_port}",
72 $real_database = Array($database, true).sort().join(',')
73 $real_user = Array($user, true).sort().join(',')
74 $real_address = $address ? {
76 default => Array($address, true).map |$a| {
77 if $a =~ Stdlib::IP::Address::V4::CIDR { $a }
78 elsif $a =~ Stdlib::IP::Address::V4::Nosubnet { "${a}/32" }
79 elsif $a =~ Stdlib::IP::Address::V6::CIDR { $a }
80 elsif $a =~ Stdlib::IP::Address::V6::Nosubnet { "${a}/128" }
81 else { fail("Do not know address type for ${a}") }
85 @concat::fragment { "postgres::cluster::pg_hba::${name}":
86 tag => "postgres::cluster::${real_version}::${real_cluster}::hba",
87 target => "postgres::cluster::${real_version}::${real_cluster}::hba",
89 content => inline_template( @(EOF) ),
92 <% @real_address.each do |addr| -%>
93 <%= [@connection_type, @real_database, @real_user, addr, @method].join(' ') %>