terraform-provider-archive icon indicating copy to clipboard operation
terraform-provider-archive copied to clipboard

AWS Lambda function "module initialization error: [Errno 13] Permission denied: '/var/task/helloworld.py'" when provisioned by archive_file type zip

Open chiuwaipun opened this issue 7 years ago • 11 comments

Hi,

Terraform Version

$ terraform -v Terraform v0.11.3

  • provider.archive v1.0.3
  • provider.aws v1.12.0

Affected Resource(s)

Please list the resources as a list, for example:

  • archive_file
  • aws_lambda_function

After upgrade archive from 1.0.0 to 1.0.3, the provisoined Lambda function received below error. module initialization error: [Errno 13] Permission denied: '/var/task/helloworld.py'

Terraform Configuration Files

data "archive_file" "helloworld_lambda_zip" {
  source_dir  = "${path.module}/lambda"
  output_path = "${path.module}/lambda.zip"
  type        = "zip"
}

resource "aws_lambda_function" "helloworld" {
  function_name    = "helloworld"
  handler          = "helloworld.lambda_handler"
  role             = "${aws_iam_role.my_lambda_role.arn}"
  runtime          = "python3.6"
  timeout          = "120"
  filename         = "${data.archive_file.helloworld_lambda_zip.output_path}"
  source_code_hash = "${data.archive_file.helloworld_lambda_zip.output_base64sha256}"
}

Debug Output

No error while provisioning the Lambda and so no debug option is provided

Panic Output

N/a

Expected Behavior

Terraform is run at Linux host.

I aware there is change of the how to zip a file and here is the output of zipinfo for the zip file created by version 1.0.0

$ zipinfo -l modules/my_module/lambda.zip Archive: modules/my_module/lambda.zip Zip file size: 2711 bytes, number of entries: 1 -rw---- 2.0 fat 11340 bl 2559 defN 80-000-00 00:00 helloworld.py

File extracted has permisson 664

Actual Behavior

And here is the zipinfo of the zip file created by version 1.0.3

$ zipinfo -l modules/my_module/lambda.zip Archive: modules/my_module/lambda.zip Zip file size: 2711 bytes, number of entries: 1 -rw------- 2.0 unx 11340 bl 2559 defN 49-Jan-01 00:00 helloworld.py

File extracted has permission of 600

AWS confirmed that files without world permission could received module initialization error: [Errno 13] Permission denied: '/var/task/xxx.py' error.

Steps to Reproduce

Please list the steps required to reproduce the issue, for example:

  1. terraform apply

Important Factoids

N/a

References

N/a

chiuwaipun avatar Mar 26 '18 04:03 chiuwaipun

The zip archive preserves file permissions, so if you have a 644 permissions file, deflate it and inflate it back up, you get 644 permissions for that file.

So to fix @chiuwaipun's issue, simply set the expected permissions before deflation, in Lambda's case, something like 755 will do.

I suggest this issue to be closed.

Note: tested in v1.0.3 (mentioned version) and v1.1.0 (latest), on Terraform v0.11.8

ricardbejarano avatar Sep 02 '18 17:09 ricardbejarano

I've also run into this as well. I think it's very much a bug still. The zip command on OSX and archiver libraries like this one https://github.com/tj/go-archive work as expected.

matthewmueller avatar Sep 26 '18 07:09 matthewmueller

AWS Lambda requires world-readable permissions on source files.

Try setting -rwxr-xr-x permissions to the to-be-zipped files and delete any previously generated zip archive.

I've successfully used archive v1.1.0 (current) with Lambda before and it only causes this error when compressing non-world-readable files (eg. -rwx------).

ricardbejarano avatar Sep 26 '18 10:09 ricardbejarano

@ricardbejarano What's your terraform code look like? Are you using source_file or source { content }?

matthewmueller avatar Sep 26 '18 12:09 matthewmueller

source_file:

data "archive_file" "hello" {
  type        = "zip"
  source_file = "hello.py"
  output_path = "hello.zip"
}

resource "aws_lambda_function" "hello" {
  ...
  filename = "hello.zip"
}

Haven't tested source_dir nor source { content = ... } but I guess the former works just like source_file and maybe the latter sets non-world-readable permissions.

You can check what permissions are set yourself by unzipping the archive in your local machine and listing the files' permissions. Example:

$ unzip hello.zip
Archive:  hello.zip
  inflating: hello.py

$ ls -l hello.py
-rwxr-xr-x  ................................. hello.py

Edit: if source { content = ... } sets non-world-readable permissions I guess you may have to use other source arguments. See the argument reference.

ricardbejarano avatar Sep 26 '18 12:09 ricardbejarano

@ricardbejarano ah okay, I hadn't tried the source_file, just source { content = ... }.. It's weird cause it's zipped up with world-readable, and unzipped with world-readable, but still causes this error. I'm thinking they need world-readable on the zip as well.

FWIW to anyone else, I wrote a custom provider for Go builds: https://github.com/matthewmueller/terraform-provider-lambda. I'd love to see other languages supported as well. For building lambdas, it seems more flexible to just write Go code rather piece together existing resources.

matthewmueller avatar Sep 28 '18 13:09 matthewmueller

I'm thinking they need world-readable on the zip as well.

Probably.

I guess we could PR the changes needed so that zipped output has the same permissions than the deflated file/folder. I'll look into it, thanks for your input!

I wrote a custom provider for Go builds

Looks great!

ricardbejarano avatar Sep 29 '18 08:09 ricardbejarano

Any updates on this? I am running through the same issue using the archive provider on windows.

haideralsh avatar Aug 26 '20 18:08 haideralsh

Hello, are there any updates on this? Having the same issue using the provider on Linux.

denisse-dev avatar Jan 22 '21 23:01 denisse-dev

@haideralsh @da-edra at this moment, the archive provider does not support setting filemode or similar for deflated/inflated contents.

Workaround

Imagine I have a folder with source code on my local machine, this source code is to be copied over to Lambda through a zip file generated with the archive provider.

  1. On your local machine, run chmod -R 755 lambda_code
  2. Delete cached archive-provider files (run find . -name '.*.zip' -delete, if I recall correctly)
  3. Run Terraform as usual

What will happen:

  • Terraform will run the archive provider on the folder again
  • That will zip/deflate the contents preserving their current filemode bits (755)
  • When Lambda uncompresses that, it should preserve those settings

Permanent solution (proposal)

In my opinion, the best way around this would be to implement chmod $FILEMODE $DIRECTORY directly into the archive provider.

Something along the lines of:

data "archive_file" "lambda_code" {
  source_dir  = "${path.module}/lambda"
  output_path = "${path.module}/lambda.zip"
  type        = "zip"
  filemode    = 0755  // this triggers: chmod -R 0755 "${path.module}/lambda"; before deflating
}

I will (after 3 years) begin work on this during the following days, but can't promise anything.

ricardbejarano avatar Jan 23 '21 06:01 ricardbejarano

Created #80.

@matthewmueller @haideralsh @da-edra ^

ricardbejarano avatar Jan 23 '21 20:01 ricardbejarano