Introdução
Contêineres empacotam e executam aplicativos, mas o empacotamento, por si só, não escolhe uma identidade de processo segura. Este worker preparado do DeskLite gera um pequeno relatório de tickets e atualmente é executado como root.
Você aprenderá o fluxo mínimo de Docker e depois reconstruirá e executará o worker com uma identidade não root e apenas o acesso a arquivos necessário à sua tarefa. O Docker e uma imagem base fixa estão preparados; não é necessário ter conta em um registro de imagens nem experiência anterior com Docker.
Conheça o projeto de contêiner preparado
Nesta etapa, você identificará os arquivos que compõem a tarefa de geração de relatórios.
Uma imagem é um sistema de arquivos empacotado com uma configuração de inicialização. Um contêiner é uma instância em execução de uma imagem, com seus próprios processos e uma camada gravável de sistema de arquivos. Um Dockerfile descreve como construir uma imagem. Uma tag, como ticket-report:practice, é um nome conveniente para uma imagem; ela pode passar a apontar para uma nova imagem após uma reconstrução.
cd /home/labex/project/ticket-worker
ls
Espere Dockerfile, worker.sh, input e output. O worker preparado lê linhas CSV, grava sua contagem em um relatório e depois permanece em execução para que possamos inspecioná-lo.
cat input/tickets.csv
Há três linhas de tickets após o cabeçalho. O relatório esperado é tickets=3.
cat Dockerfile
FROM seleciona a imagem base em cache, WORKDIR seleciona o diretório de trabalho da imagem e COPY adiciona o worker. USER root escolhe a identidade do processo. CMD é o comando padrão de inicialização, representado como uma lista. Você alterará apenas USER.
A tag base desklite-base:1.37.0 já está em cache a partir de uma imagem BusyBox fixa. Todas as construções e execuções seguintes usam arquivos locais. Os comandos Docker usam sudo para acessar o daemon deste laboratório. Esse acesso no nível do host é poderoso; ele é separado da identidade do aplicativo que estamos restringindo dentro do contêiner.
Construa e execute o worker existente
Nesta etapa, você estabelecerá o estado inicial funcional, mas com privilégios excessivos.
docker build lê o Dockerfile e um contexto de construção, o diretório de arquivos disponíveis para COPY. Aqui, . significa o diretório atual. -t atribui a tag local à imagem:
sudo docker build -t ticket-report:practice .
Espere uma construção bem-sucedida. A imagem existe, mas nenhum worker está em execução ainda.
docker run cria um contêiner. -d o executa em segundo plano, e --name atribui um nome reutilizável. --network none desativa a rede porque este relatório precisa apenas de arquivos.
Uma montagem bind expõe um caminho do host em um caminho do contêiner. Cada --mount descreve seu tipo, origem (src) e destino (dst). Este estado inicial expõe ambos os diretórios como graváveis porque nenhuma opção readonly está presente. Restringiremos a entrada mais adiante.
sudo docker run -d --name ticket-worker --network none --mount type=bind,src=/home/labex/project/ticket-worker/input,dst=/data/input --mount type=bind,src=/home/labex/project/ticket-worker/output,dst=/data/output ticket-report:practice
O Docker imprime um ID de contêiner. Ele não é o ID de usuário do worker. O worker original deve gerar seu relatório, que inspecionaremos a seguir.
Inspecione a identidade real em execução
Nesta etapa, você distinguirá um relatório bem-sucedido de uma execução com privilégio mínimo.
docker ps lista os contêineres em execução:
sudo docker ps
Localize ticket-worker. docker logs lê a saída padrão do aplicativo:
sudo docker logs ticket-worker
Espere worker uid=0 e tickets=3. O UID 0 é root. A tarefa de negócio funciona, mas usa mais privilégios do que o necessário.
docker exec executa um comando de inspeção neste contêiner em execução. id -u imprime seu ID numérico de usuário efetivo:
sudo docker exec ticket-worker id -u
Espere 0 novamente. docker inspect lê a configuração. --format seleciona um campo; copie exatamente o modelo entre aspas. .Config.User é o usuário configurado:
sudo docker inspect --format '{{.Config.User}}' ticket-worker
Espere root. A configuração da imagem e a inspeção do processo real correspondem. Um arquivo dizendo "não root" não forneceria essa evidência.
Reconstrua com o usuário não root preparado
Nesta etapa, você definirá a identidade padrão do aplicativo na imagem.
A base em cache já inclui nobody, UID 65534. Não é necessário criar usuário nem senha. Abra o Dockerfile:
nano Dockerfile
Altere apenas a instrução USER. O arquivo completo deve ser:
FROM desklite-base:1.37.0
WORKDIR /app
COPY worker.sh /app/worker.sh
USER nobody
CMD ["sh", "/app/worker.sh"]
Salve com Ctrl+O, Enter e saia com Ctrl+X.
sudo docker build -t ticket-report:practice .
Agora a tag identifica a imagem reconstruída. Contêineres existentes não passam automaticamente a usar uma imagem reconstruída; o antigo contêiner root ainda é a instância antiga. Na próxima etapa, você o substituirá e concederá à nova identidade o acesso necessário à saída.
Substitua o contêiner com montagens restritas
Nesta etapa, você combinará a identidade não root com permissões de arquivos funcionais.
docker rm remove um contêiner. -f primeiro o interrompe, se estiver em execução. Remova apenas o contêiner nomeado deste exercício:
sudo docker rm -f ticket-worker
Inicialmente, o diretório do relatório pertencia a root. Como no laboratório de permissões de arquivos, um processo não root precisa de propriedade e permissão para gravar sua saída. chown -R altera recursivamente o diretório e seu relatório existente para o UID e o GID 65534. O modo 750 dá acesso completo ao proprietário sem acesso público de gravação:
sudo chown -R 65534:65534 output
sudo chmod 750 output
Agora crie o substituto. A montagem de entrada adiciona readonly; a montagem de saída permanece gravável. Isso impede a modificação da entrada e permite gerar o relatório:
sudo docker run -d --name ticket-worker --network none --mount type=bind,src=/home/labex/project/ticket-worker/input,dst=/data/input,readonly --mount type=bind,src=/home/labex/project/ticket-worker/output,dst=/data/output ticket-report:practice
Espere um novo ID de contêiner. Agora a imagem fornece o usuário não root; não é necessário substituí-lo por root na execução.
Verifique a identidade, o acesso e a saída de negócio
Nesta etapa, você verificará as três partes do resultado no contêiner substituto.
sudo docker exec ticket-worker id -u
Espere 65534. Verifique a saída real do worker:
sudo docker logs ticket-worker
Espere worker uid=65534 e tickets=3. Leia o arquivo real de saída por meio do contêiner:
sudo docker exec ticket-worker cat /data/output/report.txt
Espere tickets=3. Isso comprova que reduzir os privilégios não interrompeu a tarefa.
Inspecione as montagens. O modelo entre aspas seleciona .Mounts e o formata como JSON:
sudo docker inspect --format '{{json .Mounts}}' ticket-worker
Localize /data/input com "RW":false e /data/output com "RW":true. RW significa leitura/gravação. Os mesmos bytes de entrada estão disponíveis para leitura, mas a montagem nega a gravação.
Tente criar um arquivo inofensivo para testar essa restrição. touch criaria um arquivo vazio se fosse permitido:
sudo docker exec ticket-worker touch /data/input/probe.txt
Espere um erro Read-only file system e um código de saída diferente de zero. Essa recusa é intencional. Não torne a entrada gravável para eliminá-la; o relatório já foi gerado com sucesso usando a entrada somente leitura.
Confirme que o worker final continua em execução
Nesta etapa, você deixará o worker pretendido pronto para inspeção.
sudo docker ps
O contêiner nomeado ticket-worker deve estar em execução. Confirme mais uma vez o usuário configurado e o relatório:
sudo docker inspect --format '{{.Config.User}}' ticket-worker
sudo docker exec ticket-worker cat /data/output/report.txt
Espere nobody e tickets=3. A verificação do curso também compara a imagem em execução com sua tag de entrega, verifica o PID real do worker e testa a entrada e a saída originais. Reconstruir um Dockerfile sem substituir o contêiner é insuficiente.
Este exercício restringe a identidade do aplicativo e o acesso a arquivos. Ele não torna o acesso ao daemon Docker sem privilégios nem estabelece uma política completa de fortalecimento de segurança de contêineres em produção.
Resumo
Você construiu uma imagem real com uma identidade de aplicativo não root, executou essa imagem com entrada restrita e acesso funcional à saída e verificou o processo e o relatório reais. A configuração da imagem, a identidade em execução, os modos de montagem e o comportamento funcional contribuem para o estado final.



