Chrony-Time-Service(at)Work er en NTP-server med web-grensesnitt for testing i lukkede nett. Klokka på serveren kan settes til en vilkårlig tid eller forskyves, og alle klienter som synkroniserer mot den, følger etter. Dokumentet beskriver arkitekturen, hvordan klokka styres, sikkerhetsmekanismene, installasjonsmodellen og grensesnittene, og er skrevet for drift, sikkerhetsgjennomgang og videreutvikling.
1. Formål og omfang
Produkt |
Chrony-Time-Service(at)Work 9.0.0 |
Komponenter |
Web-GUI ( |
Bruksområde |
Testing av tidsavhengig oppførsel: utløp av sertifikater og lisenser, sommertid, skuddår, år 2038, alarmer for tidsavvik og bortfall av tidsserver |
Ikke formål |
Presis tidsserver for produksjon. I intern modus er klokka så riktig som du stiller den. |
Målplattformer |
Rocky Linux 9 / RHEL 9 / AlmaLinux 9 / Oracle Linux 9 (primær) og VMware Photon OS, som VM i VMware eller Proxmox VE, eller på fysisk maskin |
Kjøremodell |
chronyd fra operativsystemet og en Flask-applikasjon under gunicorn, begge styrt av systemd. Ingen containere, ingen pip, ingen internettilgang. |
Språk |
Engelsk og norsk (bokmål) i web-grensesnitt, meldinger, brukermanual og installasjonsskript |
Lisens |
MIT |
2. Arkitektur
2.1. Oversikt
Nettleser (administrator) │ HTTP :5032, Basic Auth, CSRF-token på alle POST ▼ gunicorn 23 + Flask 3.1 (app.py, i18n.py) bruker chronygui (ikke root) │ lesing: chronyc -c via localhost:323 (uten sudo) │ endringer: sudo -n /usr/local/sbin/ntpctl … (den eneste sudo-regelen) ▼ ntpctl (ntpctl.py, root, python3 -I) validerer all input på nytt ├─ clock_settime(CLOCK_REALTIME) stiller systemklokka ├─ hwclock --systohc valgfritt: skriver RTC ├─ /var/lib/ntpgui/settings.json → /etc/chrony.conf └─ systemctl start|stop|restart chronyd ▼ chronyd (fra OS-et) ◀── UDP 123 ── NTP-klienter i testnettet
2.2. Kodemoduler
| Fil | Innhold |
|---|---|
|
Flask-applikasjonen: ruter, autentisering, CSRF, sikkerhetshoder, parsing av |
|
Norske oversettelser (engelsk er nøkkelen), oversettelse av meldinger fra |
|
Privilegert hjelper. Underkommandoene |
|
|
|
Bootstrap 5.3.7 (CSS), |
|
Brukermanualen som HTML, bygget fra |
|
Felles skallfunksjoner: språk, utskrift, plattformgjenkjenning, |
2.3. Prosessmodell og rettigheter
| Prosess | Bruker | Rettigheter |
|---|---|---|
|
|
|
|
|
Ingen. Én worker med fire tråder, |
|
root via sudo |
Startes for hver handling og avslutter etterpå. |
--timeout 0 er nødvendig fordi gunicorns overvåking av workeren bruker veggklokka. Når klokka stilles fram, ville workeren ellers bli drept midt i forespørselen. Hver underkommando har i stedet sin egen tidsgrense.
3. Tidsstyring
3.1. Moduser og chrony.conf
ntpctl lager hele /etc/chrony.conf fra settings.json. Bare disse direktivene kan forekomme:
| Modus | Direktiver |
|---|---|
Intern |
|
Ekstern |
|
Begge |
|
Fila skrives atomisk (midlertidig fil og rename), og SELinux-merkingen gjenopprettes med restorecon.
3.2. Stille og forskyve klokka
-
Sett tid og Synk til denne PC-ens tid sender et epoketall til
ntpctl settime. Forskyv sender sekunder tilntpctl shift, som legger dem til gjeldende tid. -
ntpctlkallertime.clock_settime(CLOCK_REALTIME, …). Klokka hopper; chronyd ser hoppet og serverer den nye tiden fra neste svar. I intern modus er systemklokka selv referansen (LOCAL, ref-ID7F7F0101). -
Gyldig område: 2000-01-01 til 2099-12-31 UTC. Største forskyvning: 10 år.
-
I ekstern modus trekker chronyd en manuelt endret klokke tilbake mot oppstrømsserverne. Resynk fra oppstrøms kjører
chronyc burst 4/4, venter, kontrollerer at en oppstrømskilde er valgt og kjørerchronyc makestep. Uten nåbar kilde endres ikke klokka. -
Med Skriv også til RTC kjøres
hwclock --systohcetterpå.
3.3. Statusavlesning
Siden henter /api/status hvert 5. sekund. app.py leser chronyc -c -n tracking og sources som brukeren chronygui gjennom chronyds kommandoport (UDP 323 på localhost), uten sudo. Klientlisten (chronyc clients) krever root og hentes gjennom ntpctl overview ved sidevisning. Live-klokka i nettleseren beregner forskjellen mellom serverens og nettleserens tid ut fra midtpunktet av forespørselen, og tikker lokalt mellom avlesningene.
3.4. Tidssynk fra hypervisor
ntpctl ser etter agenter som kan stille klokka utenom chrony, og GUI-et viser en advarsel for hver:
-
qemu-guest-agent,vboxadd-service,systemd-timesyncd,ntpd,ptp4l,phc2sys(systemd-enheter som kjører) -
periodisk tidssynk i VMware Tools (
vmware-toolbox-cmd timesync status) -
Hyper-V (
hv_utils)
install.sh slår av den periodiske synken i VMware Tools og skriver ut .vmx-parametrene som også må settes. For Proxmox VE 9.2.5 og nyere er det agent-valget sync-time-on-resume som avgjør om Proxmox stiller gjesteklokka etter gjenopptak, migrering og tilbakerulling. Det står av som standard.
4. Web-grensesnitt
4.1. Sider og HTTP-API
| Sti | Metode | Innhold |
|---|---|---|
|
GET |
Hovedsiden: klokke, tjeneste, system, still klokka, konfigurasjon, tabeller |
|
POST |
Alle handlinger ( |
|
GET |
JSON: |
|
GET |
Revisjonslogg, chronyd-journal, |
|
GET |
Brukermanualen på valgt språk |
|
GET |
|
|
GET |
Maskinlesbar liste over tredjepartskomponenter |
|
GET |
Lagrer språkvalget i informasjonskapselen |
|
GET |
|
4.2. Språk (i18n)
-
Engelsk tekst er nøkkelen.
i18n.NOholder den norske oversettelsen. Malene bruker_("…"), og Python-kodentr("…"). Mangler en oversettelse, vises engelsk. -
Språket for en forespørsel er informasjonskapselen
ntpgui_lang, ellersDEFAULT_LANGfrantpgui.env(install.sh --lang). -
Meldinger fra
ntpctler alltid på engelsk og oversettes med en liste regulære uttrykk ii18n.MESSAGE_PATTERNS. -
Tekster til
app.jssendes i<body data-i18n="…">, siden Content Security Policy ikke tillater innebygde skript. -
Testen
tests/test_i18n.pyfinner alle tekster i malene ogapp.pyog feiler hvis noen mangler norsk oversettelse eller har ulike plassholdere.
4.3. Lisenser og manual
Bunnlinjen på alle sider har lenkene Lisenser · Tredjepartsmerknader · Brukermanual. Lisensfilene leses fra NTPGUI_DOC_DIR (/opt/ntpgui). Brukermanualen er ferdig HTML i manual/manual.no.html og manual.en.html, laget med pandoc fra docs/Brukermanual.md og docs/en/User-Manual.md. Bildene ligger i static/img/.
5. Sikkerhet
5.1. Tilgangskontroll
-
Alle sider unntatt
/healthzog/static/krever HTTP Basic Auth. Brukernavn og passord sammenlignes medhmac.compare_digest. Uten passord intpgui.envslipper ingen inn. -
Alle POST krever et CSRF-token som ligger i en signert øktcookie (
SameSite=Strict,HttpOnly). -
Sikkerhetshoder:
Content-Security-Policy: default-src 'self'; style-src 'self'; script-src 'self'; img-src 'self' data:; frame-ancestors 'none'; form-action 'self',X-Frame-Options: DENY,X-Content-Type-Options: nosniff,Referrer-Policy: same-origin,Cache-Control: no-store. -
Språkbyttet godtar bare lokale stier i
next(ikke//vert, ikkehttps://…), så det kan ikke brukes til å sende brukeren videre til et annet nettsted. -
--admin-netbegrenser GUI-porten i firewalld til ett nett.
5.2. Validering i ntpctl
ntpctl stoler ikke på GUI-et og kontrollerer alt på nytt:
-
tid som tall mellom 2000 og 2099 (UTC), forskyvning høyst 10 år, ikke
NaN -
modus
internal/external, stratum 1–15 -
servere: IP-adresse (
ipaddress) eller vertsnavn etter et strengt mønster (RFC 1123), valgfritt med `pool ` foran, høyst 8 -
nett:
ipaddress.ip_networkellerall, høyst 32 -
chrony.confbygges fra en hviteliste, så det er ikke mulig å injisere egne direktiver -
alle kommandoer kjøres som argumentlister uten skall
5.3. Kjente begrensninger
-
Basic Auth over HTTP sender passordet i klartekst. GUI-et er ment for et lukket testnett. Bruk
--admin-net, eller--bind 127.0.0.1med SSH-tunnel. -
NTP er uautentisert. Alle i de tillatte nettene kan spørre serveren, og en angriper i nettet kan forfalske svar. Det er akseptabelt for en testklokke.
-
ntpgui.servicekan ikke brukeNoNewPrivilegesellerProtectSystem, sidenntpctlstartes gjennom sudo. -
click 8.1.8 har et kjent funn (PYSEC-2026-2132) i
click.edit(), som ikke brukes. Rettet versjon krever Python 3.10 (se Revisjonsrapporten).
6. Installasjon og filstruktur
6.1. Installasjonsprogrammet
install.sh er idempotent: det kan kjøres på nytt for å oppgradere eller endre passord, port og språk. Rekkefølgen er beskrevet i Installasjonsveiledningen, kapittel 5.1. Viktige detaljer:
-
SHA256SUMSkontrolleres før noe endres. -
Plattformen finnes med
/etc/os-releaseogsystemd-detect-virt.CAP_SYS_TIMEleses fraCapBndi/proc/self/status. Mangler den, legges en drop-in for chronyd inn med-x. -
Programmet byttes ut som en helhet (
app.new→app), så filer som er fjernet i en ny versjon, forsvinner. -
Sudo-regelen kontrolleres med
visudo -cffør den tas i bruk. -
Til slutt kontrolleres
/healthzog et NTP-svar på UDP 123 (ntpcheck.py). Avslutningskoden er 2 hvis selvtesten feiler.
6.2. Installert struktur
| Sti | Innhold |
|---|---|
|
|
|
Python-pakkene, utpakket fra hjulene |
|
Brukes av |
|
Dokumentene |
|
Lisenser og versjon |
|
Avinstallering og NTP-kontroll |
|
Hjelperen (root:root 0755) |
|
|
|
Tjenesten |
|
Bruker, passord, |
|
|
|
Innstillingene fra GUI-et |
|
Revisjonslogg (tid, monoton tid, IP, bruker, handling) |
|
Original |
6.3. Python-pakker
Hjulene i vendor/wheels pakkes ut med python3 -m zipfile -e i /opt/ntpgui/lib/python. Rene Python-hjul (py3-none-any) virker overalt. For MarkupSafe velges hjulet for gjeldende Python-versjon og arkitektur (Python 3.9 og 3.11, x86_64 og aarch64). Finnes det ikke, brukes et hvilket som helst MarkupSafe-hjul: C-utvidelsen lastes da ikke, og MarkupSafe bruker sin rene Python-utgave. Etter utpakking kontrolleres at flask, gunicorn, jinja2 og markupsafe kan importeres, før den gamle mappa byttes ut.
| Pakke | Versjon | Formål |
|---|---|---|
Flask |
3.1.3 |
Web-rammeverk |
Werkzeug |
3.1.9 |
HTTP og ruting |
Jinja2 |
3.1.6 |
Maler |
MarkupSafe |
3.0.4 |
HTML-escaping |
itsdangerous |
2.2.0 |
Signert øktcookie |
click |
8.1.8 |
Krav fra Flask, brukes ikke |
blinker |
1.9.0 |
Krav fra Flask |
gunicorn |
23.0.0 |
WSGI-server, nyeste med Python 3.9 |
packaging |
26.3 |
Krav fra gunicorn |
importlib_metadata |
8.7.1 |
Krav fra Flask på Python 3.9 |
zipp |
3.23.1 |
Krav fra importlib_metadata |
6.4. Oppgradering fra v8
v8 installerte Python-pakkene i en venv (/opt/ntpgui/venv). 9.0.0 bruker samme stier for innstillinger, logger, bruker og hjelper. install.sh kjenner igjen v8, beholder ntpgui.env (passord, port), settings.json og /etc/chrony.conf.ntpgui-orig, legger til DEFAULT_LANG, GUI_LISTEN og PYTHONPATH, og fjerner venv-mappa.
7. Nettverk og eksterne ressurser
7.1. Porter
| Port | Protokoll | Bruk |
|---|---|---|
123 |
UDP |
NTP. Åpnes i firewalld (tjenesten |
5032 |
TCP |
Web-GUI-et ( |
323 |
UDP |
chronyds kommandoport, bare på localhost |
7.2. Eksterne ressurser
| Situasjon | Eksterne ressurser |
|---|---|
|
Ingen. Hjulene pakkes ut lokalt. |
|
|
Drift i intern modus (standard) |
Ingen. Serveren tar ikke kontakt med noe utenfor maskinen. |
Drift i ekstern modus |
NTP (UDP 123) til serverne som er lagt inn, og DNS-oppslag på navnene |
Nettleseren |
Ingen. Alt hentes fra serveren selv (CSP |
Docker-varianten (valgfri) |
|
8. Drift
| Oppgave | Kommando |
|---|---|
Status |
|
Logger |
|
Helsesjekk |
|
NTP-kontroll |
|
Selvtest |
|
Passord, port, språk |
|
Fra skallet |
|
Avinstallering |
|
Revisjonsloggen skriver både systemtiden (som kan være endret) og mono= (sekunder siden oppstart). Rekkefølgen og avstanden mellom hendelser kan dermed leses selv etter store hopp.
9. Kvalitetssikring
| Kontroll | Innhold |
|---|---|
Enhetstester ( |
53 tester: innlogging, CSRF, alle handlinger, validering, språkbytte, åpen redirect, lisenssider, manual på begge språk, oversettelse av meldinger, |
|
Alle tekster har norsk oversettelse med samme plassholdere |
Selvtest ( |
37 kontroller mot en installert server med ekte chronyd, sudo og klokkestyring |
Installasjonstester |
Ny installasjon, oppgradering fra v8, ny kjøring, avinstallering, VMware- og KVM-gjenkjenning, LXC uten |
Statisk analyse |
|
Byggekontroll |
|
Resultatene står i Revisjonsrapporten.