JIT
← Notebook
Field notes HomelabDNSAutomation

Een AI-agent Technitium leren spreken

Een DNS-skill bouwen voor onze netwerkagent — en het twee-lagen-rechtenmodel dat onze zones verborg in het volle zicht.

We draaien een paar AI-agents in de homelab — één voor systemen, één voor security, één voor het netwerk. Het zijn geen chatbots die op een wiki zijn geschroefd. Elk is een dunne schil rond een set skills, en een skill is enkel de moeite waard om te bouwen als ze iets echts heeft om mee te praten. Dat onderscheid bepaalde het werk van deze week: de netwerkagent controle geven over DNS.

Een skill is tools, geen handboek

De eerste beslissing was wat we niet zouden bouwen. Het is verleidelijk om een “DNS-skill” te maken volgepropt met uitleg over zones, records, TTL’s en delegatie. Dat deden we niet. Een taalmodel weet al wat een CNAME is — dat in tooling verpakken verspilt enkel tokens om het dingen aan te leren waar het geen fouten tegen maakt.

Dus splitsten we op per target, niet per onderwerp: een skill voor de resolverconfig van de host, en een aparte voor wat onze DNS echt serveert — Technitium. De taak van de skill is niet om DNS uit te leggen. Het is om te weten wat Technitium anders doet.

De eigenaardigheid die het vastleggen waard is: 200 OK bij een fout

En Technitium heeft eigenaardigheden die het vastleggen waard zijn. De grootste: zijn HTTP-API geeft 200 OK terug, zelfs wanneer de request faalde. Of het lukte of niet, staat in een status-veld in de body, niet in de HTTP-code:

{ "status": "error", "errorMessage": "Access was denied." }

Dat arriveert met een opgewekte HTTP/1.1 200. Vertrouw op de statusregel en je rapporteert een write als “klaar” terwijl de server hem stilletjes weigerde. Dus de client controleert elke keer de body — en we schreven die regel in de reference van de skill, zodat de agent algemene DNS-kennis op zijn Technitiums toepast.

Gated writes en een tweede token

We waren voorzichtig met wijzigingen. Reads gebruiken een read-only token; writes gebruiken een apart read-write token, zodat een leespad nooit per ongeluk schrijfrechten kan meedragen. Elke write-tool is gated: roep ze één keer aan en ze geeft een preview terug — “voeg A-record nas.home.arpa → 10.100.0.20 toe” — en doet niets. Pas na expliciete goedkeuring voert ze uit. Geen stille wijzigingen aan live DNS.

De hapering: een zone die bestond en niet bestond

Toen kwam de kink in de kabel die ons een uur kostte. Een round-trip-test maakte een zone aan, voegde een record toe… en het teruglezen faalde met “Access was denied.” Vreemd — de read-only gebruiker had, zo werd ons verteld, leesrechten op alles. Nog vreemder: de zones oplijsten met het RO-token gaf nul zones terug, terwijl het RW-token de zone die we net hadden gemaakt wél zag. Een zone die bestond en niet bestond, afhankelijk van wie het vroeg.

De boosdoener was Technitiums twee-lagen-rechtenmodel. Er is een sectie-recht (“mag deze gebruiker de Zones-pagina zien?”) en een apart per-zone-recht op elke individuele zone. Een vers aangemaakte zone geeft enkel toegang aan zijn maker en de Administrators-groep. Onze RO- en RW-tokens horen bij twee verschillende gebruikers — dus een zone gemaakt door de RW-gebruiker was simpelweg onzichtbaar voor de RO-gebruiker. “View op alles” klopte op sectieniveau en was irrelevant op zoneniveau.

De fix kostte twee minuten zodra we het begrepen: voeg de read-only groep toe aan de rechten van de zone. Het RO-token lijstte de zone meteen op en las er elk record in.

De les

Een oude les in een nieuw jasje: rechten op sectieniveau en op objectniveau zijn niet hetzelfde, en een lege lijst is niet altijd een leeg systeem — soms is het gewoon een lijst die je niet mag zien. Het onthouden waard, of degene die leest nu een mens is of een agent.