Communication between DMR and a computer network

 1,875 total views

Anders Fongen, November 2022

Abstract: The integration of a sensor network with services from voice communication, text messaging and Global Positioning System (GPS) creates opportunities for improved situational awareness, better safety for field operators, higher confidence in sensor readings and improved return on equipment investment. Digital Mobile Radio (DMR) has been the choice of communication technology for a series of experiments where these potentials have been investigated. Additional technology components used were mostly inexpensive and open source.

The article was published in the The Sixteenth International Conference on Sensor Technologies and Applications (SENSORCOMM 2022) October 2022, Lisbon Portugal.

Demonstration videos

Below are two demonstration videos from the integration experiment, view these if you are not into reading academic papers:

The first video shows how to integrate a DMR radio into an pub-sub network using the MQTT protocol.

Demonstration video from the integration experiment – pubsub intergation

The second video shows how two MMDVM units can provide routing of IP packets across a DMR radio link.

Demonstration video from the integration experiment – IP routing

Full text of article

Download source code

This link allows you to download the source code in the form of a compressed tar file. Please observe that this is experimental code not meant for production, and:

  • The module gwtest.py is the root module, and the execution starts there
  • You will need to import the module dmr_utils3, paho-mqtt, netifaces, etc.
  • You will need to inspect the source code and modify values for ip-addresses, DMR-ids, UDP port number, MQTT topics etc.
  • You need to configure pi-star so that it connects to the Controller at its IP-address.
  • The code also includes code to route IP-packets over a DMR link. Un-comment this code if necessary, but this will require the program to run in root mode (sudo…)
  • If you make improvements and want to share them with me, you are welcome to contact me. Please accept that I cannot spend much time on advice and support otherwise.

Docker – nettverk og svermer

 610 total views,  1 views today

Anders Fongen, september 2022

Dette er et blogginnlegg som skal diskutere nettverk av Docker-kontainere, hvordan de kan kommunisere gjennom beskyttede interne nett, og hvordan de kan opptre i svermer under styring av en sentral kontrollnode. Forutsetningen for å få godt ubytte av denne teksten er grunnleggende kjennskap til bygging og kjøring av vanlige Docker-komponenter (eng. images)

Vi kan enkelt tenke oss fornuftige anvendelser hvor en Docker-komponent har nytte av å påkalle tjenester fra en annen komponent. Dette er da typisk en komponent som ikke betjenes med en HTML-basert web -dialog, men som benytter maskin-til-maskin kommunikasjon (m2m). Slik kommunikasjon kan gjerne være basert på HTTP-protokoll og benytte programmeringsbiblioteker for dette, men vil ha innholdet kodet med XML eller JSON. Slike komponenter forbinder vi med begrepet Service Oriented Architecture (SOA). Jeg kommer ikke til å komme inn på slik programmering her, men det finnes mengder av læremidler der ute basert på ditt favoritt programmeringsspråk.

Beskyttet nettverk internt i Docker

Når en komponent ønsker å kalle en annen, er det selvfølgelig mulig å utplassere den kalte komponenten slik at den kan kalles fra “utsiden” (evt. hele Internet) og bruke denne utvendige IP-adressen som servicepunkt. Det er lett å tenke seg hvorfor dette ofte ikke er ønskelig: Uvedkommende kan fritt utnytte og sabotere tjenesten med mindre man lager mekanismer for adgangskontroll, noe som strengt tatt ikke burde vært nødvendig.

Docker tilbyr derimot “interne” nettverk som kun er synlig for Docker-kontainere på den samme maskinen og som er koplet til det interne nettverket. I det man skaper et slikt nettverk:
$ docker network create my-internal-network
$ docker network ls
$ docker network inspect my-internal-network

vil det også bli tildelt en subnett-adresse, og forsynes med tjenester for tildeling av adresser fra subnettet (lik DHCP) og tjenester for å finne IP-adresser til de tilkoplede kontainerne (lik DNS). For siden å kople en kontainer til nettverket kan vi velge to metoder:

  1. Kople til nettverket i det kontaineren skapes, f.eks slik:
    $ docker run -p 80:80 --name mycontainer --net my-internal-network image-name

    Med denne metoden vil kontaineren mycontainer være knyttet til kun my-internal-network. Om kontaineren skal være knyttet til flere nettverk, bruk metode nr.2:
  2. Lage kontaineren, kople til nettverket og starte programmet, i tre steg (eksempelvis)
    $ docker create -p 80:80 -name mycontainer image-name
    $ docker network connect my-internal-network mycontainer
    $ docker network connect my-second-internal-network mycontainer
    $ docker network disconnect bridge mycontainer
    $ docker start mycontainer

    Denne listen av kommandoen viser bruken av create, som oppretter en kontainer uten å starte den, network connect som kopler kontaineren til interne nettverk, og disconnect, som kopler fra nettverk. Deretter starter kjøringen av programmet i kontaineren med $docker run.

Det forholder seg nemlig slik at en kontainer som standardinnstilling koples til et nettverk kalt bridge. Alle andre kontainere vil også ha forbindelse til denne, noe som i mange tilfeller ikke er ønskelig. Metode nr.1 vil erstatte bridge-forbindelsen med en forbindelse til my-internal-network. Metode nr.2 vil legge nye forbindelser til eksisterende.

Eksempel 1 – BusyBox

Som eksempel på viste metode nr.2 kan komponenten BusyBox brukes. Den gir et lite Linux-kjøremiljø som vi kan skrive kommandoer til.

Først lister vi opp eksisterende nettverk og skaper to nye:


Vi er interessert i å vite subnet-adressene til disse to nye nettene:


Vi skaper en kontainer med BusyBox-komponenten og knytter den til de to nye nettverkene, i tillegg til bridge:


Nå starter vi kontaineren bb med BusyBox inni, og skriver kommandoen ip a for å se nettverkskonfigurasjonen på komponenten:

Fra denne kommandoen ser vi de tre ethernet-adaptrene eth0, eth1 og eth2 med subnettadresser som tilsvarer nettverkene bridge, my-net-1 og my-net-2. Som nevnt tidligere ville vi trolig koplet fra bridge for å unngå påvirkning fra uvedkommende komponenter.

Eksempel 2 – Trafikk mellom to Docker-komponenter

Det første eksemplet viste kun konfigurasjon av nettverksforbindelser, ikke hvordan vi kan bruke dem. Derfor vil vi nå sette opp komponenten first slik at vi kan kalle den fra busybox med linux-kommandoen wget og vise html-innholdet som first sender. Komponenten first er beskrevet i et tidligere blogginnlegg.


Her brukes kommandoene som er vist som metode nr.1 ovenfor og vi starter henholdsvis first og busybox med forbindelser til my-net-3. I busybox bruker vi kommandoene slik:

  1. ip a for å se at vi har fått et nettverksadapter med en adresse fra subnettet til my-net-3
  2. ping first for å vise at det foreligger en navnetjeneste som kopler navnet first (navnet på kontaineren) til ip-adressen 172.27.0.2, og at det foreligger en virkelig forbindelse dit.
  3. wget first:8080 for å sende et http-forespørsel til 172.27.0.2, port 8080 og lagre svaret på filen index.html.
  4. more index.html for å vise innholdet av denne filen på konsollet.

Vi har altså med dette eksemplet demonstrert at to komponenter kan ha en nettverksforbindelse som er skjermet fra andre komponenter. Det som er verd å huske er:

  • Interne nettverk får automatisk en subnett-adresse.
  • Containere som kopler seg til et internt nettverk får tildelt IP-adresse automatisk.
  • Interne nettverk (unntatt bridge) har en navnetjeneste som returnerer IP-adressen til navngitte containere. Derfor er det lurt å gi containere et navn med --name parameteren.

Av en eller annen grunn er det ingen navntjeneste i nettverket bridge, slik at ping first ikke vil fungere dersom komponentene ønsket å kommunisere over det nettverket.

Docker-compose

En applikasjon vil gjerne bestå av flere Docker-containere som samarbeider og må konfigureres og startes på en kontrollert måte. Enkeltkommandoer som vist i eksemplene ovenfor kan kanskje settes sammen i en kommandofil (.bat, .sh) og kjøres samlet. Dette forutsetter at du har konsoll-adgang til maskinen som skal kjøre applikasjonen, og at ulike maskiner kan forstå denne kommandofilen. Dette er forutsetninger som ikke kan garanteres. Docker-compose vil øke portabiliteten av applikasjoner og forenkle konfigurasjonen, siden alt foregår i én fil.

Derfor kommer Docker-compose inn som et verktøy hvor detaljer vedrørende konfigurasjon og kjøring for alle komponentene i applikasjon kan uttrykkes i én fil. Denne filen har en såkalt YAML-syntaks, som skal vises i eksemplet som følger.

Filen skal hete docker-compose.yml. Som eksempel på utforming skal vi bruke konfigurasjonen i eksempel nr.2 ovenfor. Innholdet i filen er som vist under:

Syntaksen og mulige informasjonselementer i denne YAML-filer (uttales “jammel”) er ganske omfattende, og en oversikt finner du her. Derfor velger jeg heller å demonstrere ett bestemt kjent tilfelle med en typisk struktur: nettverksforbindelse, volumer, eksponerte porter. Elementene under disse to vil være tilsvarende de parametrene vi tidligere ga på kommandolinjen. For first, legg merke til at build: nå må ha et stinavn til der hvor kildefilene til first ligger.

Syntaksen i den viste docker-compose.yml skal forstås som et hierarki der innrykk av teksten viser en “tilhørighet” til linjen ovenfor med kortere innrykk. Her har vi altså tre hovedkategorier: services, volumes, networks. Før en kontainer kan knyttes til et volum eller nettverk må disse først deklareres på denne måten. Under networks finner vi hvilket nett som skal brukes i applikasjonen og hva dette skal hete.

Under services finner vi de to vi har arbeidet med så langt, bb og firsts. For bb kommer det to linjer knyttet til stdin_open og tty, som har å gjøre med at vi ønsker konsolltilgang til denne kontaineren, noe som i mange tilfeller ikke vil være aktuelt. Derfor vil denne viste filen ha de fleste av de egenskapene du i praksis vil trenge.

La oss nå gi denne filen til Docker-compose og se hva som kommer ut av det. Arbeidskatalogen (current directory) må være den som inneholder docker-compose.yml . Oppstart skjer med kommandoen $ docker-compose up:


Nå er både bb og first started i hver sine kontainere, men vi får ingen konsolltilgang til å skrive kommandoer i. Til forskjell fra eksempel nr.2 må vi skrive dette i tilegg:
$ docker exec -it bb sh
Denne kommandoen utfører kommandoen sh i kontaineren som heter bb. Parameteren -it gjør at sh også kommuniserer med konsollet, så vi får en interaktivt Linux-konsoll. Nå kan vi teste at det er kommunikasjon mellom bb og first:


Dette må dog skrives i et annet CMD-vindu, fordi vinduet der vi startet docker-compose er opptatt. Der kan vi derimot lukke applikasjonen og stanse kontainerne ved å trykke ctrl-C noen ganger:


Kommandoen $ docker ps -a viser en liste over kontainerne og at disse er stoppet. Vi kan nå slette én og en kontainer med kommandoen $ docker rm bb first, men en enklere måte er $ docker container prune, som sletter alle inaktive kontainere under ett. Inaktive kontainere kan okkupere en del ressurser i systemet, og det er sunt å rydde regelmessig.

Docker swarms

I et storskala informasjonssystem vil en web-tjeneste kjøre på mange maskiner i parallell. Da oppnår man at maskinene kan fordele kundetrafikken mellom seg for å oppnå høyere total ytelse (kalt lastfordeling), og at noen av maskinene kan falle ut av drift uten at systemet som sådan blir utilgjengelig (kalt fail-over). Denne formen for ressursorganisering krever en sjef (manager), som fordeler forespørsler mellom arbeiderne (workers) og som holder oversikt ettersom maskiner går inn eller ut av drift.

Docker-arkitekturen egner seg godt til å inngå i en slik storskala arkitektur, siden tilstandsløse komponenter kan dupliseres på flere maskiner og utføre nøyaktig den samme tjenesten. Kunder vil se ett eneste servicepunkt (IP-adresse og port) og ikke merke noe til at tjenesten er fordelt på mange maskiner. La oss derfor se på hvordan Docker-komponenter kan organiseres som en Docker swarm:

Bruk helst Linux-maskiner

Selv om kommandoene for Docker-svermer også finnes på Windows-versjonen av Docker-systemet, er det en del egenskaper som simpelthen ikke virker som forventet. Det er derfor å anbefale at et eksperiment med Docker-svermer kun benytter Linux-maskiner. Husk også at Docker-komponenter ikke er arkitekturnøytrale, de kan ikke kjøre både på X86- og ARM-maskintyper. Ikke blande f.eks. Raspberry Pi (ARM) med ordinære PCer (X86) i en Docker-sverm.

Alt foregår fra sjefen

For å bygge opp en sverm må maskinene kunne nå hverandre gjennom et IP-nettverk, det er ikke tilstrekkelig at sjefen kan nå alle arbeiderne, arbeiderne må også kunne kommunisere med hverandre. For først å bygge opp en sverm gjør vi følgende:

  1. Bestem hvilke maskiner som skal delta, skriv ned deres IP-adresser og lag et kart som viser hvem som er sjef og hvem som er arbeidere. Fra konsollet til sjefen, logg inn (med ssh) på alle arbeiderne i separate konsollvinduer. Alle kommandoer som vises som eksempler må kjøres i sudo-modus (skriv sudo bash for komme dit).
  2. På alle maskinene i svermen, sørg nå for at alle kontainere er stanset ($ docker stop ..., $ docker rm ...) og kontroller resultatet med $ docker ps -a.
  3. På sjefens maskin, sjekk om det allerede er en sverm med $ docker node ls. Dersom det finnes en, fjerne dem med kommandoen $ docker swarm leave --force.
  4. På sjefens maskin, opprett en sverm med kommandoen $ docker swarm init. Reponsen kan se omtrent slik ut:
    Swarm initialized: current node (icv8b9vnemxfmym4lb1gbto7f) is now a manager
    To add a worker to this swarm, run the following command:
    docker swarm join --token SWMTKN-1-0ezzbg9iw2glu6d7xd6c2shjvhadr7zlemwuf4l9besxl2iogl-a1yngnqehgyub0phopuslysly 192.168.2.116:2377
  5. Ta en kopi av den uthevede teksten, og lim den inn i konsollvinduet til alle arbeiderne slik at kommandoen utføres der. De vil nå kople seg til sjefen (til ip-adressen som er vist i kommandoen) og slutte seg til svermen. Nå vil de etterhvert få opprettet kontainere for applikasjonstjenester og motta klientforespørsler.
  6. Fra sjefens konsoll skriv $docker node ls for å kontrollere at alle arbeiderne er kommet inn i svermen.

Utplassering av en tjeneste i svermen

Nå kan sjefen plassere en tjenesten inn i svermen. Dette betyr, som tidligere nevnt, at en applikasjon blir plassert ut på én eller flere av arbeiderne (inkludert sjefen), og en forespørsel fra en klient blir betjent av én av dem.

Hvilken IP-adresse leder inn til den utplassert tjenesten? Svaret er at alle IP-adressene i svermen (altså endepunktet til alle arbeiderne og sjefen) gir adgang til tjenesten, også de arbeiderne som ikke betjener selve tjenesten. Det eksisterer et eget “overlay” nettverk mellom maskinene som fremforhandler fordelingen av arbeidsoppgaver og som videresender forespørsler fra klienter til en kandidat-arbeider.

Kommandoen skal skrives på sjefens konsoll. Sånn kan den se ut:

$ docker service create --name first --replicas 3 --publish 8080:8080 andfon7a/first

Den eneste nye parameteren siden de tidligere eksperimentene er --replicas som angir det maksimale antall arbeidere (inkl. sjefen) som skal laste denne applikasjonen. Legg også merke til at Docker-komponenten ikke må ligge på sjefens egen maskin, den kan hentes fra Docker-hub om nødvendig (og den må da evt. plasseres der på forhånd med $ docker push andfon7a/first).

Med kommandoen $ netstat -ant på alle maskinene i svermen kan man nå konstatere at port 8080 er “åpen”. Med en web-leser kan man kontake én av maskinenes IP-adresse på port 8080 og konstatere at tjenesten utføres korrekt.

For å inspisere tjenesten bruk kommandoen $ docker service inspect --pretty first. For å fjerne den skrives $ docker service rm first.

Opp- og nedskalering: Det opplagt nyttige i svermen er muligheten for å endre kapasiteten ved å øke eller redusere antall maskiner som deltar i en tjeneste. Det gjøres som følger (i dette eksemplet reduseres antallet fra 3 til 2):

$ docker service scale first=2

Konklusjon

Målet med dette blogginnlegget var å gi en kortfattet, men ukomplett, innføring i hvordan man setter opp nettverk og svermer av Docker-komponenter. Det fulle omfanget av muligheter og detaljer er mye større, men er blitt utelatt fordi det er lagt vekt på å vise konkret hvor enkelt det er å sette opp en grunnleggende tjeneste.

Jeg anbefaler først leseren å gjennomføre disse eksemplene på eget utstyr og så gjøre nødvendige endringer etter egen interesse: F.eks. hvordan en sverm kan operere med permanent lagring gjennom en filtjener eller en SQL-database. Slike komponenter er ikke enkle å replikere i en sverm og vil naturlig ligge i egne tjenester, gjerne i frittstående Docker-kontainere med muligheter for å lagre data i volumes.

Utplassering av Docker-komponenter i Microsoft Azure

 927 total views,  1 views today

Anders Fongen, september 2022

Å konstruere Docker-komponenter og utplassere (eng. deploy) dem i en lokal kontainer på egen maskin er en ganske overkommelig oppgave. Mer omstendelig er det å sette slike komponenter i drift i en sky. De store skytjenestene (f.eks. Amazon AWS, Google Cloud og Microsoft Azure) er svært store og komplekse installasjoner som skal kunne betjene kunder med helt ulike behov. De tilbyr alle en web-tjeneste (portal) som lar kunden laste opp egenutviklet programvare og konfigurere samspillet med de tjenestene som skyen tilbyr (f.eks. sikkerhet, backup, navnekataloger, fillagring og SQL-databaser). For alle disse skyene blir denne portalen svært omfattende og omstendelig å bruke. Kvaliteten på dokumentasjonen er dessuten svært varierende.

Jeg har tatt for meg utvikling, utplassering, feilsøking og drift av Docker-komponenter med påfølgende utplassering i Microsoft Azure. Etter vellykket utplassering er tjenesten tilgjengelig på Internet. Dette blogginnlegget vil vise hvordan det kan skje.

Hvorfor er skyen en god idé?

Visst er det mulig å sette opp en webtjener på ditt eget hjemmenett, bestille fast IP-adresse hos Internet-leverandøren, sette opp port forwarding på hjemmeruteren, og gi hjemmeadressen et DNS-navn. Denne prosessen har jeg forøvrig beskrevet i et eget blogginnlegg.

Med et slik løsning må du selv ta hånd om sikkerhet, backup, reserveløsninger ved systembrudd, brukertillatelser, og fremfor alt skalering. En vellykket tjeneste på Internet kan oppnå en svært rask vekst i kundemengden, og dersom du ikke klarer å opprettholde en akseptabel responstid under slike forhold har du mislykkes.

Disse kravene kan skyen innfri, fordi de besitter store datasentraler med høy nettverkskapasitet, og de kan raskt øke kapasiteten på tjenesten din, de kan endog gjøre det automatisk. Personellet i datasentralene er eksperter på skalering, sikkerhet, overvåking og etterforskning, og de har ingen annen jobb enn å passe på at tjenestene leverer stabilt og raskt. Du har andre oppgaver og vil ikke klare å gjøre denne jobben like godt.

Docker

Programvare som skal kjøres som en skytjeneste må skrives etter bestemte regler, og utplasseringen trenger noen opplysninger som må fremskaffes av kunden. Docker er programvare for å lage og kjøre skytjenester. Jeg skal ikke forklare Docker grundig her, fordi det finnes mye informasjon om nettopp dette på nettet:

Det er nødvendig å gå gjennom noen eksempler på bygging og kjøring av Docker-komponenter på lokal maskin: Når Docker-komponenter kjøres på lokal maskin, f.eks. BusyBox, kan de kommunisere med brukeren gjennom konsollet, dvs. skjermen som brukes for å bygge og starte komponenter. Dette er ikke mulig på Azure, hvor komponenten må kommunisere med omverdenen gjennom nettverket (Internet).

Nettverkstrafikk kan omfatte protokoller som ssh, http, mqtt og det meste annet, men komponenten må selv besørge selve protokollen, Azure besørger bare UDP- og TCP porter, samt en brannvegg for å beskytte mot angrep via nettverket. Vi skal demonstrere bruk av Azure med web-komponenter som benytter http-protokoll.

Installasjon av programvare

For å kommunisere med Azure trengs programvaren Docker Desktop, installert på Windows eller Mac (bruk lenken ovenfor). I CMD-konsollet (Windows) kan man nå skrive $ docker for å utføre diverse kommandoer.

I den påfølgende tekst vil jeg bruke “$”-symbolet for å vise en kommando slik den skal skrives inn i CMD-konsollet. Dollartegnet skal altså ikke skrives inn.

For å utplassere Docker-komponenter på Azure trenger du følgende brukerkontoer:

  1. Hos hub.docker.com. Her plasserer du dine komponenter slik at andre kan laste dem ned til seg og bruke dem. Kontoen er gratis.
  2. Hos portal.azure.com. Her foregår selve kontrollen av Azur-aktivitetene. Duu må registrere et betalingskort, men du får også en romslig kvote gratis som du kan eksperimentere med.

Eksperimentprogrammer

To små Python-programmer blir brukt i denne demonstrasjonen: De ene er et enkelt tilstandsløst web-program som adderer to tall og viser resultatet, det andre web-programmet benytter en tekstfil som lagres på et permanent lager. Skillet mellom disse to programmene er hvordan de bruker permanent lager. Programmene ser slik ut:

Summere to tall (tilstandsløst web-program)

first.py:
import web
urls = ('/','index')

class index:
   def GET(self):
      f = open("first.html","r")
      return f.read()
   def POST(self):
      i = web.input()
      if i.a.isnumeric() and i.b.isnumeric():
         return "Svaret er %d" % (int(i.a)+int(i.b))
      else:
         return "Kun numerisk inndata er lovlig"

if __name__ == '__main__':
   app = web.application(urls,globals())
   app.run()

first.html:
<html><body>
  <h1>Addere to heltall</h1>
  <form method='POST'>
     <input name='a', size='4'>
     <input name='b', size='4'>
     <input type='submit' value='finn sum'>
   </form>
</body></html>

Dockerfile:
FROM python:3.8
WORKDIR /usr/src/app
COPY . .
RUN pip3 install web.py
EXPOSE 8080
CMD ["python","./first.py"]

Dette webprogrammet kan startes direkte fra kommandolinjen og tilby en enkel tilstandsløs tjeneste. Vi kan når som helst restarte tjenesten uten å forstyrre klientene. Vi kan lage en Docker-komponent og kjøre den lokalt på vår egen maskin med disse kommandoene (de tre filene må ligge på samme katalog, og katalogen må være arbeidskatalog (current directory):

$ docker build -t first .
$ docker run --name container1 -d -p 8080:8080 first

Nå er denne webtjenesten tilgjengelig på http://localhost:8080/. For å stoppe og fjerne tjenesten (f.eks. før utplassering av en ny programversjon) kan disse kommandoene skrives:

$ docker ps -a
$ docker stop container1
$ docker rm container1

Dele en liten datafil (tilstandsfylt web-program)

third.py:
import web, os

urls = ('/','index')
os.environ['PORT'] = '80'
app = web.application(urls, locals())
filename = "message.txt"
class index:
   def GET(self):
      if not os.path.isfile(filename):
         f = open(filename,"w")
         f.close()
         message = "Ingen melding"
      else:
         f = open(filename,"r")
         message = f.read()
      resp ="<html><body><h2>Din siste melding var: %s"%(message)
      resp += "<p>Skriv inn melding:<form method='POST'><input name='m' size='20'>"
      resp += "<input type='submit' value='Lagre melding'></form></body></html>"
      return resp
   def POST(self):
      i = web.input()
      f = open(filename,"w")
      f.write(i.m)
      f.close()
      raise web.seeother('/')

if __name__ == '__main__':
   app.run()

Dockerfile:
FROM python:3.8
WORKDIR /usr/src/app
COPY . .
RUN pip3 install web.py
EXPOSE 80
CMD ["python","./third.py"]

Dette web-programmet vil ta imot en tekstlinje og lagre den på en fil, som siden kan hentes frem av denne eller andre klienter. En form for datadeling altså. Filen som lagrer tekstlinjen bør bevares også når programmet stopper og starter igjen. Dersom vi kjører third.py som et vanlig Python-program vil filen ligge på vertsmaskinens filsystem, og vil dermed bevares slik vi ønsker.

Dersom vi lager en Docker-komponent som med forrige eksempel, vil også denne tekstlinjen bevares og utveksles mens Docker-komponenten kjører. Dersom Docker-kontaineren stoppes og startes igjen:

$ docker stop container1
$ docker start container1

(gitt at kontaineren er gitt navnet container1 ved docker run – kommandoen), da vil fortsatt tekstlinjen bevares slik vi ønsker. Dersom vi derimot fjerner kontaineren og lager en ny:

$ docker stop container1
$ docker rm container1
$ docker run --name container1 -d -p 80:80 third

Da har tekstlinjen fått det innholdet den hadde da Docker-komponenten ble laget (evt. tom), og endringer etter det tidspunktet er gått tapt. Altså, ikke slik vi ønsker at webtjenesten vår skal fungere.

Docker-komponenter med volumes

For å kunne bevare data også når docker-kontaineren slettes og skapes på nytt, må dataene lagres utenfor kontaineren, i vertsmaskinens filsystem. Dette er mulig å få til gjennom å montere en del av vertsmaskinens filsystem inne i kontainerens. Vi skal først endre én programsetning i third.py:

filename = "/app/message.txt"

og bygger web-tjenesten på lignende måte:

$ docker build -t third .
$ docker run --name container3 -v textdata:/app -d -p 80:80 third

Da oppnår vi nemlig det vi ønsker, nemlig at innholdet på området textdata i vertskapets filområde (i et nærmere bestemt filområde inne i Docker-installasjonen) vises under katalogen /app inne i kontaineren, og data som lagres under /app blir bevart selv når kontaineren slettes og gjenskapes. Dette kan kontrolleres ganske enkelt i et eksperiment.

Merk at dette permanente lageret kan lagre alle slags objekter, ikke bare tekstfiler: Bilder, lyd og selvfølgelig en databasefil fra f.eks. SQLite.

Litt om tilstander i Azure/Docker

Azure, i likhet med andre skyleverandører, lar Docker-komponenter kjøre i omgivelser som støtter stor skala, høy sikkerhet og dynamisk konfigurasjon. Det vil si at web-tjenesten som kjører kan gis et elastisk ressurstilbud ettersom pågangen øker og minker. Slik automatisk skalering skjer gjennom at Docker-komponenter kjører samtidig på mange maskiner i parallell (kalt flere instanser) og fordeler forespørselene mellom seg, og at antallet samtidige maskiner øker og minsker dynamisk.

Med datalagring inne i komponenten, slik vi har demonstrert med third.py, vil ikke en slik skalering kunne finne sted, fordi alle instansene vil ha ulikt datainnhold siden de betjener ulike forespørsler. Nei, skalering krever at Docker-komponenten benytter en separat lagringstjeneste som behandler skrivbare data (som filen message.txt i third.py ovenfor). Kun lesbare data kan fortsatt legges inne i Docker-komponenten dersom mengden ikke er for stor.

Dette skillet mellom brukerbetjening, forretningslogikk og datalager er en populær og velprøvd konstruksjonsteknikk for store informasjonssystemer. Trafikken mot datalageret (kalt back-end) er ofte lavere enn mot front-end (web-tjenesten) og datalageret kan skaleres med andre teknikker enn en front-end. Derfor ser vi at dette skillet mellom utføring og lagring i adskilte tjenester går igjen hos alle skyleverandører.

Utplassering av third.py i Azure

Vi skal hoppe over utplassering av first.py i Azure fordi det skjer på samme måten som med lokal Docker-plattform med noen små endringer, som vil fremgå av forklaringen som følger. Jeg skal gå gjennom utplassering av third.py i Azure, etter at den ene programsetningen er endret (filename = "/app/message.txt). Trinn for trinn er prosessen denne:

  1. Bygge en lokal Docker-komponent. Navnet på komponenten må prefikses med brukernavnet i Docker-hub, som i mitt tilfelle er andfon7a:
    $ docker build -t andfon7a/third .
  2. Plassere komponenten i Docker-hub. Det er nemlig herfra at Azure skal hente den senere
    $ docker login (Her kreves brukernavn og passord til brukerkontoen din)
    $ docker push andfon7a/third
    $ docker logout
  3. Logge inn i Azure og opprette filområdet
    $ docker login azure (Får du feilmelding “Azure lookup failure”, har du feil
    versjon av Docker installert. Bruk nyeste versjon av Docker desktop)
    $ docker context create aci mycontext (velg “create new resource group”)
    $ docker context use mycontext
    $ docker volume create mydata --storage-account andfon7astorage
  4. Lag en kontainer og start komponenten i den. Den lastes inn fra Docker-hub
    $ docker run -p 80:80 --name third --domainname andfon7a -d -v andfon7astorage/mydata:/app andfon7a/third
  5. Sjekk at kontaineren kjører og hvilket DNS-navn den har fått.
    $ docker ps -a
    – Sjekk nå med en web-leser at du får tak i tjenesten med dette DNS-navnet

Microsofts egen infoside om denne prosessen finner du her. Docker sin tilsvarende veiledning finnes her.

For å stoppe/starte/fjerne kontaineren bruker du kommandoene:
$ docker stop third
$ docker start third
$ docker rm third

Starting av en kontainer kan ta lengre tid enn kun kommandoen i konsollet. Bruk $docker ps -a for å se status i oppstartsarbeidet.

Om DNS-registreringen: For bruk av --domainname parameteren gjelder det at DNS-navnet blir registrert på den tildelte IP-adressen med en TTL-verdi på 300 sekunder. Dersom du under f.eks. eksperimentarbeid statid starter containeren på nytt kan du komme i situasjonen hvor DNS-tjenesten fortsatt en stund returnerer den forrige IP-adressen. Om du utelater --domainname parameteren vil $docker ps vise deg IP-adressen i den samme kolonnen , som alltid er riktig.

Huskn

Når du vil igjen jobbe lokalt eller mot Docker-hub:
$ docker logout azure
$ docker context use default

Docker-tjenester fra Amazon AWS og Google Cloud

Amazon AWS og Google Cloud er to konkurrerende skytjenester som i det store bildet har mye til felles. Begge disse kan enkelt støtte tilstandsløse Docker-komponenter, enklest gjennom egne kontrollprogrammer (à la docker) som installeres i Windows-konsollet (cmd).

  • Google Cloud betjenes av programmet Gcloud som installeres på din lokale maskin. Opplastingen skjer direkte fra lokal maskin med commandoen gcloud run deploy, og nødvendige tilleggsopplysninger legges inn i den påfølgende dialogen.
  • For Amazon AWS skjer utplasseringen ved hjelp av en tilleggsfil som inneholder de nødvendige ekstraopplysningene (som ikke ligger i Dockerfile). For en veiledning for dette, sjekk avsnittet “Docker on AWS” på denne websiden.

Ingen av disse to skytjenestene støtter derimot Volumer, slik vi har vist er mulig i Azure. Derimot har begge database-tjenester som kan brukes av Docker-komponenter for lagring. Dette dekker noe av behovet for permanent lagring, men krever også at programvaren i større grad er tilpasset for dette og blir derfor mindre portabel enn hva som er ønskelig. Databasetjenester er dessuten krevende å konfigurere, sammenlignet med et filsystem.

Konfigurasjon av et Virtuelt Privat Nett med OpenVPN

 1,959 total views,  2 views today

Et Virtuelt Privat Nett (VPN) er en beskyttet sammenkopling av lokale nett eller enkeltmaskiner. Typiske anvendelser for et VPN er:

  • Bruk av bedriftens it-ressurser utenfor bedriftens lokaler, på reise eller hjemmefra
  • Beskyttet kommunikasjon mellom samarbeidende bedrifter, f.eks. mellom apotek og legekontor
  • Adgang til felles laboratorium for samarbeidende bedrifter som ikke skal ha adgang til hverandres nettverk

Denne artikkelen vil forklare hvordan VPN kan inngå i flere typer nettverksanvendelser og hvordan programmet OpenVPN kan konfigureres i hvert enkelt tilfelle.

Tunnel-prinsippet

Om jeg vil sende et brev, men ikke ønsker at postverket skal vite hvem jeg sender det til, kan jeg levere brevet til budkontor som pakker brevet i en ekstra konvolutt som adresseres til et annet budkontor. Det mottagende budkontoret vil åpne den ytterste konvolutten og besørge leveringen av selve brevet. Budkontoret har ikke en landsdekkende transporttjeneste, kun lokal levering, men kan på denne måten by på landsdekkende brevtjeneste, og postverket vil ikke vite hvem som er de egentlige avsendere og mottakere.

Det samme prinsippet kan brukes for å beskytte sendinger mellom to datamaskiner mot innsyn og endring. Ved å sende IP-pakkene via to maskiner som mellom seg utveksler dataene i en kryptert form og lagt i en egen “konvolutt”, kan dette fortone seg som å sende data via en tunnel som ikke har noen forbindelse med overflaten over. Ingen på bakken over tunnelen kan se eller endre hva som beveger seg gjennom tunnelen.

Figur 1 viser hvordan en tunnel kan fremstilles som et rød forbindelse inne i en sort forbindelse. Dette er analogt med den tidligere beskrivelsen av en konvolutt (rød) som legges i en ny konvolutt (sort). Adressene på den indre konvolutten kalles røde endepunkter, og adressene på den ytre kalles sorte endepunkter. Sorte endepunkter er de “offentlige” IP-adressene, mens de røde er private adresser som ikke er synlig for omverdenen.

Figur 1: En “rød” IP-forbindelse inne i en “sort” ip-forbindelse

Hvorfor bruker vi OpenVPN i stedet for IPSec?

Det finnes flere typer VPN-protokoller som kan brukes til formålene listet opp ovenfor. De to mest kjente kalles IPSec og OpenVPN. Denne artikkelen vil beskrive bruk av OpenVPN fremfor IPSec av disse grunner:

  • OpenVPN er enklere å konfigurere, især på Windows
  • Det er enklere å sette opp rutingtabeller for OpenVPN
  • OpenVPN gir mulighet for å sette opp såkalte linklags-tunneler

Mens det finnes mange omfattende beskrivelser av alle konfigurasjonsmuligheter i OpenVPN, vil denne artikkelen beskrive 3 typiske scenarier for bruk av VPN, og hvordan OpenVPN kan konfigureres for å realisere disse.

Hvor finnes programvaren?

OpenVPN er gratis programvare (Open Source), og finnes for Windows, Linux, IOS, Android m.m. Kun versjoner for Linux og Windows er testet for denne artikkelen, og eksemplene som er vist er utviklet på Linux og siden verifisert på Windows. Erfaringsmessig er Linux mer fleksibelt enn Windows for tjener-anvendelser, så funksjonene på tjenersiden bør realiseres på Linux.

Oppstart av programvaren er forskjellig på Windows og Linux: Fra Windows høyreklikker man på tray-ikonet og velger “connect”, på Linux skriver man
$ sudo openvpn <konfigurasjonsfil>

For installasjon på linux: $ sudo apt-get install openvpn

For installasjon på Windows:

https://www.ovpn.com/no/guides/windows-openvpn-gui

Installere programmet som vanlig, programmet starter automatisk etterpå. Ingen GUI-vindu vises, men et “tray-ikon” dukker opp nede til høyre. Det ser ut som en skjerm med hengelås på. Høyreklikk på dette ikonet og velg “settings”, deretter fanen “advanced”. For “Configuration files”, velg en egnet katalog (de foreslåtte verdiene er ok), her vil nøkkel- og konfigurasjonsfiler legges. Denne mappen vil vi heretter kalle konfigurasjonsmappen. Velg så en underkatalog “log” for loggfiler. 

Tre typiske scenarier

Tre varianter av VPN-konfigurasjoner vil dekke et stort antall bruksområder. Disse tre er:

  1. Nett-til-nett, hvor to private lokalnett blir koplet sammen gjennom en beskyttet tunnel som om det sto en vanlig ruter mellom dem.
  2. Road warrior, hvor mange klienter kan kople seg til et lokalnett mens de er hjemme eller på reise. Også kalt host-til-nett.
  3. Felles subnett, hvor et antall maskiner koples sammen som ett subnett, som om de er tilkoplet samme Ethernet-switch.

1. Nett-til-nett VPN

Figur 2 viser hvordan en OpenVPN-tunnel kan inngå i et nett-til-nett VPN. Green og Blue er to rutere som har en ubeskyttet forbindelse mellom seg, f.eks. gjennom Internet, og de har IP-adressene 9.8.7.6 og 4.5.6.7. Ruterne har OpenVPN programvare og kan sette opp en beskyttet tunnel mellom seg i form av en link og tunnelen har en selvvalgt subnett-adresse. Subnett-adressen velges fritt blant private IP-adresser som ikke finnes på nettet, f.eks. innenfor 10.0.0.0/8 eller 192.168.0.0/16. I det valgte eksemplet har tunnelen adressen 192.168.3.0/30, med 192.168.3.1 i venstre ende (Green) og 192.168.3.2 i høyre enden (Blue).

Tilkoplet ruterne Green og Blue finnes lokalnettene 10.1.0.0/16 og 10.2.0.0/16. Det er tunnelens oppgave å sørge for at maskiner på disse lokalnettene kan nå hverandre.

Figur 2: Nett-til-nett konfigurasjon av et VPN

Innsiden av en tunnel blir ofte kalt Rød side og merkes med rød farge på tegninger. Den røde siden er beskyttet fra omverdenen ved at trafikken er kryptert og pakket inn i en ekstra IP-pakke slik som vist på Figur 1.

Tunnelen settes opp ved å lage konfigurasjonsfiler og en felles krypteringsnøkkel på ruterne. Slik kan konfigurasjonsfilene se ut på henholdsvis Green og Blue:

Green:Blue:
dev tun
remote 4.5.6.7
secret greenblue.key
ifconfig 192.168.3.1 192.168.3.2
route 10.2.0.0 255.255.0.0
dev tun
remote 9.8.7.6
secret greenblue.key
ifconfig 192.168.3.2 192.168.3.1
route 10.1.0.0 255.255.0.0
Tabell 1: Konfigurasjonsfiler for Green og Blue

Krypteringsnøkkelen som skal brukes skal genereres med denne kommandoen

$ openvpn --genkey --secret greenblue.key

og overføres til den andre maskinen på en beskyttet måte, f.eks. med scp. Filen må ligge i samme katalog som konfigurasjonsfilen. Gitt at konfigurasjonsfilen på begge sider heter greenblue.conf startes nå tunnelen med Linux-kommandoen (må gjøres i begge ender)

$ sudo openvpn greenblue.conf

Resultatet på begge ruterne er at det nå oppstår et nytt adapter kalt tun0 (kan vises med kommandoen $ ip a) med adressene 192.168.3.1 og 192.168.3.2. Green og Blue kan “pinge” hverandre på disse adressene.

Tips til inspeksjon: Studere trafikken (med f.eks. tcpdump) som går mellom tun0-adaptrene mens det pinges, og notere at denne trafikken går i klartekst. Studere så trafikken mellom deres ytre adaptre (de med adresser 4.5.6.7 og 9.8.7.6) og legg merke til at den består av UDP-segmenter til port 1194 med kryptert innhold.

Demonstrasjonsvideoer: Linux til Linux forbindelse

Linux til Windows forbindelse

Ruting mellom lokalnettene

Vi forutsetter at Green og Blue begge er konfigurert til å rute IPv4-pakker. De må nå kunne rute trafikk mellom lokalnettene, dvs. at trafikk fra Green til 10.2.0.0/16 skal rutes via 192.168.3.2. Dette besørges av linjen “route 10.2.0.0 255.255.0.0” i konfigurasjonsfilen, som setter opp en linje i rutingtabellen med nettopp denne opplysningen. Det tilsvarende skjer i Blue.

Alle maskinene i lokalnettet 10.1.0.0/16 må også vite om at ruten til 10.2.0.0/16 går via Green’s IP-adresse (la oss anta at dette er 10.1.0.1). OpenVPN har ingen kommunikasjon med disse maskinene, så slik rutinginformasjon må enten legges inn manuelt i hver enkelt maskin, eller den kan komme fra DHCP-tjeneren. Dersom programmet dnsmasq brukes for DHCP-tjenesten kan denne linjen legges inn i /etc/dnsmasq.conf:

dhcp-option=121,10.2.0.0/16,10.1.0.1

Dersom Green også har oppgaven med å kople lokalnettet til Internet vil den være default gateway for maskinene der, og da vil ingen ekstra rutinginformasjon være nødvendig. Trafikk til 10.2.0.0/16 vil sendes til samme adresse som alle andre ukjente adresser, og Green vil sørge for å vidersende gjennom tunnelen, ikke til Internet. Dette forholdet er vist for Blue på Figur 2.

Det vil være en vanlig situasjon at tunnelen mellom Blue og Green vil gå gjennom Internet, selv om den på Figur 2 later til å være en separat forbindelse. Figur 2 er utformet slik for å understreke at tunnelen kan benytte enhver kommunikasjonstjeneste for sitt formål, ikke bare Internet.

Koordinering av IP-adresser

I Internet er tildeling av IP-adresser en nøyaktig planlagt prosess, som skal sikre at adressekonflikter unngås. Ved sammenkopling av lokalnett må dette besørges uten hjelp utenfra.

Lokale nett bør tildeles såkalte private IP-adresser. Dette er adresser som aldri tildeles til noder på Internet, slik at man unngår konflikter når noder på lokalnettet skal nå noder på Internet. Private adresser ligger i adresseområdene 10.0.0.0/8, 192.168.0.0/16 og 172.16.0.0/12.

Dersom lokalnettene vist på Figur 2 har samme eller overlappende adresseområde, f.eks. 10.1.0.0/16, ville de ikke kunne koples sammen, fordi rutere bare kan rute mellom ulike subnett, ikke like. Det er vanskelig å forutse fremtidige behov for sammenkopling, og mulige adressekonflikter ved sammenkopling av private nettverk er umulig å gardere seg mot. I dette eksemplet vil det være nødvendig å endre adresseplanen på ett av lokalnettene, i beste fall ved å konfigurere DHCP-tjeneren til et annet adresseområde og så restarte alle maskinene, samt rekonfigurering av ruterporter og tjenermaskiner.

Man kan derimot redusere sannsynligheten for at slike situasjoner oppstår ved å velge “uvanlige” subnettadresser. F.eks. ikke velg 192.168.1.0/24, for det er det svært mange andre som gjør.

Tunneler i flere retninger

Dersom man trenger flere tunneler mot andre nettverk kan man starte OpenVPN flere ganger med ulike konfigurasjonsfiler, én for hver tunnel. I dette tilfellet vil det kjøres flere OpenVPN-prosesser som ikke kan bruke samme UDP-port for sin kommunikasjon. Det er derfor nødvendig at konfigurasjonsfilene refererer til distinkte portnumre. Standard portnummer for OpenVPN er UDP/1194, dvs. den porten som brukes dersom ingenting annet er angitt. For VPN-tunnel nr. 2 kan vi gjerne bruke 1195 og videre oppover. Dette angis i konfigurasjonsfilen slik:

Green:Blue:
dev tun
port 1195
remote 4.5.6.7
secret greenblue.key
ifconfig 192.168.5.1 192.168.5.2
route 10.2.0.0 255.255.0.0
dev tun
port 1195
remote 9.8.7.6
secret greenblue.key
ifconfig 192.168.5.2 192.168.5.1
route 10.1.0.0 255.255.0.0
Tabell 1: Konfigurasjonsfiler for en ekstra tunnel

Forøvrig startes tunnel nr. 2 i et eget konsoll på samme måte som de andre.

2. Road Warrior VPN

I denne konfigurasjonsvarianten er det ikke to likestilte parter som kopler seg mot hverandre, men en klient-tjener konfigurasjon hvor et (potensielt høyt) antall klienter kopler sine enkeltmaskiner (ikke nettverk) til en tjener for å få tilgang et nettverk (derfor kalt host-til-nett). Det hører også med at klientene bruker varierende IP-adresser fordi de er stadig på farten og kopler seg opp fra hoteller o.l.

OpenVPN krever en sterkere kryptografisk beskyttelse av en slik forbindelse gjennom bruk av offentlige nøkler og sertifikater. Klienten har en privat nøkkel som må holdes hemmelig, og en offentlig nøkkel i form at et sertifikat som inngår i kryptering og autentisering og som alle kan kjenne til. Generering av nøkler og sertifikater er beskrevet i neste avsnitt

Generere nøkler og sertifikater

På en Linux-maskin vil programmet OpenSSL alltid være installert, og nødvendige nøkler og sertifikater for en VPN konfigurasjon kan genereres ved hjelp av skallprogrammet vist nedenfor. Merk at de to linjene med innrykk skal følge på linjen over.

# Generate keys and certificates for OpenVPN
#  Generate keys
openssl genrsa -out ca_key.pem 2048
openssl genrsa -out server_key.pem 2048
openssl genrsa -out client_key.pem 2048
#  Generate CA certificate
openssl req -new -x509 -days 1000 -key ca_key.pem -out ca_cert.pem -outform PEM -subj '/C=NO/O=CIS/CN=CA'
#  Generate Server certificate
openssl req -new -key server_key.pem -out server_csr.pem -subj '/C=NO/O=CIS/CN=OpenVPNServer'
openssl x509 -req -in server_csr.pem -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial -out 
        server_cert.pem -days 1000 -sha256
openssl verify -CAfile ca_cert.pem server_cert.pem
#  Generate Client certificate
openssl req -new -key client_key.pem -out client_csr.pem -subj '/C=NO/O=CIS/CN=OpenVPNClient'
openssl x509 -req -in client_csr.pem -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial -out
        client_cert.pem -days 1000 -sha256
openssl verify -CAfile ca_cert.pem client_cert.pem
#  Generate DH parameters
openssl dhparam 2048 > dh2048.pem
#  Remove unneccesary files
rm *_csr.pem

Programmet vil generere ett nøkkelpar for alle klientene i fellesskap. Ønskes separate nøkkelpar for hver klient kan skallprogrammet enkelt endres. Sertifikatopplysningene, f.eks. eierens navn (-subj) endres etter ønske.

De resulterende filene som skal overføres til tjener og på klientene er:

Til tjener: ca_cert.pem, server_cert.pem, server_key.pem, dh2048.pem
Til klient: ca_cert.pem, client_cert.pem, client_key.pem

Konfigurasjonsfilene

Konfigurasjonsfilene kan se slik ut:

Green/Red (klient):Blue (tjener):
dev tun
remote 4.5.6.7
client
keepalive 10 60
cipher AES-256-CBC
ca ca_cert.pem
cert client_cert.pem
key client_key.pem
dev tun
mode server
tls-server
keepalive 10 60
duplicate-cn
server 192.168.3.0 255.255.255.0
push "route 10.2.0.0 255.255.0.0"
cipher AES-256-CBC
dh dh2048.pem
ca ca_cert.pem
cert server_cert.pem
key server_key.pem

Tabell 2: Konfigurasjonsfiler for Host-til-nett bruk av OpenVPN

Disse konfigurasjonsfilene skal skrives inn på henholdsvis tjener- og klientsiden. Hver enkelt linje vil ikke forklares her, de fleste av dem forklarer seg selv. OpenVPN startes som i forrige konfigurasjon, og utlistingen på skjermen vil indikere når forbindelsen er satt opp. Maskinen Red er nå lagt til som en ekstra klient for å demonstrere muligheten for flere klienter koplet til samme tjener. Red og Green har nøyaktig samme konfigurasjon. OpenVPN startes på samme måte på hver node med konfigurasjonsfilene og nøkkelfilene liggende på samme katalog.

Studere nå IP-adressene på tun0-adapteret og rutingtabellene på hver maskin. Opplysningene der kan virke forvirrende, så her følger en forklaring på den strukturen som OpenVPN bygger for dette formålet, som vist på Figur 3.

Figur 3: Host-til-nett konfigurasjon av et VPN

Server-direktivet hos Blue instruerer OpenVPN at det skal dannes et rødt nett med dette adressesommet, 192.168.3.0/24. Adresserommet blir delt i subnett med prefiks /30 og hver klient får ett subnett. Den ene adressen i subnettet gis til klientens eller tjenerens tun0-adapter, den andre adressen tildeles en port i en tenkt ruter i det røde nettet.

Denne modellen forklarer hvorfor Green’s tun0-adapter har IP-adressen 192.168.3.10 med eneste nabo 192.168.3.9, og at ruten til 192.168.3.1 går gjennom denne naboen. Adressene på den tenkte ruteren lar seg ikke pinge, men man kan sette opp ruter via dem. Av rutingtabellene i Green og Red fremgår det også at de ikke har noen rute mellom seg, og forsøk på å pinge hverandres IP-adresser lykkes ikke.

Direktivet push "route 10.2.0.0 255.255.0.0" i Blue’s konfigurasjonsfil instruerer Blue til å levere rutinginformasjon til klientene når de kopler seg opp. I dette tilfellet vil Red få en rute til 10.2.0.0/16 via 192.168.3.5, og Green via 192.168.3.9. Siden disse gateway-adressene er ulike for alle klientene skal de ikke inngå i direktivet, men utledes under oppkoplingen. Med dette direktivet kan Green og Red oppnå en rute til nettverket som står “bak” Blue, noe som er hovedhensikten med konfigurasjonen.

Autentisering av tjeneren

Slik klientkonfigurasjonen nå er satt opp vil den kople seg til enhver tjener med et gyldig sertifikat. I dette tilfellet, der sertifikatene er utstedt for dette ene formålet, kan det være godt nok, men i prinsippet bør vi forvisse oss om identiteten til tjeneren. Det kan oppnås ved å legge til denne linjen i klientens konfigurasjonsfil:

verify-x509-name 'C=NO, O=CIS, CN=OpenVPNServer'

Dette direktivet vil forlange at tjeneren bruker et sertifikat med nettopp navnet 'C=NO, O=CIS, CN=OpenVPNServer' (se skallprogrammet overfor for å lage sertifikat med dette navnet)

OpenVPN-klient på Windows

Den viste klientkonfigurasjonen fungerer som den skal på Windows. Legg konfigurasjonsfilen (den må ha etternavnet .ovpn) sammen med de tre nøkkelfilene på OpenVPN’s konfigurasjonskatalog og kople opp gjennom å høyreklikke på tray-ikonet og velget “kople til/connect”. Noen advarsler vises, knyttet til sertifikatsjekken som kan unngåes ved å bruke direktivet som vist i forrige avsnitt.

Isolere klientene fra hverandre

I et Road Warrior brukstilfelle vil det oftest være fornuftig å isolere klientene fra hverandre, slik at Red og Green ikke kan kommunisere. I utgangspunktet kan de ikke det, men det beror på at det ikke finnes rutinginformasjon for dette. Det er derimot ingenting i veien for at Red setter opp en rute til Green via 192.168.3.5 slik:

# route add -host 192.168.3.10 gw 192.168.3.5 dev tun0

Tilsvarende må Green sette opp en rute til Red for at de skal kunne kommunisere. Vi har altså ingen tvungen separasjon av klientene, men tjeneren kan hindre slik trafikk ved å sette opp et iptables-filter (trafikken mellom Red og Green går faktisk via Blue og kan stoppes der). Bruk følgende kommando på Blue:

# iptables -A FORWARD -i tun0 -s 192.168.3.0/24 -d 192.168.3.0/24 -j DROP

Bruk av NAT (network address translation)

For at Green og Red skal kommunisere med nettet bak Blue (10.2.0.0/16) må alle maskinene på dette lokalnettet ha en rute tilbake til Green og Red (192.168.3.0/24) via Blue. Siden disse maskinene ikke er VPN-klienter kan man ikke bruke “push”-direktivet for dette formålet. Maskinene kan få denne ruten via DHCP, eller de kan bruke sin default gateway rute dersom Blue også er deres rute til Internet (slik som vist på Figur 3).

En slik løsning er ikke mulig dersom Blue ruter trafikk fra Red og Green videre til Internet. Da er det nødvendig med en NAT-tjeneste i Blue på det adapteret som forbinder til Internet (antar eth0 for dette eksemplet). En NAT-tjeneste settes opp med iptables ved hjelp av denne kommandoen:

# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

Merk at dersom eth0 kopler et helt nettverk til Internet bør det også settes opp en brannvegg i dette punktet. Det gjøres også med iptables, og er omtalt i denne artikkelen.

Demonstrasjonsvideo:

3. Felles subnett VPN

Den tredje varianten av VPN-konfigurasjon som skal presenteres er å sette alle maskiner sammen som om de er koplet til samme Ethernet-svitsj som vist på Figur 4. Det innebærer at det nå er Ethernet-rammer som utveksles, ikke IP-pakker. Denne konfigurasjonen er fornuftig dersom:

  • Flere nettverksprotokoller skal brukes, f.eks. både versjon 4 og 6 av IP.
  • Kringkastingsprotokoller skal brukes
  • Det er nødvendig med bedre kontroll med tildelte IP-adresser.
  • Klientene skal kommunisere med hverandre, f.eks. i peer-to-peer programmer
Figur 4: OpenVPN konfigurert som svitsjet felles subnett.

Grunnkonfigurasjonen av denne varianten vil identifisere endepunktene, autentisere dem og sette opp virtuelle ethernet-adaptre, kalt tap0. Derfra kan konfigurasjonen av adaptre og rutingtabeller skje med assistanse av OpenVPN, eller ved bruk av maskinens ordinære konfigurasjonsverktøy:

  1. Konfigurasjonsfilen på OpenVPN-tjeneren (Blue) kan bruke et server-direktiv for å tildele IP-adresser til klientenes tap0-adaptre, og push-direktiv for å gi rutinginformasjon.
  2. Hver klient kan konfigureres med statiske IP-adresser og statisk ruting-informasjon, f.eks. (Linux) i filen /etc/network/interfaces eller /etc/netplan/.... Dette hører inn under ordinær nettverkskonfigurasjon og omtales ikke videre her.
  3. Konfigurasjonen kan besørges av tjenester utenom OpenVPN, f.eks. DHCP og routing-protokoller. Kringkastingsrammer kan sendes i denne VPN-varianten, så alle vanlige kringkastingsprotokoller (DHCP, ARP, uPnP, SSDP m.m.) kan brukes.

Valget av metode fra denne listen vil bero på antall klienter i bruk, behovet for identiske konfigurasjonsfiler, og hvilken rolle Blue skal spille i nettvkeret utover å sette opp VPN-tunneler. Det kan nå være andre klienter som besørger rutingen til lokalnett og Internet, og som tilbyr DHCP-tjenester m.m.

Her er eksempel på konfigurasjonsfiler for alternativ 1 fra listen over:

Green/Red (klient):Blue (tjener):
remote 4.5.6.7
client
del tap
keepalive 10 60
cipher AES-256-CBC
route 10.8.0.0 255.255.0.0
verify-x509-name 'C=NO....
ca ca_cert.pem
cert client_cert.pem
key client_key.pem
dev tap
mode server
tls-server
keepalive 10 60
server 10.11.0.0 255.255.0.0
push "route 5.6.7.0 255.255.255.0"
duplicate_cn
client_to_client
cipher AES-256-CBC
dh dh2048.pem
ca ca_cert.pem
cert server_cert.pem
key server_key.pem

I dette tilfellet vil klientene tildeles dynamiske IP-adresser (innen området 10.11.0.0/16), men dynamiske adresser er ikke praktisk dersom de skal kunne nås fra andre klienter. Ruteinformasjon i klienten kan settes både av tjeneren (push "route.." og implisitt i tildeling av IP-adresse) og av klienten selv (route...). Direktivet client_to_client er viktig fordi det åpner for kommunikasjon direkte mellom klientene.

For alternativ 2 og 3 fra listen over er konfigurasjonsfilene nærmest identiske:

Green/Red (klient):Blue (tjener):
remote 4.5.6.7
client
del tap
keepalive 10 60
cipher AES-256-CBC
ifconfig 10.12.0.3 255.255.255.0
verify-x509-name 'C=NO....
ca ca_cert.pem
cert client_cert.pem
key client_key.pem
dev tap
mode server
tls-server
keepalive 10 60
ifconfig 10.12.0.1 255.255.255.0
duplicate_cn
client_to_client
cipher AES-256-CBC
dh dh2048.pem
ca ca_cert.pem
cert server_cert.pem
key server_key.pem

Direktivet ifconfig brukes for å sette IP-adresse på det lokale tap0-adapteret. Klientens tap0-adapter får her adressen 10.12.0.3/24 og tjenerens 10.12.0.1/24. Med disse konfigurasjonsfilene skjer ingen koordinert tildeling av IP-adresser, dette må i så fall besørges på annet vis.

Dersom ifconfig-direktivet på klienten (merket med rødt) fjernes, skjer det ingen konfigurering av tap0-adapteret, dette må besørges av operativsystemet eller av en DHCP-tjeneste. DHCP-tjenesten må tilbys fra en maskin som er tilknyttet OpenVPN-subnettet, siden maskinene i lokalnettet 10.2.0.0/16 tilhører et annet subnett.

Demonstrasjonsvideo:

Konfigurasjonsmengde, trafikkmengde

Denne konfigurasjonen representerer stor fleksibilitet, men mange funksjoner som blir ivaretatt av OpenVPN nå må besørges av nettverkets ordinære tjenester for konfigurasjon og ruting. Dessuten vil trafikkmengden trolig øke i en slik konfigurasjon fordi all kringkastingstrafikk vil sendes til alle klientene i VPNet og konsumere overføringskapasitet.

Dersom alle maskinene står bak brannvegger/NAT

Dersom Blue står bak en NAT-enhet, eller bak en brannvegg, må det lages en port forwarding-regel i brannveggen for at UDP-pakker til port 1194 sendes til Blue’s IP-adresse. Alle maskiner som står bak brannvegger/NAT og som skal motta oppkoplingsmeldinger må ha en slik innretning. De maskinene som alltid oppretter OpenVPN-forbindelser (typisk for klientmaskiner) trenger ikke dette.

Oppsummering

Denne artikkelen har gitt en praktisk og kortfattet introduksjon av OpenVPN og gitt eksempler på konfigurasjon for ulike bruksscenarier. Detaljeringsgraden i forklaringene er redusert med vilje for å gi mer plass til diskusjon av hvilke alternativer som foreligger og konsekvensene av å velge dem. Eksemplene på konfigurasjonsfiler og skallprogrammer er noenlunde komplette og kan skrives inn i aktuelle systemer med små tilpasninger (adresser, adapternavn osv.).

Det finnes mange kilder på Internet til detaljert dokumentasjon av OpenVPN, f.eks. denne: