From 1d9e754b6fcb8d1a72720e7e9b0a12ff65bc332a Mon Sep 17 00:00:00 2001 From: Nikhil Jain Date: Tue, 28 Jul 2026 14:50:01 +0530 Subject: [PATCH] Fix controller postgres password encryption steps for SECRET_KEY load order Document loading /etc/tower/SECRET_KEY and passing secret_key= to get_encryption_key(), matching the working RPM controller procedure and KCS https://access.redhat.com/solutions/7145931. Also fix the broken example, typo, and add validation/restart/verification steps. Co-authored-by: Cursor --- .../proc-encrypt-postgres-password.adoc | 75 ++++++++++++++++--- 1 file changed, 65 insertions(+), 10 deletions(-) diff --git a/downstream/modules/platform/proc-encrypt-postgres-password.adoc b/downstream/modules/platform/proc-encrypt-postgres-password.adoc index a0f6a3310d..4c49264e70 100644 --- a/downstream/modules/platform/proc-encrypt-postgres-password.adoc +++ b/downstream/modules/platform/proc-encrypt-postgres-password.adoc @@ -7,36 +7,91 @@ [role="_abstract"] Learn how to encrypt the PostgreSQL password used by {ControllerName} for database connections. +[NOTE] +==== +{ControllerNameStart} loads files under `/etc/tower/conf.d/` while Django settings are still being assembled. +At that point, `settings.SECRET_KEY` is not available yet. +If you call `get_encryption_key('value')` without supplying the secret key, configuration loading fails with `ImproperlyConfigured: The SECRET_KEY setting must not be empty.` +Load `/etc/tower/SECRET_KEY` from disk and pass it to `get_encryption_key()` by using the `secret_key` parameter, as shown in this procedure. + +For more information, see link:https://access.redhat.com/solutions/7145931[How to encrypt the PostgreSQL password in automation controller configuration files on Red Hat Ansible Automation Platform]. +==== + Perform the following steps on each node in the cluster: .Procedure -. Edit `/etc/tower/conf.d/postgres.py` using: +. Back up the existing PostgreSQL configuration file: + [literal, options="nowrap" subs="+quotes,attributes"] ---- -$ vim /etc/tower/conf.d/postgres.py +# mkdir -p /root/backup +# cp -a /etc/tower/conf.d/postgres.py /root/backup/postgres.py.$(date +%Y%m%d%H%M%S) ---- -. Add the following line to the top of the file. +. Edit `/etc/tower/conf.d/postgres.py`: + [literal, options="nowrap" subs="+quotes,attributes"] ---- -from awx.main.utils import decrypt_value, get_encryption_key +# vim /etc/tower/conf.d/postgres.py ---- +. Add the following lines at the top of the file to import the decryption helpers and load the {ControllerName} secret key: ++ +[literal, options="nowrap" subs="+quotes,attributes"] +---- +from awx.main.utils import decrypt_value, get_encryption_key -. Remove the password value listed after 'PASSWORD': and replace it with the following line, replacing the supplied value of `$encrytpted..` with your own hash value: +with open('/etc/tower/SECRET_KEY', 'rb') as f: + _secret_key = f.read().strip() +---- +. Remove the password value listed after `'PASSWORD':` and replace it with the following line, replacing the supplied `$encrypted$...` hash with your own hash value: + [literal, options="nowrap" subs="+quotes,attributes"] ---- -decrypt_value(get_encryption_key('value'),'$encrypted$AESCBC$Z0FBQUFBQmNONU9BbGQ1VjJyNDJRVTRKaFRIR09Ib2U5TGdaYVRfcXFXRjlmdmpZNjdoZVpEZ21QRWViMmNDOGJaM0dPeHN2b194NUxvQ1M5X3dSc1gxQ29TdDBKRkljWHc9PQ=='), +'PASSWORD': decrypt_value(get_encryption_key('value', secret_key=_secret_key),'$encrypted$AESCBC$Z0FBQUFBQmNONU9BbGQ1VjJyNDJRVTRKaFRIR09Ib2U5TGdaYVRfcXFXRjlmdmpZNjdoZVpEZ21QRWViMmNDOGJaM0dPeHN2b194NUxvQ1M5X3dSc1gxQ29TdDBKRkljWHc9PQ=='), ---- + [NOTE] ==== -The hash value in this step is the output value of `postgres_secret`. +The hash value in this step is the output value of `postgres_secret` from the procedure for creating PostgreSQL password hashes. +Use the keyword argument form `secret_key=_secret_key`. +Do not call `get_encryption_key('value')` alone, and do not pass the secret key as a positional second argument. ==== -. The full `postgres.py` resembles the following: +. The full `postgres.py` resembles the following. Keep your existing `NAME`, `USER`, `HOST`, `PORT`, and any `OPTIONS` values: + [literal, options="nowrap" subs="+quotes,attributes"] ---- -# Ansible Automation platform controller database settings. from awx.main.utils import decrypt_value, get_encryption_key DATABASES = { 'default': { 'ATOMIC_REQUESTS': True, 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'awx', 'USER': 'awx', 'PASSWORD': decrypt_value(get_encryption_key('value'),'$encrypted$AESCBC$Z0FBQUFBQmNONU9BbGQ1VjJyNDJRVTRKaFRIR09Ib2U5TGdaYVRfcXFXRjlmdmpZNjdoZVpEZ21QRWViMmNDOGJaM0dPeHN2b194NUxvQ1M5X3dSc1gxQ29TdDBKRkljWHc9PQ=='), 'HOST': '127.0.0.1', 'PORT': 5432, } }+ ----- \ No newline at end of file +# Ansible Automation Platform controller database settings. +from awx.main.utils import decrypt_value, get_encryption_key + +with open('/etc/tower/SECRET_KEY', 'rb') as f: + _secret_key = f.read().strip() + +DATABASES = { + 'default': { + 'ATOMIC_REQUESTS': True, + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': 'awx', + 'USER': 'awx', + 'PASSWORD': decrypt_value(get_encryption_key('value', secret_key=_secret_key),'$encrypted$AESCBC$Z0FBQUFBQmNONU9BbGQ1VjJyNDJRVTRKaFRIR09Ib2U5TGdaYVRfcXFXRjlmdmpZNjdoZVpEZ21QRWViMmNDOGJaM0dPeHN2b194NUxvQ1M5X3dSc1gxQ29TdDBKRkljWHc9PQ=='), + 'HOST': '127.0.0.1', + 'PORT': 5432, + } +} +---- +. Validate the configuration: ++ +[literal, options="nowrap" subs="+quotes,attributes"] +---- +# awx-manage check +---- ++ +The output should report that the system check identified no issues. +. When encryption is complete on all nodes, restart services across the cluster: ++ +[literal, options="nowrap" subs="+quotes,attributes"] +---- +# automation-controller-service restart +---- + +.Verification +* Confirm that you can log in to the UI and run jobs across all nodes. +* Confirm that the password is no longer stored as plain text in `/etc/tower/conf.d/postgres.py`.