I’m trying to get encrypted parameters to work with a python app, but not having much success.
In serverless.yml I have:
service:
name: my-sql
awsKmsKeyArn: arn:aws:kms:eu-west-1:...
provider:
name: aws
runtime: python3.6
...
environment: ${file(env_dev.yml)}
(aside: I wonder why awsKmsKeyArn goes under “service” rather than “provider”?)
And in env_dev.yml I have:
DATABASE_URL: mysql+pymysql://user:pass@etc
This all works fine without the encryption.
Now, adding the awsKmsKeyArn doesn’t seem to have made any difference to the behaviour of my app. When I deploy the stack, I find that the variable is not encrypted - that is, it is visible in the AWS lambda console, and the app finds the plain value it needs in the environment.
I can click to enable encryption in the AWS console, but after “sls deploy” it is back to plaintext.
So it’s not clear to me: if I specify “awsKmsKeyArn” by itself, what is supposed to happen? The setting does end up in the cloudformation template.
Next: when I enable encryption helper manually in the console, it gives me some suggested code to use in my application:
import boto3
import os
from base64 import b64decode
ENCRYPTED = os.environ['DATABASE_URL']
# Decrypt code should run once and variables stored outside of the function
# handler so that these are decrypted once per container
DECRYPTED = boto3.client('kms').decrypt(CiphertextBlob=b64decode(ENCRYPTED))['Plaintext']
def lambda_handler(event, context):
# TODO handle the event here
This is good, it means the decryption is supposed to take place in the application itself. But I need cloudformation to deploy with the encrypted key.
So: should I put the already-encrypted and base64-encoded data in the YAML? Or should my YAML contain the plaintext, and the encryption takes place when Cloudstack deploys it?
The next thing I tried was encrypting the data locally.
aws kms encrypt --key-id arn:aws:kms:eu-west-1:... --plaintext "mysql+pymysql://user:pass@etc"
This gave me a nice encrypted base64 blob. I put it in the YAML, added the decode logic to the python, and deployed. But now the lambda function just gives me an execution timeout error (even after upping it to 20 seconds). Adding print() statements shows it’s the decrypt() step which is hanging.
Furthermore, the AWS console displays this base64 data as if it were unencrypted text. That is, it still has the “Encrypt” button available.
I wondered if I might have to add something like this:
iamRoleStatements:
- Effect: Allow
Action:
- kms:Decrypt
Resource: arn:aws:kms:eu-west-1:...
but (a) the sls documentation doesn’t mention this, and (b) I would have expected sls to add this automatically, if this was needed, since I set awsKmsKeyArn. And anyway, I added it and it didn’t make any difference.
So I’ve clearly missed the point as to how this is supposed to work. Any clues gratefully received!
Thanks,
Brian.
P.S. I did read https://serverless.com/framework/docs/providers/aws/guide/functions#secrets-using-environment-variables-and-kms
It links to
http://docs.aws.amazon.com/lambda/latest/dg/env_variables.html#env-storing-sensitive-data
and
http://docs.aws.amazon.com/lambda/latest/dg/tutorial-env_console.html
but these aren’t very helpful, as they assume you’re using the console to encrypt the key.