diff --git a/.sync.yml b/.sync.yml index ce0b038531..7fa2304791 100644 --- a/.sync.yml +++ b/.sync.yml @@ -1,6 +1,9 @@ --- ".gitlab-ci.yml": delete: true +.puppet-lint.rc: + extra_disabled_lint_checks: + - 140chars-check appveyor.yml: delete: true diff --git a/REFERENCE.md b/REFERENCE.md index e464a74fe2..8b5439bab1 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -863,7 +863,7 @@ The following parameters are available in the `postgresql::server` class: ##### `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. @@ -1646,7 +1646,7 @@ User to create and assign access to the database upon creation. Mandatory. ##### `password` -Data type: `Any` +Data type: `Variant[String, Sensitive[String]]` Required Sets the password for the created user. @@ -2571,7 +2571,7 @@ Default value: ``true`` ##### `password_hash` -Data type: `Any` +Data type: `Variant[String, Sensitive[String]]` Sets the hash to use during password creation. @@ -2713,7 +2713,7 @@ Create a new schema. #### Examples -##### +##### ```puppet postgresql::server::schema {'private': @@ -2944,7 +2944,7 @@ Default value: ``undef`` ##### `database_password` -Data type: `Any` +Data type: `Variant[String, Sensitive[String]]` Specifies the password to connect with. @@ -3106,6 +3106,8 @@ The name of the database you are trying to validate a connection with. ##### `db_password` +Data type: `Variant[String, Sensitive[String]]` + The password required to access the target PostgreSQL database. ##### `db_username` @@ -3319,7 +3321,7 @@ This function pull default values from the `params` class or `globals` class if #### Examples -##### +##### ```puppet postgresql::default('variable') @@ -3333,7 +3335,7 @@ Returns: `Any` ##### Examples -###### +###### ```puppet postgresql::default('variable') @@ -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. @@ -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] + ### `postgresql_escape` Type: Ruby 4.x API diff --git a/lib/puppet/functions/postgresql/postgresql_password.rb b/lib/puppet/functions/postgresql/postgresql_password.rb index 30b1bfcf80..f22db18f05 100644 --- a/lib/puppet/functions/postgresql/postgresql_password.rb +++ b/lib/puppet/functions/postgresql/postgresql_password.rb @@ -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 diff --git a/manifests/server.pp b/manifests/server.pp index 07bbff49c1..5b9af035cb 100644 --- a/manifests/server.pp +++ b/manifests/server.pp @@ -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, diff --git a/manifests/server/db.pp b/manifests/server/db.pp index f98de6f268..3024c2909c 100644 --- a/manifests/server/db.pp +++ b/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. @@ -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, diff --git a/manifests/server/default_privileges.pp b/manifests/server/default_privileges.pp index 7311d5eb1a..87e079a146 100644 --- a/manifests/server/default_privileges.pp +++ b/manifests/server/default_privileges.pp @@ -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])) { diff --git a/manifests/server/passwd.pp b/manifests/server/passwd.pp index a2f52ba18b..93ceb96966 100644 --- a/manifests/server/passwd.pp +++ b/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 diff --git a/manifests/server/role.pp b/manifests/server/role.pp index 0ef4651531..cba36ec54c 100644 --- a/manifests/server/role.pp +++ b/manifests/server/role.pp @@ -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, @@ -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 # @@ -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}": @@ -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 { diff --git a/manifests/validate_db_connection.pp b/manifests/validate_db_connection.pp index 2a382006a6..7478fd4397 100644 --- a/manifests/validate_db_connection.pp +++ b/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 @@ -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, @@ -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 @@ -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}'" @@ -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 { diff --git a/spec/unit/defines/server/role_spec.rb b/spec/unit/defines/server/role_spec.rb index 7180ec2bc5..53f2e93553 100644 --- a/spec/unit/defines/server/role_spec.rb +++ b/spec/unit/defines/server/role_spec.rb @@ -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