<devzera

Aprendendo e compartilhando tecnologia

Processos em containers não devem ser executados como root

Esse artigo é uma tradução livre deProcesses In Containers Should Not Run As RootporMarc Campbell.

tldr;

Um processo dentro de um container não deve rodar com privilégios de root, assuma isso como verdade.

Ao invés disse, crie um usuário em seuDockerfilecom um conhecidoUIDeGID, e execute seu processo usando esse usuário. Imagens construídas sobre esse padrão são mais fáceis de serem executadas de forma segura por limitar o acesso a determinados recursos.

Overview

Sistemas bem arquitetados aderem aoprincípio do menor privilégio. Esse princípio diz que um aplicativo deve ter acesso apenas aos recursos necessários para executar a função necessária. Isso é muito importante quando desejamos fazer um sistema seguro. Seja malicioso ou por causa de erros, um processo pode ter consequências inesperadas em tempo de execução. Um dos melhores modos de se proteger contra qualquer acesso inesperado é conceder o mínimo privilégio para que um processo seja executado.

A maior dos processos containerizados são serviços de aplicações, sendo assim, elas não precisa de acesso comoroot. Enquanto oDocker precisa ser executado como root, os containers em si, não. Imagens Docker bem escritas, seguras e reutilizáveis ​​não devem ser executadas como root e devem fornecer um método previsível e fácil para limitar o acesso.

Por que isso é importante?

Lembre-se que um processo em execução em um container não é diferente de outro processo em execução no Linux, exceto que ele tem um pequeno pedaço de metadata informando que ele está sendo executado em um container.

Os containers são tão seguros quanto sua máquina host, portanto, qualquer coisa executada em um container deve ser tratada com a mesma consideração que qualquer coisa executada no próprio host.

Assim como você não faria (ou não deveria) executar qualquer coisa como root em seu servidor, você não deveria executar nada como root em um container em seu servidor. Executar binários que foram criados em outro lugar requer confiança, e o mesmo é verdadeiro para binários em containers.

Se um processo dentro de um container for executada como root por default, é possível mudar ouidegidquando o container for iniciado. Sendo o criador da imagem, você deve usar como padrão um usuário diferente e facilitar a limitação de acesso para ele. Criando um usuário em seuDockerfile, você está tornando não apenas ele seguro por padrão, mas também mais fácil de continuar seguro.

O exemplo abaixo mostrará o risco de executar um container comoroot. Vamos criar um arquivo no diretório/root, impedindo qualquer um diferente dorootvê-lo:

marc@srv:~$ sudo -s
root@srv:~# cd /root
root@srv:~# echo "top secret stuff" >> ./secrets.txt 
root@srv:~# chmod 0600 secrets.txt
root@srv:/root# ls -l
total 4
-rw------- 1 root root 17 Sep 26 20:29 secrets.txt
root@srv:/root# exit
exit
marc@srv:~$ cat /root/secrets.txt
cat: /root/secrets.txt: Permission denied

Agora eu tenho um arquivo/root/secrets.txtque só orootconsegue ver. Estou logado como um usuário normal(não root). Vamos criar uma imagem Docker a partir desse Dockerfile:

FROM debian:stretch
CMD ["cat", "/tmp/secrets.txt"]

E finalmente, vamos executar esseDockerfile, montando um volume a partir do/root/secrets.txtque não possa ler o arquivo/tmp/secrets.txtdentro do container.

marc@srv:~$ docker run -v /root/secrets.txt:/tmp/secrets.txt <img>
top secret stuff

Mesmo sendomarc, o container está rodando comoroote, portanto, tem acesso a tudo que oroottem acesso neste servidor. Isso não é o ideal; A execução de containers dessa maneira significa que todos os containers que você acessa do Docker Hub podem ter acesso total a tudo em seu servidor (dependendo de como você o executa).

Recomendação

A recomendação é criar um usuário com umuidconhecido noDockerfilee rodar a aplicação usando esse usuário. O começo doDockerfiledeve seguir o seguinte padrão:

FROM <base image>
RUN groupadd -g 999 appuser && \
    useradd -r -u 999 -g appuser appuser
USER appuser
... <rest of Dockerfile> ...

Usando esse padrão é fácil executar um container no contexto do usuário/grupo com o mínimo de privilégios necessários.

Por exemplo, adicionarei isso ao meuDockerfilede cima, e o executarei novamente. Meu arquivo ficou assim:

FROM debian:stretch
RUN groupadd -g 999 appuser && \
    useradd -r -u 999 -g appuser appuser
USER appuser
CMD ["cat", "/tmp/secrets.txt"]

Executando esse container com o mesmo comando de antes:

marc@srv:~$ docker run -v /root/secrets.txt:/tmp/secrets.txt <img>
cat: /tmp/secrets.txt: Permission denied

Agora, o comportamento padrão do container é que ele não terá privilégios derootno host.

Reusando outras imagens

Imagens Docker são incríveis por serem reutilizáveis, mas quando oFROMde uma imagem é executado através de um usuário normal, seu container herdará esse usuário. Se você precisar criar sua própria imagem ou executar operações comoroottenha certeza queUSER rootesteja próximo do topo de seuDockerfile. EntãoFROM appuserpara torná-lo utilizável.

Executando outros containers como usuários normais (non-root)

Imagens Docker são feitas para serem portáteis, e é normal obter outras imagens do Docker Hub. Algumas delas (imagens oficiais) seguirão as melhores práticas e serão executadas como usuários normais (non-root), mas muitas imagens não fazem isso. Muitas simplesmente executam as coisas comoroote deixam pra você descobrir como executar as coisas com segurança. Existem opções que permitirão você rodar uma imagem de forma segura que não foi criada por você.

Criando outra imagem

Primeiro, uma opção é criar outra imagem usando a imagem original com a camadaFROM. Então você poderá criar um usuário, e copiar oENTRYPOINTorigin e diretrizes doCMDpara sua própria imagem. Isso resultará em uma nova imgem que seguirá as boas práticas citadas aqui, garantindo que sua execução ocorra de forma segura. O que pode incomodar nesse ponto é que você precisará rebuildar sua imagem quando a imagem base for atualizada. Você terá que configurar um processo para fazer esse rebuild quando a imagem base for rebuildada.

Especificando um uid quando iniciando um container

Finalmente você pode criar um usuário no host e passar ouidpro Docker quando o container for iniciado. Por exemplo, revisitando o exemplo doDockerfile:

FROM debian:stretch
CMD ["cat", "/tmp/secrets.txt"]

Eu consigo executar esse container com ou sem o parâmetro userid e ver os diferentes resultados(o userid 1001 representa minha conta atual nesse servidor):

$ docker run --user 1001 -v /root/secrets.txt:/tmp/secrets.txt <img>
cat: /tmp/secrets.txt: Permission denied

$ docker run -v /root/secrets.txt:/tmp/secrets.txt <img>
top secret stuff

Isso funciona e é a mesma coisa que criar um usuário noDockerfile, mas requer que o usuário opte por executar o container com segurança. Especificar um usuário normal (non-root) noDockerfilefará com que o container seja executado com segurança por padrão.

Para leitura futura

Understanding how uid and gid work in Docker containers

Official reference to the Docker Run command (Docker)

Docker Security

— -

Se você está usando Docker para lançar uma aplicação SaaS, você deveria verificarwww.replicated.compara poder lançar uma versão corporativa e instalável do seu produto.

Comentários