Por que os processos em contêineres do Docker não devem ser executados como root

0
38


Os processos em um contêiner do Docker não devem ser executados como root. É mais seguro executar seus aplicativos como um usuário não root que você especifica como parte do seu Dockerfile ou quando você usa docker run. Isso minimiza o risco apresentando uma superfície de ataque reduzida para quaisquer ameaças em seu contêiner.

Neste artigo, você aprenderá sobre os perigos de executar aplicativos em contêiner como root. Você também verá como criar um usuário não root e configurar o namespace em situações em que isso não for possível.

Por que é perigoso executar como root?

Os contêineres são executados como root por padrão. O daemon do Docker é executado como root em seu host e os contêineres em execução também serão root.

Embora o root dentro do contêiner possa parecer um usuário separado, na verdade é o mesmo que a conta root em seu host. A separação é fornecida apenas pelos mecanismos de isolamento de contêiner do Docker. Não há limite físico forte; seu container é outro processo executado pelo usuário root no kernel do seu host. Isso significa que uma vulnerabilidade em seu aplicativo, no tempo de execução do Docker ou no kernel do Linux pode permitir que invasores saiam do contêiner e executem operações com privilégios de root em sua máquina.

Existem algumas proteções internas que reduzem o risco de isso acontecer. A raiz dentro do contêiner não é privilegiada e tem recursos restritos. Isso impede que o contêiner use comandos de administração do sistema, a menos que você adicione recursos manualmente ou use o modo privilegiado ao iniciar seus contêineres.

Apesar dessa mitigação, permitir que aplicativos sejam executados como root ainda é um perigo. Assim como você restringiria o uso de root em um ambiente tradicional, não é aconselhável usá-lo desnecessariamente em seus containers. Você está fornecendo um ambiente superprivilegiado que oferece aos invasores uma base maior caso ocorra uma violação.

Executando aplicativos em contêiner como um usuário não root

É uma boa prática que aplicativos em contêiner sejam executados como um usuário normal. A maioria dos softwares não precisa de acesso root, portanto, alterar o usuário fornece uma camada imediata de defesa contra a quebra do contêiner.

Você deve criar uma nova conta de usuário como uma das etapas finais em seu Dockerfile. Você pode conseguir isso com o USER instrução:

FROM base-image:latest
RUN apt install demo-package
USER demo-user:demo-group
ENTRYPOINT ["demo-binary"]

Os contêineres iniciados a partir desta imagem serão executados como demo-user. O usuário será um membro do demo-group conjunto. Você pode omitir o nome do grupo se não precisar que o usuário esteja em um grupo:

USER demo-user

Você pode especificar um ID de usuário (UID) e um ID de grupo (GID) em vez de nomes:

USER 950:950

A atribuição de um UID e GID conhecido geralmente é a maneira mais segura de proceder. Impede que o usuário do contêiner seja atribuído a uma conta de host com privilégios excessivos.

USER geralmente é especificado como o penúltimo estágio em um Dockerfile. Isso significa que você ainda pode executar operações que exigem root anteriormente na compilação da imagem. a apt install declaração no exemplo acima tem uma necessidade legítima de root. Se ele USER a instrução foi colocada em cima dele, apt correria como demo-user Faltaria as licenças necessárias. Como as instruções do Dockerfile se aplicam apenas a compilações de imagem, não executando contêineres, é seguro deixar a alternância de usuário para mais tarde em seu Dockerfile.

Alterar o usuário que está executando seu contêiner pode exigir que você atualize as permissões nos arquivos e pastas que ele acessa. Defina a propriedade para qualquer rota que seu aplicativo usará:

COPY initial-config.yaml /data/config.yaml

USER demo-user:demo-group
RUN chown demo-user:demo-group /data

Neste exemplo o /data o diretório deve ser de propriedade de demo-user para que o aplicativo possa fazer alterações em seu arquivo de configuração. O anterior COPY declaração terá copiado o arquivo como root. Um pequeno formulário está disponível usando o --chown bandeira com copy:

COPY --chown=demo-user:demo-group initial-config.yaml /data/config.yaml

Alterar o usuário ao iniciar um contêiner

Embora você possa alterar facilmente o usuário em seus próprios Dockerfiles, muitos aplicativos de terceiros continuam sendo executados como root. Você pode reduzir o risco associado ao uso deles definindo o --user discar toda vez que você ligar docker run. Isso substitui o conjunto de usuários no Dockerfile da imagem.

$ docker run -d --user demo-user:demo-group demo-image:latest
$ docker run -d --user demo-user demo-image:latest
$ docker run -d --user 950:950 demo-image:latest

a --user sinalizador executa o processo do contêiner como o usuário especificado. É menos seguro que o Dockerfile USER instrução porque você tem que aplicá-lo individualmente a cada docker run domínio. Uma opção melhor para imagens usadas regularmente é criar sua própria imagem derivada que pode estabelecer uma nova conta de usuário:

FROM image-that-runs-as-root:latest
USER demo-user
$ docker build . -t image-that-now-runs-as-non-root:latest

Alterar o usuário de uma imagem de terceiros pode causar problemas: se o contêiner espera ser executado como root ou precisa acessar os caminhos do sistema de arquivos pertencentes ao root, você verá erros ao usar o aplicativo. Você pode tentar alterar manualmente as permissões nas rotas que estão causando problemas. Como alternativa, verifique se o fornecedor tem um método compatível para executar o aplicativo com uma conta de usuário sem privilégios.

Manipulando aplicativos que precisam ser executados como root

User namespace é uma técnica para lidar com aplicativos que precisam de alguns privilégios de root. Permite atribuir root em um contêiner a um usuário não root em seu host. A raiz simulada dentro do contêiner tem os privilégios necessários, mas uma pausa não fornecerá acesso root ao host.

A reatribuição de namespace é ativada adicionando um userns-remap campo para você /etc/docker/daemon.json procedimentos:

{
    "userns-remap": "default"
}

Vestindo default como o valor para userns-remap diz ao Docker para criar automaticamente um novo usuário em seu host chamado dockremap. A raiz dentro dos contêineres será mapeada de volta para dockremap em seu hospedeiro. Opcionalmente, você pode especificar um usuário e grupo existente, usando uma combinação de UID/GID ou nome de usuário/nome de grupo:

{
    "userns-remap": "demo-user"
}

Reinicie o daemon do Docker após aplicar sua alteração:

$ sudo service docker restart

se você estiver usando nsuser-remap: defaulta dockremap o usuário deve agora existir em seu host:

$ id dockremap

uid=140(dockremap) gid=119(dockremap) groups=119(dockremap)

O usuário também deve aparecer no /etc/subuid S /etc/subgid arquivos de ID subordinados:

$ dockremap:231500:65535

O usuário recebeu um intervalo de 65.535 IDs subordinados começando em 231.500. No namespace do usuário, ID 231500 é atribuído a 0, tornando-o o usuário root em seus contêineres. Sendo um UID de número alto, 231500 não tem privilégios no host, portanto, os ataques de violação de contêiner não poderão causar tantos danos.

Todos os contêineres que você iniciar serão executados usando o namespace de usuário reatribuído, a menos que você desative com docker run --userns=host. O mecanismo funciona criando diretórios com namespaces dentro /var/lib/docker que são de propriedade do UID e GID subordinados do usuário com namespace:

$ sudo ls -l /var/lib/docker/231500.231500

total 14
drwx------ 5 231500 231500 13 Jul 22 19:00 aufs
drwx------ 3 231500 231500 13 Jul 22 19:00 containers
...

O namespace de usuário é uma maneira eficaz de aumentar o isolamento do contêiner, evitar interrupções e preservar a compatibilidade com aplicativos que precisam de privilégios de root. No entanto, existem alguns prós e contras: o recurso funciona melhor em uma nova instância do Docker, os volumes montados a partir do host devem ter suas permissões ajustadas e alguns drivers de armazenamento externos não oferecem suporte ao mapeamento de usuários. Você deve revisar a documentação antes de adotar esta opção.

Resumo

A execução de aplicativos em contêiner como root é um risco de segurança. Embora fácil de ignorar, o isolamento fornecido pelos contêineres não é forte o suficiente para separar completamente os usuários do kernel dos usuários do contêiner. Root no container é o mesmo que root em seu host, então um commit bem sucedido pode dar a você o controle de sua máquina.

Como autor de uma imagem, você deve incluir o USER instrução em seu Dockerfile para que seu aplicativo seja executado sem root. Os usuários de imagem podem substituir isso por docker run --user para atribuir um UID e GID específicos. Isso ajuda a atenuar os casos em que a imagem normalmente usa root.

Você pode aumentar ainda mais a segurança removendo todos os recursos do contêiner usando --cap-drop=ALLem seguida, coloque na lista de permissões aqueles que são necessários com --cap-add flags A combinação dessas técnicas executará seu aplicativo como um usuário não root com o conjunto mínimo de privilégios que você precisa, melhorando sua postura de segurança.