[HN Gopher] Docker Security Cheat Sheet
       ___________________________________________________________________
        
       Docker Security Cheat Sheet
        
       Author : soheilpro
       Score  : 241 points
       Date   : 2021-03-13 13:15 UTC (9 hours ago)
        
 (HTM) web link (cheatsheetseries.owasp.org)
 (TXT) w3m dump (cheatsheetseries.owasp.org)
        
       | Layke1123 wrote:
       | Yet another list of potentially extremely useful concepts that
       | I'll never actually have the time to fully verify.
       | 
       | I wonder where all this complexity ends. If a human can't fully
       | grok the systems we work on, then there is no way we can hope to
       | not be misled and taken advantage of. Does anyone else share
       | these concerns?
        
         | bob1029 wrote:
         | I absolutely share these concerns.
         | 
         | The art of software engineering is about managing complexity.
         | The best way to manage something is to reduce the amount of it
         | you have to worry about. For the rest, paying really close
         | attention, accepting ownership and directly engaging is key.
         | Reducing the number of parties you have to trust is typically a
         | happy side-effect of reducing complexity.
         | 
         | I look at containerization as an attempt to hand-wave away
         | critical responsibilities around ownership of complexity in an
         | application. There are tons of examples that illustrate this
         | throughout the ecosystem, but I think this one is most apt -
         | 
         | One day you discover your application is a difficult mess to
         | reconstruct from source each time. You have reached a fork in
         | the road because management is complaining that it takes 2
         | weeks to configure a new QA environment from scratch. Do you
         | either:
         | 
         | A) Review fundamental assumptions about the problem domain,
         | technology choices and teamwork. Potentially consider rewriting
         | your application from scratch using fewer tools & computers,
         | and with more focus on driving the actual business value
         | equations.
         | 
         | Or,
         | 
         | B) Decide that Tom's computer is the new golden image of
         | production and bless it as such. Now let's find a way to manage
         | a whole farm of these things!
        
           | geofft wrote:
           | The actual answer people come up with is neither of those.
           | The process of moving your application to run in containers
           | generally doesn't involve snapshotting Tom's computer - it
           | usually wouldn't even _work_ inside Docker for myriad
           | reasons.
           | 
           | And the Dockerfile format is a good way of capturing what it
           | actually takes to reconstruct your application/environment
           | from source in a manageable, version-control-able text file.
           | 
           | I do agree that the rush to containerization is generally a
           | rush to draw expansive abstraction boundaries, but this
           | particular story isn't what people are doing. (At least not
           | with containers - it's certainly what people were doing with
           | VM images ten years ago!)
        
         | deadbytes wrote:
         | A large majority of people in tech seem to have convinced
         | themselves that you solve complexity by adding even more
         | complexity ontop.
         | 
         | Yes, linux security is complicated. So why not work on
         | improving this instead? Optimise and simplify what we already
         | have.
         | 
         | Docker hasn't made the complexity of linux security go away. It
         | has just added a whole other dimension of potential security
         | issues people now need to manage in addition to the security of
         | the base system.
         | 
         | Programmers need to shift their mindset. We already have far
         | too much complexity. Stop thinking about what new things you
         | can create, start thinking about how you can improve and
         | simplify the software that we already have.
        
           | smw wrote:
           | It _has_ gotten simpler, especially for things like testing
           | safely. If you don 't think about it as docker, or
           | containers, the ability to sandbox things with namespaces and
           | cgroups is almost magical. It's effectively instant and much
           | more effective than just chroot.
           | 
           | "Run something with no -- or very specific -- network access"
           | was a really annoying problem to solve (LD_PRELOAD?) in the
           | before times.
        
           | paulryanrogers wrote:
           | Docker solves a few other problems too, like conflicting
           | dependencies in user space. Still, I agree the broader point
           | that one can't solve too much abstraction with more
           | abstraction.
        
         | closeparen wrote:
         | I think what you should take away from this is that containers
         | are not the abstraction you want for running mutually
         | distrusting workloads, and you can continue to use separate VMs
         | or even separate physical networks of bare metal servers. Some
         | people will geek out about this quixotic undertaking; you don't
         | have to be one of them.
         | 
         | Linux is not very good at security boundaries anyway, just run
         | one thing in each VM and don't leave anything else there to
         | privilege-escalate into.
        
         | ButterWashed wrote:
         | I feel this way every time I read an OpenSCAP or CIS lockdown
         | policy. They're hundreds of pages of "recommendations" that I
         | think I can trust but don't fully understand. I don't know if I
         | should worry about my lack of understanding or not.
        
           | blowski wrote:
           | My Grandad was an illiterate farmer. He didn't understand the
           | technology he used either, but it didn't matter as long as it
           | worked or he could call someone to fix it. Somebody who lives
           | 100% this stuff will abstract it and solve the problem for
           | you, just as others did then.
           | 
           | But do consider the list when some junior says they can get
           | the company billing system running on Docker on prod.
        
         | 3np wrote:
         | As a docker user, most of this aligns with my understanding,
         | it's mostly straight forward stuff and not inherently complex.
         | 
         | Try SELinux and see if you think this is still complicated ;)
         | 
         | ADD vs COPY was new to me, though.
         | 
         | ...More in general, I think it's not the systems that are
         | complex but our minds/brains that are limited to deal with it.
         | Just look at the complexity in nature.
        
         | the8472 wrote:
         | As always, it depends?
         | 
         | If you're only using docker for development to bundle things in
         | a different OS base image then there's not that much need for
         | paranoia. You probably would trust the other OS vendor with
         | your host system too. Running docker without security may be
         | perfectly fine in that case.
         | 
         | For random scripts from github running them in docker is mostly
         | a precaution so they don't screw up your host system or some
         | malicious dependency makes a low-effort attempt at exfiltrating
         | your ~/.ssh dir or whatever. In that case it makes sense to
         | understand the basics, e.g. not just running docker
         | --privileged willy-nilly just because some README asks you to.
         | 
         | If you're running some PaaS container service where users can
         | execute arbitrary code on shared hardware then you better have
         | a full-time security engineer or two who will be paid to
         | understanding all the details involved.
        
         | eeZah7Ux wrote:
         | Yes. Stay away from Docker or anything so complex. systemd-
         | nspawn does the same things and can be sandboxed very
         | effectively by the unit files.
        
         | nikisweeting wrote:
         | As a sysadmin that that worked on securing linux apps before
         | docker was a thing, imo doing it with docker is a lot less
         | complex than before.
         | 
         | No tech is perfect, but docker has dramatically reduced the
         | surface area of tunables that my application devs have to care
         | about in order to get our product shipped. Even if it's not
         | brought it down to zero, it's a step in the right direction in
         | terms of UX complexity exposed to the developer.
        
       | SkipperCat wrote:
       | Good article for some basic rules to keep your containers safe.
       | That being said, I violate rule #1 all the time. If you want to
       | have containers that launch other containers (we do that for
       | Apache Airflow), you don't have much other choice. Also, cAdvisor
       | requires that mount for monitoring.
       | 
       | Of course, if you're running containers in a ephemeral VM, no
       | biggie.
        
       | kodah wrote:
       | Rule #2 needs lots of nuance stacked on it.
       | 
       | Host-users and guest-users must be explicitly mapped by whomever
       | starts the container, so this issue is not a security threat to
       | outside of the container. That said, if a guest-os is running as
       | root and then someone compromises it, they have at their disposal
       | all the powers of root _in that container_.
       | 
       | OWASP has also mixed good container guidance with "Docker" as
       | well as some Docker specific things, which I'd like to maintain a
       | delineation with now and into the future because they _are_
       | different. I understand most uneducated people are looking for
       | "how do I do x in Docker" but subtly educating the user matters
       | for broader discourse.
        
         | rzimmerman wrote:
         | "Don't run as root in the container" definitely gets parroted
         | without the nuance you describe. Gaining root in a container
         | does not generally mean anything has been compromised on the
         | host. Unless you do something odd (like mounting the host
         | docker socket, weird setuid stuff, or run as privileged) it
         | should be fine to run the container processes as root. It's
         | kind of the main point of running a process in a docker
         | container.
         | 
         | I understand the motivation of marking scripts and binaries as
         | non-writable inside the container as an extra layer of
         | assurance (along with a non-root user that can only execute).
         | But it's a disservice to developers if you don't explain why. A
         | lot of people walk away from this thinking they're protecting
         | the host OS and wind up cargo-cult-creating a container user
         | with full write/execute permissions.
        
       | nrvn wrote:
       | CIS Docker benchmark is a very extensive rule set for assessing
       | docker host, daemon, images and containers from the security
       | perspective.
       | 
       | It comes with a very handy tool as well
       | https://github.com/docker/docker-bench-security
        
       | hivacruz wrote:
       | I use Hadolint[1] as a CI job to check if my Dockerfiles follow
       | the good "rules". But there is one rule that annoys me the most
       | and which is also present in this article, is the pinned OS
       | package version rule[2]. While I understand its interest, I
       | struggle to handle this problem.
       | 
       | When I build new images and it fails because the pinned version
       | is not available anymore, I have to dig into Debian or Ubuntu
       | packages websites to find the new ones as they don't keep the old
       | packages online.
       | 
       | I know I could ask Hadolint to ignore this rule but I don't like
       | this and I think it's important to stick to a certain version of
       | a package to avoid problems. I'm just trying to find any tip that
       | could make me use pinned version and avoid this manual search
       | every time I have to. Does apt-get install allows wildcard for
       | example?
       | 
       | 1: https://github.com/hadolint/hadolint
       | 
       | 2: https://github.com/hadolint/hadolint/wiki/DL3008
        
         | yrro wrote:
         | snapshot.debian.org?
        
           | teddyh wrote:
           | http://archive.debian.org/debian/
        
         | forty wrote:
         | You could use renovate [1] to watch your repository and open pr
         | for you when there is a new version. I don't know if it
         | supports watching debian repositories out of the box, but
         | that's probably doable with some tweaking
         | 
         | [1] https://github.com/renovatebot/renovate
        
       | terom wrote:
       | A big :+1: for running Docker containers with `--read-only`,
       | forcing you to use explicit writeable volume/bind mounts for all
       | writable data... it's not just the security benefits, you can
       | also avoid entire classes of problems like:
       | 
       | * minimizing the difference between `docker restart` (preserves
       | overlayfs changes) and container re-creates (resets overlayfs
       | back to the image state)
       | 
       | * surprise data loss on container redeployments because data was
       | unexpectedly being written to the overlayfs instead of a volume
       | 
       | * unexpectedly running out of disk space in `/var/lib/docker`
       | because data was being written outside of a volume
       | 
       | * performance issues caused by excessive overlayfs writes
       | (storage drivers and /var/lib/docker not necessarily designed for
       | IO performance)
        
         | corytheboyd wrote:
         | I was just thinking the other day about how best to manage
         | third party containers that write various logs, preventing them
         | from filling up disk space over time and crashing. This is a
         | perfect solution, assuming the third party container is good
         | about telling you every volume it needs write access to, etc.
        
           | qbasic_forever wrote:
           | If you're running into containers that are writing logs to
           | files, IMHO that's a code smell and something is off with how
           | they're using containers. Most of the container ecosystem has
           | settled on stdout and stderr as the defacto log locations and
           | then leave it up to the container orchestrator (docker-
           | compose, k8s, etc.) to deal with the log data. There might be
           | some good reasons to use files for logs, but in 2021 they're
           | likely exceptions and not the norm.
        
         | nrvn wrote:
         | I am a big fan of read-only rootfs. But for some third party
         | containers it may be challenging to apply this. In most cases
         | it is not a big deal but sometimes you end up with a bunch of
         | tmpfs mounts for those paths where it is required.
        
       | stunt wrote:
       | Quick tips to find out if your any of the tests in your project
       | are actually making outbound calls: Run it without networking
       | (--network=none)
        
         | rkeene2 wrote:
         | You can also do this without Docker. I do this as part of my
         | build system (which is just a bash script) for a Linux
         | distribution. Each package has a download phase, which permits
         | network access. After that phase completes, network access is
         | dropped.
         | 
         | https://chiselapp.com/user/rkeene/repository/bash-drop-netwo...
        
       | imwillofficial wrote:
       | Everyone running docker in their homelab should be reading this.
        
       | scaladev wrote:
       | All of these isolation techniques (and much more) can be used
       | inside systemd units. Write your .service as usual, then run this
       | command on it:                 $ systemd-analyze security
       | service-name
       | 
       | It prints out a long list of hardening flags that can be applied
       | inside of your service, like so:                   NAME
       | DESCRIPTION
       | EXPOSURE        PrivateNetwork=
       | Service has access to the host's network
       | 0.5        User=/DynamicUser=
       | Service runs as root user
       | 0.4        CapabilityBoundingSet=~CAP_SET(UID|GID|PCAP)
       | Service may change UID/GID identities/capabilities
       | 0.3        CapabilityBoundingSet=~CAP_SYS_ADMIN
       | Service has administrator privileges
       | 0.3       ...
       | 
       | Here's what I typically use for a .NET 5 application:
       | WorkingDirectory        = /opt/appname/app       ReadWritePaths
       | = /opt/appname/data       UMask                   = 0077
       | LockPersonality         = yes       NoNewPrivileges         = yes
       | PrivateDevices          = yes       PrivateMounts           = yes
       | PrivateTmp              = yes       PrivateUsers            = yes
       | ProtectClock            = yes       ProtectControlGroups    = yes
       | ProtectHome             = yes       ProtectHostname         = yes
       | ProtectKernelLogs       = yes       ProtectKernelModules    = yes
       | ProtectKernelTunables   = yes       ProtectSystem           =
       | strict       RemoveIPC               = yes
       | RestrictAddressFamilies = AF_UNIX AF_INET AF_INET6
       | RestrictNamespaces      = yes       RestrictRealtime        = yes
       | RestrictSUIDSGID        = yes       SystemCallArchitectures =
       | native       ProtectProc             = invisible
       | CapabilityBoundingSet   =       SystemCallFilter        = ~@clock
       | @module @mount @raw-io @reboot @swap @privileged @cpu-emulation
       | @obsolete
       | 
       | ReadWritePaths should be replaced with a combination of
       | DynamicUser + writing local persistent data to $STATE_DIRECTORY,
       | but I'm too lazy to do that yet.
       | 
       | See systemd.exec(5) for more.
        
         | nikisweeting wrote:
         | What's the systemd equivalent to docker-compose? The real
         | value-add of Docker imo is not the security, it's the easy
         | packaging, distribution, and running of otherwise complicated
         | apps.
        
           | dundarious wrote:
           | Writing N systemd service files with After=, etc., to match
           | your docker-compose.yml that has N services in it.
           | 
           | I have ported a few docker-compose.yml-s this way, because I
           | don't understand docker enough to troubleshoot issues with
           | getting my firewall rules to apply to docker traffic.
           | Dependency hell is not an issue for these projects, so I feel
           | happier with systemd.
        
         | CameronNemo wrote:
         | Well sure, but I'm not using systemd. If I wanted a container
         | runtime written in C, I would use crun. But I'd rather not use
         | that either.
        
           | goatinaboat wrote:
           | _Well sure, but I 'm not using systemd._
           | 
           | I hear you but fighting systemd in 2021 is like pushing water
           | uphill. With a fork.
        
         | eeZah7Ux wrote:
         | This is excellent advice. Together with systemd-nspawn it's all
         | one needs to run a container in a strong sandbox.
        
       | kayson wrote:
       | This seems a little out-dated because --link is now a legacy
       | feature: https://docs.docker.com/network/links/
       | 
       | Correct me if I'm wrong, but by default, containers can't
       | communicate with each other even if ICC isn't disabled because
       | the daemon gives them unique "default" networks. Only if you
       | specify the same network for different containers can they
       | communicate...
       | 
       | Edit: this behavior is specific to docker-compose. If you do
       | docker run without specifying a network, it does use the docker0
       | bridge.
        
       ___________________________________________________________________
       (page generated 2021-03-13 23:01 UTC)