O LXD expõe um dispositivo de caracteres do host a um contêiner adicionando um nó de dispositivo, não ensinando o convidado a criar um. Se o contêiner não tem /dev/net/tun, o host pode ter o dispositivo e o convidado ainda assim não conseguir abri-lo. A entrada unix-char é a metade desse caminho do lado do gestor, e é deliberadamente mais estreita que um contêiner privilegiado. Por isso o nó do host e o nó do contêiner merecem verificações separadas.

O mecanismo é curto o bastante para manter à vista: o LXD resolve um caminho do host, cria um nó correspondente dentro da instância e adiciona o dispositivo ao cgroup de dispositivos do contêiner. Depois, o processo do convidado precisa de sua própria permissão e capacidade para usar o nó em qualquer coisa.

O que a entrada unix-char realmente muda

Um dispositivo unix-char diz ao LXD para expor um dispositivo de caracteres do host num caminho escolhido dentro do contêiner. A entrada tem três partes que importam: o rótulo do dispositivo usado pelo gestor, o caminho source no host e o path que o convidado vê. Apenas os dois últimos descrevem o dispositivo em si. Um erro de digitação em qualquer um deles produz um nó num local que o cliente nunca abre.

No host o dispositivo normalmente é /dev/net/tun. Dentro do contêiner você pode manter o mesmo caminho ou escolher outro, mas o caminho deve corresponder ao que o cliente VPN espera. Manter /dev/net/tun evita um segundo problema de configuração, porque a maioria dos clientes abre esse caminho sem perguntar.

O gestor aplica a entrada quando a instância inicia ou quando o dispositivo é conectado a quente. Não copia um driver para o convidado e não cria uma interface de túnel. Torna o nó visível e permite o acesso pelo grupo de controle de dispositivos do contêiner.

Declare o dispositivo na instância, não dentro do convidado

Adicione a entrada pelo contexto de administração do LXD, nomeando a instância e um rótulo que você reconheça depois. Para um contêiner chamado vpnbox, o comando é:

lxc config device add vpnbox tun unix-char source=/dev/net/tun path=/dev/net/tun
lxc config device show vpnbox

O rótulo tun é local à configuração da instância. Não é um nome de interface e não precisa corresponder a nada no convidado. Se um perfil já fornece o mesmo dispositivo, adicionar uma segunda entrada cria um conflito em vez de redundância, então examine primeiro a configuração efetiva.

Editar arquivos dentro do contêiner é a camada errada. Um mknod num script de inicialização pode parecer funcionar num contêiner privilegiado e depois desaparecer na recriação ou falhar num menos privilegiado. O gestor é dono do conjunto de dispositivos da instância; deixe-o também ser dono do nó.

Ajuste a propriedade e o modo ao processo do convidado

A entrada unix-char pode definir uid, gid e mode para o nó dentro do contêiner. Use-os para corresponder à conta que executa o cliente VPN, em vez de abrir o dispositivo a todos os usuários ou passar o contêiner para o modo privilegiado.

Visibilidade não é o mesmo que permissão. Um nó de propriedade do root com modo 600 é visível para o serviço executado como usuário sem privilégios e continua impossível de abrir por ele. Verifique primeiro a conta do convidado, depois defina a propriedade para essa conta e mantenha o modo não mais amplo do que o cliente precisa.

O processo também precisa de capacidade para configurar uma interface de túnel, normalmente CAP_NET_ADMIN no espaço de nomes de rede do contêiner. Passar o dispositivo não concede essa capacidade, e conceder a capacidade não fornece o dispositivo; são requisitos independentes.

Saiba o que a entrada não concede

Um nó visível não é uma VPN funcionando. O pacote do cliente ainda precisa ser instalado, o perfil ainda precisa ser válido e o serviço ainda precisa iniciar. Autenticação, rotas e DNS continuam trabalho do cliente, e uma falha ali não é prova de que a entrada do dispositivo esteja errada.

O systemd pode acrescentar outra restrição. Uma unit com DeviceAllow ou uma política de dispositivos endurecida pode negar acesso a um nó fornecido pelo gestor de contêineres. Verifique a política de dispositivos da unit quando o nó existe mas o serviço relata erro de permissão, e mude essa política em vez de ampliar o contêiner.

A conexão a quente é opcional e explícita. Uma entrada com required=false exige um caminho de origem e pode aparecer ou desaparecer conforme o dispositivo do host muda. Esse ciclo de vida serve para hardware que vai e vem; para um dispositivo TUN que a VPN precisa no boot, uma entrada opcional pode deixar o serviço iniciar antes de seu pré-requisito existir.

Verifique visibilidade, abertura e interface nessa ordem

Primeiro confirme o nó dentro do contêiner pretendido. O caminho, os números maior e menor e a propriedade devem corresponder ao dispositivo do host e à entrada que você adicionou. Um nó ausente significa que o gestor não aplicou a entrada, ou a aplicou a outra instância.

lxc exec vpnbox -- ls -l /dev/net/tun
lxc exec vpnbox -- sh -c 'test -c /dev/net/tun && echo char-device-ok'

Depois confirme que a conta do serviço consegue abri-lo. Um teste curto como essa conta separa um problema de propriedade de um problema de serviço. Por fim, inicie o cliente e confirme que aparece uma interface de túnel; só esse terceiro passo prova o caminho inteiro, porque os dois primeiros podem passar enquanto o perfil ou a capacidade do cliente ainda estão errados.

Anote a instância, o rótulo do dispositivo, a origem no host, o caminho no convidado e a conta proprietária quando a mudança for aprovada. Esses cinco valores são o que uma recriação, migração ou mudança de perfil posterior precisa preservar, e são bem mais fáceis de comparar do que um erro de permissão sem contexto.

Artigos relacionados