Python 尽管VPN、kms密钥和策略都是正确的,但lambda单独工作,但被另一个lambda调用时不工作

Python 尽管VPN、kms密钥和策略都是正确的,但lambda单独工作,但被另一个lambda调用时不工作,python,amazon-web-services,amazon-s3,aws-lambda,aws-sam-cli,Python,Amazon Web Services,Amazon S3,Aws Lambda,Aws Sam Cli,我在一个s3存储桶中有2个lambda和3个子目录。将文件上载到sub1时会触发第一个lambda。它生成一个写入sub2的输出。然后触发lambda2,它将输出写入sub3。lambdas的标准使用 S3 bucket上传使用kms密钥进行加密,每个lambda都将该密钥配置到其环境变量中,以便可以读取/写入S3 每个lambda都附带了几个策略,以便它可以工作:s3crud、VPCAccessPolicy(因为它们位于一个vpc和2个子网内)和LambdaInvokePolicy sub1中

我在一个s3存储桶中有2个lambda和3个子目录。将文件上载到sub1时会触发第一个lambda。它生成一个写入sub2的输出。然后触发lambda2,它将输出写入sub3。lambdas的标准使用

S3 bucket上传使用kms密钥进行加密,每个lambda都将该密钥配置到其环境变量中,以便可以读取/写入S3

每个lambda都附带了几个策略,以便它可以工作:s3crud、VPCAccessPolicy(因为它们位于一个vpc和2个子网内)和LambdaInvokePolicy

sub1中有20k个条目,因此我没有下载所有条目并重新上传,而是构建了另一个lambda,它从s3 sub dir读取所有条目,创建一个包含bucket和key的事件,并将其传递到lambda 1以触发该事件。此lambda具有相同的VPC、策略和kms密钥

步骤/lambda 1工作正常,并将预期输出写入sub2,但对于我得到的每个步骤2文件:

"An error occurred (AccessDenied) when calling the GetObject operation: Access Denied", "errorType": "ClientError"
真正奇怪的是,如果我从sam cli进行本地调用,通过event.json将文件名传递给lambda2,它工作正常,并将预期的文件写入sub3,这表明lambda没有问题。但是我不能大量使用lambda3调用lambda2,尽管它有相关的kms密钥、VPN访问和策略。为什么调用lambda 1而不是lambda-2会起作用?所有这些文件都在同一个存储桶中,使用相同的kms密钥加密,并且每个lambda具有相同的密钥访问权限,并且位于相同的VPN中

谁能想到为什么会这样

这是lambda 3:

import boto3
import json
import os
import time
s3_resource = boto3.resource('s3')    

def lambda_handler(event, context):    

    # get list of files in sub dir
    obj_list = []
    bucket = s3_resource.Bucket(event['bucket'])
    for obj in bucket.objects.filter(Prefix=event['prefix'],Delimiter='/'):
        obj_list.append(str(obj.key))

     # COUNT: 20440    

    # generate list of event.json to pass into lambdas
    event_list = []
    for key in obj_list[:5]:
        x = make_template()
        x['Records'][0]['s3']['object']['key'] = key
        x['Records'][0]['s3']['bucket']['name'] = event['bucket']
        event_list.append(x)

    # invoke lambdas
    # setup boto3 and inputs 
    involeLam = boto3.client("lambda", region_name="eu-west-1")
    lambda_to_invoke = event['lambda_to_trigger']

    # invoke the lambda
    invocations = []
    for payload in event_list:
        response = involeLam.invoke(FunctionName = lambda_to_invoke, InvocationType = "RequestResponse", Payload = json.dumps(payload))    # initiate and await response
        invocations.append(response)

    time.sleep(60)

    # parse the contents of the file from the lambda return
    for i in invocations:
        print(i["Payload"].read())



    return {
            "success": True
            }


def make_template():
    template = {  
        "Records":[  
            {  
                "s3":{  
                "bucket":{  
                    "name":"mybucket"
                },
                "object":{  
                    "key":"path/to/file.csv"
                }
                }
            }
        ]
        }
    return template
以下是传递到此lambda的event.json:

{
  "bucket": "mybucket",
  "prefix": "path/to/my/",
  "lambda_to_trigger":"arn:aws:lambda:eu-west-1:number:function:MyFunction"

}
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  triggermultiplelambda

  Sample SAM Template for triggermultiplelambda

Globals:
  Function:
    Timeout: 120

Resources:
  TriggerMultipleLambdaFunction:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: triggermultiplelambda/
      Handler: triggerMultipleLambda.lambda_handler
      Runtime: python3.6
      KmsKeyArn: !Sub arn:aws:kms:eu-west-1:number:key/code-for-key
      Policies: 
        - S3CrudPolicy:
            BucketName: "*"
        - VPCAccessPolicy: {}
        - LambdaInvokePolicy:
            FunctionName: "*"

Outputs:
  TriggerMultipleLambdaFunction:
    Description: "TriggerMultipleLambda Lambda Function ARN"
    Value: !GetAtt TriggerMultipleLambdaFunction.Arn
  TriggerMultipleLambdaFunctionIamRole:
    Description: "Implicit IAM Role created for TriggerMultipleLambda function"
    Value: !GetAtt TriggerMultipleLambdaFunctionRole.Arn
下面是用于构建此lambda的template.yaml:

{
  "bucket": "mybucket",
  "prefix": "path/to/my/",
  "lambda_to_trigger":"arn:aws:lambda:eu-west-1:number:function:MyFunction"

}
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  triggermultiplelambda

  Sample SAM Template for triggermultiplelambda

Globals:
  Function:
    Timeout: 120

Resources:
  TriggerMultipleLambdaFunction:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: triggermultiplelambda/
      Handler: triggerMultipleLambda.lambda_handler
      Runtime: python3.6
      KmsKeyArn: !Sub arn:aws:kms:eu-west-1:number:key/code-for-key
      Policies: 
        - S3CrudPolicy:
            BucketName: "*"
        - VPCAccessPolicy: {}
        - LambdaInvokePolicy:
            FunctionName: "*"

Outputs:
  TriggerMultipleLambdaFunction:
    Description: "TriggerMultipleLambda Lambda Function ARN"
    Value: !GetAtt TriggerMultipleLambdaFunction.Arn
  TriggerMultipleLambdaFunctionIamRole:
    Description: "Implicit IAM Role created for TriggerMultipleLambda function"
    Value: !GetAtt TriggerMultipleLambdaFunctionRole.Arn

如果我还需要发布其他内容,请告诉我。非常感谢,我终于明白了。因此,template.yaml需要修改如下:

这一行(我已经弄明白了)需要添加到参考资料中:Function:Properties:

KmsKeyArn: !Sub arn:aws:kms:eu-west-1:number:key/code-for-key
需要将策略添加到策略部分:

- KMSDecryptPolicy:
            KeyId: code-for-key
根据用于访问S3的boto3 api,需要将以下行添加到lambda中的import语句中:

from botocore.client import Config

# EITHER
s3_resource = boto3.resource('s3', config=Config(signature_version='s3v4'))
# OR
s3_client = boto3.client('s3', config=Config(signature_version='s3v4'))
通过这些语句,我现在可以从S3读取/下载/解密使用kms密钥加密的文件

要上载文件,我使用以下行:

s3_client.upload_file('/tmp/' + outputfilename, OUTPUTBUCKET, OUTPUTFOLDER+'/'+outputfilename,  
                        ExtraArgs={"ServerSideEncryption": "aws:kms", "SSEKMSKeyId":"code-for-key"})
我从以下URL获得此解决方案:


非常感谢你的帮助jarmod,我希望这能帮助别人

我终于明白了。因此,template.yaml需要修改如下:

这一行(我已经弄明白了)需要添加到参考资料中:Function:Properties:

KmsKeyArn: !Sub arn:aws:kms:eu-west-1:number:key/code-for-key
需要将策略添加到策略部分:

- KMSDecryptPolicy:
            KeyId: code-for-key
根据用于访问S3的boto3 api,需要将以下行添加到lambda中的import语句中:

from botocore.client import Config

# EITHER
s3_resource = boto3.resource('s3', config=Config(signature_version='s3v4'))
# OR
s3_client = boto3.client('s3', config=Config(signature_version='s3v4'))
通过这些语句,我现在可以从S3读取/下载/解密使用kms密钥加密的文件

要上载文件,我使用以下行:

s3_client.upload_file('/tmp/' + outputfilename, OUTPUTBUCKET, OUTPUTFOLDER+'/'+outputfilename,  
                        ExtraArgs={"ServerSideEncryption": "aws:kms", "SSEKMSKeyId":"code-for-key"})
我从以下URL获得此解决方案:


非常感谢你的帮助jarmod,我希望这能帮助别人

这有两个部分。KMS密钥自身的策略是否允许Lambda的IAM角色对其进行解密?Lambda的IAM角色是否允许它解密KMS密钥。另请参阅感谢您的帮助,我不确定:我认为'KMS:'!子arn:aws:kms:eu-west-1:number:key/模板中“key”的代码。yaml将允许lambda解密。我没有设置密钥,所以不知道如何检查KMS密钥的策略?如果你没有权限阅读密钥策略来检查它,那么我会去找设置密钥策略的人。结果证明我有权限,所以不是那样。我已经弄明白了,将在下面发布。这有两个部分。KMS密钥自身的策略是否允许Lambda的IAM角色对其进行解密?Lambda的IAM角色是否允许它解密KMS密钥。另请参阅感谢您的帮助,我不确定:我认为'KMS:'!子arn:aws:kms:eu-west-1:number:key/模板中“key”的代码。yaml将允许lambda解密。我没有设置密钥,所以不知道如何检查KMS密钥的策略?如果你没有权限阅读密钥策略来检查它,那么我会去找设置密钥策略的人。结果证明我有权限,所以不是那样。我已经弄明白了,将在下面发布。好吧,听起来您案例中的具体问题是boto3默认为sigv2。好吧,听起来您案例中的具体问题是boto3默认为sigv2。