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 seuDockerfile
com um conhecidoUID
eGID
, 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 ouid
egid
quando 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 doroot
vê-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.txt
que só oroot
consegue 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.txt
que não possa ler o arquivo/tmp/secrets.txt
dentro do container.
marc@srv:~$ docker run -v /root/secrets.txt:/tmp/secrets.txt <img>
top secret stuff
Mesmo sendomarc
, o container está rodando comoroot
e, portanto, tem acesso a tudo que oroot
tem 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 umuid
conhecido noDockerfile
e rodar a aplicação usando esse usuário. O começo doDockerfile
deve 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 meuDockerfile
de 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 deroot
no host.
Reusando outras imagens
Imagens Docker são incríveis por serem reutilizáveis, mas quando oFROM
de 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 comoroot
tenha certeza queUSER root
esteja próximo do topo de seuDockerfile
. EntãoFROM appuser
para 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 comoroot
e 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 oENTRYPOINT
origin e diretrizes doCMD
para 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 ouid
pro 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 user_id e ver os diferentes resultados(o user_id 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) noDockerfile
fará 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)
— -
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.
Top comments (0)