39

When you call aws lambda get-function --function-name FunctionName, you'll see a CodeSha256 key. I don't know what it's Sha256'ing, though. It doesn't match shasum -a 256 FunctionName.zip, where FunctionName.zip is the package I had uploaded.

What I'd like to be able to do, for an existing lambda, is generate the sha256 from the code I'm about to upload that would match the sha256 amazon gives back in get-function. Any help is appreciated, as I haven't been able to find any information on this anywhere, except for Amazon saying it's "the SHA256 hash of the deployment package"

Hank D
  • 6,271
  • 2
  • 26
  • 35
adiktofsugar
  • 1,439
  • 14
  • 17

6 Answers6

39

As stated above, need to encode in base64. Here is a bash one-liner:
openssl dgst -sha256 -binary _your_file_path_ | openssl enc -base64

Hans
  • 391
  • 3
  • 2
15

Okay, I figured it out. All the methods for generating a sha 256 hash output it in hex, but amazon is returning it in base64.

So, to totally answer my own question, here's how to (with node), check to see if you're about to upload the same zip.

#!/usr/bin/env node
var crypto = require('crypto');
var fs = require('fs');
var path = require('path');
var AWS = require('aws-sdk');
var lambda = new AWS.Lambda({
    region: 'us-west-2'
});

var lambdaName = 'CreatePost';
var filePath = path.resolve(__dirname, 'tmp/create-post.zip');

lambda.getFunction({
    FunctionName: lambdaName
}, function (error, data) {
    if (error) {
        console.error(error);
        return process.exit(1);
    }
    var lambdaSha256 = data.Configuration.CodeSha256;

    var shasum = crypto.createHash('sha256');
    fs.createReadStream(filePath)
    .on("data", function (chunk) {
        shasum.update(chunk);
    })
    .on("end", function () {
        var sha256 = shasum.digest('base64');
        if (sha256 === lambdaSha256) {
            console.log("No need to upload, sha hashes are the same");
        } else {
            console.log("That needs to be uploaded again son.")
        }
        process.exit();
    });
});
adiktofsugar
  • 1,439
  • 14
  • 17
13

Here's a method using basic utilities on GNU/Linux:

cat function.zip |sha256sum |cut -d' ' -f1 |xxd -r -p |base64

The components may be familiar:

  • cut isolates the checksum value
  • xxd converts base16 to binary (reverse hex dump)
  • base64 converts binary to base64
Brent Bradburn
  • 51,587
  • 17
  • 154
  • 173
2

This will never work because of this: Why does Zipping the same content twice gives two files with different SHA1?

I ran into same issue trying to use the SHA from the zip. You will always get a different SHA.

airpower44
  • 541
  • 5
  • 7
  • 1
    this is the correct (if unsatisfying) answer to the question asked, but I suspect not what most other punters are looking for. – Phil Feb 28 '22 at 22:53
1

In python, the same shasum from aws lambda

ldata = ''
with open(localfilepath,'rb') as f:
    ldata = f.read()

    # openssl equivalent command used
    # $openssl dgst -sha256 -binary <binary_file> | openssl enc -base64

    if ldata:
        m = hashlib.sha256()
        m.update(ldata)
        s3_digest = m.digest()
        local_codesha256 = b64encode(s3_digest)

To verify, with the aws env set correctly,(assuming, aws token and creds are set correctly for this cli to work) compare the CodeSha256. ( using python boto3 client to get lambda details.)

 $ aws lambda get-function --function-name <functionname>
{
    "Configuration": {
        "FunctionName": "-----------",
        "FunctionArn": "arn:aws:lambda:us--1:----:function:-----",
        "Runtime": "nodejs10.x",
        "Role": "arn:aws:iam::-------:role/-------------",
        "Handler": "--------- ",
        "CodeSize": 10042831,
        "Description": "",
        "Timeout": 300,
        "MemorySize": 3008,
        "LastModified": "2019-10-09T23:44:08.222+0000",
        "CodeSha256": "aAMvEdR/MSq0x89LzD0L37+AZceFzhtrb9eymqczAh8=",
        "Version": "$LATEST",
        "Environment": {
            "Variables": {
            ...
             }
         }
    ..}
    .}

aws lambda list

response = None
resp_functions = []
lc = boto3.client('lambda',
                  aws_access_key_id=<-----> ,
                  aws_secret_access_key=<--->,
                  aws_session_token=<--->,
                  region_name=<--->)
try:
    response = lc.list_functions()
    while True:
        resp_functions.extend(response['Functions'][:])
        # copy the function and iterate with next marker
        if 'NextMarker' in response:
            response = lc.list_functions(Marker=response['NextMarker'])
        else:
            break

except Exception as ex:
    raise ex
ravi.zombie
  • 1,482
  • 1
  • 20
  • 23
0

If you need to do this in java try the following:

import java.io.File;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.util.Base64;

public class CodeHash {

    public static String fileSha256ToBase64(String path2file)  {

        try {
            byte[] data = Files.readAllBytes(new File(path2file).toPath());
            MessageDigest digester = MessageDigest.getInstance("SHA-256");
            digester.update(data);
            return Base64.getEncoder().encodeToString(digester.digest());
        } catch (Exception ex) {
            throw new IllegalArgumentException("Could not compute Sha256 for file in path: " + path2file);
        }
    }
}

For CDK users you can call this from within the infrastructure code.