O que é um contêiner LXC sem privilégios?

20

O que significa se um contêiner Linux (contêiner LXC) é chamado de "não privilegiado"?

0xC0000022L
fonte

Respostas:

20

Os contêineres LXC não privilegiados são os que utilizam os espaços de nome de usuário ( ). Ou seja, de um recurso do kernel que permite mapear um intervalo de UIDs no host para um espaço de nome dentro do qual um usuário com UID 0 pode existir novamente.

Ao contrário da minha percepção inicial de contêineres LXC sem privilégios por um tempo, isso não significa que o contêiner precise pertencer a um usuário host sem privilégios. Essa é apenas uma possibilidade.

Relevante é:

  1. que um intervalo de UIDs e GIDs subordinados está definido para o usuário host ( usermod [-v|-w|--add-sub-uids|--add-sub-gids])
  2. ... e esse intervalo é mapeado na configuração do contêiner ( lxc.id_map = ...)

Assim, rootpode possuir até contêineres sem privilégios, pois os UIDs efetivos dos processos de contêiner no host terminarão dentro do intervalo definido pelo mapeamento.

No entanto, rooté necessário definir os IDs subordinados primeiro. Ao contrário dos usuários criados via adduser, rootnão terá um intervalo de IDs subordinados definidos por padrão.

Lembre-se também de que toda a gama fornecida está à sua disposição, para que você possa ter três contêineres com as seguintes linhas de configuração (apenas o mapeamento UID mostrado):

  1. lxc.id_map = u 0 100000 100000
  2. lxc.id_map = u 0 200000 100000
  3. lxc.id_map = u 0 300000 100000

supondo que ele rootpossua os UIDs subordinados entre 100000 e 400000. Toda a documentação encontrada sugere o uso de 65536 IDs subordinados por contêiner, alguns usam 100000 para torná-lo mais legível para humanos.

Em outras palavras: você não precisa atribuir o mesmo intervalo a cada contêiner.

Com mais de 4 bilhões (~ 2^32) de IDs subordinados possíveis, significa que você pode ser generoso ao negociar os intervalos subordinados aos usuários do host.

Contêiner não privilegiado pertencente e executado pela raiz

Para esfregar isso de novo. Um convidado LXC sem privilégio não precisa ser executado por um usuário sem privilégio no host.

Configurando seu contêiner com um mapeamento UID / GID subordinado assim:

lxc.id_map = u 0 100000 100000
lxc.id_map = g 0 100000 100000

onde o usuário rootno host possuir esse intervalo de ID subordinado, permitirá restringir os convidados ainda melhor.

No entanto, há uma vantagem adicional importante nesse cenário (e sim, eu verifiquei que funciona): você pode iniciar automaticamente seu contêiner na inicialização do sistema.

Normalmente, ao vasculhar a Web em busca de informações sobre o LXC, você será informado de que não é possível iniciar automaticamente um convidado LXC sem privilégios. No entanto, isso só é verdade por padrão para os contêineres que não estão no armazenamento de contêineres em todo o sistema (geralmente algo parecido /var/lib/lxc). Se eles são (o que geralmente significa que foram criados pela raiz e iniciados pela raiz), é uma história totalmente diferente.

lxc.start.auto = 1

fará o trabalho muito bem, depois de colocá-lo na sua configuração de contêiner.

Obtendo permissões e configurações corretas

Lutei com isso um pouco, então estou adicionando uma seção aqui.

Além do snippet de configuração incluído por meio do lxc.includequal geralmente se chama o nome /usr/share/lxc/config/$distro.common.conf(onde $distroestá o nome de uma distribuição), você deve verificar se há também um /usr/share/lxc/config/$distro.userns.confno seu sistema e incluí-lo também. Por exemplo:

lxc.include = /usr/share/lxc/config/ubuntu.common.conf
lxc.include = /usr/share/lxc/config/ubuntu.userns.conf

Além disso, adicione os mapeamentos de ID subordinado:

lxc.id_map = u 0 100000 65535
lxc.id_map = g 0 100000 65535

o que significa que o host UID 100000 está root dentro do espaço de nome do usuário do convidado LXC.

Agora verifique se as permissões estão corretas. Se o nome do seu convidado fosse armazenado na variável de ambiente, $lxcguestvocê executaria o seguinte:

# Directory for the container
chown root:root $(lxc-config lxc.lxcpath)/$lxcguest
chmod ug=rwX,o=rX $(lxc-config lxc.lxcpath)/$lxcguest
# Container config
chown root:root $(lxc-config lxc.lxcpath)/$lxcguest/config
chmod u=rw,go=r $(lxc-config lxc.lxcpath)/$lxcguest/config
# Container rootfs
chown 100000:100000 $(lxc-config lxc.lxcpath)/$lxcguest/rootfs
chmod u=rwX,go=rX $(lxc-config lxc.lxcpath)/$lxcguest/rootfs

Isso deve permitir que você execute o contêiner após sua primeira tentativa ter causado alguns erros relacionados à permissão.

0xC0000022L
fonte
4
Boa resposta - mas lxcnão é uma necessidade para esse tipo de coisa. Você pode criar um recipiente namespace de qualquer tipo utilizando a util-linuxferramenta unshare. Você pode entrar no referido contêiner usando a util-linuxferramenta nsenter. A última ferramenta também permite adicionar processos em execução a um contêiner já criado a partir dele. O suporte ao namespace é implementado no kernel.
precisa saber é o seguinte
4
@mikeserv: você quer dizer que não precisa do LXC para fazer uso de usuários ? Eu sabia. Sei também que o Docker agora tem sua própria biblioteca fazendo uso dessas instalações. Mas como você contentorizaria um sistema inteiro sem a ajuda das instalações oferecidas pelo LXC? E por que você faria isso? Pretendo conter um único aplicativo e, combinado com chrootisso, pode ajudar, mas o LXC combina vários espaços de nome (UTS, montagem etc ...) para conter o sistema inteiro.
0xC0000022L
2
Bem ... Como eu disse, unshareisso já é admirável em todos / todos os vários namespaces - e você ainda recebe uma /procmontagem privada e separada com um único switch cli. Se seu aplicativo único é inite você chrooté initramfs, você recebe um contêiner inteiro em segundos.
mikeserv
0

Para followup em 0xC0000022L, cuja solução funcionou bem para mim, eu escrevi um increase-uid-gid.pl script Perl para automatizar a propriedade necessária alterações necessárias para que os arquivos dentro dos recipientes LXC estão devidamente mapeada.

Sem ele, com esta configuração proposta, um arquivo dentro de rootfs de contêiner LXC pertencentes a 0 / root no host principal será, dentro do próprio contêiner LXC, mapeado para 65534 / ninguém. Para serem mapeados para 0 / root no contêiner LXC, eles devem pertencer a 100000 no host.

Isso é descrito aqui https://yeupou.wordpress.com/2017/06/23/setting-up-lxc-containers-with-mapped-giduid/ e o script pode ser obtido diretamente no gitlab https://gitlab.com /yeupou/stalag13/blob/master/usr/local/bin/increase-uid-gid.pl

yeupou
fonte