With the Individual plan I would like to confirm that I will be able to use a Python database connector such as mysql or psycopg2 along with SSL for connectivity to Amazon RDS. I believe in either case I will need to store the Amazon server certificate, so is there a resource object in Anvil that can be accessed by the Python connector?
Hi there,
Short answer: yes!
Longer answer: With the Full Python runtimes included in the Individual Plan, you have access to a large number of Python modules, including psycopg2
, pymysql
, boto3
(the AWS API) and many more. We have people using external databases such as RDS from Anvil no problem.
You can find a full list of packages installed at https://anvil.works/doc/#python_packages - if there is something you need pip install
ing and you’re on the Individual plan or higher, drop us an email at support@anvil.works and we’ll usually get it installed within a day or so.
When using psycopg2 over SSL, in order to verify the CA I need to set the sslrootcert
to a file path. Is there a place where I can provide the PEM file such that I can refer to it with a file system path from a server module?
The filesystem in your server code is ephemeral. What I’d suggest is putting the file into a Data Table as a Media object, then writing it to a file. (In fact, the filesystem isn’t swept every time, so you only have to write it if it’s not there). Something like:
if not os.path.isfile('/tmp/rootcert.pem'):
pemdata = app_tables.cert.get()['data'].get_bytes()
with open('/tmp/rootcert.pem', 'w') as f:
f.write(pemdata)
Would adding the file as an asset work?
And be simpler?
Thanks, I can confirm this works with psycopg2
and sslmode='verify-full'
.
I got it working but I had to make a few changes. I needed to pass parameters to a dependency app, so I stored the certs in the main app and passed them as parameters to a function in the dependency app (as media objects).
I then modified @meredydd’s code slightly to this :
if "sslcert" in kwargs:
if not os.path.isfile('/tmp/ca.crt'):
with open('/tmp/ca.crt','w') as f:
f.write(kwargs['sslcert'].get_bytes().decode())
if "sslclientcert" in kwargs:
if not os.path.isfile('/tmp/client.crt'):
with open('/tmp/client.crt','w') as f:
f.write(kwargs['sslclientcert'].get_bytes().decode())
if "sslclientkey" in kwargs:
if not os.path.isfile('/tmp/client.key'):
with open('/tmp/client.key', 'w') as f:
f.write(kwargs['sslclientkey'].get_bytes().decode())
os.chmod("/tmp/client.key",0o600)
Note the client key - I needed to change the permissions to “0o600” to remove the errror :
Permissions should be u=rw (0600) or less.
I’m still feeling my way with this …
I just wanted to update this slightly to demonstrate slightly better practice.
In the example above I’m clearly storing the certs as a media object in the data tables (as shown by the fact I’m doing a get_bytes()).
Don’t do that. Instead store them as a secret, then they are encrypted at rest.