Naar de inhoud

Documentatie

Agents

De agent is het enige deel van Provibr dat op je eigen hardware draait. Hij houdt de inloggegevens van de systemen die je koppelt, voert het werk uit dat het paneel vraagt, en meldt terug wat hij ziet. Het platform belt nooit zelf in.

Wat een agent is

Eén agent bedient één netwerk: de plek van waaruit je hypervisors en panelen bereikbaar zijn. Alles wat Provibr met je infrastructuur doet gaat daardoorheen.

  • De verbinding is uitgaand. De agent opent hem naar het platform en houdt hem open; er hoeft niets vanaf het internet bereikbaar te zijn en er hoeft geen poort naar hem doorgestuurd te worden.
  • Inloggegevens blijven aan jouw kant. Ze gaan één keer naar de agent en worden op die host in een versleutelde kluis weggezet; het platform bewaart alleen de namen van de velden die je invulde.
  • Hij meldt wat hij waarneemt. Machines worden op een kort ritme gepold en elke paar minuten loopt er een volledige vergelijking, en zo merkt het paneel dat een machine buiten Provibr om is gestopt.
  • Hij raakt alleen aan wat je hebt overgedragen. Een resource zonder registratie in Provibr wordt genegeerd, geteld en weer vergeten. De agent neemt nooit uit zichzelf een machine over.

De host die hij nodig heeft

Niets bijzonders, en vooraf niets te installeren. De agent is één statisch gelinkte binary: hij draagt zijn eigen C-bibliotheek mee, dus er is geen runtime, geen interpreter en geen distributiepakket dat moet passen. Een kleine virtuele machine is genoeg. De maten die we gemeten hebben staan verderop op deze pagina.

Wat een agent-host moet bieden
EisWat je nodig hebtWaarom
Processor64-bits x86 (x86_64, ook amd64 genoemd)We publiceren één Linux-build en dit is de architectuur waarvoor hij gebouwd is. Het installatiescript controleert uname -m voordat het iets downloadt en stopt bij elke andere architectuur, in plaats van iets te installeren dat niet kan draaien. Een ARM-build is er nog niet.
BesturingssysteemElke Linux-distributieEr wordt nergens tegen je systeembibliotheken gelinkt, dus de distributie, de versie en de pakketbeheerder maken niet uit. De volgende sectie noemt de distributies waarop deze build werkelijk gestart is.
Servicemanagersystemd, of je eigenHet installatiescript schrijft een systemd-unit en zet hem aan. Op een host zonder systemd wordt alles alsnog geïnstalleerd en geënrolld, en drukt het script daarna het commando af waarmee je de agent start onder wat je in plaats daarvan gebruikt. Een halve installatie zou erger zijn dan een eerlijke.
Rechten tijdens de installatieroot, één keerInstalleren maakt het serviceaccount provibr-agent aan, twee mappen en de unit. Daarna draait de agent als dat account zonder rechten, en het updatescript waar hij niet in mag schrijven is wat dat zo houdt.
Uitgaande verbindingenTCP 50051 en 50052 naar gw.provibr.netPoort 50051 wordt één keer gebruikt, tijdens het enrollen. Poort 50052 draagt de sessie en blijft open. Allebei over TLS. Filtert je firewall uitgaand verkeer, dan zijn dat de enige twee regels die hij hoeft toe te staan.
Inkomende verbindingenGeenDe agent opent de verbinding zelf, dus er hoeft niets vanaf het internet bereikbaar te zijn en er hoeft geen poort naar hem doorgestuurd te worden. Machines over het netwerk installeren is de enige uitzondering, en zelfs dan luistert hij alleen op het lokale segment.
Bereik in je eigen netwerkTot de systemen die je koppeltJe hypervisor, controlepaneel of gamepaneel wordt vanaf deze host over zijn eigen API aangesproken. Wat de agent niet kan bereiken, kan Provibr niet beheren.
Geheugen512 MB is ruim voldoendeWe hebben 18 MB gemeten met duizend machines verdeeld over vijf systemen, het zwaarste geval in de tabel hieronder. De piek zit ergens anders: het licentiebestand ontsleutelen tijdens het enrollen kost even ongeveer 70 MB, omdat die stap met opzet duur is om te bruteforcen.
Schijf1 GB is ruim voldoendeDe binary is 17 MB en alles wat de agent daarnaast bewaart bleef in onze metingen onder 40 kB. Machines over het netwerk installeren is de uitzondering: daarvoor bewaart de agent installatiemedia in een cache, standaard tot 20 GB.
KlokOngeveer goedCertificaten en licentiebestanden dragen geldigheidsdata en beide kanten controleren ze, dus een host waarvan de klok dagen afwijkt kan niet enrollen. Elke NTP-client volstaat.
De agent draait als zijn eigen account zonder rechten, onder een dichtgetimmerde systemd-unit. Hij krijgt precies twee extra capabilities, en alleen om netwerkinstallaties te kunnen bedienen; haal je die weg, dan blijft alles behalve dat gewoon werken.

Welke Linux

Er is geen pakket om te installeren en geen distributie om bij te passen, dus wat hieronder staat is geen lijst met ondersteunde systemen. Het is de lijst met systemen waarop deze build werkelijk gestart is. Alles wat verder een 64-bits x86 Linux-kernel heeft hoort zich hetzelfde te gedragen, en zo niet dan horen we dat graag.

Linux-distributies waarop de agent gedraaid heeft
SysteemVersieOpmerkingen
Debian13 (Trixie)
Debian12 (Bookworm)De distributie waarop de volledige test draaide: geïnstalleerd, geënrolld, verbonden en aan het pollen.
Ubuntu24.04 LTSUbuntu 24.04 is de release waarin de kernel precies de namespaces ging beperken die automatiseringen nodig hebben. De agent levert daar een AppArmor-profiel voor mee; al het andere werkt ongewijzigd.
Ubuntu22.04 LTS
AlmaLinux9
AlmaLinux8Een veel oudere C-bibliotheek dan die waarop deze build gemaakt is. Dat maakt niet uit, want de agent brengt zijn eigen mee.
Fedora42
openSUSE Leap15
Amazon Linux2023
Alpine Linux3.21musl en helemaal geen glibc, de scherpste test die er is voor een statisch gelinkte binary.
Twee eerlijke grenzen aan die lijst. Hij laat zien dat de binary op elk van deze userlands start en zijn cryptografische werk doet; de volledige sessie, met certificaten en pollen, is op één ervan gemeten. En elke controle draaide op machines die één kernel deelden, dus wat hij bewijst is onafhankelijkheid van de distributie, niet van de kernelversie.

Hoeveel machine je nodig hebt

De agent zelf is klein en blijft klein. Wat groeit is de inventaris die hij in de gaten houdt: elke twintig seconden leest hij van elk gekoppeld systeem de volledige lijst machines, vergelijkt die met de ronde ervoor en stuurt alleen door wat er veranderd is. Elke vijf minuten stuurt hij in plaats daarvan het volledige beeld door, en dat is het vangnet voor alles wat een verloren bericht anders gekost zou hebben; het is ook de ronde waarin hij je nodes vraagt hoeveel capaciteit ze hebben.

Gemeten op één agent; elke rij is een venster van vijf minuten
SituatieGeheugenProcessor
Verbonden, nog niets gekoppeld8 MB0,02 % van één core
Eén systeem, 10 machines12 MB0,03 %
Eén systeem, 250 machines14 MB0,06 %
Eén systeem, 1000 machines15 MB0,14 %
Vijf systemen, elk 200 machines18 MB0,19 %
De stappen tussen de rijen zeggen meer dan de rijen zelf. Het eerste systeem koppelen kost ongeveer 4 MB en elk systeem daarna ongeveer 0,75 MB, en dat is precies waarin de laatste twee rijen verschillen. Machines worden goedkoper naarmate er meer zijn: van 10 naar 1000 kwam er in totaal 3 MB bij, zo'n 3 kB per stuk, en de stap van 250 naar 1000 was nog goedkoper. Gemeten in augustus 2026 tegen gesimuleerde systemen van precies die omvang, zodat de cijfers iets zeggen over de agent en niet over iemands cluster.

Verkeer is het andere cijfer dat de moeite waard is. Die duizend machines kosten ongeveer 250 kB per twintig seconden richting je eigen systemen, ruwweg een gigabyte per dag op je eigen netwerk, terwijl tien machines 2,5 kB per ronde kosten. Van dat cijfer voor duizend machines reist ongeveer 17 kB per ronde door naar ons, zo'n 70 MB per dag, omdat alleen doorgestuurd wordt wat er veranderd is.

Maakt het soort systeem uit? Nauwelijks. Of de agent nu met een hypervisor, een controlepaneel of een gamepaneel praat, het werk is hetzelfde: één aanroep per systeem per ronde, één vergelijking, één bericht. Twee verschillen zijn echt maar klein. Aan een hypervisor worden ook de adressen binnen zijn gasten gevraagd, hoogstens eens per vijf minuten per draaiende machine, en een paneel dat niets meet stuurt geen verbruikscijfers. Wat wél enorm verschilt is de machine aan de andere kant, en hoe groot die moet zijn volgt uit wat hij draait en niet uit de agent.

De maten hieronder zijn daarom geen minima die we gemeten hebben; de agent past in veel minder. Het is wat wij zouden bestellen, omdat een besturingssysteem, zijn logboeken en je eigen gereedschap meer ruimte willen dan de agent.

Wat wij een agent-host zouden geven
Wat hij moet aankunnenvCPUGeheugenSchijf
Tot een paar honderd machines11 GB10 GB
Tot een paar duizend machines22 GB10 GB
Ook machines over het netwerk installeren22 GB40 GB

Wat de extra's vragen

Alles hierboven is wat een agent nodig heeft om je systemen te bekijken en te bedienen. Vier van zijn mogelijkheden verdienen daarbovenop nog een woord, en ze geven allemaal eerlijk toe wanneer het niet kan: is aan een voorwaarde niet voldaan, dan doet de agent de rest gewoon en zegt hij welke mogelijkheid hij niet aanbiedt.

Machines over het netwerk installeren
Hiervoor moet de agent op hetzelfde netwerksegment staan als de machine die geïnstalleerd wordt, want hij beantwoordt het bootverzoek van die machine rechtstreeks. Zijn unit draagt de twee capabilities die hij voor de bootpoorten nodig heeft al; ze zijn zo krap mogelijk toegekend en worden alleen gebruikt zolang er een installatie loopt. Wat het wél kost is schijfruimte: installatiemedia blijven in een cache op de host staan, standaard tot 20 GB, oudste er als eerste uit.
Automatiseringen draaien
Automatiseringen zijn je eigen TypeScript, dus ze draaien in een sandbox die uit kernel-namespaces is opgebouwd, en de runtime daarvoor zit niet in de agent: één vastgezette versie van Bun moet in de map van de agent staan die van root is, waar het account waaronder de agent draait hem niet kan vervangen. Ubuntu 24.04 en nieuwer beperken precies de namespace die hiervoor nodig is; de agent levert een AppArmor-profiel mee dat die ene toestemming teruggeeft voor die ene binary. Ontbreekt een van de twee, dan zegt de agent dat bij het starten, biedt hij de mogelijkheid niet aan en gaat hij verder. Elke run krijgt minstens 4 GB adresruimte. Dat is virtueel, geen geheugen dat er moet zijn. Wat een draaiende automatisering op je host werkelijk kost hebben we niet gemeten.
De host herstarten vanuit het paneel
Herstarten is een kwestie van toestemming en niet van rechten: de agent vraagt het aan logind, logind vraagt het aan polkit, en het installatiescript laat een regel achter die precies twee action-id's toestaat voor precies dit account. Hosts die geïnstalleerd zijn voordat die regel bestond moeten het installatiescript één keer opnieuw draaien, want de agent bijwerken vanuit het paneel vervangt de binary en niets in /etc. Tot die tijd weigert het paneel het, met de reden erbij.
Console en diagnostiek
Niets te installeren. Ping en traceroute gebruiken een ICMP-socket waar geen rechten voor nodig zijn, zolang de host dat voor de groep van het serviceaccount toestaat, en dat deed hij op elke host die we gemeten hebben. Waar dat niet zo is, meet de agent met TCP en zegt hij welke methode hij gebruikte. De console loopt over de verbinding die al openstaat.

Installeren met de one-liner

Op het tabblad Instellingen van de agent bouwt het paneel één commando met een installatielink erin. Draai het als root op de host. De link werkt één keer: hij houdt op zodra de agent is ingeschreven, en uiterlijk na 72 uur. Je kunt op elk moment een nieuwe maken.

shell
curl -fsSL https://app.provibr.com/api/install/<token> | sh
Behandel de link als een inloggegeven. Wie hem heeft kan deze ene agent enrollen, net zoals een authenticatiesleutel dat zou toelaten. Hij wordt nergens in het paneel bewaard, dus maak liever een nieuwe aan dan dat je de oude opzoekt.
Commando's en terminaluitvoer zijn overal Engels, in het paneel en op deze pagina's. Één tekst, één waarheid: wat je hier leest is letterlijk wat je host teruggeeft.

Wat het commando doet, op volgorde:

  • Controleert of het als root draait op een 64-bits x86-host en kiest curl of wget, wat er is.
  • Downloadt de binary en zijn checksum en verifieert ze. Heeft de host helemaal geen gereedschap om een checksum te berekenen, dan stopt het in plaats van de controle over te slaan.
  • Maakt het serviceaccount en de twee mappen aan, installeert de binary, en zet het updatescript en zijn publieke sleutel neer, allebei van root, zodat het account waaronder de agent draait ze niet kan vervangen.
  • Vraagt de activatiecode op de terminal, haalt het licentiebestand op met die code als request-header, en installeert het.
  • Enrollt als het serviceaccount, installeert daarna de systemd-unit en start de service.

Het resultaat controleren op de host:

shell
systemctl status provibr-agent
journalctl -u provibr-agent -f
Het commando nog eens draaien is veilig, met een nieuwe link: de oude werkt niet meer sinds de agent is ingeschreven. Is de host al geënrolld, dan worden alleen de binary en de unit ververst; de identiteit, het certificaat en de credential-vault blijven ongemoeid. Op een host zonder systemd wordt alles alsnog geïnstalleerd en geënrolld, en drukt het commando af hoe je de agent zelf start.

Met de hand installeren

Alles wat de one-liner doet is ook een handvol commando's, en het paneel drukt ze voor je af met de actuele waarden ingevuld. Dit is de vorm ervan.

  1. De host klaarmaken: het serviceaccount, de mappen en de binary.

    shell
    # System user without a shell and without a home directory
    id -u provibr-agent >/dev/null 2>&1 || \
      sudo useradd --system --no-create-home --shell /usr/sbin/nologin provibr-agent
    
    # Directories for configuration (license, key) and state (identity, vault)
    sudo install -d -o provibr-agent -g provibr-agent -m 0750 /etc/provibr-agent
    sudo install -d -o provibr-agent -g provibr-agent -m 0700 /var/lib/provibr-agent
    
    # The binary from the download
    sudo install -o root -g root -m 0755 ./provibr-agent-linux-x86_64 /usr/local/bin/provibr-agent
    /usr/local/bin/provibr-agent version
  2. Het licentiebestand neerzetten. Je downloadt het op de agentpagina; het is versleuteld met de activatiecode en kan één keer per token gedownload worden.

    shell
    sudo install -o root -g provibr-agent -m 0640 \
      ./provibr-<agent>.plic /etc/provibr-agent/license.plic
  3. Enrollen als het serviceaccount, met de activatiecode.

    shell
    sudo -u provibr-agent /usr/local/bin/provibr-agent enroll \
      --license /etc/provibr-agent/license.plic --code XXXXX-XXXXX
  4. De unit installeren en de service starten.

    shell
    sudo install -o root -g root -m 0644 provibr-agent.service /etc/systemd/system/provibr-agent.service
    sudo systemctl daemon-reload
    sudo systemctl enable --now provibr-agent
Bij de download van de binary krijg je ook de checksum en de handtekening. De handtekening verifiëren is de stap die een gewone download je niet geeft; het is dezelfde controle die de updatestap bij elke nieuwe release uitvoert.

Docker en Kubernetes

De agent draait ook als container. Het image bevat dezelfde ondertekende release-binary als de Linux-download en verder niets: geen shell en geen pakketbeheerder, en hij draait als gebruiker zonder rootrechten. Hij verbindt alleen uitgaand, dus er zijn geen gepubliceerde poorten en geen service nodig.

Het inschrijven gebeurt bij de eerste start. Geef de container de installatielink uit het paneel en de activatiecode; hij haalt zijn licentiebestand op, schrijft zich in en bewaart zijn identiteit op het volume. Bij elke volgende start wordt die identiteit gebruikt en worden de twee waarden niet meer gelezen.

De installatielink en de code staan in de omgeving van de container, en dus in docker inspect, je shellgeschiedenis of het Kubernetes-secret. Dat is dezelfde blootstelling als bij de one-liner, en hij duurt tot de agent is ingeschreven: vanaf dan werkt de link niet meer. Haal hem daarna toch uit het secret; de agent leest hem niet opnieuw.
Alles wat de agent bewaart staat op het volume in /var/lib/provibr-agent: zijn certificaat, de versleutelde kluis met je inloggegevens en de sleutel van die kluis. Zonder volume is elke nieuwe container een nieuwe, niet-ingeschreven agent. Met een volume is dat volume het hele geheim: behandel een kopie ervan als een kopie van de agent.

Docker

Het paneel toont dit commando met de link en de code van jouw agent al ingevuld. Het named volume neemt zijn eigenaar over van het image, dus de agent kan erin schrijven zonder chown.

shell
docker run -d --name provibr-agent --restart unless-stopped \
  --hostname provibr-agent \
  --read-only --cap-drop ALL --security-opt no-new-privileges \
  -v provibr-agent-data:/var/lib/provibr-agent \
  -e PROVIBR_INSTALL_URL='https://app.provibr.com/api/install/<token>' \
  -e PROVIBR_ACTIVATION_CODE='XXXXX-XXXXX' \
  ghcr.io/provibr/provibr-agent:latest

Of hetzelfde als Docker Compose-bestand:

docker-compose.yml
# Provibr agent — Docker Compose.
#
# The agent connects outbound to the platform; it needs no published ports.
# On the first start it enrolls itself with the installation link and the
# activation code below, and stores its identity on the volume. After that the
# two values are no longer read; the link expires 72 hours after it was made.
#
# Update: change the image tag, then `docker compose up -d`. The volume keeps
# identity and credentials.
services:
  provibr-agent:
    image: ghcr.io/provibr/provibr-agent:latest
    container_name: provibr-agent
    hostname: provibr-agent
    restart: unless-stopped
    read_only: true
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
    environment:
      PROVIBR_INSTALL_URL: "https://app.provibr.com/api/install/<token>"
      PROVIBR_ACTIVATION_CODE: "XXXXX-XXXXX"
    volumes:
      - provibr-agent-data:/var/lib/provibr-agent

volumes:
  provibr-agent-data:
Liever een bind mount dan een named volume? Maak de map dan eerst aan en geef hem aan de gebruiker van de agent: mkdir -p /srv/provibr-agent && chown 65532:65532 /srv/provibr-agent. Een bind mount begint als eigendom van root, en de agent, die niet als root draait, kan er dan niet in schrijven.

Kubernetes

Kale manifesten, geen Helm: een namespace, een secret met de link en de code, een volume claim en een deployment. Het paneel vult het secret voor jouw agent in.

provibr-agent.yaml
# Provibr agent — Kubernetes (plain manifests, no Helm).
#
# kubectl apply -f provibr-agent.yaml
#
# The agent connects outbound to the platform; there is no Service and no port.
# On the first start it enrolls itself with the installation link and the
# activation code from the Secret, and stores its identity on the volume. After
# that the Secret is no longer read; the link expires 72 hours after it was made.
#
# Exactly one replica, and Recreate: one agent is one identity (one
# certificate). Two pods would be two agents fighting over it.
apiVersion: v1
kind: Namespace
metadata:
  name: provibr-agent
---
apiVersion: v1
kind: Secret
metadata:
  name: provibr-agent-enrollment
  namespace: provibr-agent
type: Opaque
stringData:
  PROVIBR_INSTALL_URL: "https://app.provibr.com/api/install/<token>"
  PROVIBR_ACTIVATION_CODE: "XXXXX-XXXXX"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: provibr-agent-data
  namespace: provibr-agent
spec:
  # One pod, and only one, may mount this volume. On clusters older than
  # Kubernetes 1.29 (or storage without it), use ReadWriteOnce instead; the
  # agent also refuses to start a second time on the same data directory.
  accessModes:
    - ReadWriteOncePod
  resources:
    requests:
      storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: provibr-agent
  namespace: provibr-agent
  labels:
    app.kubernetes.io/name: provibr-agent
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app.kubernetes.io/name: provibr-agent
  template:
    metadata:
      labels:
        app.kubernetes.io/name: provibr-agent
    spec:
      hostname: provibr-agent
      automountServiceAccountToken: false
      enableServiceLinks: false
      securityContext:
        runAsNonRoot: true
        runAsUser: 65532
        runAsGroup: 65532
        fsGroup: 65532
        # Only when the volume root does not match yet; otherwise the kubelet
        # widens the modes on the private keys at every mount.
        fsGroupChangePolicy: OnRootMismatch
        seccompProfile:
          type: RuntimeDefault
        # The ping check uses an unprivileged ICMP socket. Some container
        # runtimes keep those closed, and then the check reports a source
        # error. This safe sysctl opens them for the agent's group only.
        sysctls:
          - name: net.ipv4.ping_group_range
            value: "65532 65532"
      containers:
        - name: agent
          image: ghcr.io/provibr/provibr-agent:latest
          args: ["run"]
          envFrom:
            # optional: the agent reads it on its first start only, so you can
            # delete the Secret once it is enrolled.
            - secretRef:
                name: provibr-agent-enrollment
                optional: true
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities:
              drop: ["ALL"]
          resources:
            requests:
              cpu: 50m
              memory: 32Mi
            limits:
              memory: 256Mi
          volumeMounts:
            - name: data
              mountPath: /var/lib/provibr-agent
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: provibr-agent-data
Houd replicas op 1 en de strategie op Recreate. Eén agent is één identiteit: twee pods op hetzelfde volume delen één certificaat en duwen elkaar van het platform, en twee pods met elk een eigen volume schrijven zich allebei in, waarna alleen de laatste geldig is. Een rolling update zou precies dat even doen.
De ping-check gebruikt een ICMP-socket zonder rechten, niet de capability NET_RAW. Sommige containerruntimes houden die sockets dicht; gemeten met ze dicht viel een diagnostische ping terug op TCP en meldde de monitoringcheck een bronfout. Het manifest zet ze open voor de groep van de agent met de veilige sysctl net.ipv4.ping_group_range. NET_RAW toevoegen helpt niet: de agent draait niet als root, dus hij krijgt geen effectieve capabilities.

Voor Kubernetes is het licentiebestand de betere weg: zet het licentiebestand en de code in het secret in plaats van de installatielink, koppel het bestand in de pod en zet PROVIBR_LICENSE_FILE op het pad ervan. Het token in het bestand werkt precies één keer, dus het secret bevat niets waarmee de agent een tweede keer kan worden ingeschreven.

Een container bijwerken

Standaard werkt een container zichzelf niet bij: het image is de release. Het paneel toont welk image actueel is; haal het op en maak de container opnieuw aan, of zet de nieuwe tag op de deployment. Het volume bewaart identiteit en inloggegevens. Automatische updates slaan deze agents over; de optie hieronder verandert dat.

shell
docker pull ghcr.io/provibr/provibr-agent:latest
docker stop provibr-agent && docker rm provibr-agent
# then run the same docker run command again with the new image
shell
kubectl -n provibr-agent set image deployment/provibr-agent agent=ghcr.io/provibr/provibr-agent:latest

Optie: zichzelf bijwerken vanaf het volume

Zet PROVIBR_SELF_UPDATE=volume, of vink de optie aan in het paneel. De container doet dan mee met de updateknop en de nachtelijke updates: een nieuwe versie wordt gedownload, de handtekening wordt gecontroleerd tegen de platformsleutel die in het image zit, en hij komt op het volume. De container stopt met exitcode 0, Docker of de kubelet start hem opnieuw, en de binary in het image start de nieuwe versie vanaf het volume nadat hij de handtekening nog een keer heeft gecontroleerd.

shell
docker run -d --name provibr-agent --restart unless-stopped \
  --hostname provibr-agent \
  --read-only --cap-drop ALL --security-opt no-new-privileges \
  -v provibr-agent-data:/var/lib/provibr-agent \
  -e PROVIBR_INSTALL_URL='https://app.provibr.com/api/install/<token>' \
  -e PROVIBR_ACTIVATION_CODE='XXXXX-XXXXX' \
  -e PROVIBR_SELF_UPDATE=volume \
  ghcr.io/provibr/provibr-agent:latest

Een nieuwe versie heeft 60 seconden om het platform te bereiken. Lukt dat niet, dan wordt hij op het volume als slecht gemarkeerd en nooit meer gestart, en komt de container terug met de vorige versie. Rol je een nieuwer image uit, dan wint het image: wat er voor het oude image op het volume stond wordt niet meer gebruikt.

Wat je inruilt: de image-tag zegt niet meer welke versie er draait (het paneel wel), imagescanners kijken naar de binary in het image en niet naar die op het volume, en een GitOps-tool ziet een pod die iets anders draait dan zijn manifest zegt. Voor clusters die door een GitOps-tool beheerd worden raden we het niet aan.

Optie: het tools-image voor automatiseringen

Het standaardimage heeft geen runtime voor automatiseringen. Het tools-image, met het tag-achtervoegsel -tools, bevat dezelfde getekende agent op Debian met de vastgepinde runtime voor automatiseringen erbij, zodat automatiseringen in de container kunnen draaien. De Docker-voorbeelden geven het een kleine /tmp en een pids-limiet (--pids-limit); op Kubernetes is /tmp een emptyDir in het geheugen, en een pids-limiet stel je in op de kubelet (podPidsLimit), niet in het manifest. Het root-bestandssysteem blijft alleen-lezen.

shell
docker run -d --name provibr-agent --restart unless-stopped \
  --hostname provibr-agent \
  --read-only --cap-drop ALL --security-opt no-new-privileges \
  --tmpfs /tmp:rw,noexec,nosuid,size=16m --pids-limit 256 \
  -v provibr-agent-data:/var/lib/provibr-agent \
  -e PROVIBR_INSTALL_URL='https://app.provibr.com/api/install/<token>' \
  -e PROVIBR_ACTIVATION_CODE='XXXXX-XXXXX' \
  ghcr.io/provibr/provibr-agent:latest-tools
Op een Linux-host draait een automatisering in een sandbox met eigen namespaces: geen netwerk, geen bestanden van de host, een eigen procesboom. Een container kan die namespaces niet maken, dus in het tools-image begrenst de agent de runtime op twee andere manieren. Een seccomp-filter, dat op elke kernel werkt, blokkeert elke netwerksocket (TCP en UDP), signalen naar andere processen, het starten van nieuwe processen en het lezen van het geheugen van een ander proces. Landlock (Linux 5.13 of nieuwer) begrenst de bestanden: een script kan alleen de runtime en de systeembibliotheken lezen en niets schrijven. De agent test allebei bij het starten; laten de kernel of het seccomp-profiel van de containerruntime ze niet toe, dan blijven automatiseringen in de container uit. Wat overblijft is zwakker dan op een host: een script kan nog zien welke processen er in de container draaien. Wie het tools-image kiest, kiest daarvoor.

Wat niet werkt in een container

Sommige functies hebben de host zelf nodig, en die heeft een afgeschermde container niet:

  • Netwerkinstallaties (PXE): die hebben het hostnetwerk en poorten onder 1024 nodig.
  • De host herstarten vanuit het paneel: de container kan niet bij het init-systeem van de host.
  • Automatiseringen in het standaardimage: daar zit geen runtime voor automatiseringen in, en de sandbox die ze op een host krijgen heeft user namespaces nodig, die een afgeschermde container niet geeft. Het tools-image draait ze in plaats daarvan in de container zelf.
  • Hostmetingen: cpu, geheugen en uptime beschrijven de machine waarop de container draait, niet de eigen limieten van de container.

De activatiecode en het licentiebestand

Als je een agent aanmaakt, toont het paneel één keer een activatiecode. Hij wordt nergens vastgelegd, ook niet als hash. De code is waarmee het licentiebestand versleuteld is, dus het bestand op je host is versleuteld met iets dat niet op die host staat.

Code kwijt, of het bestand? Genereer een nieuw token op de agentpagina. Dat zet het vorige buiten werking, inclusief een licentiebestand dat al onderweg was, en levert je een nieuwe code en een nieuwe download op.

Het licentiebestand zelf draagt geen geheim over je infrastructuur. Het vertelt de agent bij welk platform hij hoort, welke certificaatautoriteit hij moet vertrouwen, en het eenmalige token waarmee hij enrollt.

Agents beheren in het paneel

De agentlijst laat alles in één keer zien: status, versie, of hij nu verbonden is, wanneer hij voor het laatst gezien is en wanneer zijn certificaat verloopt.

  • Naam en omschrijving mag je zelf wijzigen en zijn alleen labels. Een naam die al in een afgeleverd licentiebestand staat blijft zoals hij was; dat is cosmetisch en geen reden om opnieuw te enrollen.
  • Verbonden of niet wordt gelezen uit een live signaal met een korte houdbaarheid, niet uit het moment waarop er voor het laatst een regel is weggeschreven. Kunnen we het niet vaststellen, dan zegt het paneel dat, in plaats van te beweren dat je agent eruit ligt.
  • Versie en besturingssysteem zijn wat de agent bij zijn laatste verbinding meldde. Een agent die nooit verbond toont een streepje in plaats van een gok.
  • Selecteer meerdere agents in de lijst om ze in één keer bij te werken. De knop telt alleen de agents die nu echt bijgewerkt kunnen worden, dus je ziet vóór het klikken dat twaalf geselecteerd er drie bijgewerkt betekent.
  • De voortgang wordt gelezen uit de opdracht die loopt, niet uit iets dat je browser onthouden had, dus een herlaadbeurt pakt hem weer op.

De drie toestanden

Wacht op enrollment
Aangemaakt in het paneel, nog niet geënrolld. Er staat een token en een activatiecode voor hem klaar, en nog geen certificaat.
Geënrolld
Hij heeft zijn eigen certificaat en mag verbinden. Dit is de enige toestand waarin hij werk kan krijgen, en de enige waarin hij niet verwijderd kan worden.
Ingetrokken
Door jou ingetrokken. Zijn sessie is gesloten, openstaande tokens zijn vervallen, en terugkomen mag hij niet.

Een agent intrekken

Intrekken is de knop waar je naar grijpt als een host gecompromitteerd is, uit dienst gaat of gewoon niet meer van jou is. Het werkt zonder dat je de host aanraakt.

  • Een lopende sessie wordt binnen de minuut gesloten. De agent krijgt te horen waarom, in plaats van er zomaar uit te vliegen.
  • De agent wist daarna zijn eigen identiteit, zijn certificaat en zijn credential-vault. De inloggegevens van je hypervisor zijn van die host verdwenen.
  • Openstaande enrollment-tokens vervallen, dus een licentiebestand dat al gedownload was kan niet gebruikt worden om terug te komen.
Er is geen ongedaan maken. Een agent die je per ongeluk introk moet opnieuw aangemaakt, opnieuw geïnstalleerd en opnieuw van inloggegevens voorzien worden.

Een agent verwijderen

Verwijderen haalt de agent uit het paneel. Het is een aparte stap naast intrekken, en het is met opzet kieskeurig over wanneer het mag.

  • Een geënrollde agent kan niet verwijderd worden. Trek hem eerst in, want anders zou je de registratie weghalen van iets dat nog verbonden is.
  • Een agent met integraties of servers eronder kan ook niet verwijderd worden, en de weigering noemt allebei de aantallen. Die regels hangen aan de agent, dus één klik zou je inventaris meenemen.
  • Heeft de agent nooit een opdracht uitgevoerd en nooit een server gehad, dan verdwijnt de registratie echt. Anders wordt hij overal verborgen maar blijft zijn opdrachtgeschiedenis bewaard, want een auditspoor dat je kunt wissen door zijn onderwerp te verwijderen is geen auditspoor.

Hem van de host halen

Intrekken wist de geheimen van de agent maar laat de bestanden staan. Om de host op te ruimen biedt het paneel een tweede one-liner, en dezelfde vier stappen met de hand.

Dit script trekt niets in. Trek eerst in het paneel in en ruim daarna de host op, in die volgorde. Andersom houd je een host over die nog een geldige identiteit heeft.
  1. De service stoppen, uitzetten en de unit verwijderen.

    shell
    # Stop the service and forget the unit
    sudo systemctl disable --now provibr-agent
    sudo rm -f /etc/systemd/system/provibr-agent.service
    sudo systemctl daemon-reload
    sudo systemctl reset-failed provibr-agent 2>/dev/null || true
  2. De binary, het updatescript en de updatesleutel verwijderen.

    shell
    # Binary, update script and the trust anchor of the update step
    sudo rm -f /usr/local/bin/provibr-agent
    sudo rm -f /usr/local/lib/provibr-agent/apply-update.sh /usr/local/lib/provibr-agent/license-signing.pub
    
    # The polkit rule that allowed host.reboot (and its 0.105 fallback)
    sudo rm -f /etc/polkit-1/rules.d/49-provibr-agent-reboot.rules /etc/polkit-1/localauthority/50-local.d/49-provibr-agent-reboot.pkla
    
    # Only if nothing else lives in there
    sudo rmdir /usr/local/lib/provibr-agent 2>/dev/null || true
  3. De data verwijderen. Dit is de stap die telt: de licentie, de vault-sleutel en de versleutelde inloggegevens staan hier.

    shell
    # License and vault key
    sudo rm -rf /etc/provibr-agent
    
    # Identity, encrypted credential vault, outbox and staged updates
    sudo rm -rf /var/lib/provibr-agent
  4. Het serviceaccount verwijderen.

    shell
    sudo userdel provibr-agent
    sudo groupdel provibr-agent 2>/dev/null || true

Daarna horen deze twee allebei helemaal niets af te drukken:

shell
ls -d /etc/provibr-agent /var/lib/provibr-agent /usr/local/lib/provibr-agent /usr/local/bin/provibr-agent /etc/systemd/system/provibr-agent.service /etc/polkit-1/rules.d/49-provibr-agent-reboot.rules /etc/polkit-1/localauthority/50-local.d/49-provibr-agent-reboot.pkla 2>/dev/null
id provibr-agent 2>/dev/null
# Both commands should print nothing at all