{"id":983,"date":"2024-06-26T13:33:55","date_gmt":"2024-06-26T13:33:55","guid":{"rendered":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2024\/06\/26\/understanding-the-docker-user-instruction\/"},"modified":"2024-06-26T13:33:55","modified_gmt":"2024-06-26T13:33:55","slug":"understanding-the-docker-user-instruction","status":"publish","type":"post","link":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2024\/06\/26\/understanding-the-docker-user-instruction\/","title":{"rendered":"Understanding the Docker USER Instruction"},"content":{"rendered":"<p>In the world of containerization, security and proper user management are crucial aspects that can significantly affect the stability and security of your applications. The <a href=\"https:\/\/docs.docker.com\/reference\/dockerfile\/\" target=\"_blank\" rel=\"noopener\">USER instruction<\/a> in a Dockerfile is a fundamental tool that determines which user will execute commands both during the image build process and when running the container. By default, if no USER is specified, Docker will run commands as the root user, which can pose significant security risks.\u00a0<\/p>\n<p>In this blog post, we will delve into the best practices and common pitfalls associated with the USER instruction. Additionally, we will provide a hands-on demo to illustrate the importance of these practices. Understanding and correctly implementing the USER instruction is vital for maintaining secure and efficient Docker environments. Let\u2019s explore how to manage user permissions effectively, ensuring that your Docker containers run securely and as intended.<\/p>\n<h2 class=\"wp-block-heading\">Docker Desktop\u00a0<\/h2>\n<p>The commands and examples provided are intended for use with <a href=\"https:\/\/www.docker.com\/products\/docker-desktop\/\" target=\"_blank\" rel=\"noopener\">Docker Desktop<\/a>, which includes <a href=\"https:\/\/docs.docker.com\/engine\/\" target=\"_blank\" rel=\"noopener\">Docker Engine<\/a> as an integrated component. Running these commands on Docker Community Edition (standalone Docker Engine) is possible, but your output may not match that shown in this post. The blog post <a href=\"https:\/\/www.docker.com\/blog\/blog-how-to-check-docker-version\/\" target=\"_blank\" rel=\"noopener\"><strong>How to Check Your Docker Installation: Docker Desktop vs. Docker Engine<\/strong><\/a> explains the differences and how to determine what you are using.<\/p>\n<h2 class=\"wp-block-heading\">UID\/GID: A refresher<\/h2>\n<p>Before we discuss best practices, let\u2019s review UID\/GID concepts and why they are important when using Docker. This relationship factors heavily into the security aspects of these best practices.<\/p>\n<p>Linux and other Unix-like operating systems use a numeric identifier to identify each discrete user called a UID (user ID). Groups are identified by a GID (group ID), which is another numeric identifier. These numeric identifiers are mapped to the text strings used for <em>username<\/em> and <em>groupname<\/em>, but the numeric identifiers are used by the system internally.<\/p>\n<p>The operating system uses these identifiers to manage permissions and access to system resources, files, and directories. A file or directory has ownership settings including a UID and a GID, which determine which user and group have access rights to it. Users can be members of multiple groups, which can complicate permissions management but offers flexible access control.<\/p>\n<p>In Docker, these concepts of UID and GID are preserved within <a href=\"https:\/\/www.docker.com\/resources\/what-container\/\" target=\"_blank\" rel=\"noopener\">containers<\/a>. When a Docker container is run, it can be configured to run as a specific user with a designated UID and GID. Additionally, when mounting volumes, Docker respects the UID and GID of the files and directories on the host machine, which can affect how files are accessed or modified from within the container. This adherence to Unix-like UID\/GID management helps maintain consistent security and access controls across both the host and containerized environments.\u00a0<\/p>\n<h2 class=\"wp-block-heading\">Groups<\/h2>\n<p>Unlike USER, there is no GROUP directive in the <a href=\"https:\/\/docs.docker.com\/reference\/dockerfile\/\" target=\"_blank\" rel=\"noopener\">Dockerfile instructions<\/a>. To set up a group, you specify the groupname (GID) after the username (UID). For example, to run a command as the <em>automation<\/em> user in the <em>ci<\/em> group, you would write USER automation:ci in your Dockerfile.<\/p>\n<p>If you do not specify a GID, the list of groups that the user account is configured as part of is used. However, if you do specify a GID, <em>only<\/em> that GID will be used.\u00a0<\/p>\n<h2 class=\"wp-block-heading\">Current user<\/h2>\n<p>Because <a href=\"https:\/\/www.docker.com\/products\/docker-desktop\/\" target=\"_blank\" rel=\"noopener\">Docker Desktop<\/a> uses a virtual machine (VM), the UID\/GID of your user account on the host (Linux, Mac, Windows HyperV\/WSL2) will almost certainly not have a match inside the Docker VM.<\/p>\n<p>You can always check your UID\/GID by using the id command. For example, on my desktop,\u00a0I am UID 503 with a primary GID of 20:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n$ id<br \/>\nuid=503(jschmidt) gid=20(staff) groups=20(staff),&lt;&#8211;SNIP&#8211;&gt;\n<\/div>\n<h2 class=\"wp-block-heading\">Best practices<\/h2>\n<h3 class=\"wp-block-heading\">Use a non-root user to limit root access<\/h3>\n<p>As noted above, by default Docker containers will run as UID 0, or root. This means that if the Docker container is compromised, the attacker will have host-level root access to all the resources allocated to the container. By using a non-root user, even if the attacker manages to break out of the application running in the container, they will have limited permissions if the container is running as a non-root user.\u00a0<\/p>\n<p>Remember, if you don\u2019t set a USER in your Dockerfile, the user will default to root. Always explicitly set a user, even if it\u2019s just to make it clear who the container will run as.<\/p>\n<h3 class=\"wp-block-heading\">Specify user by UID and GID<\/h3>\n<p>Usernames and groupnames can easily be changed, and different Linux distributions can assign different default values to system users and groups. By using a UID\/GID you can ensure that the user is consistently identified, even if the container\u2019s \/etc\/passwd file changes or is different across distributions. For example:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\nUSER 1001:1001\n<\/div>\n<h3 class=\"wp-block-heading\">Create a specific user for the application<\/h3>\n<p>If your application requires specific permissions, consider creating a dedicated user for your application in the Dockerfile. This can be done using the RUN command to add the user.\u00a0<\/p>\n<p>Note that when we are creating a user and then switching to that user within our Dockerfile, we do not need to use the UID\/GID because they are being set within the context of the image via the useradd command. Similarly, you can add a user to a group (and create a group if necessary) via the RUN command.<\/p>\n<p>Ensure that the user you set has the necessary privileges to run the commands in the container. For instance, a non-root user might not have the necessary permissions to bind to ports below 1024. For example:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\nRUN useradd -ms \/bin\/bash myuser<br \/>\nUSER myuser\n<\/div>\n<h3 class=\"wp-block-heading\">Switch back to root for privileged operations<\/h3>\n<p>If you need to perform privileged operations in the Dockerfile after setting a non-root user, you can switch to the root user and then switch back to the non-root user once those operations are complete. This approach adheres to the principle of least privilege; only tasks that require administrator privileges are run as an administrator. Note that it is not recommended to use sudo for privilege elevation in a Dockerfile. For example:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\nUSER root<br \/>\nRUN apt-get update &amp;&amp; apt-get install -y some-package<br \/>\nUSER myuser\n<\/div>\n<h3 class=\"wp-block-heading\">Combine USER with WORKDIR<\/h3>\n<p>As noted above, the UID\/GID used within a container applies both within the container and with the host system. This leads to two common problems:<\/p>\n<p>Switching to a non-root user and not having permissions to read or write to the directories you wish to use (for example, trying to create a directory under \/ or trying to write in \/root.<\/p>\n<p>Mounting a directory from the host system and switching to a user who does not have permission to read\/write to the directory or files in the mount.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\nUSER root<br \/>\nRUN mkdir \/app&amp;&amp;chown ubuntu<br \/>\nUSER ubuntu<br \/>\nWORKDIR \/app\n<\/div>\n<h2 class=\"wp-block-heading\">Example<\/h2>\n<p>The following example shows you how the UID and GID behave in different scenarios depending on how you write your Dockerfile. Both examples provide output that shows the UID\/GID of the running Docker container. If you are following along, you need to have a running Docker Desktop installation and a basic familiarity with the docker command.<\/p>\n<h3 class=\"wp-block-heading\">Standard Dockerfile<\/h3>\n<p>Most people take this approach when they first begin using <a href=\"https:\/\/www.docker.com\/blog\/getting-started-with-docker-desktop\/\" target=\"_blank\" rel=\"noopener\">Docker<\/a>; they go with the defaults and do not specify a USER.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n# Use the official Ubuntu image as the base<br \/>\nFROM ubuntu:20.04\n<p># Print the UID and GID<br \/>\nCMD sh -c &#8220;echo &#8216;Inside Container:&#8217; &amp;&amp; echo &#8216;User: $(whoami) UID: $(id -u) GID: $(id -g)'&#8221;\n<\/p><\/div>\n<h3 class=\"wp-block-heading\">Dockerfile with USER<\/h3>\n<p>This example shows how to create a user with a RUN command inside a Dockerfile and then switch to that USER.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n# Use the official Ubuntu image as the base<br \/>\nFROM ubuntu:20.04\n<p># Create a custom user with UID 1234 and GID 1234<br \/>\nRUN groupadd -g 1234 customgroup &amp;&amp; <br \/>\n    useradd -m -u 1234 -g customgroup customuser<\/p>\n<p># Switch to the custom user<br \/>\nUSER customuser<\/p>\n<p># Set the workdir<br \/>\nWORKDIR \/home\/customuser<\/p>\n<p># Print the UID and GID<br \/>\nCMD sh -c &#8220;echo &#8216;Inside Container:&#8217; &amp;&amp; echo &#8216;User: $(whoami) UID: $(id -u) GID: $(id -g)'&#8221;\n<\/p><\/div>\n<p>Build the two images with:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n$ docker build -t default-user-image -f Dockerfile1 .<br \/>\n$ docker build -t custom-user-image -f Dockerfile2 .\n<\/div>\n<h3 class=\"wp-block-heading\">Default Docker image<\/h3>\n<p>Let\u2019s run our first image, the one that does not provide a USER command. As you can see, the UID and GID are 0\/0, so the superuser is root. There are two things at work here. First, we are not defining a UID\/GID in the Dockerfile so Docker defaults to the superuser. But how does it become a superuser if my account is not a superuser account? This is because the Docker Engine runs with root permissions, so containers that are built to run as root inherit the permissions from the Docker Engine.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n$ docker run &#8211;rm default-user-image<br \/>\nInside Container:<br \/>\nUser: root UID: 0 GID: 0<br \/>\nCustom User Docker Image\n<\/div>\n<h3 class=\"wp-block-heading\">Custom Docker image<\/h3>\n<p>Let\u2019s try to fix this \u2014 we really don\u2019t want Docker containers running as root. So, in this version, we explicitly set the UID and GID for the user and group. Running this container, we see that our user is set appropriately.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n$ docker run &#8211;rm custom-user-image<br \/>\nInside Container:<br \/>\nUser: customuser UID: 1234 GID: 1234\n<\/div>\n<h2 class=\"wp-block-heading\">Enforcing best practices<\/h2>\n<p>Enforcing best practices in any environment can be challenging, and the best practices outlined in this post are no exception. Docker understands that organizations are continually balancing security and compliance against innovation and agility and is continually working on ways to help with that effort. Our <a href=\"https:\/\/docs.docker.com\/desktop\/hardened-desktop\/enhanced-container-isolation\/\" target=\"_blank\" rel=\"noopener\">Enhanced Container Isolation (ECI)<\/a> offering, part of our <a href=\"https:\/\/docs.docker.com\/desktop\/hardened-desktop\/\" target=\"_blank\" rel=\"noopener\">Hardened Docker Desktop<\/a>, was designed to address the problematic aspects of having containers running as root.<\/p>\n<p>Enhanced Container Isolation mechanisms, such as user namespaces, help segregate and manage privileges more effectively. User namespaces isolate security-related identifiers and attributes, such as user IDs and group IDs, so that a root user inside a container does not map to the root user outside the container. This feature significantly reduces the risk of privileged escalations by ensuring that even if an attacker compromises the container, the potential damage and access scope remain confined to the containerized environment, dramatically enhancing overall security.<\/p>\n<p>Additionally, <a href=\"https:\/\/www.docker.com\/products\/docker-scout\/\" target=\"_blank\" rel=\"noopener\">Docker Scout<\/a> can be leveraged on the user desktop to enforce policies not only around CVEs, but around best practices \u2014 for example, by ensuring that images run as a non-root user and contain mandatory LABELs.<\/p>\n<h2 class=\"wp-block-heading\">Staying secure<\/h2>\n<p>Through this demonstration, we\u2019ve seen the practical implications and benefits of configuring Docker containers to run as a non-root user, which is crucial for enhancing security by minimizing potential attack surfaces. As demonstrated, Docker inherently runs containers with root privileges unless specified otherwise. This default behavior can lead to significant security risks, particularly if a container becomes compromised, granting attackers potentially wide-ranging access to the host or Docker Engine.<\/p>\n<h3 class=\"wp-block-heading\">Use custom user and group IDs<\/h3>\n<p>The use of custom user and group IDs showcases a more secure practice. By explicitly setting UID and GID, we limit the permissions and capabilities of the process running inside the Docker container, reducing the risks associated with privileged user access. The UID\/GID defined inside the Docker container does not need to correspond to any actual user on the host system, which provides additional isolation and security.<\/p>\n<h3 class=\"wp-block-heading\">User namespaces<\/h3>\n<p>Although this post extensively covers the USER instruction in Docker, another approach to secure Docker environments involves the use of namespaces, particularly user namespaces. User namespaces isolate security-related identifiers and attributes, such as user IDs and group IDs, between the host and the containers.\u00a0<\/p>\n<p>With user namespaces enabled, Docker can map the user and group IDs inside a container to non-privileged IDs on the host system. This mapping ensures that even if a container\u2019s processes break out and gain root privileges within the Docker container, they do not have root privileges on the host machine. This additional layer of security helps to prevent the escalation of privileges and mitigate potential damage, making it an essential consideration for those looking to bolster their Docker security framework further. Docker\u2019s ECI offering leverages user namespaces as part of its security framework.<\/p>\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n<p>When deploying containers, especially in development environments or on Docker Desktop, consider the aspects of container configuration and isolation outlined in this post. Implementing the enhanced security features available in <a href=\"https:\/\/www.docker.com\/products\/business\/\" target=\"_blank\" rel=\"noopener\">Docker Business<\/a>, such as Hardened Docker Desktop with Enhanced Container Isolation, can further mitigate risks and ensure a secure, robust operational environment for your applications.<\/p>\n<h2 class=\"wp-block-heading\">Learn more<\/h2>\n<p>Read the <a href=\"https:\/\/docs.docker.com\/reference\/dockerfile\/\" target=\"_blank\" rel=\"noopener\">Dockerfile reference guide<\/a>.<\/p>\n<p>Get the latest release of<a href=\"https:\/\/www.docker.com\/products\/docker-desktop\/\" target=\"_blank\" rel=\"noopener\"> Docker Desktop<\/a>.<\/p>\n<p>Explore <a href=\"https:\/\/docs.docker.com\/guides\/\" target=\"_blank\" rel=\"noopener\">Docker Guides<\/a>.<\/p>\n<p>New to Docker? <a href=\"https:\/\/docs.docker.com\/guides\/getting-started\/get-docker-desktop\/\" target=\"_blank\" rel=\"noopener\">Get started<\/a>.<\/p>\n<p>Subscribe to the<a href=\"https:\/\/www.docker.com\/newsletter-subscription\/\" target=\"_blank\" rel=\"noopener\"> Docker Newsletter<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>In the world of containerization, security and proper user management are crucial aspects that can significantly affect the stability and [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[4],"tags":[],"class_list":["post-983","post","type-post","status-publish","format-standard","hentry","category-docker"],"_links":{"self":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/983","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/comments?post=983"}],"version-history":[{"count":0,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/983\/revisions"}],"wp:attachment":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media?parent=983"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/categories?post=983"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/tags?post=983"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}