awx-operator
awx-operator copied to clipboard
Add pg password encrypt functionality
In the following KCS, we allow the passing of encrypted postgres password in credentials.py: https://access.redhat.com/solutions/4309941
In the operator, this is not possible at the moment as any changes to that file is not persistent. I have added a variable to toggle adding the from awx.main.utils import decrypt_value, get_encryption_key
in order to enable the functionality. By default, I have disabled it.
I wonder if we should we enable this option or defer to Secret
encryption in the underlying k8s cluster to make this happen?
Secret encryption would still leave it unencrytped in the credentials.py when mounted wouldn't it?
Also, when using this, I believe it'll only work with external databases, otherwise that decrypt_value
function will be inserted into the postgres password for our postgresql deployment
Secret encryption would still leave it unencrytped in the credentials.py when mounted wouldn't it?
Also, when using this, I believe it'll only work with external databases, otherwise that
decrypt_value
function will be inserted into the postgres password for our postgresql deployment
Oh true, you are right, nvm
For your concern here:
We still need to use the decrypt_value and get_encryption_key functions in the credentials.py.j2 template to get the password value.
I figured the customer would've copied the whole value of that into the PG_PASSWORD field, for example, I would imagine their secret looks like this:
apiVersion: v1
data:
...
password: decrypt_value(get_encryption_key('value'),'$encrypted$AESCBC$Z0FBQUFBQmNONU9BbGQ1VjJyNDJRVTRKaFRIR09Ib2U5TGdaYVRfcXFXRjlmdmpZNjdoZVpEZ21QRWViMmNDOGJaM0dPeHN2b194NUxvQ1M5X3dSc1gxQ29TdDBKRkljWHc9PQ==')
As for the boolean, I can change it no problem, I just thought since no_log was configured the same way that this would carry over as well.
As for the blank line, would that still show up if the condition is false?
I figured the customer would've copied the whole value of that into the PG_PASSWORD field, for example, I would imagine their secret looks like this:
This won't work because the awx_postgres_pass
variable is quoted in the credentials.py.j2 [1]Â so the decrypt_value
and get_encryption_key
functions won't be executed.
As for the blank line, would that still show up if the condition is false?
it won't show up, I don't remember why I put that comment, so you can dismiss it
[1] https://github.com/ansible/awx-operator/blob/devel/roles/installer/templates/credentials.py.j2#L7
So let me see if I have this right:
- The goal here is for the user to have a deployment that does not have the PG Password exposed in plaintext in the credentials.py file inside the task and web containers. For VM installs, we have the KCS article, but that won't work in openshift.
For operator deployments, to have this value encrypted in the resulting credentials.py file with this PR, the user needs to:
- Create an AutomationController CR with a pg config secret using the unencrypted password
- Exec into the container and use the symmetric key (SECRET_KEY) unique to that deployment to encrypt the PG password using awx-manage and the steps in the KCS article.
- Modify the pg secret to include the encrypted value
- Restart the deployment: oc rollout deployment
- It will re-create the credentials.py file mounted into the container with the encrypted PG password.
There are currently 3 other places where the awx_postgres_pass is used, the backup and restore roles, and the migrate_data.yml logic.
Once the pg 12 --> 13 upgrade logic lands that will be another. The backup and restore ones are not a problem, but the upgrade and migrate data ones are because the PG_PASSWORD value must be decrypted by the operator before being used.
So, while the awx-task container is still up, we will need to have a k8s_exec task that will decrypt it and register the output as a variable. @rh-dluong
So, I'm wracking my brain and it seems there's a bit of a hitch with this. I'm assume the way the decrypt works is that we use the SECRET_KEY to decrypt, however, due to these migrate_data task(s), this kinda shoots down this whole thing.
I've tested this, and it does decrypt the var successfully as a mockup:
- name: Set old postgres password if encrypted
kubernetes.core.k8s_exec:
namespace: dluong-aap
pod: dluong-controller-5c5b7477c5-hq27x
container: dluong-controller-task
command: |
awx-manage shell_plus -c """
from awx.main.utils import decrypt_value, get_encryption_key
decrypted_value = decrypt_value(get_encryption_key('value'),'{{postgresql_password}}')
print(decrypted_value)
"""
register: decrypt_old_postgres
when: "'encrypted' in postgresql_password"
- name: debug
debug:
var: decrypt_old_postgres.stdout_lines[-1]
However, in order for this to work with migrating data, we would need to probably, when backing up, unencrypt the password if it is encrypted, and store it in the config file since there is no reference to the old tower/controller app environment in the postgresql secret. Though, that kinda seems against the spirit of having this in the first place. And then when restoring or migrating, they will need to manually encrypt it again. This seems like the only feasible way this PR can move on functionally.
Also, you can ignore this next part, this is just for me to track where we're setting some things later depending on how we want to go about this:
tasks/creation.yml: - include_tasks: postgres.yml
tasks/creation.yml: - include_tasks: secrets.yml
tasks/secrets.yml: include_tasks: dump_generated_secret.yml
tasks/secrets.yml: include_tasks: dump_secret.yml
tasks/secrets.yml: include_tasks: dump_secret.yml
tasks/secrets.yml: include_tasks: dump_secret.yml
tasks/secrets.yml: bash -c "echo '{{ secrets | to_yaml }}' > {{ backup_dir }}/secrets.yml"
tasks/main.yml: include_tasks: creation.yml