Encrypted ENV Vars in AWS Lambda



  • I'm having issues setting access policies properly in AWS to allow my service user to decrypt encrypted env vars.

    lambda function (nodejs 6.10):

    'use strict';
    
    const AWS = require('aws-sdk');
    
    const ekeys = [process.env['var1'], process.env['var2']];
    
    let dkeys = {};
    
    exports.handler = (event, context, callback) => {
        
        Promise.all(ekeys.map(decryptKMS))
    
            .then(([var1, var2]) => {
    
                dkeys.var1 = var1;
    
                dkeys.var2 = var2;
    
                handle(event, context, callback);
    
            })
    
            .catch(console.log);
    
    };
    
    function handle (event, context, callback) {
    
        console.log(JSON.stringify(dkeys));
        
        callback(null, 'Hello from Lambda');
        
    }
    
    function decryptKMS(key) {
    
        return new Promise((resolve, reject) => {
    
            const kms = new AWS.KMS()
    
            kms.decrypt({ CiphertextBlob: new Buffer(key, 'base64') }, (err, data) => {
    
                if (err) {
    
                    reject(err)
    
                }
    
                else {
    
                    resolve(data.Plaintext.toString('ascii'))
    
                }
    
            })
    
        })
    
    }
    

    Cloudwatch Logs:
    START RequestId: 1333cc77-9973-11e7-82ee-df1685ee811f Version: $LATEST
    2017-09-14T17:35:18.374Z 1333cc77-9973-11e7-82ee-df1685ee811f { AccessDeniedException: The ciphertext refers to a customer master key that does not exist, does not exist in this region, or you are not allowed to access.
    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)
    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)
    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)
    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)
    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)
    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)
    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10
    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)
    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)
    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:115:18)
    message: 'The ciphertext refers to a customer master key that does not exist, does not exist in this region, or you are not allowed to access.',
    code: 'AccessDeniedException',
    time: 2017-09-14T17:35:18.374Z,
    requestId: '136515f5-9973-11e7-a6a0-bf9d40e78864',
    statusCode: 400,
    retryable: false,
    retryDelay: 36.392640096935345 }
    END RequestId: 1333cc77-9973-11e7-82ee-df1685ee811f
    REPORT RequestId: 1333cc77-9973-11e7-82ee-df1685ee811f Duration: 319.12 ms Billed Duration: 400 ms Memory Size: 128 MB Max Memory Used: 33 MB

    I can't seem to figure out what specific permission is missing; I've granted KMS:Decrypt to the user and granted access to the resource. The lambda function and the resource are also both in the same region.

    Any suggestions would be most appreciated.



  • Here's the Key Policy for the encryption key (the lambda IAM user is one of the AWS principals that can read the key):

    {
      "Version": "2012-10-17",
      "Id": "key-consolepolicy-3",
      "Statement": [
        {
          "Sid": "Enable IAM User Permissions",
          "Effect": "Allow",
          "Principal": {
            "AWS": "[REDACTED]"
          },
          "Action": "kms:*",
          "Resource": "*"
        },
        {
          "Sid": "Allow access for Key Administrators",
          "Effect": "Allow",
          "Principal": {
            "AWS": "[REDACTED]"
          },
          "Action": [
            "kms:Create*",
            "kms:Describe*",
            "kms:Enable*",
            "kms:List*",
            "kms:Put*",
            "kms:Update*",
            "kms:Revoke*",
            "kms:Disable*",
            "kms:Get*",
            "kms:Delete*",
            "kms:TagResource",
            "kms:UntagResource",
            "kms:ScheduleKeyDeletion",
            "kms:CancelKeyDeletion"
          ],
          "Resource": "*"
        },
        {
          "Sid": "Allow use of the key",
          "Effect": "Allow",
          "Principal": {
            "AWS": "[REDACTED]"
          },
          "Action": [
            "kms:Encrypt",
            "kms:Decrypt",
            "kms:ReEncrypt*",
            "kms:GenerateDataKey*",
            "kms:DescribeKey"
          ],
          "Resource": "*"
        },
        {
          "Sid": "Allow attachment of persistent resources",
          "Effect": "Allow",
          "Principal": {
            "AWS": "[REDACTED]"
          },
          "Action": [
            "kms:CreateGrant",
            "kms:ListGrants",
            "kms:RevokeGrant"
          ],
          "Resource": "*",
          "Condition": {
            "Bool": {
              "kms:GrantIsForAWSResource": "true"
            }
          }
        }
      ]
    }
    


  • Nevermind; I solved it.

    AWS has/had some sort of issue and no decryption policy was actually bound to my service account. The policy seems to not exist, so I created the following User Managed Policy and bound it to the role:

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "kms:Encrypt",
                    "kms:Decrypt",
                    "kms:ReEncrypt*",
                    "kms:GenerateDataKey*",
                    "kms:DescribeKey"
                ],
                "Resource": "*"
            }
        ]
    }
    

  • Notification Spam Recipient

    @rad131304 said in Encrypted ENV Vars in AWS Lambda:

    The policy seems to not exist,

    That seems to happen a lot when following tutorials that assume you know what you're doing...



  • @tsaukpaetra This more looks like it's supposed to be a policy that AWS has by default but is missing for us - it exists as a pre-defined add-able policy type during the role creation step of the function creation.

    Though, yeah, bad AWS tutorials are everywhere which doesn't help much.


Log in to reply