Azure / static-web-apps

Azure Static Web Apps. For bugs and feature requests, please create an issue in this repo. For community discussions, latest updates, kindly refer to the Discussions Tab. To know what's new in Static Web Apps, visit https://aka.ms/swa/ThisMonth
https://aka.ms/swa
MIT License
330 stars 57 forks source link

Failing because EACCES since static-web-apps-deploy uses Docker with root #1285

Open mohamedmansour opened 1 year ago

mohamedmansour commented 1 year ago

This is the weirdest thing that is happening, when using static-web-apps-deploy the api folder in self-hosted github runner, is always root, this happens when I don't skip the build for static-web-apps-deploy. and let oryx do its building. But as soon as I say skip api build, the folders are not changed, still mmansour. As soon as I allow the runner to build API it messes up the permissions causing my whole self-hosted agent to fail the next time it runs:

Error: File was unable to be removed Error: EACCES: permission denied, unlink '/home/mmansour/actions-runner/_work/app/app/api/.funcignore'

My monitoring the syscalls in the Github Action,

time->Wed Sep 20 22:12:57 2023
type=PROCTITLE msg=audit(1695273177.138:52877): proctitle=6D6B646972002D70002E6F7279785F70726F645F6E6F64655F6D6F64756C6573
type=PATH msg=audit(1695273177.138:52877): item=1 name=".oryx_prod_node_modules" inode=23231831 dev=fd:01 mode=040755 ouid=0 ogid=0 rdev=00:00 nametype=CREATE cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(1695273177.138:52877): item=0 name="/github/workspace/api" inode=23231945 dev=fd:01 mode=040755 ouid=1000 ogid=1000 rdev=00:00 nametype=PARENT cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(1695273177.138:52877): cwd="/github/workspace/api"
type=SYSCALL msg=audit(1695273177.138:52877): arch=c000003e syscall=83 success=yes exit=0 a0=7fff41c1f8f5 a1=1ff a2=0 a3=fffffffffffffd8c items=2 ppid=1619239 pid=1619685 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="mkdir" exe="/bin/mkdir" subj=docker-default key="api-watch"

The uuid and guid is 0 which is root, and ls -al the solution:

drwxr-xr-x 12 mmansour mmansour   4096 Sep 20 22:12 .
drwxr-xr-x  3 mmansour mmansour   4096 Sep 20 21:32 ..
drwxr-xr-x  7 root     root       4096 Sep 20 22:12 api
drwxr-xr-x  4 mmansour mmansour   4096 Sep 20 22:12 dist
drwxr-xr-x  8 mmansour mmansour   4096 Sep 20 22:13 .git
drwxr-xr-x  3 mmansour mmansour   4096 Sep 20 22:12 .github
-rw-r--r--  1 mmansour mmansour     39 Sep 20 22:12 .gitignore
drwxr-xr-x 12 mmansour mmansour   4096 Sep 20 22:12 node_modules
-rw-r--r--  1 mmansour mmansour   2498 Sep 20 22:12 package.json
-rw-r--r--  1 mmansour mmansour 215312 Sep 20 22:12 pnpm-lock.yaml
drwxr-xr-x  2 mmansour mmansour   4096 Sep 20 22:12 public
-rw-r--r--  1 mmansour mmansour   1714 Sep 20 22:12 README.md
drwxr-xr-x  7 mmansour mmansour   4096 Sep 20 22:12 src

It is chowning all the /api folder to be owned by root:

----
time->Wed Sep 20 22:12:58 2023
type=PROCTITLE msg=audit(1695273178.714:58159): proctitle=63686F776E002D5200726F6F743A726F6F74002F6769746875622F776F726B73706163652F617069
type=PATH msg=audit(1695273178.714:58159): item=0 name="types.d.ts.map" inode=23343409 dev=fd:01 mode=0100644 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(1695273178.714:58159): cwd="/github/workspace/api/.oryx_prod_node_modules"
type=SYSCALL msg=audit(1695273178.714:58159): arch=c000003e syscall=260 success=yes exit=0 a0=9 a1=5633dff02298 a2=0 a3=0 items=1 ppid=1619239 pid=1619703 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="chown" exe="/bin/chown" subj=docker-default key="api-watch"
----

How can we tell that Github Action static-web-apps-deploy to run as a certain user and not root? (my alias is mmansour in msft if we can talk there too)

mohamedmansour commented 1 year ago

I tried doing this https://docs.docker.com/engine/security/userns-remap/, so that when root writes back to the volume that was mounted in docker run, it will use my local username mmansour, but the logs spit out.


Removing existing manifest file
Creating directory for command manifest file if it does not exist
Creating a manifest file...
Node Build Command Manifest file created.

Using Node version:
v16.20.2

Using Npm version:
8.19.4
mkdir: cannot create directory ‘.oryx_prod_node_modules’: Permission denied

---End of Oryx build logs---
Oryx has failed to build the solution.
mohamedmansour commented 1 year ago

I found the documentation: https://docs.github.com/en/actions/creating-actions/dockerfile-support-for-github-actions#user

Docker actions must be run by the default Docker user (root). Do not use the USER instruction in your Dockerfile, because you won't be able to access the GITHUB_WORKSPACE directory. For more information, see "[Variables](https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables)" and [USER reference](https://docs.docker.com/engine/reference/builder/#user) in the Docker documentation.

I need to run the action as root so, for this action to work static-web-apps-deploy which is unfortunate, it would be great if mcr.microsoft.com/appsvc/staticappsclient:stable did not write back to the volume directory that it uses and uses some out folder instead. Because right now it does the following:

/usr/bin/docker run --name efd717c49587fb9570528479f82037edf48_364cf5 --label 363efd --workdir /github/workspace --rm -e "PNPM_HOME" -e "INPUT_AZURE_STATIC_WEB_APPS_API_TOKEN" -e "INPUT_REPO_TOKEN" -e "INPUT_ACTION" -e "INPUT_APP_LOCATION" -e "INPUT_API_LOCATION" -e "INPUT_OUTPUT_LOCATION" -e "INPUT_SKIP_APP_BUILD" -e "INPUT_API_BUILD_COMMAND" -e "INPUT_APP_ARTIFACT_LOCATION" -e "INPUT_APP_BUILD_COMMAND" -e "INPUT_ROUTES_LOCATION" -e "INPUT_CONFIG_FILE_LOCATION" -e "INPUT_SKIP_API_BUILD" -e "INPUT_PRODUCTION_BRANCH" -e "INPUT_DEPLOYMENT_ENVIRONMENT" -e "INPUT_IS_STATIC_EXPORT" -e "INPUT_DATA_API_LOCATION" -e "HOME" -e "GITHUB_JOB" -e "GITHUB_REF" -e "GITHUB_SHA" -e "GITHUB_REPOSITORY" -e "GITHUB_REPOSITORY_OWNER" -e "GITHUB_REPOSITORY_OWNER_ID" -e "GITHUB_RUN_ID" -e "GITHUB_RUN_NUMBER" -e "GITHUB_RETENTION_DAYS" -e "GITHUB_RUN_ATTEMPT" -e "GITHUB_REPOSITORY_ID" -e "GITHUB_ACTOR_ID" -e "GITHUB_ACTOR" -e "GITHUB_TRIGGERING_ACTOR" -e "GITHUB_WORKFLOW" -e "GITHUB_HEAD_REF" -e "GITHUB_BASE_REF" -e "GITHUB_EVENT_NAME" -e "GITHUB_SERVER_URL" -e "GITHUB_API_URL" -e "GITHUB_GRAPHQL_URL" -e "GITHUB_REF_NAME" -e "GITHUB_REF_PROTECTED" -e "GITHUB_REF_TYPE" -e "GITHUB_WORKFLOW_REF" -e "GITHUB_WORKFLOW_SHA" -e "GITHUB_WORKSPACE" -e "GITHUB_ACTION" -e "GITHUB_EVENT_PATH" -e "GITHUB_ACTION_REPOSITORY" -e "GITHUB_ACTION_REF" -e "GITHUB_PATH" -e "GITHUB_ENV" -e "GITHUB_STEP_SUMMARY" -e "GITHUB_STATE" -e "GITHUB_OUTPUT" -e "RUNNER_OS" -e "RUNNER_ARCH" -e "RUNNER_NAME" -e "RUNNER_ENVIRONMENT" -e "RUNNER_TOOL_CACHE" -e "RUNNER_TEMP" -e "RUNNER_WORKSPACE" -e "ACTIONS_RUNTIME_URL" -e "ACTIONS_RUNTIME_TOKEN" -e "ACTIONS_CACHE_URL" -e GITHUB_ACTIONS=true -e CI=true -v "/var/run/docker.sock":"/var/run/docker.sock" -v "/home/mmansour/actions-runner/_work/_temp/_github_home":"/github/home" -v "/home/mmansour/actions-runner/_work/_temp/_github_workflow":"/github/workflow" -v "/home/mmansour/actions-runner/_work/_temp/_runner_file_commands":"/github/file_commands" -v "/home/mmansour/actions-runner/_work/app/app":"/github/workspace" 363efd:717c49587fb9570528479f82037edf48

And the docker container writes back to the volume and overwrites all the user folder as root. We shouldn't do that.

mohamedmansour commented 1 year ago

Unfortunately we cannot run self hosted github actions as root, it doesn't allow you. So this is a blocker for self hosted builds, that we cannot run static-web-apps-deploy action since it requires it to be root since it uses docker and overwrites the user files and cannot clean it up since it lost its access.

thomasgauvin commented 1 year ago

Oryx will always use the root user to build the project. If this is a blocker for your configuration, you could consider configuring your own build and using the staticappsclient image to deploy only

mohamedmansour commented 1 year ago

Oryx will always use the root user to build the project. If this is a blocker for your configuration, you could consider configuring your own build and using the staticappsclient image to deploy only

Isn't that a problem though? Why would oryx rewrite itself to the same system volume? Github Action Runners cannot run in root and once oryx runs it corrupts the entire _work directory.

Is there an example to use staticappsclient image to deploy? I tried doing this:

      - name: Deploy
        run: >
          pnpm swa deploy -n "app" 
          --app-location ./dist/www 
          --api-location ./api 
          --output-location ./ 
          --api-language node 
          --api-version 18
        env:
          AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
          SWA_CLI_DEPLOYMENT_TOKEN: ${{ secrets.SWA_CLI_DEPLOYMENT_TOKEN }}

And the output is just this which doesn't update deployment, it is missing a lot of things that oryx does:

Welcome to Azure Static Web Apps CLI (1.1.4)

Deploying front-end files from folder:
  /var/lib/actions-runner/_work/app/app/dist/www

Deploying API from folder:
  /var/lib/actions-runner/_work/app/app/api

Deploying to environment: preview

Deploying project to Azure Static Web Apps...
- Preparing deployment. Please wait...
✔ Project deployed to  🚀
mohamedmansour commented 1 year ago

Hey @thomasgauvin the core issue is oryx where it reuses the same volume that was mounted in the docker image causing this overwrite of files on disk, Is there anyone that can help? Or am I forced to create an unmanaged NodeJS API?

thomasgauvin commented 1 year ago

Hi @mohamedmansour, I'll check in with our engineering team about the issue you're describing. If you cannot use Oryx due to root user restrictions, you can use the StaticSitesClient only to deploy and avoid building with Oryx by using the skip_app_build and skip_api_build configuration parameters as described in our docs: https://learn.microsoft.com/en-us/azure/static-web-apps/build-configuration?tabs=github-actions

The example you shared above does something similar, but by using the SWA CLI (the SWA CLI uses the StaticSitesClient under the hood). It should work, and will not use Oryx to build the project. You will have to build the project separately.