Last active
July 21, 2020 17:39
-
-
Save mattupstate/27f2bf26d3712b6b7973 to your computer and use it in GitHub Desktop.
Just a clever way to set an RDS master password with Terraform and Ansible to prevent the password from being stored in plain text
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
resource "aws_db_instance" "core" { | |
username = "postgres" | |
password = "changeme" | |
... | |
} | |
resource "null_resource" "master_password" { | |
triggers { | |
db_host = "${aws_db_instance.address}" | |
} | |
provisioner "local-exec" { | |
command = "ansible localhost -e @path/to/secrets.yml --vault-password-file path/to/vault.txt -a 'set-postgres-master-password --host ${aws_db_instance.address} --password changeme --new-password {{ my_new_master_password }}'" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import argparse | |
import psycopg2 | |
def main(host, port, user, password, newpassword): | |
sql = "ALTER ROLE %s WITH PASSWORD '%s';" % (user, newpassword) | |
conn_str = 'host=%s user=%s password=%s' % (host, user, password) | |
connection = psycopg2.connect(conn_str) | |
cursor = connection.cursor() | |
cursor.execute(sql) | |
connection.commit() | |
cursor.close() | |
connection.close() | |
print('New password set successfully') | |
if __name__ == '__main__': | |
parser = argparse.ArgumentParser( | |
description='Sets a PostgreSQL database master password') | |
parser.add_argument('--user', dest='user', default='postgres', | |
help='the master username') | |
parser.add_argument('--password', dest='password', required=True, | |
help='the current master username') | |
parser.add_argument('--new-password', dest='newpassword', required=True, | |
help='the new password') | |
parser.add_argument('--host', dest='host', required=True, | |
help='the host to connect to') | |
parser.add_argument('--port', dest='port', default=5432, | |
help='the port to connect to') | |
args = parser.parse_args() | |
main(args.host, args.port, args.user, args.password, args.newpassword) |
Not a criticism just pointing it out in case anyone reads this and assumes the alternative does the same thing as this one.
If one is storing the state in s3 then it's fair enough to source the password from a file on disk through an env var.
@tonglil I've updated my original comment to reflect the added risk in case anyone doesn't read this far.
It looks like "the current master username" on line 23 should read "the current password".
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
That's fair. In my case my statefile is encrypted in S3 so this is an acceptable risk to be able to manage it this way, but I definitely see the advantage to your way.