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": "*"
            }
        ]
    }
    

  • Impossible Mission Players - A

    @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
 

Looks like your connection to What the Daily WTF? was lost, please wait while we try to reconnect.