Estou trabalhando em um projeto que implementa simulações distribuídas: código arbitrário é executado em vários nós e os resultados são posteriormente coletados e agregados.
Cada nó é uma instância de uma máquina virtual Ubuntu Linux e executa um processo mestre que cuida do encaminhamento do código a ser executado para vários processos de trabalho (1 para cada núcleo).
Esta pergunta é sobre como garantir que cada trabalhador opere em um ambiente em área restrita sem recorrer ao uso de uma instância de máquina virtual para cada um deles. Os requisitos exatos para os trabalhadores são:
- fs : sem permissão de gravação, permissão somente leitura limitada a um único diretório (e subpastas)
- net : somente comunicações locais permitidas (IPC, TCP, qualquer que seja ...)
- mem : limite de uso de memória (sem memória swap) mata se estiver acima do limite de mem
- CPU : apenas 1 núcleo permitido, matar se ao longo do tempo
Nenhuma outra limitação deve ser imposta: o trabalhador deve poder carregar bibliotecas dinâmicas (da pasta somente leitura), gerar novos threads ou processos, chamar a função do sistema, ecc ecc, mas os limites devem ser herdados pelas entidades geradas / carregadas e deve aplicar-se de maneira sumária (por exemplo, não podemos ter um trabalhador gerando dois threads que usam 800 MB cada, o limite de memória para esse trabalhador é de 1 GB).
Escusado será dizer que não deve haver maneira para o trabalhador aumentar seus direitos.
Passei um tempo considerável revisando as alternativas disponíveis (SELinux, AppArmor, cgroups, ulimit, namespaces do Linux, LXC, Docker, ...) para a solução mais simples que satisfaz meus requisitos, mas minha experiência em campo é limitada.
Entendimento atual: o LXC e o Docker estão um pouco pesados para o meu caso de uso e não são completamente seguros 1 . O AppArmor é preferível ao SELinux devido à configuração mais fácil, use-o para restrições de rede e rede; cgroups preferível ao ulimit (que opera em um único processo), usou-o para restrições de mem e cpu.
Essa é a maneira mais simples de alcançar meu objetivo? Posso usar o AppArmor ou cgroups exclusivamente? Existe alguma falha de segurança óbvia no meu modelo? A diretriz deve ser "permitida ao trabalhador derrubar a si mesma, mas nada mais" .
Respostas:
Sim, você pode usar o cgroups e o SELinux / AppArmor exclusivamente para monitorar e controlar o código arbitrário que você executará.
Com o cgroups, você pode fazer o seguinte:
cpuset
subsistemamemory
subsistema, rastreando até os garfos. Veja https://github.com/gsauthof/cgmemtime para obter um exemplo.lo
comnet_prio
subsistema.E com o SELinux / AppArmor, você pode limitar o acesso de leitura / gravação do processo.
Nota: Não estou familiarizado com o AppArmor, mas é um sistema de Controle de acesso obrigatório (MAC), o que significa que proteger a escrita e a leitura é o seu trabalho.
O uso desses sistemas é uma questão de escrever as configurações adequadas. Claro, tudo isso é muito mais fácil dizer do que fazer. Então, aqui estão alguns links de referência para você começar:
Boa sorte!
fonte
Eu descartaria o SELinux for AppArmor apenas se estivesse usando o Ubuntu . (realmente muito difícil)
O LXC não é seguro por si só Se você precisar de segurança, deverá usá-los via libvirt (baseado no SELinux MLS ).
Seu problema é infinito, portanto, não tente encontrar nenhuma solução pronta e sem tempo infinito, lembre-se de que até o kernel.org foi copiado e muito recentemente o FBI declarou que alguém usa seus sistemas há anos sem ser detectado até agora.
Eu irei com o LXC / libvirt para obter uma segurança muito boa ou tentarei os "novos" contêineres claros da Intel , que usam uma VM muito leve para o seu contêiner com o uso claro do DAX / KSM (eu não os testei, mas eles parecem muito promissor de fato).
Se você está preocupado com a exploração do kernel, o grsecurity é sua solução, mas você precisa integrá-lo à sua solução de contêiner (dores de cabeça, com certeza).
Portanto, não é tarefa fácil, com certeza, o LXC / libvirt é realmente legal, mas talvez contêineres limpos sejam o caminho a percorrer.
Docker? Eu não usei / não usaria o docker para mais do que testes locais, quando não havia uma caixa vagrant disponível, eles precisam de muito mais trabalho e muito melhor comunidade.
É claro que os contêineres do systemd também são bons, mas presumo que você não os goste / os queira, porque você nem os mencionou e eles não são uma solução independente de fornecedor.
Se você quiser algo "mais fácil" e mais amador, poderá verificar o firejail , eu o uso em alguns "aplicativos" da área de trabalho e ele faz o trabalho (é muito fácil criar o modelo para seu aplicativo personalizado, use "private" monta em cima de seus diretórios e restringe a rede apenas para uso local, processos gerados herdam para o pai e continuam ...).
Saúde e divirta-se sem enlouquecer. ;)
fonte
O seccomp-bpf é outra opção que funciona bem para OpenSSH, vsftpd e Chromium; ele só possui exit (), sigreturn (), read () e também usa write (), embora permita a filtragem de chamadas do sistema usando regras configuráveis do Berkeley Packet Filter. Também pode ser usado em conjunto com cgroups para memória, cpu etc ...
https://wiki.mozilla.org/Security/Sandbox/Seccomp
fonte
Você pode querer examinar os sistemas de computação em grade. Em particular, o BOINC ( http://boinc.berkeley.edu ) verifica quase todas as suas caixas.
Eu acredito que ele opera com seus parâmetros como tal:
fs: pode ler / gravar em seu próprio diretório, em nenhum outro lugar
net: pode ser configurado para permitir apenas o acesso à rede no servidor BOINC, mas não é o padrão fora da caixa IIRC
mem: sim, limites de memória separados para máquinas ociosas e não ociosas
cpu: sim, pode até dizer "não execute se o computador não estiver ocioso"
fonte