New postgres_hba_conf resource (#1964)

* Created pg_hba_conf resource

Signed-off-by: Rony Xavier <rx294@nyu.edu>

* Created pg_hba_conf resource

Signed-off-by: Rony Xavier <rx294@nyu.edu>

* Corrections

* updated to parse auth-options

Signed-off-by: Aaron Lippold <lippold@gmail.com>

* updated `conf_path` instance var to `conf_file` for consistancy.

Signed-off-by: Aaron Lippold <lippold@gmail.com>

* pg_hba_conf - updated the parse_line method
added test and doc files

Signed-off-by: Rony Xavier <rx294@nyu.edu>

* Updated few bugs on pg_hba_conf
updated test files and docs

Signed-off-by: Rony Xavier <rx294@nyu.edu>

* Updated docs

Signed-off-by: Rony Xavier <rx294@nyu.edu>

* Made updates based on the reccomendations

Signed-off-by: Rony Xavier <rx294@nyu.edu>

* PR commit

Signed-off-by: Rony Xavier <rx294@nyu.edu>

* PR Commit

Signed-off-by: Rony Xavier <rx294@nyu.edu>

* Update Gemfile.lock

* PR Commit

Signed-off-by: Rony Xavier <rx294@nyu.edu>

* Updated doc file for postgres_hba_conf resource to use
'cmp' matcher instead of 'eq'

Signed-off-by: Rony Xavier <rx294@nyu.edu>

* Made requested changes, except for SimpleConfig - will address that later.

Signed-off-by: Aaron Lippold <lippold@gmail.com>
This commit is contained in:
Aaron Lippold 2017-07-03 14:13:51 -04:00 committed by Christoph Hartmann
parent 57864f1488
commit 224935e9cf
6 changed files with 265 additions and 0 deletions

View file

@ -0,0 +1,104 @@
---
title: About the postgres_hba_conf Resource
---
# postgres_hba_conf
Use the `postgres_hba_conf` InSpec audit resource to test the client authentication data defined in the pg_hba.conf file.
## Syntax
An `postgres_hba_conf` InSpec audit resource block declares client authentication data that should be tested:
describe postgres_hba_conf.where { type == 'local' } do
its('auth_method') { should eq ['peer'] }
end
where
* `'attribute'` is a attribute in the pg hba configuration file
* `'filter_value'` is the value that is to be filtered for
* `'value'` is the value that is to be matched expected
## Matchers
This InSpec audit resource matches any service that is listed in the HBA configuration file:
its('auth_method') { should_not cmp 'peer' }
or:
its('auth_method') { should cmp 'peer' }
For example:
describe postgres_hba_conf.where { type == 'type' } do
its('auth_method') { should cmp 'value' }
its('user') { should cmp 'value' }
end
### be
<%= partial "/shared/matcher_be" %>
### cmp
<%= partial "/shared/matcher_cmp" %>
### eq
<%= partial "/shared/matcher_eq" %>
### include
<%= partial "/shared/matcher_include" %>
### match
<%= partial "/shared/matcher_match" %>
## Supported Properties
'address', 'auth_method', 'auth_params', 'conf_dir' , 'conf_file' , 'database', 'params' ,'type', 'user'
## Property Examples and Return Types
### address([String])
`address` returns a an array of strings that matches the where condition of the filter table
describe postgres_hba_conf.where { type == 'local' } do
its('address') { should cmp 'value' }
end
### auth_method([String])
`auth_method` returns a an array of strings that matches the where condition of the filter table
describe postgres_hba_conf.where { type == 'local' } do
its('auth_method') { should cmp 'value' }
end
### database([String])
`database` returns a an array of strings that matches the where condition of the filter table
describe postgres_hba_conf.where { type == 'local' } do
its('database') { should cmp 'value' }
end
### type([String])
`type` returns a an array of strings that matches the where condition of the filter table
describe postgres_hba_conf.where { database == 'acme_test_db' } do
its('type') { should cmp 'value' }
end
### user([String])
`user` returns a an array of strings that matches the where condition of the filter table
describe postgres_hba_conf.where { database == 'acme_test_db' } do
its('user') { should cmp 'value' }
end

View file

@ -122,6 +122,7 @@ require 'resources/package'
require 'resources/packages'
require 'resources/parse_config'
require 'resources/passwd'
require 'resources/postgres_hba_conf'
require 'resources/postgres_ident_conf'
require 'resources/pip'
require 'resources/port'

View file

@ -0,0 +1,101 @@
# encoding: utf-8
# author: Rony Xavier,rx294@nyu.edu
# author: Aaron Lippold, lippold@gmail.com
require 'resources/postgres'
module Inspec::Resources
class PostgresHbaConf < Inspec.resource(1)
name 'postgres_hba_conf'
desc 'Use the `postgres_hba_conf` InSpec audit resource to test the client
authentication data defined in the pg_hba.conf file.'
example "
describe postgres_hba_conf.where { type == 'local' } do
its('auth_method') { should eq ['peer'] }
end
"
attr_reader :conf_file, :params
# @todo add checks to ensure that we have data in our file
def initialize(hba_conf_path = nil)
return skip_resource 'The `postgres_hba_conf` resource is not supported on your OS.' unless inspec.os.linux?
@conf_file = hba_conf_path || File.expand_path('pg_hba.conf', inspec.postgres.conf_dir)
@content = ''
@params = {}
read_content
end
filter = FilterTable.create
filter.add_accessor(:where)
.add_accessor(:entries)
.add(:type, field: 'type')
.add(:database, field: 'database')
.add(:user, field: 'user')
.add(:address, field: 'address')
.add(:auth_method, field: 'auth_method')
.add(:auth_params, field: 'auth_params')
filter.connect(self, :params)
def to_s
"Postgres Hba Config #{@conf_file}"
end
private
def clean_conf_file(conf_file = @conf_file)
data = inspec.file(conf_file).content.to_s.lines
content = []
data.each do |line|
line.chomp!
content << line unless line.match(/^\s*#/) || line.empty?
end
content
end
def read_content(config_file = @conf_file)
file = inspec.file(config_file)
if !file.file?
return skip_resource "Can't find file \"#{@conf_file}\""
end
raw_conf = file.content
if raw_conf.empty? && !file.empty?
return skip_resource("Can't read the contents of \"#{@conf_file}\"")
end
# @todo use SimpleConfig here if we can
# ^\s*(\S+)\s+(\S+)\s+(\S+)\s(?:(\d*.\d*.\d*.\d*\/\d*)|(::\/\d+))\s+(\S+)\s*(.*)?\s*$
@content = clean_conf_file(@conf_file)
@params = parse_conf(@content)
@params.each do |line|
if line['type'] == 'local'
line['auth_method'] = line['address']
line['address'] = ''
end
end
end
def parse_conf(content)
content.map do |line|
parse_line(line)
end.compact
end
def parse_line(line)
x = line.split(/\s+/)
{
'type' => x[0],
'database' => x[1],
'user' => x[2],
'address' => x[3],
'auth_method' => x[4],
'auth_params' => ('' if x.length == 4) || x[5..-1].join(' '),
}
end
end
end

View file

@ -153,6 +153,7 @@ class MockLoader
# Test DH parameters, 2048 bit long safe prime, generator 2 for dh_params in PEM format
'dh_params.dh_pem' => mockfile.call('dh_params.dh_pem'),
'default.toml' => mockfile.call('default.toml'),
'/test/path/to/postgres/pg_hba.conf' => mockfile.call('pg_hba.conf'),
'/etc/postgresql/9.5/main/pg_ident.conf' => mockfile.call('pg_ident.conf'),
'C:/etc/postgresql/9.5/main/pg_ident.conf' => mockfile.call('pg_ident.conf'),
'/etc/postgresql/9.5/main' => mockfile.call('9.5.main'),

View file

@ -0,0 +1,16 @@
# BEGIN ANSIBLE MANAGED BLOCK
# TYPE DATABASE USER ADDRESS METHOD
local all all peer
# host all all ::1/128 md5
# host all all 127.0.0.1/32 md5
host acme_test_db all ::1/0 md5
host acme_test_db all 127.0.0.1/0 md5
host acme_test all ::1/0 md5
host acme_test all 127.0.0.1/0 md5
# hostssl all all 127.0.0.1/32 cert clientcert=1 map=ssl-test
# hostssl all all ::1/128 cert clientcert=1 map=ssl-test
hostssl acme_test_db all ::/0 cert clientcert=1 map=ssl-test
hostssl acme_test_db all 0.0.0.0/0 cert clientcert=1 map=ssl-test
hostssl acme_test all ::/0 cert clientcert=1 map=ssl-test
hostssl acme_test all 0.0.0.0/0 cert clientcert=1 map=ssl-test
# END ANSIBLE MANAGED BLOCK

View file

@ -0,0 +1,42 @@
# encoding: utf-8
# copyright: 2017
# author: Aaron Lippold, lippold@gmail.com
# author: Rony Xavier, rx294@nyu.edu
require 'helper'
require 'inspec/resource'
describe 'Inspec::Resources::PGHbaConf' do
describe 'PGHbaConf Paramaters' do
resource = load_resource('postgres_hba_conf', '/test/path/to/postgres/pg_hba.conf')
it 'Verify postgres_hba_conf filtering by `type`' do
entries = resource.where { type == 'local' }
_(entries.database).must_include 'all'
_(entries.auth_method).must_equal ['peer']
end
it 'Verify postgres_hba_conf filtering by `database`' do
entries = resource.where { database == 'acme_test' }
_(entries.type).must_include 'host'
_(entries.user).must_include 'all'
end
it 'Verify postgres_hba_conf filtering by `auth_method`' do
entries = resource.where { auth_method == 'cert' }
_(entries.type).must_include 'hostssl'
_(entries.database).must_include 'acme_test'
end
it 'Verify postgres_hba_conf attributes' do
_(resource.auth_method).must_include 'cert'
_(resource.database).must_include 'acme_test'
_(resource.type).must_include 'hostssl'
end
it 'parses the pg_hba.conf file correctly' do
_(resource.type).must_equal ["local", "host", "host", "host", "host", "hostssl", "hostssl", "hostssl", "hostssl"]
_(resource.database).must_equal ["all", "acme_test_db", "acme_test_db", "acme_test", "acme_test", "acme_test_db", "acme_test_db", "acme_test", "acme_test"]
_(resource.user).must_equal ["all", "all", "all", "all", "all", "all", "all", "all", "all"]
_(resource.address).must_equal ["", "::1/0", "127.0.0.1/0", "::1/0", "127.0.0.1/0", "::/0", "0.0.0.0/0", "::/0", "0.0.0.0/0"]
_(resource.auth_method).must_equal ["peer", "md5", "md5", "md5", "md5", "cert", "cert", "cert", "cert"]
_(resource.auth_params).must_equal ["", "", "", "", "", "clientcert=1 map=ssl-test", "clientcert=1 map=ssl-test", "clientcert=1 map=ssl-test", "clientcert=1 map=ssl-test"]
end
end
end