$ cat docs/README
Dokumentace platformy Pampeliška 3.0
Příručka pro administrátora, který platformu nasazuje a provozuje: od požadavků přes instalaci až po zálohy, upgrade a řešení problémů. Adresy a domény v příkladech jsou ilustrační — nahraďte je hodnotami svého prostředí.
01Úvod a komponenty
Pampeliška 3.0 je Infrastructure-as-Code platforma: tři virtuální stroje tvoří K3s cluster s embedded etcd, který provisionuje Ansible a jehož veškerý další stav (infrastruktura i aplikace) popisují manifesty v Git repozitáři a nasazuje Flux CD. Nad clusterem běží automatizace (Semaphore UI + Ansible), trezor tajemství pro automatizaci (OpenBao), datová vrstva (PostgreSQL + PostgREST), interní PKI a monitoring.
| Komponenta | Role |
|---|---|
| K3s | Kubernetes distribuce; 3 serverové uzly s embedded etcd (řídicí vrstva). |
| kube-vip | Plovoucí virtuální IP pro Kubernetes API (API VIP). |
| WireGuard | Šifrovaný mesh mezi uzly (node↔node); provoz podů šifruje Flannel v režimu wireguard-native. |
| Ansible | Provisioning: VM na hostiteli LXD/MicroCloud (lxd_vms), S3 cíl záloh (backup_s3), základní konfigurace uzlů (common), CIS hardening (hardening), hostový firewall (firewall), WireGuard, K3s, kube-vip a důvěra v interní CA na uzlech (pki_trust). |
| Flux CD | GitOps: průběžně srovnává cluster se stavem v Gitu; nasadí jen revizi s podepsaným posledním commitem (GPG podpis HEAD). Stav Kustomizací a HelmReleasů ukáže flux get all -A. |
| Gitea | Git server uvnitř clusteru, ze kterého Flux čte manifesty (1 instance, SQLite na lokálním úložišti uzlu). |
| MetalLB | Přiděluje IP adresy službám typu LoadBalancer (ingress, CA). |
| Traefik | Ingress controller — HTTPS vstup pro webová rozhraní a API. |
| Longhorn | Distribuované blokové úložiště pro perzistentní svazky (2 repliky), snapshoty a zálohy do S3. |
| Garage | S3 úložiště záloh mimo cluster (VM na samostatném hostiteli, TLS přes nginx, denní snapshoty VM). |
| CloudNativePG | Operátor PostgreSQL 16: HA cluster, failover, zálohy a WAL archivace do S3; pooler PgBouncer (2 instance). |
| PostgREST | REST API nad databází (grafový model nodes/edges). |
| Semaphore UI | Webové rozhraní pro spouštění a plánování Ansible playbooků. |
| step-ca + step-issuer | Interní certifikační autorita (ACME a JWK provisioner); step-issuer napojuje step-ca na cert-manager. |
| cert-manager + trust-manager | Automatické vystavení a obnova certifikátů; distribuce kořenového certifikátu CA do namespaců. |
| Sealed Secrets | Šifrovaná tajemství v Gitu; dešifruje je jen controller v clusteru. |
| OpenBao | Trezor přístupových údajů pro automatizaci (síťové prvky, firewally, servery, API tokeny); 3 repliky s integrovaným úložištěm Raft, audit každého přístupu. Viz Tajemství (OpenBao). |
| Trivy Operator | Průběžné skenování zranitelností image a konfigurace; generuje SBOM (SbomReport). |
| Prometheus, Alertmanager, Grafana | Metriky, alerty a dashboardy. |
| Loki + Grafana Alloy | Sběr a uložení logů včetně auditního logu Kubernetes API (Alloy je sběrný agent). Viz Audit Kubernetes API. |
| ntfy | Doručování notifikací z Alertmanageru (self-hosted push notifikace). |
Plánované funkce zde popsané nejsou — viz Roadmapa na hlavním webu.
02Požadavky
Uzly clusteru
Tři VM clusteru zakládá samo nasazení (Ansible role lxd_vms, první krok ansible/playbooks/site.yml) na hostiteli LXD/MicroCloud. Parametry VM jsou v ansible/roles/lxd_vms/defaults/main.yml:
| Parametr | Hodnota |
|---|---|
| Počet VM | 3 |
| vCPU / RAM na VM | 4 vCPU / 8 GiB (minimum); doporučeno 12 GiB RAM — proměnná lxd_vm_memory, viz měření níže |
| Disky na VM (SSD) | systémový 40 GiB + datový 60 GiB pro Longhorn (druhý disk /dev/sdb; role common ho naformátuje a připojí podle labelu) |
| Operační systém | Ubuntu Server 24.04 LTS |
| Kubernetes | podporovaná řada K3s dle lifecycle politiky |
| Přístup | SSH s klíčem z řídicího stroje (veřejný klíč ~/.ssh/id_ed25519.pub vloží do VM cloud-init); uživatel podle remote_user v ansible/ansible.cfg a ssh_allowed_users ve vars.yml, se sudo |
Bez spravovaných workloadů spotřebuje Kubernetes na třech uzlech celkem zhruba 13 GiB RAM z 24 GiB (~55 %) a 3,7 jádra CPU z 12 (~30 %). Nejvíc paměti berou monitoring (~3 GiB: Prometheus, Grafana, Loki, Alloy) a Longhorn (~1,5 GiB). Rozložení mezi uzly je nerovnoměrné — nejvytíženější uzel měl ~74 % RAM. 8 GiB na VM je proto minimum; aby při výpadku uzlu zbylé dva unesly celý cluster, doporučujeme 12 GiB RAM na VM.
Virtualizační hostitelé
Referenčním prostředím je Canonical MicroCloud — 3 fyzické servery s LXD (VM), MicroCeph (úložiště VM, RBD) a MicroOVN (síť). Tři VM clusteru jsou rozložené na všechny tři servery, úložiště záloh (Garage, S3) běží v samostatné VM na serveru MicroCloudu. Pozor: tím sdílí hardware i Ceph s clusterem, takže zálohy nejsou fyzicky oddělené — pro produkci použijte S3 na samostatném hostiteli nebo mimo lokalitu (proměnné backup_s3_*). VM jsou připojené do OVN sítě se statickými IP adresami portů; virtuální IP (kube-vip pro API, MetalLB pro ingress a CA) v OVN síti fungují. Postup pro MicroCloud viz Instalace na Canonical MicroCloud.
- Hostitel LXD/MicroCloud pro VM clusteru — po
lxd init, se storage poolem a sítí, které odpovídají proměnnýmlxd_*(lxd_remote_host,lxd_storage_pool,lxd_network,vm_gatewaya seznamlxd_vmsse jmény a IP adresami VM). - Samostatný LXD hostitel pro úložiště záloh — role
backup_s3na něm založí VM s Garage (2 vCPU, 2 GiB RAM, disk 60 GiB). Proměnnébackup_s3_*jsou vansible/roles/backup_s3/defaults/main.yml(mj.backup_s3_lxd_host,backup_s3_vm_ip). Hostitel je samostatný, aby zálohy přežily ztrátu clusteru. - Na obou hostitelích musí předem existovat SSH uživatel z
ansible.cfg(remote_user) s vaším veřejným klíčem a sesudobez hesla — první krok nasazení se připojuje přímo na hostitele, protože VM ještě neexistují. - Jinou virtualizaci (VMware, cloud) referenční provisioning nepodporuje; VM připravíte sami a krok LXD se upraví v rámci onboardingu.
Síť
Kromě adres tří uzlů (v příkladech 192.168.10.11–13) potřebujete tři pevné, nepoužívané IP adresy ve stejném segmentu a adresu VM úložiště záloh:
| Účel | Příklad | Poskytuje |
|---|---|---|
| API VIP (Kubernetes API) | 192.168.10.20 | kube-vip |
| Ingress (HTTPS vstup webových služeb) | 192.168.10.21 | MetalLB → Traefik |
| Certifikační autorita (step-ca) | 192.168.10.22 | MetalLB → step-ca |
| VM úložiště záloh (Garage), mimo pool MetalLB | 192.168.10.30 | role backup_s3 |
DNS záznamy pro webová rozhraní (např. *.example.internal) směrujte na adresu ingressu.
Úložiště záloh
S3 kompatibilní objektové úložiště mimo cluster (referenční nasazení: Garage ve VM na samostatném LXD hostiteli, v příkladech https://s3.example.internal:9000), dostupné z uzlů přes HTTPS. Zakládá ho ansible/playbooks/backup-s3.yml, který deploy.sh spouští před nasazením clusteru. Zálohy uložené uvnitř clusteru by při jeho ztrátě zmizely spolu s ním.
Řídicí stroj
Instalace se spouští z řídicího stroje. Dnes je to macOS — tajemství se ukládají do macOS Keychain. Potřebné nástroje:
kubectl, ansible-playbook, ansible-vault, git, openssl, curl, python3, gpg, kubeseal, flux (Flux CLI). Volitelně bao (OpenBao CLI) pro práci s tajemstvími z příkazové řádky.
GPG podpisový klíč musí být v lokálním keyringu a v git config user.signingkey ještě před prvním commitem — Flux přijme jen podepsaný HEAD větve main a bootstrap.sh bez klíče odmítne pokračovat.
Ansible kolekce mimo ansible-core nainstalujete z pinovaného seznamu:
ansible-galaxy collection install -r ansible/requirements.yml03Instalace
Repozitář platformy si naklonujte na řídicí stroj; přístup k repozitáři poskytujeme na vyžádání (support@pampeliska.io).
git clone <URL repozitáře> pampeliska && cd pampeliska-
Upravte inventář a proměnné. Výchozí hodnoty v repozitáři popisují referenční prostředí — před instalací je nahraďte svými:
ansible/inventory/hosts.yml— adresy tří uzlů (první uzel mák3s_init: true) a jejich adresy ve WireGuard síti,ansible/inventory/group_vars/all/vars.yml—vip_address,kube_vip_interface,wireguard_subnet,backup_s3_endpoint,cluster_domain,ssh_allowed_usersa verze komponent,- proměnné
lxd_*(ansible/roles/lxd_vms/defaults/main.yml) abackup_s3_*(ansible/roles/backup_s3/defaults/main.yml) — viz Požadavky; IP adresy VM vlxd_vmsmusí odpovídatansible_hostv inventáři, - IP adresy služeb: pool v
kubernetes/infrastructure/metallb/pool.yamla anotacemetallb.io/loadBalancerIPsv HelmRelease Traefiku (kubernetes/infrastructure/traefik/) a step-ca (kubernetes/infrastructure/step-ca/), - domény v manifestech
IngressRoutea povolené správcovské sítě pro OpenBao vkubernetes/infrastructure/openbao/allowlist.yaml, - wildcard certifikát pro vaši doménu nakopírujte do gitignorovaného adresáře
certs/(názvy souborů očekáváscripts/prepare-secrets.sh).
# ansible/inventory/hosts.yml (výřez) node1: ansible_host: 192.168.10.11 wireguard_ip: 172.16.10.1 # adresa v overlay síti WireGuard — musí ležet ve wireguard_subnet k3s_init: true node2: ansible_host: 192.168.10.12 wireguard_ip: 172.16.10.2 k3s_init: false node3: ansible_host: 192.168.10.13 wireguard_ip: 172.16.10.3 k3s_init: false # ansible/inventory/group_vars/all/vars.yml (výřez) vip_address: 192.168.10.20 wireguard_subnet: 172.16.10.0/24 # výchozí hodnota v repu je jiná — změňte ji spolu s wireguard_ip backup_s3_endpoint: "192.168.10.30:9000" cluster_domain: example.internal -
Připravte tajemství.
./scripts/prepare-secrets.shSkript vygeneruje sealing klíč Sealed Secrets a další tajemství do macOS Keychain (včetně klíče pro odpečetění OpenBao a hesla jeho nouzového účtu
admin), vytvoří Ansible Vault a přepečetí SealedSecrets vkubernetes/infra-config/sealed-secrets/. Je idempotentní: existující položky Keychain nepřegeneruje. -
Commitněte přepečetěná tajemství podepsaně do
main. Bootstrap nahraje větevmainz vašeho checkoutu do Gitea v clusteru a Flux z ní nasazuje — nepodepsaný HEAD nebo nezacommitované SealedSecrets cluster nerozběhnou.git add kubernetes/infra-config/sealed-secrets/ ansible/inventory/ # + další upravené soubory git commit -S -m "chore: přepečetěná tajemství a inventář" -
Spusťte nasazení. Z kořene repozitáře:
./deploy.sh --skip-secretsVolba
--skip-secretspřeskočí přípravu tajemství (proběhla v kroku 2). Skript spustíscripts/bootstrap.sh, který postupně:- zkontroluje prerekvizity na řídicím stroji (nástroje, položky Keychain, GPG klíč),
- spustí
ansible/playbooks/backup-s3.yml(VM s úložištěm záloh) aansible/playbooks/site.yml(VM clusteru, příprava OS, hardening, WireGuard, K3s HA, kube-vip, hostový firewall), - stáhne kubeconfig, obnoví sealing klíč z Keychain do clusteru, nasadí Gitea v clusteru, nahraje do ní repozitář a napojí Flux.
Samotné
./deploy.sh(bez volby) spustíprepare-secrets.shi bootstrap za sebou, bez prostoru pro commit mezi nimi — pro čistou instalaci proto použijte postup výše. Nápověda:./deploy.sh --help. -
Ověřte stav.
export KUBECONFIG=~/.kube/pampeliska.yaml kubectl get nodes -o wide # 3 uzly ve stavu Ready flux get all -A # všechny zdroje a Kustomizace Ready=True kubectl get pods -A | grep -v -E 'Running|Completed' # nic nevisíPrvní reconcile všech komponent trvá několik minut; stav sledujte opakováním
flux get kustomizations -A.
Uložte kopii sealing klíče (pampeliska-sealing-key) a klíče pro odpečetění OpenBao z Keychain do trezoru mimo řídicí stroj a vyexportujte klíče PKI — viz Klíče a tajemství. Bez sealing klíče nelze po obnově clusteru dešifrovat tajemství v Gitu, bez klíče pro odpečetění nelze obnovit data OpenBao.
OpenBao ani další komponenty clusteru se ručně neinstalují — nasadí je Flux z Gitu. OpenBao se při prvním startu samo inicializuje z konfigurace v Gitu (viz Tajemství).
Opakované spuštění provisioningu je idempotentní (nemění nic, co už odpovídá):
ansible-playbook ansible/playbooks/site.ymlInstalace na Canonical MicroCloud (OVN)
Referenční nasazení na MicroCloudu je v repozitáři vedené jako samostatná větev prostředí s vlastním inventářem ansible/inventory/<prostředí>/ (hosts.yml a group_vars/all/vars.yml). Pro síť OVN nastavuje inventář mj.:
# ansible/inventory/<prostředí>/group_vars/all/vars.yml (výřez)
lxd_network: default # spravovaná síť OVN
lxd_nic_type: ovn
lxd_storage_pool: remote # Ceph RBD
vm_gateway: 192.168.10.1 # router sítě OVN
lxd_vms: # statické IP portů — musí odpovídat ansible_host
- { name: pampeliska-1, ip: 192.168.10.11 }
- { name: pampeliska-2, ip: 192.168.10.12 }
- { name: pampeliska-3, ip: 192.168.10.13 }Instalaci obaluje skript scripts/bootstrap-microcloud.sh. Nastaví inventář prostředí, adresu prvního uzlu a API VIP, vlastní kubeconfig a endpoint S3 a jako zdroj pro in-cluster Gitea zrcadlí aktuální větev checkoutu. Postup:
-
Tajemství (volá
prepare-secrets.sh):./scripts/bootstrap-microcloud.sh secrets -
Podepsaný commit přepečetěných SealedSecretů do větve prostředí:
git add kubernetes/infra-config/sealed-secrets/ git commit -S -m "chore(env): přepečetěná tajemství" -
Nasazení (volá
bootstrap.sh: VM úložiště záloh, VM clusteru a K3s, Gitea, Flux):./scripts/bootstrap-microcloud.sh deploy
Selže-li bootstrap uprostřed, pokračujte od daného kroku bez nového provisioningu VM — kroky jsou provision_cluster, fetch_kubeconfig, restore_sealing_key, bootstrap_gitea, seed_gitea, flux_install_controllers, apply_gotk_sync, finalize (kontrola prerekvizit běží vždy):
START_AT=seed_gitea ./scripts/bootstrap-microcloud.sh deployNa referenčním MicroCloudu trvá čistá instalace zhruba hodinu: provisioning VM a K3s ~15 minut, vrstvy Flux ~8 minut, start všech služeb dalších 20–30 minut.
Pro další prostředí zkopírujte vzor: adresář inventáře, adresy ve wrapperu (první uzel, API VIP, endpoint S3), pool MetalLB a anotace IP adres Traefiku a step-ca. Pokud veřejné DNS směruje názvy platformy jinam než na ingress clusteru, doplňte remap v CoreDNS (kubernetes/extras/coredns-custom.yaml), jinak by Flux a pody chodily na služby mimo cluster.
04První přihlášení
| Služba | Adresa (příklad) | Uživatel | Heslo v Keychain |
|---|---|---|---|
| Semaphore UI | https://semaphore.example.internal | admin | pampeliska-semaphore-admin |
| Grafana | https://grafana.example.internal | admin | pampeliska-grafana-admin |
| Gitea | https://git.example.internal | gitea_admin | pampeliska-gitea-admin |
| OpenBao | https://bao.example.internal | admin (metoda Username) | pampeliska-openbao-admin |
| PostgREST API | https://restapi.example.internal | čtení anonymně, zápis JWT | pampeliska-pgrst-jwt (podpisový klíč) |
| ntfy | https://ntfy.example.internal | admin (viz Alerty) | pampeliska-ntfy-admin |
Úvodní hesla vygeneroval prepare-secrets.sh a uložil je do macOS Keychain řídicího stroje. Přečtete je takto:
security find-generic-password -s pampeliska-grafana-admin -wHesla po prvním přihlášení neměňte jen v aplikaci — zdrojem pravdy je Keychain + zapečetěný Secret v Gitu. Změnu proveďte úpravou položky v Keychain, novým během prepare-secrets.sh a commitem přepečetěných souborů.
Názvy hostů webových služeb jsou definované v manifestech IngressRoute v adresáři kubernetes/ a HTTPS ingressu obsluhuje wildcard certifikát pro vaši doménu, který se zapečetí při přípravě tajemství. Nastavení domén a dodání certifikátu je součástí onboardingu.
Napojení na firemní identitu (LDAP / SSO) není ve výchozí instalaci zapnuté; řeší se jako integrace v rámci onboardingu.
05Běžné použití
Spuštění playbooku v Semaphore UI
- V projektu založte Key Store položku (SSH klíč k cílovým strojům, případně heslo Ansible Vault). Přístupové údaje ke spravovaným zařízením a systémům do Semaphore neukládejte — playbook si je načte z OpenBao (viz Tajemství).
- Přidejte Repository s playbooky (Git URL a větev) a Inventory s cílovými hosty.
- Vytvořte Task Template: vyberte playbook, inventář, repozitář a klíč. Volitelně nastavte plán (cron) pro pravidelné spouštění.
- Spusťte šablonu tlačítkem Run a průběh sledujte ve výpisu úlohy. Historie běhů zůstává v Semaphore.
Data přes PostgREST
Databáze obsahuje grafový model infrastruktury: tabulka nodes (zařízení, služby, certifikáty…; pole id, type, name, properties JSONB) a edges (vztahy source_id → target_id s typem, např. depends_on). Změny v obou tabulkách zapisuje trigger do audit_log.
| Role | Jak ji získáte | Oprávnění |
|---|---|---|
web_anon | požadavek bez tokenu | čtení nodes, edges, v_graph_echarts; volání get_impact_radius |
web_user | JWT s claimem "role": "web_user" | plný zápis do nodes, edges; čtení audit_log |
# čtení
curl -s 'https://restapi.example.internal/nodes?type=eq.server&select=id,name,properties'
curl -s 'https://restapi.example.internal/edges?type=eq.depends_on'
# dopadová analýza: co všechno závisí na uzlu (průchod hran source → target, výchozí hloubka 3)
curl -s -X POST 'https://restapi.example.internal/rpc/get_impact_radius' \
-H 'Content-Type: application/json' \
-d '{"start_node": "<UUID uzlu>", "max_depth": 3}'Funkce vrací řádky node_id, node_name, node_type, depth, path (pole UUID); cykly v grafu se přeskakují.
Pro zápis podepište JWT algoritmem HS256 klíčem z Keychain položky pampeliska-pgrst-jwt. Příklad bez externích knihoven:
TOKEN=$(SECRET="$(security find-generic-password -s pampeliska-pgrst-jwt -w)" python3 - <<'EOF'
import base64, hashlib, hmac, json, os, time
b64 = lambda b: base64.urlsafe_b64encode(b).rstrip(b"=").decode()
h = b64(json.dumps({"alg": "HS256", "typ": "JWT"}).encode())
p = b64(json.dumps({"role": "web_user", "exp": int(time.time()) + 3600}).encode())
s = b64(hmac.new(os.environ["SECRET"].encode(), f"{h}.{p}".encode(), hashlib.sha256).digest())
print(f"{h}.{p}.{s}")
EOF
)
curl -s -X POST 'https://restapi.example.internal/nodes' \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-H 'Prefer: return=representation' \
-d '{"type": "server", "name": "app-01", "properties": {"criticality": "high"}}'Tokeny vydávejte s krátkou platností (exp) a podpisový klíč nesdílejte mimo administrátory.
Grafana dashboardy
Kromě standardních dashboardů Kubernetes z kube-prometheus-stack platforma obsahuje:
- Certificate Expiry — čas do expirace certifikátů v clusteru (z cert-manageru) a tabulka externích certifikátů evidovaných v databázi (tabulka
certificates). - Certificate Chain — strom řetězce interní PKI; koncové certifikáty načítá živě z tabulky
certificates. - ICT Topology, Dependency Impact Map a Firewall toky (Sankey) — ukázkové dashboardy nad demo daty: čtou statické tabulky
viz_topology_nodes/viz_topology_edges,viz_dependenciesaviz_firewall_flows, které naplní Jobinfra-viz-seed(kubernetes/apps/monitoring/infra-viz/). S grafovým modelemnodes/edgeszatím propojené nejsou; napojení na vaše data je součástí onboardingu. Dopadovou analýzu nadnodes/edgesnabízí funkceget_impact_radiusv REST API (viz výše).
Alerty
Alertmanager posílá alerty přes most ntfy-alertmanager do ntfy, topic alerts. ntfy běží s výchozím přístupem deny-all — anonymní čtení ani zápis nejsou povolené. Uživatelé a tokeny jsou deklarativní ze Secretu ntfy-auth, který vytváří prepare-secrets.sh:
admin— čte všechny topicy; heslo v Keychainpampeliska-ntfy-admin. Pro odběr alertů se v aplikaci ntfy nebo na webu přihlaste tímto účtem a přihlaste se k topicualerts.alertmanager— servisní účet mostu; smí jen zapisovat do topicualerts.
Alert na certifikáty hlásí zpožděnou obnovu (CertManagerCertRenewalOverdue — cert-manager měl certifikát obnovit před více než hodinou), ne „brzy vyprší“; vypršelý certifikát hlásí CertManagerCertExpired.
Účty ntfy jsou spravované deklarativně — další účet přidejte do scripts/prepare-secrets.sh (seznam users pro Secret ntfy-auth) a jeho oprávnění do proměnné NTFY_AUTH_ACCESS v kubernetes/apps/monitoring/ntfy/deployment.yaml (např. jmeno:alerts:ro). Účty přidané ručně příkazem ntfy user nemusí restart přežít.
06Certifikáty
Interní certifikáty vydává step-ca. Pro workloady v clusteru je žádá a obnovuje cert-manager přes step-issuer a issuer StepClusterIssuer s názvem step-ca-cluster-issuer.
Issuer není uložený v Gitu: odvozuje ho z běžící CA CronJob step-issuer-reconcile (namespace pki, každou hodinu). Po první instalaci nebo po reinicializaci CA proto může trvat až hodinu, než issuer existuje. Ruční spuštění:
kubectl -n pki create job --from=cronjob/step-issuer-reconcile step-issuer-reconcile-manual
kubectl get stepclusterissuer step-ca-cluster-issuerVystavení certifikátu
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: moje-aplikace
namespace: moje-aplikace
spec:
secretName: moje-aplikace-tls
dnsNames:
- app.example.internal
duration: 24h # platnost (výchozí krátká platnost)
renewBefore: 8h # obnova s předstihem
issuerRef:
group: certmanager.step.sm
kind: StepClusterIssuer
name: step-ca-cluster-issuerManifest commitněte do Gitu (viz GitOps). cert-manager uloží certifikát a klíč do Secretu secretName a obnovuje ho automaticky před vypršením. Stav:
kubectl get certificate -A
kubectl describe certificate moje-aplikace -n moje-aplikaceExpiraci hlídá alert v Prometheu (PrometheusRule cert-manager-expiry) a dashboard Certificate Expiry.
Důvěra v interní CA
- Workloady v clusteru — trust-manager vytváří v každém namespace s labelem
app.kubernetes.io/part-of: pampeliskaConfigMappampeliska-trust-bundle(klíčroot-ca.crt); připojte ji do trust storu aplikace. - Uzly clusteru — veřejný kořenový certifikát uložte do
ansible/roles/pki_trust/files/pampeliska-root-ca.crta spusťteansible-playbook ansible/playbooks/pki-trust.yml. - Pracovní stanice administrátorů — kořenový certifikát importujte ručně do systémového úložiště důvěry.
Externí zařízení a servery
Pro servery mimo cluster slouží playbook ansible/playbooks/cert-renewal.yml, spouštěný plánovaně ze Semaphore UI. Certifikát obnoví jen tehdy, když zbývající platnost klesne pod práh (renew_before_minutes), a webový server poté gracefully reloaduje. Na cílovém hostu musí být step CLI s bootstrapnutou CA a soubor s heslem JWK provisioneru (/etc/step/provisioner.pwd, práva 0600). Playbook je dnes připravený pro Apache; domény, cesty k certifikátům a platnost se nastavují proměnnými playbooku.
Wildcard certifikát, kterým Traefik obsluhuje webová rozhraní, se neobnovuje automaticky. Před jeho expirací nahraďte materiál, spusťte scripts/prepare-secrets.sh (přepečetí Secret) a změnu commitněte.
Revokace: step ca revoke zablokuje jen obnovu certifikátu. CRL/OCSP nasazené není — revokaci nahrazuje krátká platnost (výchozí 24 h); u certifikátů s delší platností počítejte s tím, že je nelze odvolat.
07Změny konfigurace a GitOps
Zdrojem pravdy pro stav clusteru je Git. Každá změna jde cestou: úprava manifestu → podepsaný commit → push → Flux reconcile. Ruční kubectl apply používejte jen pro diagnostiku — Flux ruční změny při dalším reconcile přepíše.
git config commit.gpgsign true # jednou
git add kubernetes/apps/...
git commit -S -m "feat: ..."
git push
flux reconcile source git pampeliska # nečekat na interval
flux get kustomizations -AFlux ověřuje GPG podpis posledního commitu (verify.mode: HEAD) proti veřejným klíčům v Secretu flux-gpg-public-keys. Nepodepsaný commit nebo commit podepsaný neznámým klíčem způsobí, že zdroj zůstane NotReady a žádné změny se nenasadí.
Tajemství v Gitu
Do Gitu patří jen zapečetěná podoba Secretu:
kubectl create secret generic moje-tajemstvi -n moje-aplikace \
--from-literal=heslo='...' --dry-run=client -o yaml \
| ./scripts/seal-secret.sh > moje-tajemstvi-sealed.yamlTajemství pro provisioning (token K3s, šifrovací klíč, přístup k S3) jsou v Ansible Vault: ansible-vault edit ansible/inventory/group_vars/all/vault.yml.
Přístupové údaje ke spravovaným zařízením a systémům do Gitu nepatří ani zapečetěné — ukládejte je do OpenBao (viz Tajemství).
08Tajemství (OpenBao)
OpenBao je centrální úložiště tajemství pro automatizaci: přístupové údaje ke spravovaným zařízením a systémům (síťové prvky, firewally, servery, API tokeny), které používají Ansible playbooky spouštěné ze Semaphore UI. Tajemství nejsou v Gitu ani v Semaphore.
- Vysoká dostupnost: 3 repliky (jedna na každém uzlu) s integrovaným úložištěm Raft. Při výpadku uzlu proběhne volba lídra a služba pokračuje po krátkém přepnutí v řádu sekund.
- Automatické odpečetění: statický klíč (
seal "static") uložený jako Secretopenbao-unsealv namespaceopenbao(zapečetěný Sealed Secrets, kopie v Keychainpampeliska-openbao-unseal). Po restartu se OpenBao odpečetí samo. - Deklarativní inicializace: při prvním startu se OpenBao samo inicializuje z konfigurace v Gitu — bez ručního
bao operator init, bez ručního odpečeťování a bez trvalého root tokenu (po inicializaci se revokuje). Zapne audit, úložiště KV v2secret/, ověřování přes Kubernetes ServiceAccount a nouzový účetadmin. - Politiky a role jako kód: ACL politiky a role přístupu jsou v Gitu; CronJob
openbao-config-reconcileje každou hodinu aplikuje a ruční odchylky vrací do stavu v Gitu. - Nejmenší oprávnění: Semaphore UI smí tajemství pod
secret/automation/*pouze číst. Přihlašuje se krátkodobým tokenem svého Kubernetes ServiceAccountu (audienceopenbao) — žádný statický token. - Audit a metriky: každý přístup k tajemství zapisuje audit device na stdout; Grafana Alloy ho předává do Loki (v Grafaně dotaz
{namespace="openbao"}). Metriky sbírá Prometheus (ServiceMonitor). - Síť: do OpenBao smí podle NetworkPolicy jen Traefik, Semaphore UI, namespace
monitoringa pody OpenBao samotné. - Ochrana účtů: po 5 chybných přihlášeních metodou Username se účet na 15 minut zablokuje (
user_lockout).
Přihlášení
Webové UI i API jsou na https://bao.example.internal (HTTPS přes Traefik), dostupné jen ze správcovských sítí — z jiné adresy vrátí Traefik 403; povolené rozsahy jsou v kubernetes/infrastructure/openbao/allowlist.yaml. Přihlaste se metodou Username účtem admin; heslo je v Keychain řídicího stroje:
security find-generic-password -s pampeliska-openbao-admin -wZ příkazové řádky:
export BAO_ADDR=https://bao.example.internal
bao login -method=userpass username=admin
# token pro další nástroje (např. lookup v playboocích spouštěných z pracovní stanice)
export BAO_TOKEN=$(bao login -method=userpass -token-only username=admin)Pokud certifikát ingressu nevydala CA, které systém důvěřuje, nastavte i BAO_CACERT na soubor s kořenovým certifikátem. Účet admin je nouzový a administrátorský — pro aplikace používejte vlastní role s ověřováním přes ServiceAccount (viz níže).
Uložení tajemství
V UI: Secrets Engines → secret/ → Create secret, cesta např. automation/cisco/core1. Z příkazové řádky:
bao kv put secret/automation/cisco/core1 username=netadmin password=- # heslo zadáte na stdin, nezůstane v historii shellu
bao kv get secret/automation/cisco/core1
bao kv metadata get secret/automation/cisco/core1 # verze (KV v2 drží historii)Tajemství pro automatizaci ukládejte pod secret/automation/ — na tuto cestu má Semaphore UI právo čtení.
Použití v playbooku
Lookup plugin openbao je součástí repozitáře platformy a nepotřebuje žádné další Python závislosti. Cesta je relativní k úložišti secret/, parametr field vybírá položku:
- hosts: core_switches
gather_facts: false
vars:
ansible_user: "{{ lookup('openbao', 'automation/cisco/core1', field='username') }}"
ansible_password: "{{ lookup('openbao', 'automation/cisco/core1', field='password') }}"
tasks:
- name: Ověření spojení
ansible.netcommon.cli_command:
command: show version- Ze Semaphore UI se lookup přihlásí sám tokenem ServiceAccountu Semaphore — v šabloně úlohy nic nenastavujete.
- Z pracovní stanice nastavte
BAO_ADDRaBAO_TOKEN(viz Přihlášení). - Ve vlastním repozitáři playbooků zkopírujte plugin do adresáře
lookup_plugins/vedle playbooku.
Přístup pro další aplikaci
Politiky a role jsou soubory v Gitu v adresáři kubernetes/infrastructure/openbao/config/. Pro novou aplikaci přidejte dvojici souborů.
Politika policy-moje-aplikace.hcl — jen čtení vlastní větve tajemství (KV v2: cesta obsahuje data/):
path "secret/data/automation/moje-aplikace/*" {
capabilities = ["read"]
}Role role-moje-aplikace.json — role ověřování přes Kubernetes ServiceAccount (příklad):
{
"bound_service_account_names": ["moje-aplikace"],
"bound_service_account_namespaces": ["moje-aplikace"],
"audience": "openbao",
"token_policies": ["moje-aplikace"],
"token_ttl": "15m"
}Politiky a role spravujte jen v Gitu — reconciler smaže každou politiku nebo roli, která v Gitu není (kromě vestavěných default a root), takže ruční změny v UI se do hodiny ztratí.
Změnu commitněte (podepsaný commit, viz GitOps). CronJob openbao-config-reconcile ji aplikuje nejpozději do hodiny; okamžitě takto:
kubectl -n openbao create job --from=cronjob/openbao-config-reconcile rucni-$(date +%s)
kubectl -n openbao get jobsBěží-li aplikace v clusteru, musí ji do OpenBao pustit i NetworkPolicy — rozšiřte ji v manifestech kubernetes/infrastructure/openbao/. Aplikace se přihlašuje tokenem svého ServiceAccountu s audience openbao (projected token).
Zálohy a obnova
- Svazky Raft zálohuje denně Longhorn do S3 mimo cluster (stejně jako ostatní svazky, viz Zálohy a obnova). Svazky jsou lokální (Longhorn 1 replika, strict-local) — data mezi uzly replikuje Raft.
- Konzistentní snapshot pořiďte ručně účtem
admin, nejlépe před upgradem a po větších změnách:
bao operator raft snapshot save openbao-$(date +%F).snap
# obnova (přepíše aktuální data OpenBao)
bao operator raft snapshot restore openbao-2026-10-01.snap
# do nově inicializovaného clusteru (jiná sada klíčů) je potřeba -force
bao operator raft snapshot restore -force openbao-2026-10-01.snapData OpenBao (svazky i snapshoty) jsou šifrovaná. Bez klíče pro odpečetění (pampeliska-openbao-unseal v Keychain, kopie v trezoru mimo cluster) je nelze obnovit. Před obnovou do nového clusteru musí Secret openbao-unseal obsahovat původní klíč. Při obnově přes ./deploy.sh --skip-secrets (viz DR) to platí automaticky — zapečetěný Secret je v Gitu a obnovený sealing klíč ho rozšifruje. Pokud tajemství přegenerováváte během prepare-secrets.sh, vraťte nejdřív do Keychain původní položku pampeliska-openbao-unseal.
Upgrade
StatefulSet OpenBao používá strategii OnDelete: po změně verze v manifestu a reconcile Fluxem se pody nerestartují samy. Restartujte je ručně po jednom — nejdřív repliky ve stavu standby, nakonec aktivní:
# který pod je aktivní (HA Mode: active / standby)
for i in 0 1 2; do echo "openbao-$i"; kubectl -n openbao exec openbao-$i -- bao status | grep -E 'HA Mode|Version'; done
kubectl -n openbao delete pod openbao-1 # standby; počkejte na Ready a Sealed=false
kubectl -n openbao wait --for=condition=Ready pod/openbao-1 --timeout=5m
# … druhý standby stejně, nakonec aktivní pod (proběhne volba lídra)Před upgradem pořiďte snapshot Raft (viz výše).
Omezení
- TLS uvnitř clusteru: OpenBao zatím nemá vlastní TLS listener. HTTPS končí na Traefiku; provoz mezi uzly šifruje WireGuard, uvnitř uzlu ale provoz mezi Traefikem/Semaphore a OpenBao šifrovaný není. TLS uvnitř clusteru je na Roadmapě.
- Klíč pro odpečetění je v clusteru: statický klíč leží jako Kubernetes Secret, takže kdo získá přístup k Secretům v namespace
openbaoa ke svazkům, může data rozšifrovat. Pro regulované prostředí doporučujeme nahradit statický klíč HSM (PKCS#11), KMS nebo zákaznickým trezorem — jde o konfigurační volbu OpenBao, kterou platforma sama nenastavuje; lze ji připravit v rámci onboardingu. - Dynamické krátkodobé přístupové údaje, automatické snapshoty Raft do S3 a synchronizace tajemství do Kubernetes (External Secrets Operator) zatím nejsou — viz Roadmapa.
- Vztah k Sealed Secrets: Sealed Secrets zůstávají pro tajemství platformy potřebná už při bootstrapu (hesla databází, přístupy k S3); OpenBao je pro provozní tajemství automatizace. Zákaznický PAM (např. CyberArk) lze napojit jako integraci na zakázku.
09Zálohy a obnova
| Co | Jak | Kam | Retence |
|---|---|---|---|
| PostgreSQL | průběžná archivace WAL + denní base backup ve 02:00 (CloudNativePG) | S3, bucket pampeliska-cnpg | 14 dní |
| Svazky Longhorn | hodinové snapshoty (lokálně) + denní záloha ve 02:30 | snapshoty v clusteru; zálohy S3, bucket longhorn-backup | 24 snapshotů / 14 záloh |
| etcd (stav Kubernetes) | automatické snapshoty každých 6 h; ruční ./scripts/backup-etcd.sh <IP server uzlu> [ssh uživatel] | lokálně na uzlech + S3, bucket k3s-etcd; ruční do backups/etcd/ na řídicím stroji | lokálně 28 na uzel (7 dní); v S3 84 za cluster (počet serverů × 28) |
| OpenBao (Raft) | denní záloha svazků Longhorn ve 02:30; ruční bao operator raft snapshot save | S3, bucket longhorn-backup; snapshot na řídicím stroji | jako svazky Longhorn |
| Klíč Sealed Secrets | prepare-secrets.sh | macOS Keychain pampeliska-sealing-key | trvale |
| Klíče step-ca | ./scripts/backup-pki-keys.sh | macOS Keychain pampeliska-step-ca-backup | trvale |
| Klíč pro odpečetění OpenBao | prepare-secrets.sh | macOS Keychain pampeliska-openbao-unseal | trvale |
Heslo účtu admin OpenBao | prepare-secrets.sh | macOS Keychain pampeliska-openbao-admin | trvale |
| Konfigurace platformy | Git | repozitář (in-cluster Gitea + autoritativní kopie mimo cluster) | historie Gitu |
Zálohovací cíl S3
- Referenční cíl je Garage (S3 API) ve VM na samostatném hostiteli, s TLS na portu 9000. Zakládá ho
ansible/playbooks/backup-s3.yml—deploy.shho spouští automaticky před nasazením clusteru. - Každý klient má vlastní přístupový klíč jen na svůj bucket: PostgreSQL →
pampeliska-cnpg, Longhorn →longhorn-backup, etcd →k3s-etcd. Klíče generujeprepare-secrets.sh. - Kopie mimo dosah clusteru: hostitel pořizuje denně snapshot celé VM se zálohami (expirace 14 dní). Snapshoty nejsou dostupné přes S3 klíče z clusteru, takže je nesmaže ani kompromitovaný cluster; neměnné nejsou — správce hostitele je smazat může. Pro skutečně neměnnou kopii doporučujeme offsite S3 s Object Lock. Obnova:
lxc copy garage-pampeliska/<snapshot> garage-restore(nebolxc restore).
Obnova PostgreSQL k okamžiku (PITR)
CloudNativePG obnovuje do nového clusteru z base backupu a WAL archivu. Vytvořte manifest s bootstrap.recovery a cílovým časem:
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: pampeliska-db-restore
namespace: postgres-system
spec:
instances: 3
imageName: ghcr.io/cloudnative-pg/postgresql:16.15 # stejná major verze jako záloha
storage:
storageClass: longhorn
size: 10Gi
walStorage:
storageClass: longhorn
size: 2Gi
bootstrap:
recovery:
source: pampeliska-db
recoveryTarget:
targetTime: "2026-10-01 08:00:00.00000+02"
externalClusters:
- name: pampeliska-db # = název původního clusteru (adresář v bucketu)
barmanObjectStore:
destinationPath: s3://pampeliska-cnpg/
endpointURL: https://s3.example.internal:9000
endpointCA:
name: backup-s3-ca
key: ca.crt
s3Credentials:
accessKeyId:
name: backup-s3-cnpg
key: ACCESS_KEY_ID
secretAccessKey:
name: backup-s3-cnpg
key: ACCESS_SECRET_KEY
wal:
maxParallel: 8- In-tree
barmanObjectStoreje od CNPG 1.26 zastaralé a v 1.31 bude odstraněno; platforma plánuje přechod na Barman Cloud Plugin — příklad odpovídá současné verzi. - Obnovený cluster nesmí zapisovat zálohy do stejné cesty jako původní — sekci
backupbuď vynechte, nebo použijte jinoudestinationPath. - Bez
recoveryTargetse obnoví k poslednímu dostupnému WAL. - Průběh:
kubectl -n postgres-system get cluster pampeliska-db-restorea logy podů*-full-recovery-*. Po ověření dat přepněte aplikace (connection string / služba-rw) na nový cluster. Výměna produkčního clusteru je provozní zásah — naplánujte ji.
Obnova svazku Longhorn
- Otevřete Longhorn UI:
kubectl -n longhorn-system port-forward svc/longhorn-frontend 8080:80→http://localhost:8080. - V záložce Backup vyberte svazek a zálohu a zvolte Restore (nový svazek).
- U obnoveného svazku vytvořte PV/PVC (Create PV/PVC) se jménem, které čeká aplikace, a aplikaci restartujte (škálování na 0 a zpět).
Pro návrat v rámci posledních 24 hodin stačí lokální snapshot (záložka svazku → Snapshots → Revert; svazek musí být odpojený).
Obnova etcd ze snapshotu
Obnova etcd vrací celý stav Kubernetes do okamžiku snapshotu. Proveďte ji jen při ztrátě nebo poškození řídicí vrstvy, v okně údržby.
# 1) na VŠECH třech uzlech
sudo systemctl stop k3s
# 2) na prvním uzlu (snapshot z /var/lib/rancher/k3s/server/db/snapshots/ nebo stažený z S3)
sudo k3s server --cluster-reset \
--cluster-reset-restore-path=/var/lib/rancher/k3s/server/db/snapshots/<snapshot>
sudo systemctl start k3s
# 3) na ostatních dvou uzlech: smazat lokální data etcd a připojit znovu
sudo rm -rf /var/lib/rancher/k3s/server/db
sudo systemctl start k3sPo obnově ověřte kubectl get nodes a flux get all -A; Flux dorovná případné změny z Gitu provedené po pořízení snapshotu.
Klíče a tajemství
- Klíč Sealed Secrets vzniká na řídicím stroji při běhu
prepare-secrets.sha je jen v Keychain (pampeliska-sealing-key), žádná souborová kopie na disku. Při bootstrapu nového clusteru hobootstrap.shobnoví do clusteru dřív, než Flux začne aplikovat SealedSecrets. - Klíče step-ca (root i intermediate klíč, hesla, certifikáty, konfigurace) exportuje
./scripts/backup-pki-keys.shdo Keychain (pampeliska-step-ca-backup). Export spusťte po instalaci a po každé změně PKI. Obnova až po prvním nasazení step-ca: instalace Helm chartu generuje novou CA a objekty obnovené předem by přepsala. Po nasazení (flux get hr -n pki step-certificates= Ready) export aplikujte (security find-generic-password -s pampeliska-step-ca-backup -w | base64 -d | kubectl apply -f -), restartujtekubectl -n pki rollout restart statefulset/step-certificatesa ověřte otisk kořenového certifikátu. - Klíč pro odpečetění OpenBao (
pampeliska-openbao-unseal) a heslo nouzového účtuadmin(pampeliska-openbao-admin) vygenerovalprepare-secrets.shdo Keychain. Bez klíče pro odpečetění nejdou data OpenBao obnovit — ani ze záloh svazků, ani ze snapshotu Raft. Viz Tajemství. - Kopii všech těchto položek a souboru
ansible/vault_passworduložte do trezoru mimo cluster i mimo řídicí stroj. Ztráta stroje se zálohou = ztráta možnosti obnovy.
Havárie celého clusteru (DR)
- Připravte tři nové VM dle požadavků a upravte inventář.
- Obnovte položky Keychain (sealing key, klíč pro odpečetění OpenBao, hesla) a GPG podpisový klíč z trezoru a spusťte
./deploy.sh --skip-secrets— cluster vznikne z Gitu včetně všech komponent a tajemství. - Obnovte data: PostgreSQL z S3 (PITR výše), svazky Longhorn ze záloh, klíče step-ca z exportu (až po nasazení step-ca, viz výše), data OpenBao ze snapshotu Raft nebo ze záloh svazků (viz Tajemství).
- Ověřte funkčnost služeb a přihlášení.
Obnovu testujte nejméně jednou za čtvrtletí na odděleném prostředí — záloha, ze které se nikdy neobnovovalo, není ověřená záloha.
10Vysoká dostupnost
Cluster přežije výpadek jednoho ze tří uzlů. Ne všechny služby jsou ale replikované — jednoinstanční služby se při výpadku uzlu přeplánují na jiný uzel, což znamená výpadek v řádu minut. Výjimkou je Gitea na lokálním úložišti uzlu, která čeká na návrat svého uzlu.
| Služba | Režim | Chování při výpadku uzlu |
|---|---|---|
| Řídicí vrstva K3s (etcd) | 3 uzly | etcd kvórum 2 ze 3; API dostupné přes VIP |
| PostgreSQL (CloudNativePG) | 3 instance | primár + synchronní replika + další replika; automatický failover |
| Traefik (ingress) | 2 repliky | provoz pokračuje přes druhou repliku |
| PostgREST | 2 repliky | provoz pokračuje přes druhou repliku |
| OpenBao | 3 repliky (Raft) | volba lídra, krátké přepnutí v řádu sekund; svazky lokální (Longhorn 1 replika, strict-local), data replikuje Raft |
| Data Longhorn | 2 repliky | svazek dostupný z druhé repliky; svazky PostgreSQL mají 1 lokální repliku (třída longhorn-db, strict-local) — redundanci zajišťují 3 instance CloudNativePG |
| Semaphore UI (Community) | 1 instance | přeplánování, výpadek v řádu minut |
| Gitea (zdroj pro Flux) | 1 instance, lokální úložiště uzlu | nedostupná do návratu uzlu (data na local-path, nepřeplánuje se); běžící workloady pokračují, nové změny se nenasazují |
| Grafana, Prometheus, Alertmanager, Loki | 1 instance | přeplánování, výpadek v řádu minut |
| step-ca, cert-manager | 1 instance | přeplánování; existující certifikáty platí dál, vydávání a obnova se pozdrží |
| ntfy | 1 instance | přeplánování, výpadek v řádu minut |
Loki: výchozí retence logů je 30 dní na lokálním svazku. Delší retence vyžaduje objektové úložiště a dimenzování v rámci onboardingu — např. 18 měsíců, které pro záznamy událostí požaduje vyhláška č. 409/2025 Sb., § 22 odst. 5 písm. c) (subjekty režimu vyšších povinností); ISO 27001 A.8.15 a DORA (RTS (EU) 2024/1774, čl. 12) kladou požadavky na samotné logování.
11Upgrade a lifecycle politika
Upgrade K3s
ANSIBLE_CONFIG=ansible/ansible.cfg ansible-playbook \
-i ansible/inventory/hosts.yml ansible/playbooks/upgrade-k3s.yml \
--vault-password-file ansible/vault_password \
-e k3s_target_version=vX.Y.Z+k3sNPlaybook nejprve pořídí snapshot etcd a pak upgraduje uzly postupně po jednom: cordon → drain → upgrade → čekání na Ready a správnou verzi → uncordon → čekání, až jsou všechny svazky Longhorn zdravé a všechny instance PostgreSQL připravené; teprve pak pokračuje dalším uzlem. Kubernetes API volá přes jiný uzel, takže selhání upgradovaného uzlu nezablokuje diagnostiku.
- Upgradujte jen o jednu minor verzi najednou (1.30 → 1.31 → 1.32 …).
- Před upgradem ověřte kompatibilitu Helm chartů komponent s cílovou verzí Kubernetes. Během drainu uzlu s interní Gitea (zdroj pro Flux) Flux dočasně nereconciluje.
- Po upgradu:
kubectl get nodes(verze všech uzlů) aflux get helmreleases -A.
Verze komponent v clusteru (Helm charty, image) jsou pinnuté v manifestech v Gitu; upgrade komponenty = změna verze v manifestu → podepsaný commit → Flux.
Flux nasazuje z Gitea uvnitř clusteru. Na MicroCloudu se nový podepsaný commit do in-cluster Gitea dostane opakovaným seedem START_AT=seed_gitea ./scripts/bootstrap-microcloud.sh deploy — bez něj cluster nové commity nevidí (viz Flux nevidí nový commit).
Lifecycle politika
| Oblast | Pravidlo |
|---|---|
| K3s | Provozujeme řadu podporovanou upstreamem (jedna z posledních tří minor verzí). Upgrade minor verze nejméně jednou za čtvrtletí. Bezpečnostní patch verze do 30 dní od vydání. |
| Operační systém | Ubuntu Server LTS (24.04) po dobu standardní podpory. |
| Komponenty | Pinnuté verze Helm chartů a image; revize při každém upgradu platformy. |
| Okno údržby | Doporučeno neděle 02:00–06:00 (Europe/Prague). |
12Řešení problémů
Flux nereconciluje změny
flux get sources git -A
flux get kustomizations -A
flux logs --level=error --since=1hNejčastější příčiny: nepodepsaný commit (zdroj NotReady, chyba ověření podpisu), nedostupná in-cluster Gitea, chyba v manifestu (kustomize build). Lokální kontrola: kustomize build kubernetes/infrastructure. Po opravě: flux reconcile source git pampeliska.
Flux nevidí nový commit
Flux čte manifesty z Gitea uvnitř clusteru, ne z vašeho vzdáleného repozitáře. Nový commit, který jste pushnuli jinam, cluster neuvidí, dokud se větev znovu nenahraje do in-cluster Gitea. Na MicroCloudu to udělá opakovaný seed (bez nového provisioningu):
START_AT=seed_gitea ./scripts/bootstrap-microcloud.sh deploy
flux get sources git -A # revize musí odpovídat podepsanému HEADHelmRelease ve stavu failed
flux get helmreleases -A
kubectl describe helmrelease <název> -n <namespace>
flux suspend helmrelease <název> -n <namespace> # po opravě hodnot v Gitu:
flux resume helmrelease <název> -n <namespace>Pod visí v Pending kvůli PVC / Longhorn
kubectl describe pod <pod> -n <namespace> # Events: FailedScheduling / FailedAttachVolume
kubectl get pvc -A
kubectl -n longhorn-system get volumes.longhorn.io
kubectl -n longhorn-system get nodes.longhorn.ioZkontrolujte volné místo na disku uzlů (/var/lib/longhorn) a zda jsou všechny uzly v Longhornu Ready a schedulable. Při dvou replikách a jednom nedostupném uzlu jede svazek v degradovaném režimu, dokud se uzel nevrátí.
Certifikát se nevystavuje nebo neobnovuje
kubectl get certificate,certificaterequest -A
kubectl describe certificaterequest <název> -n <namespace>
kubectl get stepclusterissuer step-ca-cluster-issuer -o wide
kubectl -n pki get cronjob step-issuer-reconcile
kubectl -n pki logs job/<poslední job step-issuer-reconcile>Chybí-li issuer nebo není Ready, spusťte reconcile ručně (viz Certifikáty). Ověřte, že běží step-ca: kubectl exec -n pki step-certificates-0 -- step ca provisioner list.
Failover PostgreSQL (CNPG)
kubectl -n postgres-system get cluster pampeliska-db
kubectl -n postgres-system get pods -l cnpg.io/cluster=pampeliska-db -L role
kubectl -n postgres-system describe cluster pampeliska-dbPo výpadku primáru operátor povýší repliku automaticky a služba pampeliska-db-rw začne ukazovat na nový primár. Pokud cluster nepřejde do Cluster in healthy state, zkontrolujte události a logy operátoru (operátor běží v namespace postgres-system: kubectl -n postgres-system logs deploy/cloudnative-pg). Ruční zásahy do CNPG clusteru plánujte jako provozní zásah.
SealedSecret nejde rozšifrovat
kubectl get sealedsecrets -A
kubectl describe sealedsecret <název> -n <namespace> # no key could decrypt secret
kubectl -n kube-system get secret -l sealedsecrets.bitnami.com/sealed-secrets-keyPříčinou bývá, že controller nemá původní sealing klíč (nový cluster bez obnovy klíče). Sealing klíč je jen v macOS Keychain (pampeliska-sealing-key); ruční obnova z kořene repozitáře:
bash -c 'source scripts/lib/secrets-common.sh && sealing_key_secret' | kubectl apply -f -
kubectl -n kube-system rollout restart deploy/sealed-secrets-controllerHlášení already exists and is not managed by SealedSecret znamená, že v clusteru už existuje stejnojmenný Secret vytvořený jinak — controller ho nepřepíše. Smažte ho jen vědomě (controller ho vytvoří znovu ze SealedSecret).
OpenBao je sealed / pod neběží
kubectl -n openbao get pods,pvc
kubectl -n openbao get secret openbao-unseal # musí existovat (vzniká ze SealedSecret)
kubectl -n openbao get sealedsecret
kubectl -n openbao exec openbao-0 -- bao status # Sealed, HA Mode, Raft
kubectl -n openbao logs openbao-0 --tail=100Chybí-li Secret openbao-unseal, nejde rozšifrovat jeho SealedSecret — viz SealedSecret nejde rozšifrovat. Obsahuje-li jiný klíč, než kterým byla data zapečetěna (např. nový cluster s nově vygenerovaným klíčem), OpenBao se neodpečetí; obnovte původní klíč z Keychain pampeliska-openbao-unseal. Raft potřebuje kvórum 2 ze 3 replik — při výpadku dvou uzlů služba nepokračuje, dokud se aspoň jeden nevrátí.
Playbook nedostane tajemství (403)
kubectl -n openbao get cronjob openbao-config-reconcile
kubectl -n openbao get jobs --sort-by=.metadata.creationTimestamp
kubectl -n openbao logs job/<poslední job openbao-config-reconcile>
bao policy read <politika>
bao read auth/kubernetes/role/<role>Odpověď 403 permission denied znamená, že token nemá politiku pro danou cestu. Zkontrolujte, že:
- politika a role jsou v Gitu a reconcile job je aplikoval bez chyby (případně ho spusťte ručně, viz Tajemství),
- cesta v politice obsahuje u KV v2 segment
data/(secret/data/automation/…) a tajemství leží tam, kam politika míří, - role váže správný ServiceAccount a namespace a token má audience
openbao.
Odmítnuté požadavky najdete v auditním logu v Loki ({namespace="openbao"}). Nedostane-li se aplikace k OpenBao vůbec (timeout místo 403), blokuje ji NetworkPolicy.
VM nejde vytvořit — pozůstatky předchozí instalace v Cephu
Po předchozí instalaci mohou ve sdíleném úložišti Ceph zůstat osiřelé RBD image (virtual-machine_<jméno>) nebo staré datové svazky. Vytvoření VM se stejným jménem pak selže. Zkontrolujte a vědomě ukliďte:
lxc list
lxc storage volume list remote | grep pampeliska
sudo rbd ls -p <pool> | grep pampeliska # na serveru MicroClouduMazání svazků a image je nevratné — ověřte, že nepatří běžící VM.
SSH odmítá připojení po reinstalaci VM
Nová VM na stejné IP adrese má nový klíč hostitele a SSH (i Ansible) hlásí změnu identity. Smažte starý záznam na řídicím stroji:
ssh-keygen -R 192.168.10.11 # pro každý reinstalovaný uzelAlerty nechodí do ntfy
kubectl -n monitoring get secret ntfy-auth ntfy-alertmanager
kubectl -n monitoring logs deploy/ntfy-alertmanager --tail=50 # 401/403 = chybí účet nebo token
kubectl -n monitoring logs deploy/ntfy --tail=50ntfy běží s výchozím přístupem deny-all a účty admin a alertmanager i token mostu jsou deklarativní ze Secretu ntfy-auth (a ntfy-alertmanager), které vytváří prepare-secrets.sh. Chybí-li Secret nebo nesedí token, spusťte prepare-secrets.sh, commitněte přepečetěné SealedSecrets podepsaně a nechte je nasadit Flux. Viz Alerty.
Uzel je NotReady
kubectl get nodes -o wide
kubectl describe node <uzel>
ssh <uživatel>@192.168.10.12 'sudo systemctl status k3s; sudo journalctl -u k3s --since "30 min ago"'13Bezpečnost a hlášení zranitelností
- Zranitelnosti hlaste e-mailem na support@pampeliska.io s předmětem „Security“. Kontaktní údaje jsou také v
security.txt. - Postupujeme podle principu koordinovaného zveřejnění: nález nezveřejňujte, dokud není k dispozici oprava nebo dohodnutý termín.
- Podrobnosti postupu jsou v souboru
SECURITY.mdv repozitáři platformy.
Bezpečnostní opatření platformy
- NetworkPolicy (default-deny pro příchozí provoz) v namespaces
postgres-system,gitea,semaphore,flux-system,pki,monitoring,longhorn-systemaopenbao(kubernetes/infra-config/network-policies/); povolené jsou jen vyjmenované toky. - Pod Security Admission na úrovni
baselinepro namespaces platformy; výjimkuprivilegedmají jenlonghorn-system(Longhorn potřebuje přístup k disku uzlu) agitea(CI runner s Docker-in-Docker). Definice:kubernetes/infrastructure/namespaces/namespaces.yaml. - Uzly: CIS hardening OS (role
hardening: SSH, auditd, AppArmor) i kubeletu (protect-kernel-defaults), hostový firewall ufw s výchozím zákazem příchozího provozu (rolefirewall), šifrování Secrets v etcd. - OpenBao je dostupné jen ze správcovských sítí (allowlist v Traefiku) a blokuje účet po opakovaném chybném přihlášení — viz Tajemství.
CI runner Gitea Actions (kubernetes/apps/gitea-runner/) dnes běží v namespace gitea jako pod s privilegovaným kontejnerem Docker-in-Docker. Privilegovaný kontejner má prakticky plný přístup k uzlu: kdo ovládne CI úlohu (např. přes škodlivý workflow nebo závislost) a unikne z kontejneru, získá roota na uzlu clusteru. Spouštějte proto jen důvěryhodné workflow z vlastních repozitářů. Přesun runneru mimo cluster do samostatné VM je plánovaný — viz Roadmapa.
Audit Kubernetes API
K3s zapisuje auditní log kube-apiserveru podle politiky ansible/roles/k3s/templates/audit-policy.yaml.j2 do /var/log/kubernetes/audit/audit.log na každém serverovém uzlu. Grafana Alloy ho předává do Loki. V Grafaně: Explore → Loki a dotaz:
{job="k3s-audit"}
# např. jen zásahy do Secretů
{job="k3s-audit"} |= `"resource":"secrets"`- Co se loguje (úroveň
Metadata— kdo, co, kdy, nad jakým objektem a s jakým výsledkem): všechny změny objektů (create, update, patch, delete),exec/attach, změny RBAC a každý přístup k Secretům, ConfigMapám, tokenům ServiceAccountů a SealedSecrets — i při čtení. Obsah požadavků a odpovědí se neukládá, hodnoty Secretů ani tokeny se do logu nedostanou. - Co se neloguje: běžná čtení ostatních objektů (get, list, watch), health a metrické endpointy (
/healthz,/readyz,/livez,/metrics…), obnovy leases a události (events). - Retence je stejná jako u ostatních logů v Loki (výchozí 30 dní, viz Vysoká dostupnost); export do SIEM je katalogová integrace.
Doporučení pro provoz
- Výsledky Trivy Operatoru (zranitelnosti, konfigurace, SBOM) procházejte pravidelně:
kubectl get vulnerabilityreports,configauditreports,sbomreports -A. - Přístupové údaje ke spravovaným zařízením ukládejte do OpenBao, ne do Gitu ani do Key Store Semaphore; účet
adminOpenBao používejte jen pro správu a nouzové situace. - Tajemství nikdy necommitujte nezapečetěná;
ansible/vault_password,kubeconfiga zálohy klíčů držte mimo Git. - Patch verze K3s a komponent nasazujte dle lifecycle politiky.