Juice-shop: [๐Ÿš€] Running Juice-shop in Raspberry Pi 4

Created on 17 Apr 2020  ยท  25Comments  ยท  Source: bkimminich/juice-shop

:rocket: Feature request

Description

In issue #380 , @battletux was kind enough to provide a solution to run Juice-Shop in a Docker container inside of a Raspberry Pi (as shown below) and in the Docker Hub repository at: https://hub.docker.com/r/arclight/juice-shop_arm

Unfortunately, this does not work in newer platforms such as the Raspberry Pi 4.
This was the original Dockerfile in issue #380:

# OWASP Juice Shop - An intentionally insecure JavaScript Web Application
FROM            arm32v7/node:6
LABEL version = "5.0.0"

COPY . /juice-shop
WORKDIR /juice-shop
RUN npm install --production --unsafe-perm

EXPOSE  3000
CMD ["npm", "start"]

Running this in a Raspberry Pi 4 does not work and generates the following errors:

npm ERR! code ENOENT
npm ERR! syscall open
npm ERR! path /juice-shop/package.json
npm ERR! errno -2
npm ERR! enoent ENOENT: no such file or directory, open '/juice-shop/package.json'
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent

npm ERR! A complete log of this run can be found in:
npm ERR!     /root/.npm/_logs/2020-04-17T03_39_11_426Z-debug.log

Solution ideas

I am opening this issue to try to fix it and (if I am successful) I will document the solution here. If I am not successful in the next week or so, I will close this issue and leave it as a documented problem.

Possible alternatives

I also tried the latest arm32v7/node image and it didn't work.

FROM            arm32v7/node

However, I will try to build the container manually and (again, if successful) I will upload to Docker Hub and document it here.

Running Juice-shop in Raspberry Pi's allow students with low resources to build a cool lab. I am a super big fan of Juice-shop and run it in numerous environments (cloud, intel nucs with containers, proxmox, etc.).

continuous integration docker feature help wanted

Most helpful comment

The Travis-CI jobs are now caching more efficiently and use npm prune --production instead of deleting all node_modules resulting in way faster builds even on arm64. Timeouts do not occur any more.

@santosomar, could you maybe check if the v10.2.1 package still works inside a Docker image on your RasPi? Also, I've added a variable in my ebook for the last Juice Shop version you built the Arm-based Docker image for:

"armDockerImageVersion": "v10.2.0"

If you think about automating your image creation somehow, please let me know, then I remove it again. Otherwise I'll try to remember to regularly check for your current version and update the variable. You can of course also send a PR updating it in https://github.com/bkimminich/pwning-juice-shop/blob/master/book.json and https://github.com/bkimminich/pwning-juice-shop/blob/master/book-ctf.json.

Works like a charm!

> [email protected] start /root/juice-shop_10.2.1
> node app

info: All dependencies in ./package.json are satisfied (OK)
info: Detected Node.js version v12.16.2 (OK)
info: Detected OS linux (OK)
info: Detected CPU arm64 (OK)
info: Required file index.html is present (OK)
info: Required file styles.css is present (OK)
info: Required file main-es2015.js is present (OK)
info: Required file tutorial-es2015.js is present (OK)
info: Required file polyfills-es2015.js is present (OK)
info: Required file runtime-es2015.js is present (OK)
info: Required file vendor-es2015.js is present (OK)
info: Required file main-es5.js is present (OK)
info: Required file tutorial-es5.js is present (OK)
info: Required file polyfills-es5.js is present (OK)
info: Required file runtime-es5.js is present (OK)
info: Required file vendor-es5.js is present (OK)
info: Configuration default validated (OK)
info: Port 3000 is available (OK)
<output ommited for brevity>
info: Server listening on port 3000

All 25 comments

Thanks a lot for opening your first issue with us! ๐Ÿงก We'll get back to you shortly! โณ If it was a _Support Request_, please consider asking on the community chat next time! ๐Ÿ’ฌ

Having a new Docker image for RasPi would by awesome! If that could somehow be built automatically, that'd be even better... ๐Ÿ˜€

On a sidenote, thanks a lot, @santosomar, for donating to OWASP! Just saw that your name had popped up on the https://owasp.org/www-project-juice-shop/#div-supporters list, which means our automation there works like it should! ๐Ÿ‘

The following is an update for documentation and troubleshooting purposes.

I have tried using the Docker images arm32v7/node and also tried installed node and all the underlying components in arm32v7/ubuntu.

The Juice-Shop npm install works after cloning this existing repository (i.e., git clone https://github.com/bkimminich/juice-shop.git).

However, when running npm start the following error messages are displayed.

root@juice-test2:~/juice-shop# npm start
> [email protected] start /root/juice-shop
> node app

info: All dependencies in ./package.json are satisfied (OK)
(node:2386) UnhandledPromiseRejectionWarning: Error: ENOENT: no such file or directory, copyfile '/root/juice-shop/data/static/JuiceShopJingle.vtt' -> '/root/juice-shop/frontend/dist/frontend/assets/public/videos/JuiceShopJingle.vtt'
    at Object.copyFileSync (fs.js:1896:3)
    at restoreOverwrittenFilesWithOriginals (/root/juice-shop/lib/startup/restoreOverwrittenFilesWithOriginals.js:13:6)
    at Object.<anonymous> (/root/juice-shop/server.js:96:62)
    at Module._compile (internal/modules/cjs/loader.js:1123:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1143:10)
    at Module.load (internal/modules/cjs/loader.js:972:32)
    at Function.Module._load (internal/modules/cjs/loader.js:872:14)
    at Module.require (internal/modules/cjs/loader.js:1012:19)
    at require (internal/modules/cjs/helpers.js:72:18)
    at /root/juice-shop/app.js:7:18
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:2386) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:2386) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

The root cause is similar to issue #843 . I also get the following error message:

npm WARN lifecycle [email protected]~postinstall: cannot run in wd [email protected] cd frontend && npm install && cd .. && npm run build (wd=/root/juice-shop)
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: [email protected] (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for [email protected]: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"arm"})

I am running as root in the container and checked all permissions without success. The challenge is that most of the underlying components are done for linux x86 or darwin. However, since Raspberry Pi uses arm current: {"os":"linux","arch":"arm"}, I have not found the way to be able to run it successfully.

The pre-packaged Juice-shop version(s) also fail.

Hm, I can try to build on Linux/Arm on Travis-CI just for fun to see what happens...
https://blog.travis-ci.com/2019-10-07-multi-cpu-architecture-support

Here we go: https://travis-ci.org/github/bkimminich/juice-shop/builds/677423201

If that works for installing and unit testing, it might also give us valid .tgz archives for Linux/Arm64 which then in turn might work on a RasPi with the matching Node.js version...? Or am I being too naive here?

Oh that would be awesome. I am more than glad to test and document, if needed.

Compiling on Arm64 works, unit tests I had to turn off b/c Chrome is not available, but I would assume the deploy step that creates the .tgz archive should work now too. I'll create a dummy tag to test this and paste the link to the archives here so you can test if they work on your RasPi, ok?

Building on Arm on Travis-CI is a real pain... But it seems I at least got one archive prepared for Node12: https://github.com/bkimminich/juice-shop/releases/download/v10.2.0/juice-shop-10.2.0_node12_linux_arm64.tgz

Can you maybe try that out on your RasPi, @santosomar? If it doesn't work, then I can remove this 90%-breaking job from Travis-CI right away and if it does work then I can seek some competent help in optimizing the build time.

Thank you very much! Unfortunately, it did not work :-(

For some reason the ELF format still does not work: wrong ELF class: ELFCLASS64

root@juice-test2:~/juice-shop_10.2.0# npm start

> [email protected] start /root/juice-shop_10.2.0
> node app

info: All dependencies in ./package.json are satisfied (OK)
(node:2540) UnhandledPromiseRejectionWarning: Error: /root/juice-shop_10.2.0/node_modules/libxmljs2/build/Release/xmljs.node: wrong ELF class: ELFCLASS64
    at Object.Module._extensions..node (internal/modules/cjs/loader.js:1173:18)
    at Module.load (internal/modules/cjs/loader.js:972:32)
    at Function.Module._load (internal/modules/cjs/loader.js:872:14)
    at Module.require (internal/modules/cjs/loader.js:1012:19)
    at require (internal/modules/cjs/helpers.js:72:18)
    at bindings (/root/juice-shop_10.2.0/node_modules/bindings/bindings.js:112:48)
    at Object.<anonymous> (/root/juice-shop_10.2.0/node_modules/libxmljs2/lib/bindings.js:1:37)
    at Module._compile (internal/modules/cjs/loader.js:1123:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1143:10)
    at Module.load (internal/modules/cjs/loader.js:972:32)
    at Function.Module._load (internal/modules/cjs/loader.js:872:14)
    at Module.require (internal/modules/cjs/loader.js:1012:19)
    at require (internal/modules/cjs/helpers.js:72:18)
    at Object.<anonymous> (/root/juice-shop_10.2.0/node_modules/libxmljs2/index.js:4:16)
    at Module._compile (internal/modules/cjs/loader.js:1123:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1143:10)
(node:2540) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:2540) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

I am going to try to start from scratch on another Raspbery Pi and use the arm64v8/node base image that was just updated a few minutes ago.

I will provide an update by the end of the day. Thanks again for all your time and help on this!

SUCCESS!!!!

Using arm64v8/node:12-buster I was able to make it work on a Raspberry Pi 4!

I will be cleaning up things a bit and will publish the image to Docker Hub by tomorrow.

@bkimminich - thank you so much for your continuous support! It is great that we will be able to provide a Juice-shop base image in Docker-hub for Raspberry Pi!

Awesome!!! Now I kind of need to make this arm64 job actually pass consistently on Travis-CI...

โœ… Currently the normal branch builds pass usually, also on arm64. They take up to 20min but they pass.
โŒ The tag builds on the other hand tend to fail from a timeout after 20-25min saying that they didn't get any output on the console for 10min. But, they not always fail as can be seen here: https://travis-ci.org/github/bkimminich/juice-shop/builds/677926428. But most of the time they do fail, and that's of course annoying if you want to base a Docker image creation on them... ๐Ÿ˜ž

My Travis-CI and npm/Angular build tuning skills are probably not sufficient to fix this alone. So any assistance is highly welcome!

@santosomar Make sure to send me a link to the Docker image, then I'll add it to our README and documentation for as long as you keep it updated.

Thank you again, @bkimminich ! I have pushed and documented the new container at:
https://hub.docker.com/r/santosomar/juice-shop-arm64

I will continue to maintain it.

Awesome, thank you so much! I'll soon add your image link to the "Ecosystem" tab of the website and also mention it in the ebook.

The request for help with the Travis CI tag builds on Arm64 will get it's own ticket as well within the week.

The Travis-CI jobs are now caching more efficiently and use npm prune --production instead of deleting all node_modules resulting in way faster builds even on arm64. Timeouts do not occur any more.

@santosomar, could you maybe check if the v10.2.1 package still works inside a Docker image on your RasPi? Also, I've added a variable in my ebook for the last Juice Shop version you built the Arm-based Docker image for:

"armDockerImageVersion": "v10.2.0"

If you think about automating your image creation somehow, please let me know, then I remove it again. Otherwise I'll try to remember to regularly check for your current version and update the variable. You can of course also send a PR updating it in https://github.com/bkimminich/pwning-juice-shop/blob/master/book.json and https://github.com/bkimminich/pwning-juice-shop/blob/master/book-ctf.json.

The Travis-CI jobs are now caching more efficiently and use npm prune --production instead of deleting all node_modules resulting in way faster builds even on arm64. Timeouts do not occur any more.

@santosomar, could you maybe check if the v10.2.1 package still works inside a Docker image on your RasPi? Also, I've added a variable in my ebook for the last Juice Shop version you built the Arm-based Docker image for:

"armDockerImageVersion": "v10.2.0"

If you think about automating your image creation somehow, please let me know, then I remove it again. Otherwise I'll try to remember to regularly check for your current version and update the variable. You can of course also send a PR updating it in https://github.com/bkimminich/pwning-juice-shop/blob/master/book.json and https://github.com/bkimminich/pwning-juice-shop/blob/master/book-ctf.json.

Works like a charm!

> [email protected] start /root/juice-shop_10.2.1
> node app

info: All dependencies in ./package.json are satisfied (OK)
info: Detected Node.js version v12.16.2 (OK)
info: Detected OS linux (OK)
info: Detected CPU arm64 (OK)
info: Required file index.html is present (OK)
info: Required file styles.css is present (OK)
info: Required file main-es2015.js is present (OK)
info: Required file tutorial-es2015.js is present (OK)
info: Required file polyfills-es2015.js is present (OK)
info: Required file runtime-es2015.js is present (OK)
info: Required file vendor-es2015.js is present (OK)
info: Required file main-es5.js is present (OK)
info: Required file tutorial-es5.js is present (OK)
info: Required file polyfills-es5.js is present (OK)
info: Required file runtime-es5.js is present (OK)
info: Required file vendor-es5.js is present (OK)
info: Configuration default validated (OK)
info: Port 3000 is available (OK)
<output ommited for brevity>
info: Server listening on port 3000

Awesome! I guess I need to buy a new RasPi now after all...

pi@raspberrypi:~ $ docker run -p 3000:3000 santosomar/juice-shop-arm64
standard_init_linux.go:211: exec user process caused "exec format error"

Docker installation worked fine, SSH is set up properly, Docker image was pulled as well:

pi@raspberrypi:~ $ docker images
REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE
santosomar/juice-shop-arm64   latest              2c7f1f1b527d        5 days ago          1.27GB

I'm trying this on a RasPi Model 3A+ with Raspian (freshly updated/upgraded) - any ideas what I might be doing wrong?

My Docker installation:

pi@raspberrypi:~ $ docker -v
Docker version 19.03.8, build afacb8b
pi@raspberrypi:~ $ docker version
Client: Docker Engine - Community
 Version:           19.03.8
 API version:       1.40
 Go version:        go1.12.17
 Git commit:        afacb8b
 Built:             Wed Mar 11 01:35:24 2020
 OS/Arch:           linux/arm
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.8
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.17
  Git commit:       afacb8b
  Built:            Wed Mar 11 01:29:22 2020
  OS/Arch:          linux/arm
  Experimental:     false
 containerd:
  Version:          1.2.13
  GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

And my Raspian:

pi@raspberrypi:~ $ cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 10 (buster)"
NAME="Raspbian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"
pi@raspberrypi:~ $

Ah, I suppose what comes out of travis-CI it only works on Arm8 architecture, so not on anything older than a RasPi 4 ...

pi@raspberrypi:~/Downloads $ uname -m
armv7l

Okay, I solved it by installing Ubuntu 64bit on my 3A+ model. I've updated the documentation to be more specific about the need to run 64bit for the image.

Sorry for the delay. Yes indeed. I used Ubuntu 64 and also have a few other earlier Raspberry Pi models that I can test, but it looks like you already have it running. Cheers!

Did you check on your RasPi4 if it works there with Raspian? I cannot test that, but if it doesn't I would change the docs to only recommend Ubuntu.

Will do. I will check over the weekend. I will install Raspbian in the Pi4 and Pi3s and will update this issue.

I've set up my RasPi 3A+ as a permanent Prometheus/Grafana server, so it is already quite busy considering its specs, which is why it didn't really bother me that this now happens when I try to launch the Docker image on it:

ubuntu@ubuntu:~$ docker image ls
REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE
santosomar/juice-shop-arm64   latest              2c7f1f1b527d        9 days ago          1.27GB
ubuntu@ubuntu:~$ docker run -d --rm -p 3001:3000 santosomar/juice-shop-arm64
590d2a52c23df2a49862cbf0da1b0b948e0cb0341a8faab4571c4a43ab1e3241
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "process_linux.go:449: container init caused \"process_linux.go:432: running prestart hook 0 caused \\\"error running hook: signal: killed, stdout: , stderr: \\\"\"": unknown.

What I realized only then, is how huge the image is. Do you build it manually or with a Dockerfile? Is there maybe some room for optimization regarding size? The x86 Docker images we provide have been quite heavily optimized by @J12934 so they are ~120 MB only. Do you think it's possible to get the RasPi images a little smaller too? Maybe some layers could be removed with chaining commands more etc.?

What happens when you build the official Dockerfile on the Raspi / Arm?

I thought it should work as the node base image has official ARM support build in.
Or does this not work with something specific in our npm install?

I tried to reproduce this on my mac using docker buildx to build for arm but gave up as it seemingly took forever, but might just be because of the cross arch build.

My RasPi 3 can't build from source locally because it dies during Angular build step, probably because of lacking memory.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

agrawalarpit14 picture agrawalarpit14  ยท  4Comments

junathanadi picture junathanadi  ยท  3Comments

bkimminich picture bkimminich  ยท  4Comments

bkimminich picture bkimminich  ยท  8Comments

bkimminich picture bkimminich  ยท  4Comments