Docker app - Permission denied / no write access to mapped volume

docker

#1

I’m trying to install my own docker image-based app via test-app-center on a local development UCS running in VirtualBox.

The container is started but exits prematurely with an error code. From the logs I can see that the app has no write access to the mapped volume /var/lib/univention-appcenter/apps/sphairas/conf/ i.e. it cannot create files on this volume, the container logs lots of file access “Permission denied” errors.

And then I see:

Traceback (most recent call last):
  File "/usr/lib/pymodules/python2.7/univention/appcenter/actions/__init__.py", line 226, in call_with_namespace
    result = self.main(namespace)
  File "/usr/lib/pymodules/python2.7/univention/appcenter/actions/install.py", line 73, in main
    return self.do_it(args)
  File "/usr/lib/pymodules/python2.7/univention/appcenter/actions/install_base.py", line 105, in do_it
    self._do_it(app, args)
  File "/usr/lib/pymodules/python2.7/univention/appcenter/actions/docker_install.py", line 63, in _do_it
    ret = super(Install, self)._do_it(app, args)
  File "/usr/lib/pymodules/python2.7/univention/appcenter/actions/install.py", line 90, in _do_it
    if self._install_app(app, args):
  File "/usr/lib/pymodules/python2.7/univention/appcenter/actions/docker_install.py", line 57, in _install_app
    self._start_docker_image(app, hostdn, password, args)
  File "/usr/lib/pymodules/python2.7/univention/appcenter/actions/docker_base.py", line 249, in _start_docker_image
    raise AppCenterErrorContainerStart(msg)
AppCenterErrorContainerStart: 
The container for 4.1/xxxx=0.1 could not be started!

The image runs fine on my own development machine.

My app need to write persistent config files right after the start. What am I doing wrong?


Why is preinst executed before the settings screen?
#2

Hi @bheithecker,

that sounds a bit weird. My apps all write to /var/lib/univention-appcenter/apps/appname/data/ without problems and this folder does not have any other permissions. But maybe the following tip that I got from the Univention guys would help you in this case.

Instead of using /var/lib/univention-appcenter/apps/appname/ for storing you app data, you should create own folders (for example during the run of preinst). So instead of putting your config in conf create a folder in /etc for your config files.

Folders in /var/lib/univention-appcenter/apps/ are manipulated during app update/removal so using your own folder structure safes you from headaches.


#3

Okay, found out a bit more…

The problem seems to be that the default app folders /var/lib/univention-appcenter/apps/appname/data/ and …/config are owned by root. A container app can only write to these volumes if the app inside the container is also running as root. This is really not recommended, especially for web applications, for security reasons. (It’s easier to to use an exploit - a miner, for example - if the web app runs with root privileges. It’s my personal experience.)

To fix this, i’m now working on a pre-install script which:

  1. creates a user with uid 1000: useradd --system -s /bin/bash --uid 1000 <app-name>
    (UID 1000 is also the uid of the user running the app inside the container)
  2. create a directory: mkdir -p /opt/<app-name>/app-resources
  3. chown the created dir: chown 1000 -R /opt/sphairas/app-resources

Installation fails with this script too, but I get another error. Here are the relevant logs:

  8857 actions.install                  18-05-22 10:26:29 [    INFO]: Executing interface restore_data_before_setup for <app-name
  8857 actions.install                  18-05-22 10:26:29 [ WARNING]: Interface script /usr/share/univention-docker-container-mode/restore_data_before_setup not found!
  8857 actions.install                  18-05-22 10:26:29 [    INFO]: Executing interface setup for <app-name>
  8857 actions.install                  18-05-22 10:26:29 [ WARNING]: Interface script /usr/share/univention-docker-container-mode/setup not found!
  8857 packages                         18-05-22 10:26:29 [   DEBUG]: Releasing LOCK
  8857 actions.install                  18-05-22 10:26:29 [CRITICAL]: Setup script failed!
  8857 actions.install                  18-05-22 10:26:29 [ WARNING]: Aborting...
  8857 actions.remove                   18-05-22 10:26:29 [   DEBUG]: Calling remove

If I comment out the chown part of the above script, I keep getting the old “permission denied” errors.

Boris


#4

Ah, thats actually easy to fix:

if you are not using an Univention base image for your app, the you need to disable these lifecycle scripts in the provider portal (or supply your own version of them)


#5

Okay, thank you
I got it working now with the following Preinst script (meaning that the app is running, I’m still having problems accessing the web interface):

#!/bin/bash
#
echo "Executing <app-name> Preinst script."
id -u <app-name> &>/dev/null || useradd --system -s /bin/bash --uid 1000 <app-name>
if [ ! 1000=$(id -u <app-name>) ]; then
    echo "UID of user <app-name> is not 1000. The application <app-name> cannot be installed. Exiting."
    exit 1;
fi
mkdir -p /opt/<app-name>/app-resources
chown 1000 -R /opt/<app-name>/app-resources

The created volume /opt/<app-name>/app-resources is mapped to a corresponding volume inside docker.

This is, of course, a very bad solution. In case a user with UID 1000 already exists, our app won’t be installed.
Does anybody see a better solution?

Boris


#6

maybe https://docs.docker.com/engine/reference/run/#user would help you. I’m using this in https://stash.z-hub.io/projects/K4U/repos/kopano-apps/browse/kopano-konnect/kopano-konnect.preinst. Here you could create just any local user (and preferably a system user as well) and have the container be run with the same userid as this user.


#7

Okay, thank you.
I didn’t know I can modify the start-up parameters for my container (the last line in your script). Am I missing the documentation somewhere?
I’m doing it like this now:

#!/bin/bash
#

APP_LOGIN=<app-name>
APP_RESOURCES_DIR=/opt/$APP_LOGIN/app-resources

echo "Executing <app-name> Preinst script."

#Add user APP_LOGIN if not existing
if ! id $APP_LOGIN >/dev/null 2>&1; then
    echo "Creating user $APP_LOGIN"
    adduser --no-create-home --disabled-login $APP_LOGIN
fi
APP_LOGIN_UID=$(id -u $APP_LOGIN)
APP_LOGIN_GID=$(id -g $APP_LOGIN)

#Create app-resources dir and set permissions
mkdir -p $APP_RESOURCES_DIR
chown $APP_LOGIN_UID:$APP_LOGIN_GID $APP_RESOURCES_DIR
chmod 700 -R $APP_RESOURCES_DIR

echo "Adding docker start-up parameter"
ucr set appcenter/apps/$APP_LOGIN/docker/params="--user=$APP_LOGIN_UID:$APP_LOGIN_GID"

Boris


#8

No, I don’t think this is explicitly documented somewhere. I also only learned about it recently.