Poseu un client VPN en un contenidor i obtindreu un espai de noms amb un túnel a dins, no un amfitrió que encamina tot el seu trànsit per una VPN. Són projectes separats, i tractar-los com un de sol és com els contenidors acaben privilegiats per accident. Aquest manual només cobreix el primer: una imatge revisada, un perfil protegit i un procés de client confinat al seu propi espai de noms de xarxa.

Comenceu per un artefacte que algú ja ha aprovat. Els passos següents assumeixen una imatge que conté l’executable openvpn i un perfil de client complet amb el certificat i el material de clau ja resolts dins del muntatge. No construeixen programari, no emeten credencials ni cobreixen entorns sense root i contenidors natius de Windows, cadascun dels quals canvia la resposta.

Què rep el contenidor i què no

Manteniu el perfil i tot el que referencia en un directori local amb permisos restringits, muntat en només lectura. Les rutes relatives dins del perfil s’han de resoldre dins d’aquest muntatge; és un detall que la gent passa per alt quan un certificat és un directori per sobre del perfil i el contenidor no el veu mai.

services:
  vpn:
    image: ${VPN_CLIENT_IMAGE:?set the reviewed image reference}
    cap_add:
      - NET_ADMIN
    devices:
      - /dev/net/tun:/dev/net/tun
    volumes:
      - ./vpn:/vpn:ro
    working_dir: /vpn
    entrypoint: ["openvpn"]
    command: ["--config", "/vpn/client.ovpn"]

Aquest fitxer concedeix tres coses i no demana res més. La referència de la imatge s’ha de fixar per digest si la vostra política de desplegament ho diu, i el perfil ha de ser el revisat, no una còpia que algú va editar in situ a l’amfitrió.

Només lectura aquí vol dir que el contenidor no pot modificar els vostres fitxers de l’amfitrió; no vol dir que no pugui llegir la clau privada que heu muntat. Aquest és tot el sentit del muntatge, i també per això els permisos de fitxer, la propietat i com el secret va arribar a l’amfitrió encara importen. No passeu mai una contrasenya a la línia d’ordres ni la incrusteu en una capa d’imatge, perquè totes dues sobreviuen en llocs que no podreu netejar després.

Capacitats, entrypoint i la trampa entre elles

Calen dos paràmetres i fan feines no relacionades. NET_ADMIN permet manipular interfícies i rutes dins de l’espai de noms del contenidor. L’entrada de dispositiu /dev/net/tun permet al procés obrir el dispositiu de túnel. Concedir-ne un sense l’altre produeix un fracàs clar, cosa que és convenient: un dispositiu TUN absent falla en obrir-lo, mentre que una capacitat absent falla quan el client intenta configurar la interfície.

Cap de les dues no justifica privileged: true. Un contenidor privilegiat rep totes les capacitats més accés als dispositius, i és una concessió molt més gran del que aquesta càrrega de treball necessita. La referència de privilegis i capacitats de l’entorn d’execució explica fins on arriba aquesta concessió. Si un chart o una entrada de blog ho demana, comproveu primer si el requisit era en realitat una ruta de dispositiu absent o una capacitat absent.

La substitució de entrypoint és la part que mossega. Invocar openvpn directament és correcte per a una imatge normal i incorrecte per a qualsevol imatge de producte l’script d’inici de la qual prepara regles de tallafocs, fitxers de resolutor o credencials abans d’executar el dimoni. Substituir aquest script omet la preparació i us deixa depurant un túnel que va arrencar en un espai de noms mig configurat.

Executeu el client en primer pla i deixeu que sigui el procés principal del contenidor. Un procés que es daemonitza surt immediatament, el contenidor es reinicia en bucle, i els registres que necessiteu queden repartits entre reinicis que semblen idèntics.

Verifiqueu des de dins de l’espai de noms, no des de l’amfitrió

Aixequem la pila, confirmeu al registre que el client ha assolit un estat connectat i, després, inspeccioneu l’espai de noms que realment conté el túnel.

docker compose up -d
docker compose logs --tail 40 vpn
docker compose exec vpn ip -br addr
docker compose exec vpn ip route

La llista d’adreces hauria de mostrar una interfície de túnel amb una adreça del pool, i la taula de rutes hauria de mostrar les destinacions empenyudes apuntant-hi. Si la interfície falta, el client mai va arribar a crear-la. Si existeix però cap ruta la fa servir, el lloc on mirar és el push o les opcions de ruta.

Després proveu la destinació que us importa, des de l’espai de noms que ha d’usar el túnel, amb l’aplicació i no només amb un ping. La resolució de noms és un fracàs a part que val la pena provar explícitament: una adreça DNS empenyuda no actualitza el resolutor del contenidor per si sola, i un client autònom que ignora el push resoldrà noms a través del que la imatge hagi configurat.

L’estat desconnectat forma part del contracte

El comportament de reconnexió necessita la seva pròpia comprovació, perquè una política de reinici demostra que el procés es reinicia i no diu res sobre què fa el trànsit entremig. Atureu el túnel, proveu la destinació prevista i observeu si la connexió es refusa, es penja o té èxit silenciosament per la ruta ordinària del contenidor. L’últim resultat és el que importa, i és invisible en un registre sa.

Si la càrrega de treball no ha d’usar mai el camí ordinari, dissenyeu-ho explícitament amb regles de tallafocs i un senyal de preparació dins de l’espai de noms. Un kill switch és una política que escriviu i proveu, no una propietat que hereteu de fer córrer un client en un contenidor.

Finalment, recordeu la frontera: aquestes rutes viuen a l’espai de noms del contenidor i no substitueixen la taula d’encaminament de l’amfitrió. Les regles de reenviament, traducció i tallafocs de Docker continuen formant part del camí exterior, i un port publicat no és una interfície VPN.

Articles relacionats