1
votes

I have 2 cloudformation templates - one that creates a kms key and the other template uses the kms key to encrypt a env variable used in the lambda function.

I wanted to know if there is a way to run the kms encrypt command from within the cloudformation as a prior step and then use the encrypted text for the environment variable while creating the lambda function.

aws kms encrypt --key-id <key-id-output-from-stack1> --plaintext fileb://file.txt --query CiphertextBlob --output text > fileoutput.txt

This command outputs the encrypted text and I would need to use this text in the lambda function for one of the environment variables as below.

GTMLambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: s3://test.google.com/lambdas/09yu567943879
      Handler: src/lambda.handler
      FunctionName: !Ref GTMLambdaFunctionName
      Runtime: nodejs10.x
      MemorySize: !Ref GTMLambdaMemorySize
      Timeout: !Ref GTMLambdaTimeout
      AutoPublishAlias: prod
      Role: !GetAtt GTMLambdaRole.Arn
      KmsKeyArn: !ImportValue GTMKMSKeyArn
      Environment:
        Variables:
          url: >-
            **{insert encrypted text}**
          tbl_prefix: gtm-

If this is not possible is there any recommendations on how to achieve this? Thanks in advance.

1

1 Answers

2
votes

You can use a custom resource for this. It will execute a Lambda function that will encrypt and return the value. That value can then be used in the environment variable.

Something like the following. Make sure to have a resource/parameter/output called KeyId with the KMS key id.

Resources:
  EncryptEnvRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Policies:
        - PolicyName: DescribeImages
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Action: kms:Encrypt
                Effect: Allow
                Resource: "*"
  EncryptEnvFunction:
    Type: AWS::Lambda::Function
    Properties:
      Runtime: python3.6
      Handler: index.handler
      Role: !Sub ${EncryptEnvRole.Arn}
      Timeout: 60
      Code:
        ZipFile:
          Fn::Sub: |
            import base64
            import boto3
            import cfnresponse
            import traceback

            def handler(event, context):
              try:
                t = event['ResourceProperties']['Value']
                k = event['ResourceProperties']['KeyId']
                v = base64.b64encode(boto3.client('kms').encrypt(KeyId=k, Plaintext=t.encode('utf-8'))['CiphertextBlob']).decode('utf-8')

                cfnresponse.send(event, context, cfnresponse.SUCCESS, {}, v)
              except:
                traceback.print_last()
                cfnresponse.send(event, context, cfnresponse.FAIL, {}, 'ok')
  EncryptedEnv:
    Type: Custom::EncryptEnv
    Properties:
      ServiceToken: !Sub ${EncryptEnvFunction.Arn}
      Value: "hello world"
      KeyId: !ImportValue KeyId
  GTMLambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: s3://test.google.com/lambdas/09yu567943879
      Handler: src/lambda.handler
      FunctionName: !Ref GTMLambdaFunctionName
      Runtime: nodejs10.x
      MemorySize: !Ref GTMLambdaMemorySize
      Timeout: !Ref GTMLambdaTimeout
      AutoPublishAlias: prod
      Role: !GetAtt GTMLambdaRole.Arn
      KmsKeyArn: !ImportValue GTMKMSKeyArn
      Environment:
        Variables:
          url: !Ref EncryptedEnv
          tbl_prefix: gtm-