{"id":935,"date":"2019-09-05T18:55:49","date_gmt":"2019-09-05T06:55:49","guid":{"rendered":"http:\/\/mdickinson.dyndns.org\/php\/wordpress\/?p=935"},"modified":"2019-09-05T18:55:49","modified_gmt":"2019-09-05T06:55:49","slug":"docker-isolation-and-non-isolation","status":"publish","type":"post","link":"https:\/\/mdickinson.dyndns.org\/php\/wordpress\/?p=935","title":{"rendered":"Docker Isolation, and non-Isolation"},"content":{"rendered":"<p>Docker is not KVM, there are major security trade-offs with a container, The key ones are shown below.<\/p>\n<h2>Processes are not isolated<\/h2>\n<p>The processes that are run by containers run for all intents and purposes as processes on the Docker host machine, this is an issue as an admin on the host machine may inadvertently cause failure of applications within a container. For example in a memory shortage situation on the host an admin may kill a process that is a memory hog on the host without realising it is spawned from a container application. <\/p>\n<p>The display below is a process display on the host, every single one of the results (apart from the grep itself) are processes launced from within the container.<\/p>\n<pre>\r\n[root@vosprey2 log]# ps -ef | grep herc\r\nroot      1203  1185  0 15:45 ?        00:00:00 \/bin\/bash \/home\/mark\/hercules\/tk4-minus\/start_system_wrapper.sh\r\nroot      1240  1203  0 15:45 ?        00:00:00 \/usr\/bin\/su -c bash \/home\/mark\/hercules\/tk4-minus\/start_system.sh > \/var\/tmp\/hercstart.log 2>&1 mark\r\nmark      1241  1240  0 15:45 ?        00:00:00 bash -c bash \/home\/mark\/hercules\/tk4-minus\/start_system.sh > \/var\/tmp\/hercstart.log 2>&1\r\nmark      1242  1241  0 15:45 ?        00:00:00 bash \/home\/mark\/hercules\/tk4-minus\/start_system.sh\r\nmark      1244  1203  0 15:45 ?        00:00:00 SCREEN -t hercules -S hercules -p hercules -d -m hercules -f mark\/marks.conf\r\nmark      1246  1244  9 15:45 pts\/0    00:00:49 hercules -f mark\/marks.conf\r\nmark      3321  1246  0 15:46 pts\/0    00:00:00 hercules -f mark\/marks.conf\r\nmark      3322  3321  0 15:46 pts\/0    00:00:00 \/bin\/bash \/home\/mark\/hercules\/tk4-minus\/mark\/scripts\/printer_interface.sh\r\nmark      3333  3322  0 15:46 pts\/0    00:00:00 \/bin\/bash \/home\/mark\/hercules\/tk4-minus\/mark\/scripts\/printer_interface.sh\r\nroot     11963 10154  0 15:53 pts\/0    00:00:00 grep --color=auto herc\r\n[root@vosprey2 log]# \r\n<\/pre>\n<h2>Network connections are hidden<\/h2>\n<p>In a complete reverse of the above issue, network connections to applications within a Docker container are not visible on the host machine. That can make the job of diagnosing network connectivity issues difficult as the admin would normally look on the host for established tcpip sessions; but established sessions to container applications are not visible on the host.<\/p>\n<p>Refer to the output below. The container application listens on port 3270 but while netstat shows no established sessions in this example a computer remote to the docker host does have an established connection via the host into the container on that port. A docker exec into the application lets us see that established connection from 192.168.1.187 and it is dangerous to not have that connection displayed on the docker host. The last command in the output below was run on the computer that established the session, it correctly shows it is connected to the docker host (189) to access the port mapped to the container even though displays on the docker host do not show the connection.<\/p>\n<p>By dangerous I mean in a large environment if there are network issues to be resolved an admin cannot be expected to attach to or exec into every container to see what established connections exist on a host (assuming the container is even built to contain the netstat command), not having established connections to a host displayable on the host I would consider a serious issue. And a &#8216;ip netns&#8217; shows no network namespaces are in use so I really don&#8217;t know how the connection is being hidden.<\/p>\n<pre>\r\n[root@vosprey2 log]# netstat -an | grep 3270\r\ntcp6       0      0 :::3270                 :::*                    LISTEN     \r\n\r\n[root@vosprey2 log]# docker exec -ti mvs38j1 \/bin\/bash\r\nbash-5.0# netstat -an | grep 3270\r\ntcp        0      0 0.0.0.0:3270            0.0.0.0:*               LISTEN     \r\ntcp        0      0 127.0.0.1:3270          127.0.0.1:39892         ESTABLISHED\r\ntcp        0      0 127.0.0.1:39896         127.0.0.1:3270          ESTABLISHED\r\ntcp        0      0 172.17.0.2:3270         192.168.1.187:48842     ESTABLISHED\r\ntcp        0      0 127.0.0.1:39892         127.0.0.1:3270          ESTABLISHED\r\ntcp        0      0 127.0.0.1:3270          127.0.0.1:39896         ESTABLISHED\r\ntcp        0      0 127.0.0.1:39894         127.0.0.1:3270          ESTABLISHED\r\ntcp        0      0 127.0.0.1:3270          127.0.0.1:39894         ESTABLISHED\r\nunix  2      [ ACC ]     STREAM     LISTENING     16297755 \/run\/screen\/S-mark\/71.c3270A\r\nunix  2      [ ACC ]     STREAM     LISTENING     16297819 \/run\/screen\/S-mark\/76.c3270B\r\nbash-5.0# exit\r\nexit\r\n\r\n[root@vosprey2 log]# netstat -an | grep 3270 \r\ntcp6       0      0 :::3270                 :::*                    LISTEN     \r\n[root@vosprey2 log]#\r\n[root@vosprey2 log]# ip netns\r\n[root@vosprey2 log]#\r\n\r\n[mark@phoenix mvs38j]$ netstat -an | grep 3270\r\ntcp        0      0 192.168.1.187:48842     192.168.1.189:3270      ESTABLISHED\r\n[mark@phoenix mvs38j]$ \r\n<\/pre>\n<h2>The dangers of running apps in containers as non-root<\/h2>\n<p>Everybody will tell you user applications should never be run as the root user, and applications in containers should also follow that rule.<\/p>\n<p>There is a <b><em>major<\/em><\/b> issue with running applications as a non-root user in containers however.<\/p>\n<p>Remember the processes lauched within a host container run as actual processes on the docker host, and as containers are supposed to be portable there is no way to guarantee that UIDs assigned to users within the container will match UIDs on the docker host.<\/p>\n<p>Refer the the output shown below. Within the container the application runs under the userid &#8216;ircserver&#8217; with a uid of 1000, all good right.<\/p>\n<pre>\r\n[root@vosprey2 log]# docker exec -ti ircserver1 \/bin\/bash\r\nbash-5.0# ps -ef \r\nUID        PID  PPID  C STIME TTY          TIME CMD\r\nroot         1     0  0 03:28 ?        00:00:00 \/bin\/bash \/home\/ircserver\/marks_irc_server\r\nircserv+    23     1  0 03:28 ?        00:00:00 \/home\/ircserver\/IRC\/inspircd-3.3.0\/run\/bin\/inspircd --config=\/home\/ircserver\/IRC\/inspircd-3.3.0\/run\/conf\/inspircd.conf\r\nroot        81     1  0 03:58 ?        00:00:00 sleep 600\r\nroot        82     0  7 04:01 ?        00:00:00 \/bin\/bash\r\nroot        87    82  0 04:01 ?        00:00:00 ps -ef\r\nbash-5.0# grep ircserver \/etc\/passwd\r\nircserver:x:1000:1000:Used to run the inspircd IRC server:\/home\/ircserver:\/bin\/bash\r\nbash-5.0# \r\n<\/pre>\n<p><b>Wrong !<\/b>. Displaying the process on the docker host shows a different story. On the docker host it also runs under UID 1000 correctly, <b>but<\/b> on the docker host the ircserver user does not exist and another user is assigned uid 1000.<\/p>\n<pre>\r\n[root@vosprey2 log]# ps -ef | grep IRC | grep -v grep\r\nmark     17875 17834  0 15:28 ?        00:00:00 \/home\/ircserver\/IRC\/inspircd-3.3.0\/run\/bin\/inspircd --config=\/home\/ircserver\/IRC\/inspircd-3.3.0\/run\/conf\/inspircd.conf\r\n[root@vosprey2 log]# \r\n[root@vosprey2 log]# grep 1000 \/etc\/passwd\r\nmark:x:1000:1000:Mark Dickinson:\/home\/mark:\/bin\/bash\r\n[root@vosprey2 log]# \r\n<\/pre>\n<p>The obvious major issue here is that unless all container applications are run as root they cannot be considered portable, as there is no way to ensure UIDs either match or do not exist on every docker host that may ever run the image.<\/p>\n<p>Imagine again from a admin perspective trying to troubleshoot a memory hog process, and a &#8216;ps&#8217; shows the issue causing process is being run by user &#8216;fred&#8217; but user fred swears he never started the process; he may not have started the process, it could have been spawned from a container using a matching UID for fred. Admitedly if they were all root processes admins would still have to track down the container causing the impact; but would not have been sidetracked into wasting time chasing after fred.<\/p>\n<p>Also lets not forget that &#8216;fred&#8217; can at any time kill any of those processes he has been granted ownership of, causing issues with the application within the container.<\/p>\n<h2>Operating system dependent<\/h2>\n<p>Containers are not truely portable, they should be considered operating system dependent and a container build on Fedora 30 should only run on a Fedora 30 host; and the container and host should be on similar patch levels. If an OS upgrade is done all containers should be rebuilt.<\/p>\n<p>Obviously this depends on the complexity of your container applications. One I have been working on requires &#8211;device mapping and overlaying the host \/lib\/modules directory over the container&#8230; because when the container is run &#8216;uname&#8217; reports the host kernel level not the kernel version the container was build from so the container does not have the correct modules. But it is fair to say a container OS must be a very close match to the host OS in order to function.<\/p>\n<h2>Summary<\/h2>\n<p>If you are security conscious you would not consolidate applications running on KVM hosts into Docker containers.<\/p>\n<p>If your environment is secure and totally locked down then docker containers can be used to consolidate applications running on KVM instances. You will get no application memory savings from moving an application (if an app needs 1Gb to run on a KVM instance it will still need 1Gb to run in a Docker container) but you will get around 750Mb OS alone overhead back from each KVM instance shutdown if you are migrating from KVM to Docker.<\/p>\n<p>And of course containers start faster than booting a KVM, which I personally do not consider a selling point. If designed properly images enable copies of applications to be started in containers on multiple hosts with minimal effort, of course KVM live migration has been a thing for a long time now so thats not really a major selling point either. Being able to encapulate an entire online application in an image is useful.<\/p>\n<p>Docker networking between Docker containers in a multihost docker engine environment is much hyped, and much is touted about docker swarms, so I&#8217;m sure docker internal networking works well although I have not needed to play with any of that stuff.<\/p>\n<p>External networking from the docker containers is another issue. One network issue I have already highlighted above, from a troubleshooting viewpoint on the host.<\/p>\n<p>There are many other networking issues I will probably cover in a later post, when I figure out how to resolve them, lets just say if your docker container needs pass-through access to external hosts outside the internal docker network, prepare for a long frustrating time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Docker is not KVM, there are major security trade-offs with a container, The key ones are shown below. Processes are not isolated The processes that are run by containers run for all intents and purposes as processes on the Docker &hellip; <a href=\"https:\/\/mdickinson.dyndns.org\/php\/wordpress\/?p=935\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-935","post","type-post","status-publish","format-standard","hentry","category-my-nux-thoughts-and-notes"],"_links":{"self":[{"href":"https:\/\/mdickinson.dyndns.org\/php\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/935","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mdickinson.dyndns.org\/php\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mdickinson.dyndns.org\/php\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mdickinson.dyndns.org\/php\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/mdickinson.dyndns.org\/php\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=935"}],"version-history":[{"count":3,"href":"https:\/\/mdickinson.dyndns.org\/php\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/935\/revisions"}],"predecessor-version":[{"id":938,"href":"https:\/\/mdickinson.dyndns.org\/php\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/935\/revisions\/938"}],"wp:attachment":[{"href":"https:\/\/mdickinson.dyndns.org\/php\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=935"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mdickinson.dyndns.org\/php\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=935"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mdickinson.dyndns.org\/php\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=935"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}