how to decrypt the environment variables in aws lambda using python 3

Viewed 3245

I am trying to encrypt my postgres connection string variable.

db_host = os.environ.get('db_host')
db_port = os.environ.get('db_port')
db_name =os.environ.get('db_name')
db_user =os.environ.get('db_user')
db_pass =os.environ.get('db_pass')

as you can see I have used environment variable, but I want to encrypt it.

I have figured out a way to encrypt it was also checking a way to decrypt it.

Lambda function suggested a below code.

import boto3
import os

from base64 import b64decode

ENCRYPTED = os.environ['db_host']
# 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),
    EncryptionContext={'LambdaFunctionName': os.environ['AWS_LAMBDA_FUNCTION_NAME']}
)['Plaintext'].decode('utf-8')

def lambda_handler(event, context):
    # TODO handle the event here
    pass

Questions:

  1. Can I include this in the same .py file which contents my lambda function?

  2. This shows the decryption of a single variable. I have multiple variables how do I implement for that so that all are decrypted in one go?

EncryptionContext={'LambdaFunctionName': os.environ['AWS_LAMBDA_FUNCTION_NAME']} )['Plaintext'].decode('utf-8')

What is {'LambdaFunctionName': os.environ['AWS_LAMBDA_FUNCTION_NAME']}

2 Answers
  1. It depends on the size of your lambda script, really. If it's a really small script with very few decrypt calls, you can have them inside your Lambda function. Or else, if you want to separate decryption calls for better readability and manageability you can either create a function or have decryption in a different .py file and import it in the lambda function.

  2. You can not decrypt multiple ciphers using the decrypt call. You might've to call decrypt multiple times to accomplish this. Otherwise, you can pack the entire content as a comma-separated list or JSON encoded array and store the encrypted value in the environment variable. This is not a recommended way to go. Highly recommended alternative solution will be to use the SSM parameter store to encrypt and store the sensitive strings. SSM get_parameters allows to get multiple parameters in a single API call. These links might help Parameter store - SecureString Parameters - boto3 ssm get_parameters

  3. EncryptionContext is non-secret data to support additional authentication, only applicable for symmetric encryptions. If you encrypt some data using a key-value pair of EncryptionContext, you must provide the exact EncryptionContext to decrypt the same. In your example, it simply means that you've specified EncryptionContext as {'LambdaFunctionName': '<your-function-name>'}, so in order to decrypt, you must provide the exact EcryptionContext while calling decrypt.

  1. EncryptionContext={'LambdaFunctionName': os.environ['AWS_LAMBDA_FUNCTION_NAME']} )['Plaintext'].decode('utf-8')

This is a boto3 kms decryption option. https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/kms.html#KMS.Client.decrypt

so. If you want to use this option, first add the "Encryption Context" option when encrypting.

For example, for the AWS CLI

aws kms encrypt --key-id alias/SlackKey --plaintext "hooks.slack.com/services/xxxxxxxxx" --region ap-northeast-2 --encryption-context "LambdaFunctionName=[you function name]"

As above, you can attach options when encrypting.

The key is

--encryption-context "LambdaFunctionName=[you function name]"

Related