aws-cdk: Code.fromAsset Bundling for NodeJS uses Wrong User

When using the bundling option to provide Lambda code, the default behaviour for NODEJS based runtimes is broken, since it’s using a non-root user within the Docker container. It can be manually fixed by providing root as user as part of the bundling options.

Reproduction Steps

    new lambda.Function(this, 'Handler', {
      code: lambda.Code.fromAsset('/path/to/lambda/folder', {
        bundling: {
          image: lambda.Runtime.NODEJS_12_X.bundlingDockerImage,
          command: [
            'bash', '-c', [
              `cp -R /asset-input/* /asset-output/`,
              `cd /asset-output`,
              `npm install`
            ].join(' && ')
          ],
        },
      }),
      runtime: lambda.Runtime.NODEJS_12_X,
      handler: "index.handler",
    });

Error Log

Failed to run bundling Docker image for asset Foo: Error: [Status 243] stdout:


stderr: npm ERR! correctMkdir failed to make directory /.npm/_locks
npm WARN origin-response@1.0.0 No description
npm WARN origin-response@1.0.0 No repository field.

npm ERR! code EACCES
npm ERR! syscall mkdir
npm ERR! path /.npm
npm ERR! errno -13
npm ERR!
npm ERR! Your cache folder contains root-owned files, due to a bug in
npm ERR! previous versions of npm which has since been addressed.
npm ERR!
npm ERR! To permanently fix this problem, please run:
npm ERR!   sudo chown -R 501:20 "/.npm"
Subprocess exited with error 1

Environment

  • CLI Version : 1.46.0 (build 63860b2)
  • **Framework Version:**1.46.0
  • Node.js Version: v13.8.0
  • OS : macOS Catalina
  • Language (Version): all

Other

Since the fix is passing user: 'root' as argument, I think this change is causing the behaviour https://github.com/aws/aws-cdk/pull/8492


This is 🐛 Bug Report

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 7
  • Comments: 21 (9 by maintainers)

Commits related to this issue

Most upvoted comments

The missing thing for me was it needs to be run by root.

const myLayer = new LayerVersion(this, 'my-layer', {
  code: Code.fromAsset(assetPath, {
    assetHashType: cdk.AssetHashType.BUNDLE,
    bundling: {
      user: 'root',
...

@skorfmann This is because npm wants to write cache in root folder, to fix this:

 const layer = new lambda.LayerVersion(this, 'MyLayer', {
      code: lambda.Code.fromAsset(path.join(__dirname, '../lambda/'), {
        bundling: {
          image: lambda.Runtime.NODEJS_12_X.bundlingDockerImage,
          command: [
            'bash', '-xc', [
              'export npm_config_update_notifier=false',  // Disable npm upgrade check 
              'export npm_config_cache=$(mktemp -d)',  // Change npm default cache folder
              'cd $(mktemp -d)',
              'cp -v /asset-input/package*.json .',
              'npm i --only=prod',
              'mkdir -p /asset-output/nodejs/',
              'cp -au node_modules /asset-output/nodejs/',
            ].join('&&'),
          ],
        },
      }),
      compatibleRuntimes: [lambda.Runtime.NODEJS_12_X],
      description: 'A layer to test the L2 construct',
    });

I am getting similar error but for go-1-x lambda Failed to run bundling Docker image for asset xxx Error: spawnSync docker ENOENT

This error message means that docker is not available. You can make docker available in your environment, use the CDK_DOCKER env var or use the new “local bundling” alternative (the latest will be available in the next release)

Hi, i am a newby. Please be patient with me. The following bundling command worked for my lambda functions.

const command = [
  'bash', '-c',
  `cp -aur . /asset-output &&
   cd /asset-output &&
   mkdir .npm &&
   export npm_config_cache=.npm &&
   npm install`,
];

I changed the cache location to a folder created by the current user.

I suppose that means this issue is resolved. Thanks for helping out @jogold.

@nija-at I don’t think because @apoorvmote issue wasn’t related to the original issue, created by bundling assets owned by root according to @jogold

@jogold Thanks for patiently helping me out. I don’t know what I did. I copy pasted lot of code from lot of google search. I don’t know what it means but the net result is I have successfully build lambda inside docker container and deployed to aws. I tested api to verify if lambda is actually been deployed. Also after deploy I tried cdk diff and it actually printed There were no differences. It does bundling each time I do cdk diff but also knows if code has changed or not.

@eladb We don’t want to have bundled assets owned by root (see #8489) but at the same time we should allow running the container as root…

Need to try this but how about running the image again with command: ['sh', '-c', 'chmod -R 777 /asset-output'] after this (both runs would run as root)?

https://github.com/aws/aws-cdk/blob/cc5bf4ec55506061f4e60d582859a6f9b5e3bd50/packages/%40aws-cdk/core/lib/asset-staging.ts#L171-L181