Skip to content

Commit

Permalink
Merge pull request sous-chefs#438 from sous-chefs/hba_access
Browse files Browse the repository at this point in the history
Postgresql Access resource
  • Loading branch information
tas50 authored Oct 24, 2017
2 parents 9cfce48 + 1e7f6e5 commit 48a2ee5
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 33 deletions.
115 changes: 99 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,41 @@ Installs and configures PostgreSQL as a client or a server.

### Chef

- Chef 12.1+
- Chef 12.9+

### Cookbooks

- `compat_resource`
- `openssl`
- `build-essential`

## Deprecation notice for pg_hba.conf

Updating the pg_hba configuration can now be done with the `postgresql_access` resource which is documented below. There is a backward-compatible migration left in the `server_conf` recipe, but it will be removed in the next major release.

For each of the `node['postgresql']['pg_hba']` hashes, you want to make a corresponding postgresql_access resource like the following example:

```ruby
# What used to be this:
default['postgresql']['pg_hba'] = {
type: 'local',
db: 'all',
user: 'postgres',
addr: nil,
method: 'ident'
}

# Is now this:
postgresql_access 'local_postgres_superuser' do
access_type 'local'
access_db 'all'
access_user 'postgres'
access_addr nil
access_method 'ident'
end
```

**Note**: The default notification for the new `postgresql_access` resource is now `:reload` which is the recommended method of notifying PostgreSQL of access changes without requiring a full database restart. Before, the access template would defer to the notification method specified by node['postgresql']['server']['config_change_notify']

## Attributes

The following attributes are set based on the platform, see the `attributes/default.rb` file for default values.
Expand All @@ -43,7 +70,7 @@ The following attributes are generated in `recipe[postgresql::server]`.

## Configuration

The `postgresql.conf` and `pg_hba.conf` files are dynamically generated from attributes. Each key in `node['postgresql']['config']` is a postgresql configuration directive, and will be rendered in the config file. For example, the attribute:
The `postgresql.conf` file is dynamically generated from attributes. Each key in `node['postgresql']['config']` is a postgresql configuration directive, and will be rendered in the config file. For example, the attribute:

```ruby
node['postgresql']['config']['listen_addresses'] = 'localhost'
Expand Down Expand Up @@ -80,31 +107,87 @@ port = 5432

Note that the `unix_socket_directory` configuration was renamed to `unix_socket_directories` in Postgres 9.3 so make sure to use the `node['postgresql']['unix_socket_directories']` attribute instead of `node['postgresql']['unix_socket_directory']`.

The `pg_hba.conf` file is dynamically generated from the `node['postgresql']['pg_hba']` attribute. This attribute must be an array of hashes, each hash containing the authorization data. As it is an array, you can append to it in your own recipes. The hash keys in the array must be symbols. Each hash will be written as a line in `pg_hba.conf`. For example, this entry from `node['postgresql']['pg_hba']`:
## Resources

```
[{:comment => '# Optional comment',
:type => 'local', :db => 'all', :user => 'postgres', :addr => nil, :method => 'md5'}]
```
### postgresql_extention

This resource manages postgresql extensions with a given database to ease installation/removal. It uses the name of the resource in the format `database/extension` to determine the database and extention to install.

#### Actions

- `create` - (default) Creates an extension in a given database
- `drop` - Drops an extension from the database

#### Properties

| Name | Types | Description | Default | Required? |
|------|-------|-------------|---------|-----------|
| database | String | Name of the database to install the extention into | Name of resource | yes |
| extention | String | Name of the extention to install the database | Name of resource | yes |

Will result in the following line in `pg_hba.conf`:
#### Examples

To install the adminpack extension:

```ruby
# Add the contrib package in Ubuntu/Debian
package 'postgresql-contrib-9.6'

# Install adminpack extension
postgresql_extension 'postgres/adminpack'
```
# Optional comment
local all postgres md5

### postgresql_access

This resource uses the accumulator pattern to build up the `pg_hba.conf` file via chef resources instead of piling on a mountain of chef attributes to make this cookbook more reusable. It directly mirrors the configuration options of the postgres hba file in the resource and by default notifies the server with a reload to avoid a full restart, causing a potential outage of service. To revoke access, simply remove the resource and the access change won't be computed into the final `pg_hba.conf`

#### Actions

- `grant` - (default) Creates an access line inside of `pg_hba.conf`

#### Properties

| Name | Types | Description | Default | Required? |
|------|-------|-------------|---------|-----------|
| name | String | Name of the access resource, this is left as a comment inside the `pg_hba` config | Resource name | yes |
| source | String | The cookbook template filename if you want to use your own custom template | 'pg_hba.conf.erb' | yes |
| cookbook | String | The cookbook to look in for the template source | 'postgresql' | yes |
| comment | String, nil | A comment to leave above the entry in `pg_hba` | nil | no |
| `access_type` | String | The type of access, e.g. local or host | 'local' | yes |
| `access_db` | String | The database to access. Can use 'all' for all databases | 'all' | yes |
| `access_user` | String | The user accessing the database. Can use 'all' for any user | 'all' | yes |
| `access_addr` | String, nil | The address(es) allowed access. Can be nil if method ident is used since it is local then | nil | yes |
| `access_method` | String | Authentication method to use | 'ident' | yes |
| notification | Symbol | How to notify Postgres of the access change. | `:reload` | yes |

#### Examples

To grant access to the postgresql user with ident authentication:

```ruby
postgresql_access 'local_postgres_superuser' do
comment 'Local postgres superuser access'
access_type 'local'
access_db 'all'
access_user 'postgres'
access_addr nil
access_method 'ident'
end
```

Use `nil` if the CIDR-ADDRESS should be empty (as above). Don't provide a comment if none is desired in the `pg_hba.conf` file.
This generates the following line in the `pg_hba.conf`:
```
# Local postgres superuser access
local all postgres ident
```

Note that the following authorization rule is supplied automatically by the cookbook template. The cookbook needs this to execute SQL in the PostgreSQL server without supplying the clear-text password (which isn't known by the cookbook). Therefore, your `node['postgresql']['pg_hba']` attributes don't need to specify this authorization rule:
**Note**: The template by default generates a local access for Unix domain sockets only to support running the SQL execute resources. In Postgres version 9.1 and higher, the method is 'peer' instead of 'ident' which is identical. It looks like this:

```
# "local" is for Unix domain socket connections only
local all all ident
local all all peer
```

(By the way, the template uses `peer` instead of `ident` for PostgreSQL-9.1 and above, which has the same effect.)

## Recipes

### default
Expand Down
8 changes: 2 additions & 6 deletions attributes/default.rb
Original file line number Diff line number Diff line change
Expand Up @@ -229,12 +229,8 @@
default['postgresql']['config']['default_text_search_config'] = 'pg_catalog.english'
end

default['postgresql']['pg_hba'] = [
{ type: 'local', db: 'all', user: 'postgres', addr: nil, method: 'ident' },
{ type: 'local', db: 'all', user: 'all', addr: nil, method: 'ident' },
{ type: 'host', db: 'all', user: 'all', addr: '127.0.0.1/32', method: 'md5' },
{ type: 'host', db: 'all', user: 'all', addr: '::1/128', method: 'md5' },
]
# Deprecated: Please use the new postgresql_access resource. See README for information.
default['postgresql']['pg_hba'] = []

default['postgresql']['password'] = {}

Expand Down
3 changes: 1 addition & 2 deletions metadata.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
version '6.1.1'
source_url 'https://github.com/sous-chefs/postgresql'
issues_url 'https://github.com/sous-chefs/postgresql/issues'
chef_version '>= 12.1' if respond_to?(:chef_version)
chef_version '>= 12.9' if respond_to?(:chef_version)

supports 'ubuntu', '>= 12.04'
supports 'debian', '>= 7.0'
Expand All @@ -23,6 +23,5 @@
supports el, '>= 6.0'
end

depends 'compat_resource', '>= 12.16.3'
depends 'build-essential', '>= 2.0.0'
depends 'openssl', '>= 4.0'
20 changes: 14 additions & 6 deletions recipes/server_conf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,18 @@
notifies change_notify, 'service[postgresql]', :immediately
end

template "#{node['postgresql']['dir']}/pg_hba.conf" do # ~FC037
source 'pg_hba.conf.erb'
owner 'postgres'
group 'postgres'
mode '0600'
notifies change_notify, 'service[postgresql]', :immediately
if !node['postgresql']['pg_hba'].empty?
Chef::Log.warn 'Configuring access via attributes is **DEPRECATED**. Please use the new postgresql_access resource. See README for migration information'
node['postgresql']['pg_hba'].each do |access|
# Generate a unique string for the resource to avoid cloning
access_name = "#{access[:type]}_#{access[:db]}_#{access[:user]}_#{access[:method]}"
postgresql_access access_name do
access_type access[:type]
access_db access[:db]
access_user access[:user]
access_addr access[:addr]
access_method access[:method]
notification change_notify
end
end
end
54 changes: 54 additions & 0 deletions resources/access.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# frozen_string_literal: true
#
# Cookbook:: postgresql
# Resource:: access
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

property :name, String, name_property: true
property :source, String, required: true, default: 'pg_hba.conf.erb'
property :cookbook, String, required: true, default: 'postgresql'
property :comment, [String, nil], required: false, default: nil
property :access_type, String, required: true, default: 'local'
property :access_db, String, required: true, default: 'all'
property :access_user, String, required: true, default: 'postgres'
property :access_addr, [String, nil], required: true, default: nil
property :access_method, String, required: true, default: 'ident'
property :notification, Symbol, required: true, default: :reload

action :grant do
with_run_context :root do
edit_resource(:template, "#{node['postgresql']['dir']}/pg_hba.conf") do |new_resource|
source new_resource.source
cookbook new_resource.cookbook
owner 'postgres'
group 'postgres'
mode '0600'
variables['pg_hba'] ||= {}
variables['pg_hba'] << {
comment: new_resource.comment,
name: new_resource.name,
type: new_resource.access_type,
db: new_resource.access_db,
user: new_resource.access_user,
addr: new_resource.access_addr,
method: new_resource.access_method,
}

action :nothing
delayed_action :create
notifies new_resource.notification, 'service[postgresql]', :immediately
end
end
end
6 changes: 3 additions & 3 deletions templates/default/pg_hba.conf.erb
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
###########
# Other authentication configurations taken from chef node defaults:
###########
<% node['postgresql']['pg_hba'].each do |auth| -%>
<% @pg_hba.each do |auth| -%>

<% if auth[:comment] %>
<% if auth[:comment] -%>
# <%= auth[:comment] %>
<% end %>
<% end -%>
<% if auth[:addr] %>
<%= auth[:type].ljust(7) %> <%= auth[:db].ljust(15) %> <%= auth[:user].ljust(15) %> <%= auth[:addr].ljust(23) %> <%= auth[:method] %>
<% else %>
Expand Down

0 comments on commit 48a2ee5

Please sign in to comment.