Contêineres com LXC – parte 4

lxc-4_unprivileged

Fazendo uma pausa com a programação de baixo nível para concluir o assunto sobre o LXC trazendo finalmente os contêineres não privilegiados, ou seja, os contêineres que são criados, iniciados e gerenciados a partir de um usuário “comum e corrente” e não pelo usuário root.

Só relembrando que os contêineres que criei até agora com o LXC o foram partir do usuário root. Ou seja, cada contêiner é um processo rodando com permissões de administrador e basta que alguém, ou alguma coisa, lá dentro saiba exatamente o o que fazer/como fazer para conseguir acesso total à máquina hospedeira.

Configurando a conta do usuário

A solução implementada pelo LXC é a utilização de UID e GID sem uso pelo sistema nos arquivos e processos dentro do contêiner em espaço do usuário. A primeira coisa a fazer é definir uma área de UID e GID que ficarão subordinados ao seu usuário, isto é feito com o comando usermod:

$ sudo usermod --add-subuids 100000-165535 giovanni
$ sudo usermod --add-subgids 100000-165535 giovanni

O que este comando faz é informar que o “giovanni” (ou qualquer outro usuário) está autorizado a usar uma faixa de 65.536 UID e 65.356 GID entre 100.000 e 165.535. Aliás, nem preciso dizer que você deve fazer encerrar a sessão — logout — e entrar novamente — login — para que as alterações no usuário façam efeito. 🙂

Querendo certificar se está tudo correto com o usuário, faça:

$ grep giovanni /etc/sub?id
/etc/subgid:giovanni:100000:65536
/etc/subuid:giovanni:100000:65536

Sim, no usermod indicamos a faixa(100.000 a 165.535) mas aqui ele diz o UID e GID inicial e o tamanho da área.

E só precisa fazer isto? Não!

Configurando localmente o LXC

Vou deixar o próprio LXC “explicar” o que se deve fazer. Hora de (tentar) criar um novo contêiner, o “undebian” (o unprivileged debian) só para ver o que acontece:

$ lxc-create -n undebian -t download
No mapping for container root
Error chowning /home/giovanni/.local/share/lxc/undebian/rootfs to
container root
You must either run as root, or define uid mappings pass uid
mappings to lxc-create, you could create ~/.config/lxc/default.conf:
lxc.include = /etc/lxc/default.conf
lxc.id_map = u 0 100000 65536
lxc.id_map = g 0 100000 65536
Error creating backing store type (none) for undebian
Error creating container undebian

O próprio lxc-create já dá a dica do que é necessário ser feito, isto é, criar um arquivo de configuração local para o LXC e acrescentar as informações de mapeamento de UID e GID. Então:

$ mkdir -p ~/.config/lxc
$ cat > ~/.config/lxc/default.conf
lxc.include = /etc/lxc/default.conf
lxc.id_map = u 0 100000 65536
lxc.id_map = g 0 100000 65536

Será criada uma estrutura análoga ao que o LXC cria em “/var” dentro do diretório do usuário em “~/.local”.

Agora é possível seguir adiante.

Criando um contêiner não privilegiado

Nos contêineres não privilegiados apenas o modelo “download” está disponível, o que teoricamente não quer dizer que o número de opções disponíveis tenha sido reduzido:

$ lxc-create -t download -n undebian
Setting up the GPG keyring
Downloading the image index
---
DIST    RELEASE  ARCH    VARIANT BUILD
---
centos  6        amd64   default 20160204_02:16
centos  6        i386    default 20160204_02:16
centos  7        amd64   default 20160204_02:16
debian  jessie   amd64   default 20160203_22:42
debian  jessie   armel   default 20160111_22:42
                      ...
ubuntu  xenial   amd64   default 20160204_03:49
ubuntu  xenial   armhf   default 20160204_13:02
ubuntu  xenial   i386    default 20160204_03:49
---
Distribution: debian 
Release: jessie
Architecture: amd64

The cached copy has expired, re-downloading...
Downloading the image index
Downloading the rootfs
Unpacking the rootfs
---
You just created a Debian container (release=jessie, arch=amd64,
variant=default)
To enable sshd, run: apt-get install openssh-server
For security reason, container images ship without user accounts
and without a root password.
Use lxc-attach or chroot directly into the rootfs to set a root
password or create user accounts

Basta escolher a distribuição, versão e arquitetura (atenção para não usar arquiteturas não compatíveis com o hardware hospedeiro) e aguarde enquanto os arquivos são baixados e descompactados, desta vez dentro da estrutura de “~/.” (ou tal do $HOME).

Antes de executar o contêiner um último detalhe, é necessário autorizar seu usuário a utilizar a interface de rede do LXC:

$ grep giovanni /etc/lxc/lxc-usernet
giovanni veth lxcbr0 10

No caso estou habilitando para o usuário a criação até dez interfaces de rede virtuais.

Ei, mas e o que acontece se eu ultrapassar meu limite?

$ lxc-start -n test02 --foreground
Quota reached
... start.c: lxc_spawn: 1047 failed to create the configured network
... start.c: __lxc_start: 1213 failed to spawn 'test02'
... lxc_start.c: main: 344 The container failed to start.
... lxc_start.c: main: 348 Additional information can be obtained by
    setting the --logfile and --logpriority options.

Ultrapassando o limite definido o LXC não consegue criar a(s) interface(s) de rede necessária(s) e o contêiner não é iniciado.

Ou seja, você pode criar quantas máquinas o espaço em disco disponível permitir mas o  número de contêineres executados fica a cargo do root definir.

Os subUID e subGID na prática

Apenas para matar a curiosidade sobre como a coisa funciona na prática, a base de funcionamento do LXC são os control groupscgroups — e servem para limitar e isolar a utilização de recursos (processador, memória, disco, rede etc) de uma coleção de processos. Inclusive os usuários:

$ cd ~/.local/share/lxc/undebian/rootfs/etc/
$ ls -l shadow
-rw-r----- 1 100000 100042 779 Fev  6 10:36 shadow
$ cd
$ lxc-start -n undebian
$ lxc-attach -n undebian 
root@undebian:/# ls -l /etc/shadow
-rw-r----- 1 root shadow 779 Feb  6 12:36 /etc/shadow

Repare no mesmo arquivo visto do “lado de fora” e pelo “lado de dentro” do contêiner com suas permissões remapeadas pelo LXC.

Finalmente, o fim

Todas as operações do LXC (veja as primeira e segunda partes) funcionarão normalmente em contêineres não privilegiados. Sendo até possível definir quais contêineres do usuário serão iniciados automaticamente.

Até onde pude verificar não existem diferenças de funcionamento entre os dois tipos mas vou deixa a dica para não usar o lxc-attach:

$ lxc-start -n undebian
$ whoami
giovanni
$ lxc-attach -n undebian 
# whoami
root
# env | grep giovanni
XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/giovanni
USER=giovanni
PATH=/home/giovanni/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:
/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
PWD=/home/giovanni
HOME=/home/giovanni
LOGNAME=giovanni
XAUTHORITY=/home/giovanni/.Xauthority

Ao executar o lxc-attach você executa um processo de dentro do contêiner e teu ambiente vai junto, daí alguns comandos podem se comportar de um modo esquisito Solução? Use o parâmetro “- -clear-env” ou faça um SSH para dentro do contêiner.

Também é bom lembrar que cada usuário enxerga e manipula somente seus próprios contêineres, inclusive o root que enxerga apenas os contêineres criados debaixo de “/var” e ignorando os demais.

E não pense que esgotei o assunto, há algumas coisas interessantes que preferi deixar para falar em outra oportunidade.

Anúncios

2 comentários sobre “Contêineres com LXC – parte 4

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s