Pular para o conteúdo principal

Container Immutability

O que isso significa?

O container não será modificado durante seu tempo de vida. Nada será adicionado ou removido do container. Caso seja necessário outra imagem será criada com a devida modificação e uma nova instância será criada.

A vantagem dessa abordagem é que sempre sabemos o estado em que o container se encontra. Entrar em uma aplicação e alterar uma configuração não será possível replicar novamente.

Container imutáveis nos permite:

  • Utilizar métodos avançados de deployment
  • Facilidade no rollback
  • Maior confiabilidade
  • Melhor segurança (em nível de container), pois sempre podemos criar um novo tendo certeza que não existe nenhuma processo malicioso rodando.

A imutabilidade e a facilidade de queimar novas imagens é um dos motivos que tornaram os containers tão populares.

O que podemos fazer para ter certeza que os containers estão imutáveis.

  • Remover bash/shell para que não seja possível iteragir com o container.
  • Tornar o file system read only para que não seja possívei escrever
  • Rodar com um usuário e não com o root.

Isso é o que manda as boas práticas e como fazer o hardening de um container.

Mas e se não tivermos o controle das imagens dos containers? Nesse caso sempre é possível utilizar a image como base e alterar gerando uma nova.

Se ainda sim não for possível é possível fazer algumas coisas.

Podemos alterar o command e passar todos os comandos que quisermos e por ultimos chamar o comando que rodará o container.

  containers:
- image: nginx
name: nginx
# recomendo toda permissão de escrita recursivamente antes de chamar o executavel do nginx
command:
- "chmod a-w -R / && nginx"
resources: {}

Ainda podemos resolver isso usando o startup probe que é bem similar ao readness ou liveness probes, porém esses dois últimos somente irão ser executados depois que o startup probe obtiver sucesso caso contrário o container ficará restartando todo tempo. Desta forma não precisaremos nem conhecer o entrypoint do container.

  containers:
- image: nginx
name: nginx
startupProbe:
exec:
command:
- chmod
- a-w -R /
initialDelaySeconds: 1
periodSeconds: 5

Esses método acima são possíveis, mas não é por que é possível que devermos fazer isso.

A melhor maneira seria impor read only no /root usando o SecurityContext e ou PodSecurityPolicies.

  containers:
- image: httpd
name: httpd
securityContext:
readOnlyRootFilesystem: true

Porém esse pod irá precisar escrever em /usr/local/apache2/logs. Quando isso acontecer podemos montar um emptyDir.

  containers:
- image: httpd
name: httpd
securityContext:
readOnlyRootFilesystem: true
volumeMounts:
- mountPath: /usr/local/apache2/logs
name: logs
volumes:
- name: logs
emptyDir: {}

Se transportamos isso para o mundo do docker seria como executar o comando abaixo.

docker run --read-only --tmpfs /run my-container

Ainda poderíamos usar o recurso do init container que inicia antes da aplicação, prepara o terreno e somente depois que termina será disparado o container da aplicação. Se o init container preparar o volume que será usado pela aplicação dando a ela somente recursos de leitura pode ser um bom cenário.

alt text

Obviamente é necessaário proteger que usuários mudam o spec de um pod usando RBAC.