Skip to content

Commit

Permalink
Use Puppet-Datatype Sensitive for Passwords
Browse files Browse the repository at this point in the history
- add Parameter "sensitive" to Function postgresql_password to decide if its Returnvalue should be of Datatype Sensitive
- let defined Type postgresql::server::role accept Datatype Sensitive for $password_hash
- let defined Type postgresql::server::db accept Datatype Sensitive for $password
- let Class postgresql::server accept Datatype Sensitive for $postgres_password
- let defined Type postgresql::validate_db_connection accept Sensitive for $database_password
  • Loading branch information
Cocker Koch committed Aug 16, 2021
1 parent 09b242a commit d878d13
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 57 deletions.
3 changes: 3 additions & 0 deletions .sync.yml
@@ -1,6 +1,9 @@
---
".gitlab-ci.yml":
delete: true
.puppet-lint.rc:
extra_disabled_lint_checks:
- 140chars-check
appveyor.yml:
delete: true

Expand Down
24 changes: 16 additions & 8 deletions REFERENCE.md
Expand Up @@ -863,7 +863,7 @@ The following parameters are available in the `postgresql::server` class:

##### <a name="postgres_password"></a>`postgres_password`

Data type: `Any`
Data type: `Variant[String, Sensitive[String]]`

Sets the password for the postgres user to your specified value. By default, this setting uses the superuser account in the Postgres database, with a user called postgres and no password.

Expand Down Expand Up @@ -1646,7 +1646,7 @@ User to create and assign access to the database upon creation. Mandatory.

##### <a name="password"></a>`password`

Data type: `Any`
Data type: `Variant[String, Sensitive[String]]`

Required Sets the password for the created user.

Expand Down Expand Up @@ -2571,7 +2571,7 @@ Default value: ``true``

##### <a name="password_hash"></a>`password_hash`

Data type: `Any`
Data type: `Variant[String, Sensitive[String]]`

Sets the hash to use during password creation.

Expand Down Expand Up @@ -2713,7 +2713,7 @@ Create a new schema.

#### Examples

#####
#####

```puppet
postgresql::server::schema {'private':
Expand Down Expand Up @@ -2944,7 +2944,7 @@ Default value: ``undef``

##### <a name="database_password"></a>`database_password`

Data type: `Any`
Data type: `Variant[String, Sensitive[String]]`

Specifies the password to connect with.

Expand Down Expand Up @@ -3106,6 +3106,8 @@ The name of the database you are trying to validate a connection with.

##### <a name="db_password"></a>`db_password`

Data type: `Variant[String, Sensitive[String]]`

The password required to access the target PostgreSQL database.

##### <a name="db_username"></a>`db_username`
Expand Down Expand Up @@ -3319,7 +3321,7 @@ This function pull default values from the `params` class or `globals` class if

#### Examples

#####
#####

```puppet
postgresql::default('variable')
Expand All @@ -3333,7 +3335,7 @@ Returns: `Any`

##### Examples

######
######

```puppet
postgresql::default('variable')
Expand Down Expand Up @@ -3369,7 +3371,7 @@ Type: Ruby 4.x API

This function returns the postgresql password hash from the clear text username / password

#### `postgresql::postgresql_password(Variant[String[1],Integer] $username, Variant[String[1],Integer] $password)`
#### `postgresql::postgresql_password(Variant[String[1],Integer] $username, Variant[String[1], Sensitive[String[1]], Integer] $password)`

The postgresql::postgresql_password function.

Expand All @@ -3387,6 +3389,12 @@ Data type: `Variant[String[1],Integer]`

The clear text `password`

##### `sensitive`

Data type: `Boolean`

If the Postgresql-Passwordhash should be of Datatype Sensitive[String]

### <a name="postgresql_escape"></a>`postgresql_escape`

Type: Ruby 4.x API
Expand Down
20 changes: 15 additions & 5 deletions lib/puppet/functions/postgresql/postgresql_password.rb
Expand Up @@ -6,15 +6,25 @@
# The clear text `username`
# @param password
# The clear text `password`
# @param sensitive
# If the Postgresql-Passwordhash should be of Datatype Sensitive[String]
#
# @return [String]
# @return
# The postgresql password hash from the clear text username / password.
dispatch :default_impl do
param 'Variant[String[1],Integer]', :username
param 'Variant[String[1],Integer]', :password
required_param 'Variant[String[1], Integer]', :username
required_param 'Variant[String[1], Sensitive[String[1]], Integer]', :password
optional_param 'Boolean', :sensitive
return_type 'Variant[String, Sensitive[String]]'
end

def default_impl(username, password)
'md5' + Digest::MD5.hexdigest(password.to_s + username.to_s)
def default_impl(username, password, sensitive = false)
password = password.unwrap if password.respond_to?(:unwrap)
result_string = 'md5' + Digest::MD5.hexdigest(password.to_s + username.to_s)
if sensitive
Puppet::Pops::Types::PSensitiveType::Sensitive.new(result_string)
else
result_string
end
end
end
2 changes: 1 addition & 1 deletion manifests/server.pp
Expand Up @@ -83,7 +83,7 @@
# @param extra_systemd_config Adds extra config to systemd config file, can for instance be used to add extra openfiles. This can be a multi line string
#
class postgresql::server (
$postgres_password = undef,
Optional[Variant[String[1], Sensitive[String[1]], Integer]] $postgres_password = undef,

$package_name = $postgresql::params::server_package_name,
$package_ensure = $postgresql::params::package_ensure,
Expand Down
4 changes: 2 additions & 2 deletions manifests/server/db.pp
@@ -1,5 +1,5 @@
# @summary Define for conveniently creating a role, database and assigning the correctpermissions.
#
#
# @param user User to create and assign access to the database upon creation. Mandatory.
# @param password Required Sets the password for the created user.
# @param comment Defines a comment to be stored about the database using the PostgreSQL COMMENT command.
Expand All @@ -13,7 +13,7 @@
# @param owner Sets a user as the owner of the database.
define postgresql::server::db (
$user,
$password,
Variant[String, Sensitive[String]] $password,
$comment = undef,
$dbname = $title,
$encoding = $postgresql::server::encoding,
Expand Down
2 changes: 1 addition & 1 deletion manifests/server/default_privileges.pp
Expand Up @@ -144,7 +144,7 @@
psql_group => $group,
psql_path => $psql_path,
unless => $unless_cmd,
environment => "PGOPTIONS=--client-min-messages=error"
environment => 'PGOPTIONS=--client-min-messages=error'
}

if($role != undef and defined(Postgresql::Server::Role[$role])) {
Expand Down
7 changes: 6 additions & 1 deletion manifests/server/passwd.pp
@@ -1,6 +1,11 @@
# @api private
class postgresql::server::passwd {
$postgres_password = $postgresql::server::postgres_password
$postgres_password = if $postgresql::server::postgres_password =~ Sensitive {
$postgresql::server::postgres_password.unwrap
} else {
$postgresql::server::postgres_password
}

$user = $postgresql::server::user
$group = $postgresql::server::group
$psql_path = $postgresql::server::psql_path
Expand Down
33 changes: 19 additions & 14 deletions manifests/server/role.pp
Expand Up @@ -20,7 +20,7 @@
# @param module_workdir Specifies working directory under which the psql command should be executed. May need to specify if '/tmp' is on volume mounted with noexec option.
define postgresql::server::role (
$update_password = true,
$password_hash = false,
Variant[Boolean, String, Sensitive[String]] $password_hash = false,
$createdb = false,
$createrole = false,
$db = $postgresql::server::default_database,
Expand All @@ -38,6 +38,11 @@
$module_workdir = $postgresql::server::module_workdir,
Enum['present', 'absent'] $ensure = 'present',
) {
$password_hash_unsensitive = if $password_hash =~ Sensitive[String] {
$password_hash.unwrap
} else {
$password_hash
}
#
# Port, order of precedence: $port parameter, $connect_settings[PGPORT], $postgresql::server::port
#
Expand Down Expand Up @@ -75,17 +80,17 @@
$createdb_sql = $createdb ? { true => 'CREATEDB', default => 'NOCREATEDB' }
$superuser_sql = $superuser ? { true => 'SUPERUSER', default => 'NOSUPERUSER' }
$replication_sql = $replication ? { true => 'REPLICATION', default => '' }
if ($password_hash != false) {
$password_sql = "ENCRYPTED PASSWORD '${password_hash}'"
if ($password_hash_unsensitive != false) {
$password_sql = "ENCRYPTED PASSWORD '${password_hash_unsensitive}'"
} else {
$password_sql = ''
}

postgresql_psql { "CREATE ROLE ${username} ENCRYPTED PASSWORD ****":
command => Sensitive("CREATE ROLE \"${username}\" ${password_sql} ${login_sql} ${createrole_sql} ${createdb_sql} ${superuser_sql} ${replication_sql} CONNECTION LIMIT ${connection_limit}"),
unless => "SELECT 1 FROM pg_roles WHERE rolname = '${username}'",
require => undef,
sensitive => true,
command => Sensitive("CREATE ROLE \"${username}\" ${password_sql} ${login_sql} ${createrole_sql} ${createdb_sql} ${superuser_sql} ${replication_sql} CONNECTION LIMIT ${connection_limit}"),
unless => "SELECT 1 FROM pg_roles WHERE rolname = '${username}'",
require => undef,
sensitive => true,
}

postgresql_psql { "ALTER ROLE \"${username}\" ${superuser_sql}":
Expand Down Expand Up @@ -124,17 +129,17 @@
unless => "SELECT 1 FROM pg_roles WHERE rolname = '${username}' AND rolconnlimit = ${connection_limit}",
}

if $password_hash and $update_password {
if($password_hash =~ /^md5.+/) {
$pwd_hash_sql = $password_hash
if $password_hash_unsensitive and $update_password {
if($password_hash_unsensitive =~ /^md5.+/) {
$pwd_hash_sql = $password_hash_unsensitive
} else {
$pwd_md5 = md5("${password_hash}${username}")
$pwd_md5 = md5("${password_hash_unsensitive}${username}")
$pwd_hash_sql = "md5${pwd_md5}"
}
postgresql_psql { "ALTER ROLE ${username} ENCRYPTED PASSWORD ****":
command => Sensitive("ALTER ROLE \"${username}\" ${password_sql}"),
unless => Sensitive("SELECT 1 FROM pg_shadow WHERE usename = '${username}' AND passwd = '${pwd_hash_sql}'"),
sensitive => true,
command => Sensitive("ALTER ROLE \"${username}\" ${password_sql}"),
unless => Sensitive("SELECT 1 FROM pg_shadow WHERE usename = '${username}' AND passwd = '${pwd_hash_sql}'"),
sensitive => true,
}
}
} else {
Expand Down
18 changes: 12 additions & 6 deletions manifests/validate_db_connection.pp
@@ -1,5 +1,5 @@
# @summary This type validates that a successful postgres connection.
#
#
# @note
# This validated if the postgres connection can be established
# between the node on which this resource is run and a specified postgres
Expand All @@ -20,7 +20,7 @@
define postgresql::validate_db_connection (
$database_host = undef,
$database_name = undef,
$database_password = undef,
Optional[Variant[String, Sensitive[String]]] $database_password = undef,
$database_username = undef,
$database_port = undef,
$connect_settings = undef,
Expand All @@ -34,6 +34,12 @@

warning('postgresql::validate_db_connection is deprecated, please use postgresql_conn_validator.')

$database_password_unsensitive = if $database_password =~ Sensitive[String] {
$database_password.unwrap
} else {
$database_password
}

$psql_path = $postgresql::params::psql_path
$module_workdir = $postgresql::params::module_workdir
$validcon_script_path = $postgresql::client::validcon_script_path
Expand All @@ -55,9 +61,9 @@
undef => "--dbname ${postgresql::params::default_database} ",
default => "--dbname ${database_name} ",
}
$pass_env = $database_password ? {
$pass_env = $database_password_unsensitive ? {
undef => undef,
default => "PGPASSWORD=${database_password}",
default => "PGPASSWORD=${database_password_unsensitive}",
}
$cmd = join([$cmd_init, $cmd_host, $cmd_user, $cmd_port, $cmd_dbname], ' ')
$validate_cmd = "${validcon_script_path} ${sleep} ${tries} '${cmd}'"
Expand All @@ -66,8 +72,8 @@
# time it takes to run each psql command.
$timeout = (($sleep + 2) * $tries)

# Combine $database_password and $connect_settings into an array of environment
# variables, ensure $database_password is last, allowing it to override a password
# Combine $database_password_unsensitive and $connect_settings into an array of environment
# variables, ensure $database_password_unsensitive is last, allowing it to override a password
# from the $connect_settings hash
if $connect_settings != undef {
if $pass_env != undef {
Expand Down
64 changes: 45 additions & 19 deletions spec/unit/defines/server/role_spec.rb
Expand Up @@ -20,30 +20,56 @@
'test'
end

let :params do
{
password_hash: 'new-pa$s',
}
end

let :pre_condition do
"class {'postgresql::server':}"
end

it { is_expected.to contain_postgresql__server__role('test') }
it 'has create role for "test" user with password as ****' do
is_expected.to contain_postgresql_psql('CREATE ROLE test ENCRYPTED PASSWORD ****')
.with('command' => 'Sensitive [value redacted]',
'sensitive' => 'true',
'unless' => "SELECT 1 FROM pg_roles WHERE rolname = 'test'",
'port' => '5432')
context 'with Password Datatype String' do
let :params do
{
password_hash: 'new-pa$s',
}
end

it { is_expected.to contain_postgresql__server__role('test') }
it 'has create role for "test" user with password as ****' do
is_expected.to contain_postgresql_psql('CREATE ROLE test ENCRYPTED PASSWORD ****')
.with('command' => 'Sensitive [value redacted]',
'sensitive' => 'true',
'unless' => "SELECT 1 FROM pg_roles WHERE rolname = 'test'",
'port' => '5432')
end
it 'has alter role for "test" user with password as ****' do
is_expected.to contain_postgresql_psql('ALTER ROLE test ENCRYPTED PASSWORD ****')
.with('command' => 'Sensitive [value redacted]',
'sensitive' => 'true',
'unless' => 'Sensitive [value redacted]',
'port' => '5432')
end
end
it 'has alter role for "test" user with password as ****' do
is_expected.to contain_postgresql_psql('ALTER ROLE test ENCRYPTED PASSWORD ****')
.with('command' => 'Sensitive [value redacted]',
'sensitive' => 'true',
'unless' => 'Sensitive [value redacted]',
'port' => '5432')

context 'with Password Datatype Sensitive[String]' do
let :params do
{
password_hash: sensitive('new-pa$s'),
}
end

it { is_expected.to contain_postgresql__server__role('test') }
it 'has create role for "test" user with password as ****' do
is_expected.to contain_postgresql_psql('CREATE ROLE test ENCRYPTED PASSWORD ****')
.with('command' => 'Sensitive [value redacted]',
'sensitive' => 'true',
'unless' => "SELECT 1 FROM pg_roles WHERE rolname = 'test'",
'port' => '5432')
end
it 'has alter role for "test" user with password as ****' do
is_expected.to contain_postgresql_psql('ALTER ROLE test ENCRYPTED PASSWORD ****')
.with('command' => 'Sensitive [value redacted]',
'sensitive' => 'true',
'unless' => 'Sensitive [value redacted]',
'port' => '5432')
end
end

context 'with specific db connection settings - default port' do
Expand Down

0 comments on commit d878d13

Please sign in to comment.