@ -7,9 +7,11 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
__metaclass__ = type
ANSIBLE_METADATA = { ' metadata_version ' : ' 1.1 ' ,
ANSIBLE_METADATA = {
' metadata_version ' : ' 1.1 ' ,
' status ' : [ ' stableinterface ' ] ,
' status ' : [ ' stableinterface ' ] ,
' supported_by ' : ' community ' }
' supported_by ' : ' community '
}
DOCUMENTATION = '''
DOCUMENTATION = '''
@ -34,60 +36,70 @@ version_added: "0.6"
options :
options :
name :
name :
description :
description :
- n ame of the user ( role ) to add or remove
- N ame of the user ( role ) to add or remove .
required : true
required : true
password :
password :
description :
description :
- set the user ' s password, before 1.4 this was required.
- Set the user ' s password, before 1.4 this was required.
- >
- Password can be passed unhashed or hashed ( MD5 - hashed ) .
When passing an encrypted password , the encrypted parameter must also be true , and it must be generated with the format
- Unhashed password will automatically be hashed when saved into the
C ( ' str[ \\ " md5 \\ " ] + md5[ password + username ] ' ) , resulting in a total of 35 characters . An easy way to do this is :
database if C ( encrypted ) parameter is set , otherwise it will be save in
C ( echo \\" md5`echo -n \\ " verysecretpasswordJOE \\" | md5` \\ " ) . Note that if the provided password string is already in
plain text format .
MD5 - hashed format , then it is used as - is , regardless of encrypted parameter .
- When passing a hashed password it must be generated with the format
C ( ' str[ " md5 " ] + md5[ password + username ] ' ) , resulting in a total of
35 characters . An easy way to do this is C ( echo " md5$(echo -n
' verysecretpasswordJOE ' | md5sum ) " ).
- Note that if the provided password string is already in MD5 - hashed
format , then it is used as - is , regardless of C ( encrypted ) parameter .
db :
db :
description :
description :
- name of database where permissions will be granted
- N ame of database where permissions will be granted .
fail_on_user :
fail_on_user :
description :
description :
- i f C ( yes ) , fail when user can ' t be removed. Otherwise just log and continue
- I f C ( yes ) , fail when user can ' t be removed. Otherwise just log and
type : bool
continue .
default : ' yes '
default : ' yes '
type : bool
port :
port :
description :
description :
- Database port to connect to .
- Database port to connect to .
default : 5432
default : 5432
login_user :
login_user :
description :
description :
- User ( role ) used to authenticate with PostgreSQL
- User ( role ) used to authenticate with PostgreSQL .
default : postgres
default : postgres
login_password :
login_password :
description :
description :
- Password used to authenticate with PostgreSQL
- Password used to authenticate with PostgreSQL .
login_host :
login_host :
description :
description :
- Host running PostgreSQL .
- Host running PostgreSQL .
default : localhost
default : localhost
login_unix_socket :
login_unix_socket :
description :
description :
- Path to a Unix domain socket for local connections
- Path to a Unix domain socket for local connections .
priv :
priv :
description :
description :
- " PostgreSQL privileges string in the format: C(table:priv1,priv2) "
- " PostgreSQL privileges string in the format: C(table:priv1,priv2) . "
role_attr_flags :
role_attr_flags :
description :
description :
- " PostgreSQL role attributes string in the format: CREATEDB,CREATEROLE,SUPERUSER "
- " PostgreSQL role attributes string in the format: CREATEDB,CREATEROLE,SUPERUSER . "
- Note that ' [NO]CREATEUSER ' is deprecated .
- Note that ' [NO]CREATEUSER ' is deprecated .
default : " "
choices : [ " [NO]SUPERUSER " , " [NO]CREATEROLE " , " [NO]CREATEDB " , " [NO]INHERIT " , " [NO]LOGIN " , " [NO]REPLICATION " , " [NO]BYPASSRLS " ]
choices : [ " [NO]SUPERUSER " , " [NO]CREATEROLE " , " [NO]CREATEDB " , " [NO]INHERIT " , " [NO]LOGIN " , " [NO]REPLICATION " , " [NO]BYPASSRLS " ]
state :
state :
description :
description :
- The user ( role ) state
- The user ( role ) state .
default : present
default : present
choices : [ present , absent ]
choices : [ " present " , " absent " ]
encrypted :
encrypted :
description :
description :
- whether the password is stored hashed in the database . boolean . Passwords can be passed already hashed or unhashed , and postgresql ensures the
- Whether the password is stored hashed in the database . Passwords can be
stored password is hashed when encrypted is set .
passed already hashed or unhashed , and postgresql ensures the stored
password is hashed when C ( encrypted ) is set .
- " Note: Postgresql 10 and newer doesn ' t support unhashed passwords. "
- Previous to Ansible 2.6 , this was C ( no ) by default .
default : ' yes '
type : bool
version_added : ' 1.4 '
version_added : ' 1.4 '
expires :
expires :
description :
description :
@ -97,22 +109,26 @@ options:
version_added : ' 1.4 '
version_added : ' 1.4 '
no_password_changes :
no_password_changes :
description :
description :
- if C ( yes ) , don ' t inspect database for password changes. Effective when C(pg_authid) is not accessible (such as AWS RDS). Otherwise, make
- If C ( yes ) , don ' t inspect database for password changes. Effective when
C ( pg_authid ) is not accessible ( such as AWS RDS ) . Otherwise , make
password changes as necessary .
password changes as necessary .
type : bool
default : ' no '
default : ' no '
type : bool
version_added : ' 2.0 '
version_added : ' 2.0 '
ssl_mode :
ssl_mode :
description :
description :
- Determines whether or with what priority a secure SSL TCP / IP connection will be negotiated with the server .
- Determines whether or with what priority a secure SSL TCP / IP connection
- See https : / / www . postgresql . org / docs / current / static / libpq - ssl . html for more information on the modes .
will be negotiated with the server .
- See U ( https : / / www . postgresql . org / docs / current / static / libpq - ssl . html ) for
more information on the modes .
- Default of C ( prefer ) matches libpq default .
- Default of C ( prefer ) matches libpq default .
default : prefer
default : prefer
choices : [ disable , allow , prefer , require , verify - ca , verify - full ]
choices : [ " disable " , " allow " , " prefer " , " require " , " verify-ca " , " verify-full " ]
version_added : ' 2.3 '
version_added : ' 2.3 '
ssl_rootcert :
ssl_rootcert :
description :
description :
- Specifies the name of a file containing SSL certificate authority ( CA ) certificate ( s ) . If the file exists , the server ' s certificate will be
- Specifies the name of a file containing SSL certificate authority ( CA )
certificate ( s ) . If the file exists , the server ' s certificate will be
verified to be signed by one of these authorities .
verified to be signed by one of these authorities .
version_added : ' 2.3 '
version_added : ' 2.3 '
conn_limit :
conn_limit :
@ -128,14 +144,11 @@ notes:
PostgreSQL must also be installed on the remote host . For Ubuntu - based
PostgreSQL must also be installed on the remote host . For Ubuntu - based
systems , install the postgresql , libpq - dev , and python - psycopg2 packages
systems , install the postgresql , libpq - dev , and python - psycopg2 packages
on the remote host before using this module .
on the remote host before using this module .
- If the passlib library is installed , then passwords that are encrypted
in the DB but not encrypted when passed as arguments can be checked for
changes . If the passlib library is not installed , unencrypted passwords
stored in the DB encrypted will be assumed to have changed .
- If you specify PUBLIC as the user , then the privilege changes will apply
- If you specify PUBLIC as the user , then the privilege changes will apply
to all users . You may not specify password or role_attr_flags when the
to all users . You may not specify password or role_attr_flags when the
PUBLIC user is specified .
PUBLIC user is specified .
- The ssl_rootcert parameter requires at least Postgres version 8.4 and I ( psycopg2 ) version 2.4 .3 .
- The ssl_rootcert parameter requires at least Postgres version 8.4 and
I ( psycopg2 ) version 2.4 .3 .
requirements : [ psycopg2 ]
requirements : [ psycopg2 ]
author : " Ansible Core Team "
author : " Ansible Core Team "
'''
'''
@ -148,10 +161,11 @@ EXAMPLES = '''
password : ceec4eif7ya
password : ceec4eif7ya
priv : " CONNECT/products:ALL "
priv : " CONNECT/products:ALL "
# Create rails user, grant privilege to create other databases and demote rails from super user status
# Create rails user, set its password (MD5-hashed) and grant privilege to create other
# databases and demote rails from super user status
- postgresql_user :
- postgresql_user :
name : rails
name : rails
password : secret
password : md59543f1d82624df2b31672ec0f7050460
role_attr_flags : CREATEDB , NOSUPERUSER
role_attr_flags : CREATEDB , NOSUPERUSER
# Remove test user privileges from acme
# Remove test user privileges from acme
@ -184,7 +198,7 @@ EXAMPLES = '''
- postgresql_user :
- postgresql_user :
db : test
db : test
user : test
user : test
password : NULL
password : " "
'''
'''
import itertools
import itertools
@ -248,7 +262,7 @@ def user_add(cursor, user, password, role_attr_flags, encrypted, expires, conn_l
query_password_data = dict ( password = password , expires = expires )
query_password_data = dict ( password = password , expires = expires )
query = [ ' CREATE USER %(user)s ' %
query = [ ' CREATE USER %(user)s ' %
{ " user " : pg_quote_identifier ( user , ' role ' ) } ]
{ " user " : pg_quote_identifier ( user , ' role ' ) } ]
if password is not None :
if password is not None and password != ' ' :
query . append ( " WITH %(crypt)s " % { " crypt " : encrypted } )
query . append ( " WITH %(crypt)s " % { " crypt " : encrypted } )
query . append ( " PASSWORD %(password)s " )
query . append ( " PASSWORD %(password)s " )
if expires is not None :
if expires is not None :
@ -277,11 +291,16 @@ def user_should_we_change_password(current_role_attrs, user, password, encrypted
# Do we actually need to do anything?
# Do we actually need to do anything?
pwchanging = False
pwchanging = False
if password is not None :
if password is not None :
# Empty password means that the role shouldn't have a password, which
# means we need to check if the current password is None.
if password == ' ' :
if current_role_attrs [ ' rolpassword ' ] is not None :
pwchanging = True
# 32: MD5 hashes are represented as a sequence of 32 hexadecimal digits
# 32: MD5 hashes are represented as a sequence of 32 hexadecimal digits
# 3: The size of the 'md5' prefix
# 3: The size of the 'md5' prefix
# When the provided password looks like a MD5-hash, value of
# When the provided password looks like a MD5-hash, value of
# 'encrypted' is ignored.
# 'encrypted' is ignored.
if ( ( password . startswith ( ' md5 ' ) and len ( password ) == 32 + 3 ) or encrypted == ' UNENCRYPTED ' ) :
el if ( password . startswith ( ' md5 ' ) and len ( password ) == 32 + 3 ) or encrypted == ' UNENCRYPTED ' :
if password != current_role_attrs [ ' rolpassword ' ] :
if password != current_role_attrs [ ' rolpassword ' ] :
pwchanging = True
pwchanging = True
elif encrypted == ' ENCRYPTED ' :
elif encrypted == ' ENCRYPTED ' :
@ -360,8 +379,11 @@ def user_alter(db_connection, module, user, password, role_attr_flags, encrypted
alter = [ ' ALTER USER %(user)s ' % { " user " : pg_quote_identifier ( user , ' role ' ) } ]
alter = [ ' ALTER USER %(user)s ' % { " user " : pg_quote_identifier ( user , ' role ' ) } ]
if pwchanging :
if pwchanging :
if password != ' ' :
alter . append ( " WITH %(crypt)s " % { " crypt " : encrypted } )
alter . append ( " WITH %(crypt)s " % { " crypt " : encrypted } )
alter . append ( " PASSWORD %(password)s " )
alter . append ( " PASSWORD %(password)s " )
else :
alter . append ( " WITH PASSWORD NULL " )
alter . append ( role_attr_flags )
alter . append ( role_attr_flags )
elif role_attr_flags :
elif role_attr_flags :
alter . append ( ' WITH %s ' % role_attr_flags )
alter . append ( ' WITH %s ' % role_attr_flags )
@ -715,7 +737,7 @@ def main():
port = dict ( default = ' 5432 ' ) ,
port = dict ( default = ' 5432 ' ) ,
fail_on_user = dict ( type = ' bool ' , default = ' yes ' ) ,
fail_on_user = dict ( type = ' bool ' , default = ' yes ' ) ,
role_attr_flags = dict ( default = ' ' ) ,
role_attr_flags = dict ( default = ' ' ) ,
encrypted = dict ( type = ' bool ' , default = ' no ' ) ,
encrypted = dict ( type = ' bool ' , default = ' yes ' ) ,
no_password_changes = dict ( type = ' bool ' , default = ' no ' ) ,
no_password_changes = dict ( type = ' bool ' , default = ' no ' ) ,
expires = dict ( default = None ) ,
expires = dict ( default = None ) ,
ssl_mode = dict ( default = ' prefer ' , choices = [
ssl_mode = dict ( default = ' prefer ' , choices = [