awslabs/cdk-serverless-clamscan

How do I use the OnResult function correctly?

james-wilson-sp opened this issue · 7 comments

Hello!
Sorry I'm back with another question, so I want to use the onResult function to send the payload to a Lambda function so I have done this in CDK.

    const clamScanDeleteLambda = new lambda.Function(this, 'clamscan-delete-file', {
      runtime: lambda.Runtime.NODEJS_14_X,  
      code: lambda.Code.fromAsset('lambda'),  
      handler: 'index.handler',  
    });

    const sc = new ServerlessClamscan(this, 'Clamscan', {
      resultDest: new destinations.LambdaDestination(clamScanDeleteLambda)
    });

However it doesn't seem to like the destination defined in this way?

Object literal may only specify known properties, and 'resultDest' does not exist in type 'ServerlessClamscanProps'.ts(2345)

Am I doing this wrong?

The property is call onResult not resultDest. This example may help with that

Interesting @dontirun I actually had is as onResult in my original code. But it didn't send across the event to my Lambda functions so I presumed I did it wrong and it should be resultDest.

I originally had this

    const BackEndBucket = S3.Bucket.fromBucketName(
      this,
      `mybucket`,
      `mybucket`,
    );
    const clamScanDeleteLambda = new lambda.Function(this, 'clamscan-delete-file', {
      runtime: lambda.Runtime.NODEJS_14_X,  
      code: lambda.Code.fromAsset('lambda'),  
      handler: 'index.handler',  
    });

  const sc = new ServerlessClamscan(this, 'Clamscan', {
      acceptResponsibilityForUsingImportedBucket: true,
      onResult: new destinations.LambdaDestination(clamScanDeleteLambda)
    });
    sc.addSourceBucket(BackEndBucket);

    sc.infectedRule?.addTarget(
      new SnsTopic(infectedTopic, {
        message: RuleTargetInput.fromEventPath(
          '$.detail',
        ),
      }),
    );

I can see the destination was added on the ClamScan Lambda Function, but when I uploaded an infected file into S3, it marked it as infected correctly, but no logs indicated that the Lambda function was actually called. My Lambda function is just this for testing reasons right now.

Lambda Function

exports.handler = async (event) => {
  // TODO implement
  const response = {
      statusCode: 200,
      body: JSON.stringify('Hello from Lambda!'),
      event
  };
  return response;
};

Anything obvious I am missing? I can't see why this wouldn't work.

What I'm trying to achieve here is a way to delete the files straight away once they have been marked as infected, so my idea was to take the event and just write some code to delete the infected file.

That's strange. Does the scan lambda have proper permissions to invoke your lambda function?

Good point @dontirun is there a way I can even add that, because the scan lambda is inside your module? 🤔
Edit:
Actually it added the permissions automatically to my function (this is from the function its sending from)
image

So the ClamscanServerlessClamscan is being called, I can see the cloudwatch logs but its not calling the Lambda function at the same time, I'm thinking maybe I should put an SNS Queue before the Lambda function to see if that fixes this, its a bit strange though. 🤔

Maybe the destination bucket needs permissions!?
image

@dontirun Okay so, im wrong it is being invoked, for some reason if you don't log anything with console.log() it doesn't log any logs to say the Lambda function ran 🤔 I'm not sure if thats by design or not, but I am now receiving the payload so I can handle it.

Example Payload:

{
  version: '1.0',
  timestamp: '2022-10-06T07:19:38.972Z',
  requestContext: {
    requestId: '3be2dc97-c8da-4495-9636-6da14aa924ea',
    functionArn: 'arn:aws:lambda:us-east-1:983324074397:function:clamscan-development2-ClamscanServerlessClamscan66-Aoox7o5tESer:$LATEST',
    condition: 'Success',
    approximateInvokeCount: 1
  },
  requestPayload: { Records: [ [Object] ] },
  responseContext: { statusCode: 200, executedVersion: '$LATEST' },
  responsePayload: {
    source: 'serverless-clamscan',
    input_bucket: 'saas-upgrade-bucket-development',
    input_key: 'dangerousfile (1).com',
    status: 'INFECTED',
    message: 'Scanning /mnt/lambda/3be2dc97-c8da-4495-9636-6da14aa924ea/dangerousfile (1).com\n' +
      '/mnt/lambda/3be2dc97-c8da-4495-9636-6da14aa924ea/dangerousfile (1).com: Win.Test.EICAR_HDB-1 FOUND\n' +
      '\n' +
      '----------- SCAN SUMMARY -----------\n' +
      'Known viruses: 8638808\n' +
      'Engine version: 0.103.7\n' +
      'Scanned directories: 1\n' +
      'Scanned files: 1\n' +
      'Infected files: 1\n' +
      'Data scanned: 0.00 MB\n' +
      'Data read: 0.00 MB (ratio 0.00:1)\n' +
      'Time: 26.368 sec (0 m 26 s)\n' +
      'Start Date: 2022:10:06 07:19:12\n' +
      'End Date:   2022:10:06 07:19:38\n'
  }
}```

@dontirun I have a quick question for you, sorry to be a pain!
So in our use case here, we are scanning the S3 bucket which is great, is it technically possible for us to call this Lambda function inside our application code? I'm guessing its not?

So for example, when someone is uploading a file in our code, our developer wants to invoke this lambda function with the file and see if its infected, I am not sure what inputs the lambda requires, and if this is at all possible?

Not with how the solution is currently designed.

Additionally lambda destinations (so the infected file delete you have set up) doesn't run if the scan lambda is invoked synchronously, lambda destinations only work on asynchronous invokes