Search code examples
amazon-web-servicesaws-cloudformationaws-cliamazon-kms

Run AWS CLI KMS encrypt commands from Cloudformation


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.


Solution

  • 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-