Non-Root Docker Update Summary

I haven't got time to learn Docker systematically so far, but I still gain a lot from daily tasks. This post is a brief summary for what I have done to upgrade the container from own by root to noon-root for security reason required by our customers.

I will talk the development workflow instead of the detail about how to set and modify the configurations inside the container:

I have a base image at beginning, let's say root_is_engine.tar.gz, load it:

docker load -i root_is_engine.tar.gz

you can check the loaded image by running:

docker images

Now I am going to create the container from this template, but wait, I don't want it to run any script or program when I initialize it, what I need is it just hangs there like a fresh new white paper and I will draw something step by step on it.

That means I need to override the default entry point (entry point sets the command and parameters that will be executed first when a container is run) in docker run command:

docker run --detach \
         --cap-add=SYS_ADMIN \
         --privileged=false --name=${ENGINE_HOST} --hostname=${ENGINE_HOST} \
         --restart=always --add-host="${SERVICES_HOST} ${DB2_XMETA_HOST} ${ENGINE_HOST}":${ENGINE_HOST_IP} \
         -p 8449:8449 \
         -v ${DEDICATED_ENGINE_VOLPATH}/${ENGINE_HOST}/EngineClients/db2_client/dsadm:/home/dsadm \
         --entrypoint=/bin/sh \
         ${DOCKER_IMAGE_TAG_ENGINE}:${DOCKER_IMAGE_VERSION} \
         -c 'tail -f /dev/null'

Note that place the arguments to your entrypoint at the end of your docker command , here is -c 'tail -f /dev/null'

Run docker ps command, you can see under COMMAND column the entry point is what we specified:

CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS              PORTS                     NAMES
b462f6123684        is-engine-image:1       "/bin/sh -c 'tail -f..."   2 days ago          Up 2 days           0.0.0.0:8449->8449/tcp   is-en-conductor-0.en-cond

Then get into the container by running:

docker exec -it <container id or container name> bash

Also if you check the process status, you can see the init process with PID #1 is running tail command to track /dev/null device file:

ps aux

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   5968   616 ?        Ss   16:47   0:00 tail -f /dev/null
root        27  1.5  0.0  13420  1992 pts/0    Ss   16:50   0:00 bash
root        45  0.0  0.0  53340  1864 pts/0    R+   16:50   0:00 ps aux

OK, now I can make changes inside container like create and switch to ordinary user with specified user id and group id, grant them privileges, modify the owner and permission of some files, run startup script line by line to see if the applications setup correctly with non-root.

Note if you have mount path with host machine, you may need to chown correct uid and gid in that path in host, otherwise ordinary user in container cannot access these directories.

After verification with simple tests, I need to commit the changes into a new image.

  • First understand how does docker commit work? what will be committed into new image?

    The container has a writable layer that stacks on top of the image layers. This writable layer allows you to make changes to the container since the lower layers in the image are read-only.

    From the docker documentation, it said: It can be useful to commit a container’s file changes or settings into a new image.

    The commit operation will not include any data contained in volumes mounted inside the container.

    By default, the container being committed and its processes will be paused while the image is committed. This reduces the likelihood of encountering data corruption during the process of creating the commit. If this behavior is undesired, set the --pause option to false.

    The --change option will apply Dockerfile instructions to the image that is created. Supported Dockerfile instructions: CMD|ENTRYPOINT|ENV|EXPOSE|LABEL|ONBUILD|USER|VOLUME|WORKDIR

  • How about processes inside the container?

    When you start container from image then process will start here - processes exists only in executing container, when container stops there are no processes anymore - only files from container's filesystem.

Note: Before committing, you need to quiesce the services and remove the mount path content, unlink any other broken symbolic links.

When commit, remember to restore the old entry point:

docker commit --change 'ENTRYPOINT ["/opt/xx/initScripts/startcontainer.sh"]' <container ID> is-engine-image:1

OK, now start to run the new image with non-root user:

docker run --detach \
         --user 1000 \
         --cap-add=SYS_ADMIN \
         --privileged=false --name=${ENGINE_HOST} --hostname=${ENGINE_HOST} \
         --restart=always --add-host="${SERVICES_HOST} ${DB2_XMETA_HOST} ${ENGINE_HOST}":${ENGINE_HOST_IP} \
         -p 8449:8449 \
         -v ${DEDICATED_ENGINE_VOLPATH}/${ENGINE_HOST}/EngineClients/db2_client/dsadm:/home/dsadm \
         ${DOCKER_IMAGE_TAG_ENGINE}:${DOCKER_IMAGE_VERSION}

Let's see the processes in the non-root container:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
dsadm        1  0.0  0.0  13288  1604 ?        Ss   18:29   0:00 /bin/bash /opt/xx/initScripts/startcontainer.sh
dsadm      540  0.0  0.0   5968   620 ?        S    18:29   0:00 tail -f /dev/null
dsadm      568  0.1  0.3 2309632 24792 ?       Sl   18:29   0:00 /opt/xx/../../jdk
dsadm      589  2.5  0.0  13420  2012 pts/0    Ss   18:36   0:00 bash
dsadm      610  0.0  0.0  53340  1868 pts/0    R+   18:36   0:00 ps aux

If all things work good, save the image into tar.gz format, of course you can use a new tag before saving:

docker save is-engine-image:1 > ~/nonroot_is_engine.tar.gz
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章