Merge pull request #5576 from inspec/vasundhara/postgresql_resource_update

Update postgresql resources to normalize it for platform supports
This commit is contained in:
Clinton Wolfe 2021-07-08 18:48:04 -05:00 committed by GitHub
commit 69213b555b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 69 additions and 28 deletions

View file

@ -4,6 +4,8 @@ module Inspec::Resources
class Postgres < Inspec.resource(1)
name "postgres"
supports platform: "unix"
supports platform: "windows"
desc "The 'postgres' resource is a helper for the 'postgres_conf', 'postgres_hba_conf', 'postgres_ident_conf' & 'postgres_session' resources. Please use those instead."
attr_reader :service, :data_dir, :conf_dir, :conf_path, :version, :cluster
@ -43,11 +45,17 @@ module Inspec::Resources
@conf_dir = "/etc/postgresql/#{@version}/#{@cluster}"
@data_dir = "/var/lib/postgresql/#{@version}/#{@cluster}"
end
elsif inspec.os.windows?
dir = "C:\\Program Files\\PostgreSQL"
@version = version_from_psql || version_from_dir_windows(dir)
unless @version.to_s.empty?
@data_dir = "#{dir}\\#{@version}\\data\\"
end
else
@version = version_from_psql
if @version.to_s.empty?
if inspec.directory("/var/lib/pgsql/data").exist?
warn "Unable to determine PostgreSQL version: psql did not return" \
Inspec::Log.warn "Unable to determine PostgreSQL version: psql did not return" \
"a version number and unversioned data directories were found."
else
@version = version_from_dir("/var/lib/pgsql")
@ -69,13 +77,13 @@ module Inspec::Resources
def verify_dirs
unless inspec.directory(@conf_dir).exist?
warn "Default postgresql configuration directory: #{@conf_dir} does not exist. " \
Inspec::Log.warn "Default postgresql configuration directory: #{@conf_dir} does not exist. " \
"Postgresql may not be installed or we've misidentified the configuration " \
"directory."
end
unless inspec.directory(@data_dir).exist?
warn "Default postgresql data directory: #{@data_dir} does not exist. " \
Inspec::Log.warn "Default postgresql data directory: #{@data_dir} does not exist. " \
"Postgresql may not be installed or we've misidentified the data " \
"directory."
end
@ -84,7 +92,15 @@ module Inspec::Resources
def version_from_psql
return unless inspec.command("psql").exist?
inspec.command("psql --version | awk '{ print $NF }' | awk -F. '{ print $1\".\"$2 }'").stdout.strip
version = inspec.command("psql --version").stdout.strip.split(" ")[2].split(".")
unless version.empty?
if version.first.to_i >= 10
version.first
else
"#{version[0]}.#{version[1]}"
end
end
end
def locate_data_dir_location_by_version(ver = @version)
@ -100,7 +116,7 @@ module Inspec::Resources
data_dir_loc = dir_list.detect { |i| inspec.directory(i).exist? }
if data_dir_loc.nil?
warn 'Unable to find the PostgreSQL data_dir in expected location(s), please
Inspec::Log.warn 'Unable to find the PostgreSQL data_dir in expected location(s), please
execute "psql -t -A -p <port> -h <host> -c "show hba_file";" as the PostgreSQL
DBA to find the non-standard data_dir location.'
end
@ -112,15 +128,32 @@ module Inspec::Resources
entries = dirs.lines.count
case entries
when 0
warn "Could not determine version of installed postgresql by inspecting #{dir}"
Inspec::Log.warn "Could not determine version of installed postgresql by inspecting #{dir}"
nil
when 1
warn "Using #{dirs}: #{dir_to_version(dirs)}"
Inspec::Log.warn "Using #{dirs}: #{dir_to_version(dirs)}"
dir_to_version(dirs)
else
warn "Multiple versions of postgresql installed or incorrect base dir #{dir}"
Inspec::Log.warn "Multiple versions of postgresql installed or incorrect base dir #{dir}"
first = dir_to_version(dirs.lines.first)
warn "Using the first version found: #{first}"
Inspec::Log.warn "Using the first version found: #{first}"
first
end
end
def version_from_dir_windows(dir)
dirs = inspec.command("Get-ChildItem -Path \"#{dir}\" -Name").stdout
entries = dirs.lines.count
case entries
when 0
Inspec::Log.warn "Could not determine version of installed PostgreSQL by inspecting #{dir}"
nil
when 1
dir_to_version(dirs)
else
Inspec::Log.warn "Multiple versions of PostgreSQL installed or incorrect base dir #{dir}"
first = dir_to_version(dirs.lines.first)
Inspec::Log.warn "Using the first version found: #{first}"
first
end
end
@ -137,13 +170,13 @@ module Inspec::Resources
else
dirs = inspec.command("ls -d #{dir}/*/").stdout.lines
if dirs.empty?
warn "No postgresql clusters configured or incorrect base dir #{dir}"
Inspec::Log.warn "No postgresql clusters configured or incorrect base dir #{dir}"
return nil
end
first = dirs.first.chomp.split("/").last
if dirs.count > 1
warn "Multiple postgresql clusters configured or incorrect base dir #{dir}"
warn "Using the first directory found: #{first}"
Inspec::Log.warn "Multiple postgresql clusters configured or incorrect base dir #{dir}"
Inspec::Log.warn "Using the first directory found: #{first}"
end
first
end

View file

@ -22,6 +22,8 @@ module Inspec::Resources
include FileReader
include ObjectTraverser
attr_accessor :conf_path
def initialize(conf_path = nil)
@conf_path = conf_path || inspec.postgres.conf_path
if @conf_path.nil?

View file

@ -5,6 +5,7 @@ module Inspec::Resources
class PostgresHbaConf < Inspec.resource(1)
name "postgres_hba_conf"
supports platform: "unix"
supports platform: "windows"
desc 'Use the `postgres_hba_conf` InSpec audit resource to test the client
authentication data defined in the pg_hba.conf file.'
example <<~EXAMPLE
@ -19,7 +20,7 @@ module Inspec::Resources
# @todo add checks to ensure that we have data in our file
def initialize(hba_conf_path = nil)
@conf_file = hba_conf_path || File.expand_path("pg_hba.conf", inspec.postgres.conf_dir)
@conf_file = hba_conf_path || File.join(inspec.postgres.conf_dir, "pg_hba.conf")
@content = ""
@params = {}
read_content

View file

@ -5,6 +5,7 @@ module Inspec::Resources
class PostgresIdentConf < Inspec.resource(1)
name "postgres_ident_conf"
supports platform: "unix"
supports platform: "windows"
desc 'Use the postgres_ident_conf InSpec audit resource to test the client
authentication data is controlled by a pg_ident.conf file.'
example <<~EXAMPLE
@ -18,7 +19,7 @@ module Inspec::Resources
attr_reader :params, :conf_file
def initialize(ident_conf_path = nil)
@conf_file = ident_conf_path || File.expand_path("pg_ident.conf", inspec.postgres.conf_dir)
@conf_file = ident_conf_path || File.join(inspec.postgres.conf_dir, "pg_ident.conf")
@content = nil
@params = nil
read_content

View file

@ -12,7 +12,7 @@ module Inspec::Resources
end
def lines
output.split("\n")
output.split("\n").map(&:strip)
end
def to_s
@ -54,7 +54,7 @@ module Inspec::Resources
raise Inspec::Exceptions::ResourceFailed, "#{resource_exception_message}" if resource_failed?
psql_cmd = create_psql_cmd(query, db)
cmd = inspec.command(psql_cmd, redact_regex: /(PGPASSWORD=').+(' psql .*)/)
cmd = inspec.command(psql_cmd, redact_regex: %r{(:\/\/[a-z]*:).*(@)})
out = cmd.stdout + "\n" + cmd.stderr
if cmd.exit_status != 0 || out =~ /could not connect to .*/ || out.downcase =~ /^error:.*/
raise Inspec::Exceptions::ResourceFailed, "PostgreSQL query with errors: #{out}"
@ -66,7 +66,7 @@ module Inspec::Resources
private
def test_connection
query("select now()")
query("select now()\;")
end
def escaped_query(query)
@ -74,8 +74,12 @@ module Inspec::Resources
end
def create_psql_cmd(query, db = [])
dbs = db.map { |x| "-d #{x}" }.join(" ")
"PGPASSWORD='#{@pass}' psql -U #{@user} #{dbs} -h #{@host} -p #{@port} -A -t -c #{escaped_query(query)}"
dbs = db.map { |x| "#{x}" }.join(" ")
if inspec.os.windows?
"psql -d postgresql://#{@user}:#{@pass}@#{@host}:#{@port}/#{dbs} -A -t -w -c \"#{query}\""
else
"psql -d postgresql://#{@user}:#{@pass}@#{@host}:#{@port}/#{dbs} -A -t -w -c #{escaped_query(query)}"
end
end
end
end

View file

@ -153,7 +153,7 @@ class MockLoader
"database.xml" => mockfile.call("database.xml"),
"/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"),
"C:/Program Files/PostgreSQL/9.5/main/pg_ident.conf" => mockfile.call("pg_ident.conf"),
"/etc/postgresql/9.5/main" => mockfile.call("9.5.main"),
"/var/lib/postgresql/9.5/main" => mockfile.call("var.9.5.main"),
"/etc/hosts" => mockfile.call("hosts"),

View file

@ -5,7 +5,7 @@ require "inspec/resources/directory"
describe "Inspec::Resources::PGIdentConf" do
describe "PGIdentConf Paramaters" do
resource = load_resource("postgres_ident_conf")
resource = load_resource("postgres_ident_conf", "C:/Program Files/PostgreSQL/9.5/main/pg_ident.conf")
it "Verify postgres_ident_conf filtering by `system_username`" do
entries = resource.where { system_username == "bryanh" }
_(entries.map_name).must_equal ["omicron"]

View file

@ -6,27 +6,27 @@ require "inspec/resources/command"
describe "Inspec::Resources::PostgresSession" do
it "verify postgres_session create_psql_cmd with a basic query" do
resource = load_resource("postgres_session", "myuser", "mypass", "127.0.0.1", 5432)
_(resource.send(:create_psql_cmd, "SELECT * FROM STUDENTS;", ["testdb"])).must_equal "PGPASSWORD='mypass' psql -U myuser -d testdb -h 127.0.0.1 -p 5432 -A -t -c SELECT\\ \\*\\ FROM\\ STUDENTS\\;"
_(resource.send(:create_psql_cmd, "SELECT * FROM STUDENTS;", ["testdb"])).must_equal "psql -d postgresql://myuser:mypass@127.0.0.1:5432/testdb -A -t -w -c SELECT\\ \\*\\ FROM\\ STUDENTS\\;"
end
it "verify postgres_session escaped_query with a complex query" do
resource = load_resource("postgres_session", "myuser", "mypass", "127.0.0.1", 5432)
_(resource.send(:create_psql_cmd, "SELECT current_setting('client_min_messages')", ["testdb"])).must_equal "PGPASSWORD='mypass' psql -U myuser -d testdb -h 127.0.0.1 -p 5432 -A -t -c SELECT\\ current_setting\\(\\'client_min_messages\\'\\)"
_(resource.send(:create_psql_cmd, "SELECT current_setting('client_min_messages')", ["testdb"])).must_equal "psql -d postgresql://myuser:mypass@127.0.0.1:5432/testdb -A -t -w -c SELECT\\ current_setting\\(\\'client_min_messages\\'\\)"
end
it "verify postgres_session redacts output" do
cmd = %q{PGPASSWORD='mypass' psql -U myuser -d testdb -h 127.0.0.1 -p 5432 -A -t -c "SELECT current_setting('client_min_messages')"}
options = { redact_regex: /(PGPASSWORD=').+(' psql .*)/ }
cmd = %q{psql -d postgresql://myuser:mypass@127.0.0.1:5432/testdb -A -t -w -c "SELECT current_setting('client_min_messages')"}
options = { redact_regex: %r{(:\/\/[a-z]*:).*(@)} }
resource = load_resource("command", cmd, options)
expected_to_s = %q{Command: `PGPASSWORD='REDACTED' psql -U myuser -d testdb -h 127.0.0.1 -p 5432 -A -t -c "SELECT current_setting('client_min_messages')"`}
expected_to_s = %q{Command: `psql -d postgresql://myuser:REDACTED@127.0.0.1:5432/testdb -A -t -w -c "SELECT current_setting('client_min_messages')"`}
_(resource.to_s).must_equal(expected_to_s)
end
it "verify postgres_session works with empty port value" do
resource = load_resource("postgres_session", "myuser", "mypass", "127.0.0.1")
_(resource.send(:create_psql_cmd, "SELECT * FROM STUDENTS;", ["testdb"])).must_equal "PGPASSWORD='mypass' psql -U myuser -d testdb -h 127.0.0.1 -p 5432 -A -t -c SELECT\\ \\*\\ FROM\\ STUDENTS\\;"
_(resource.send(:create_psql_cmd, "SELECT * FROM STUDENTS;", ["testdb"])).must_equal "psql -d postgresql://myuser:mypass@127.0.0.1:5432/testdb -A -t -w -c SELECT\\ \\*\\ FROM\\ STUDENTS\\;"
end
it "verify postgres_session works with empty host and port value" do
resource = load_resource("postgres_session", "myuser", "mypass")
_(resource.send(:create_psql_cmd, "SELECT * FROM STUDENTS;", ["testdb"])).must_equal "PGPASSWORD='mypass' psql -U myuser -d testdb -h localhost -p 5432 -A -t -c SELECT\\ \\*\\ FROM\\ STUDENTS\\;"
_(resource.send(:create_psql_cmd, "SELECT * FROM STUDENTS;", ["testdb"])).must_equal "psql -d postgresql://myuser:mypass@localhost:5432/testdb -A -t -w -c SELECT\\ \\*\\ FROM\\ STUDENTS\\;"
end
it "fails when no user, password" do
resource = load_resource("postgres_session", nil, nil, "localhost", 5432)