fix(security): GitOps SSH-sleutel uit image + OPI RBAC inscoping#80
Conversation
|
Blokker 1: Stale rebase op prod deployment-patch
Fix: rebase op huidige main, behoud alle drie de blokken, pas alleen de image-regel + nieuwe Secret-volume aan. Blokker 2: Ontbrekende bootstrap voor
|
e7da687 to
a3615b0
Compare
Follow-up: PR-omschrijving deels op onjuiste info, scope herzienNa een diepere audit op de premissen van deze PR is gebleken dat de "kritieke leak"-claim grotendeels niet klopt. Wat overblijft is wel reëel maar minder dramatisch. Branch is gerebased + augmenteerd (`a3615b0c`). Wat de "geleakte" files werkelijk zijn
Niet nodig dus (in tegenstelling tot wat PR-omschrijving stelt):
Wat WEL valide is en behouden blijft
Augmentation deze ronde (`a3615b0c`)`nodes/services/endpoints` regel uit alle drie de cluster-roles verwijderd. Code-grep bewijst:
Wel behouden:
Rebase-resolutionsTwee conflicten met main, opgelost:
ODCN coördinatie nodig`overlays/odcn-production/cluster-role.yaml` + `cluster-binding.yaml` zijn nu declaratief in repo, maar productie-cluster RBAC wordt door ODCN-team beheerd, niet via onze ArgoCD-sync. Pre-merge actie: stem af met ODCN of zij deze ClusterRole + Binding toepassen. Test op staging vóór merge```bash Plus rookproef OPI-pod start zonder `git-server-key` Secret (optional-volume werkt) en de getrimmde RBAC volstaat voor namespace-creatie + secret-rotatie. Hooks: alle pre-push checks groen (ruff, pyright, pytest 3347, pip-audit). LGTM op deze scope. |
Follow-up issues aangemaakt
|
…AC in De operations-manager image bakte de SSH-privésleutel waarmee naar alle drie de GitOps-repos wordt gepusht plus .env/.env.production in de image-lagen. Iedereen die de (als :latest gerefereerde) image kan pullen of de repo kan lezen kreeg daarmee de GitOps-schrijfsleutel en kon willekeurige manifests committen die ArgoCD vervolgens toepast. Daarnaast gaf de ClusterRole namespace-manager cluster-breed secrets create/get/list/patch/update en pods create/delete. Cluster-breed secrets list betekent dat OPI elke tenant-secret kon lezen. Wijzigingen: - Dockerfile: COPY van keys/git-server-key(.pub), .env en .env.production verwijderd; de SSH-sleutel komt nu via een read-only Secret-volume op /app/keys/git-server-key (GIT_SERVER_KEY_PATH). Env komt al via envFrom operations-manager-env-secrets. - base/deployment.yaml: Secret-volume git-server-key toegevoegd, zelfde patroon als de bestaande sops-age-key (operator levert het materiaal). - local + sandboxed-local cluster-role: cluster-brede secrets list en update verwijderd; alleen create/get/patch behouden. - odcn-production overlay: scoped cluster-role en cluster-binding toegevoegd zodat productie-RBAC auditeerbaar is vanuit de repo. - odcn-production image niet langer :latest maar een te vervangen versietag-placeholder (digest-pin vereist voor merge). - .gitignore: keys/ en .env* uitgesloten.
…ete toe aan productie-RBAC
Twee defecten in de oorspronkelijke fix verholpen.
1. base/deployment.yaml verwees naar een niet-optionele Secret-volume
"git-server-key" die door geen enkele overlay (local, sandboxed-local,
odcn-production) wordt aangemaakt. Een niet-optionele secret-volume
waarvan de Secret ontbreekt houdt de pod permanent in ContainerCreating
(MountVolume.SetUp failed: secret "git-server-key" not found), waardoor
OPI na deze wijziging in elke omgeving niet meer zou starten. De SSH-
sleutel wordt door geen enkele overlay gebruikt: alle pushen naar de
GitOps-repos gaan via HTTPS met een SOPS-versleutelde PAT
(GIT_ARGO_APPLICATIONS_URL is https://, GIT_ARGO_APPLICATIONS_KEY is "").
optional: true toegevoegd, gelijk aan de sops-age-key-referentie die
ook optional: true is.
2. De nieuwe productie-ClusterRole gaf secrets create/get/patch maar geen
delete, terwijl project_manager bij rotatie van de SOPS-sleutelparen de
verouderde sops-age-key Secret in een tenant-namespace verwijdert
(delete_resource("secret", "sops-age-key", namespace)). delete
toegevoegd zodat de in-repo ClusterRole overeenkomt met wat de code
daadwerkelijk uitvoert.
…espace-manager ClusterRole OPI gebruikt deze resources nergens in de Python-code: - nodes, nodes/proxy, nodes/metrics: geen K8s nodes-API-calls in opi/ - services, endpoints: alleen interne string-referenties naar Service-namen, geen kubectl get services/endpoints De comment 'Prometheus service discovery' was aspirational; Prometheus draait met zijn eigen ServiceAccount en doet de discovery zelf, niet via OPI's SA. Non-resource /metrics en /metrics/cadvisor blijven staan: mogelijke in-cluster Prometheus-scrape onder dezelfde SA in dev-omgeving (twijfelgeval, behouden om geen onverwachte Kind-breakage). Watch-verbs op events en pods blijven ook staan: marginale praktische winst en code gebruikt geen K8s Watch API (alleen polling via kubectl get). Geldt voor local, sandboxed-local en odcn-production overlays.
…luster-role als blueprint Twee aanpassingen: - nodes/services/endpoints rule terug in productie cluster-role; behoud ruimte voor Prometheus service-discovery onder dezelfde SA. - cluster-role.yaml en cluster-binding.yaml hernoemd naar _blueprint-cluster-*.yaml en uit kustomization.yaml gehaald. ODC platform-team beheert de werkelijke ClusterRole; deze files documenteren de gewenste rechten-inrichting voor parity, ArgoCD past ze niet toe.
a3615b0 to
6c42192
Compare
De SSH-key onder keys/git-server-key was van een oude lokale Docker-git- daemon opzet (host.docker.internal:2222). Productie + sandbox gebruiken HTTPS naar GitHub met PATs in operations-manager-env-secrets; geen enkele URL begint met git:// of ssh://. De key werd nergens gelezen. Verwijderd: - keys/git-server-key, keys/git-server-key.pub (tracked files) - /app/keys Secret-volume + mount in base/deployment.yaml De resterende cleanup (config.py env-vars, dood SSH-URL-pad in argo_manager/git_monitor) komt na merge van #72 in een aparte PR.
- Dockerfile: /app/keys mkdir + verbose comment-blok weg - patches/deployment.yaml: TODO-comment over digest-pin weg (zit in follow-up issue #92) - .gitignore: alleen /keys/ als forward-protection; comments + onnodige patronen weg
…ployed task update-operations-manager runt kustomize build | kubectl apply op de odcn-production overlay; cluster-role.yaml + cluster-binding.yaml horen in resources te staan en worden zo daadwerkelijk toegepast. Geen blueprint — productie ClusterRole 'namespace-manager' bestaat al op de cluster (creationTimestamp 2026-05-21) zonder argo-tracking, consistent met manual-bootstrap pad.
Productie RBAC wordt geleverd via Capsule per-tenant RoleBindings naar de built-in admin ClusterRole; geen cluster-brede namespace-manager ClusterRole bestaat op productie (geverifieerd live). De files in overlays/odcn-production documenteren de gewenste set rechten als referentie. Hernoemd naar _blueprint-*.yaml en uit kustomization.yaml zodat task update-operations-manager ze niet probeert toe te passen.
Productie zou na .env-removal in debug-mode draaien want config.py default was True en het container env zet DEBUG niet expliciet. Sluit defense-in-depth: expliciet DEBUG=true overschrijven in dev .env is duidelijker dan vertrouwen op een onveilige default.
Blueprint is minimum-rechten zoals local/sandbox draaien. Productie via Capsule krijgt feitelijk wijdere rechten per tenant-namespace (built-in admin) plus tenant-ownership voor namespace-creatie. Header documenteert het verschil kort.
PR #80 verwijderde al de SSH-key files (keys/git-server-key + .pub) en de volume mount in deployment.yaml. Hierna is de SSH-key-injectie code-pad functioneel dood — een open(/app/keys/git-server-key) zou nu crashen. Restanten: - keys/authorized_keys (alleen gemount door git-test-server) - git-test-server/ docker-compose + README (lokale SSH git-daemon) - functional_tests/ (consumeerde alleen die docker-git server) - GIT_SERVER_KEY_PATH + GIT_ARGO_APPLICATIONS_KEY in config.py - SSH-key file-read in argo_manager.py + git_monitor.py - GIT_ARGO_APPLICATIONS_KEY="" regels uit cluster overlays - GIT_*_KEY regels uit operations-manager/python/.env(.production) - functional_tests-referentie uit operations-manager/CLAUDE.md Per-project SSH-keys (AGE-encrypted via project file -> ArgoCD repo Secret) blijven werken via een ander code-pad; deze opruiming raakt alleen het 'globale SSH-key path uit settings' patroon dat niemand meer gebruikt.
…ls, wizard-fixes, parallelle deploys (#124) * fix(forms): voorkom corruptie van component-aliases met '=' in YAML-waarden De alias-editor verstuurt vrije YAML; KeyValueConverter splitste echter elke regel naar voren op '=' waardoor URL-waarden als 'KEY: "postgres://...?schema=x"' onleesbaar werden opgeslagen. Daarnaast detecteerde _detect_env_var_format een YAML-regel niet zodra de waarde een '=' bevatte, zodat de validator dezelfde fallback maakte. - _detect_env_var_format herkent nu YAML aan 'KEY:' aan regelbegin, ongeacht een '=' verderop in de waarde. - KeyValueConverter._parse_env_text delegeert naar validate_and_parse_env_vars zodat YAML- en KEY=VALUE-invoer beide correct geparseerd worden; bestaande KEY=VALUE-flow (user-env-vars) blijft ongewijzigd door write_as="string" pad. * fix(csrf): herstel form-body verlies en ontbrekende tokens op htmx-knoppen CSRFMiddleware parste de form-body om het token te valideren, maar onder BaseHTTPMiddleware consumeerde dat de body zonder hem te cachen, waardoor de downstream handler een lege body kreeg en elk veld als ontbrekend las ('Dit veld is verplicht'). Cache de body nu voor het parsen. Voeg daarnaast de X-CSRF-Token toe aan de tune-, preset- en refresh-knoppen (htmx hx-post) en geef 'request' door aan de subdomein-modal render, zodat deze POSTs niet langer op centrale CSRF-enforcement stuklopen (403/500). * fix(env-vars): behoud bewust geplaatste quotes in user-env-vars waarden _decrypt_and_clean_env_vars stripte onvoorwaardelijk omringende quotes van elke waarde, nadat validate_and_parse_env_vars de quote-semantiek al correct had afgehandeld. Daardoor werd een waarde die de quotes bewust als inhoud nodig heeft (bv. cal.com ALLOWED_HOSTNAMES: '"host"' zodat de app deze tot een JSON-array kan wrappen) stil gecorrumpeerd tot de kale waarde -- geen enkele quote-vorm in het project-bestand overleefde dit. Verwijder de dubbele strip; quote-afhandeling hoort op een plek thuis (validate_and_parse_env_vars). Met regressietests. * fix(netpol): sta ACME HTTP-01 solver-poort 8089 toe in acme-http NetworkPolicy cert-manager's HTTP-01 solver pod luistert op 8089 (de router stuurt de challenge door naar de pod op 8089, niet 80). De gegenereerde acme-http-<app>-network-policy selecteert alle pods (podSelector:{}) maar stond alleen poort 80 toe, waardoor verkeer naar de solver op 8089 werd gedropt: TCP connect lukt, HTTP-request hangt, self-check faalt met 'context deadline exceeded' en het certificaat wordt nooit Ready. Eén van de drie generatie-locaties was al gecorrigeerd; de andere twee (o.a. het pad dat rig-prd-ia-fky genereerde) stonden nog op [80]. Alle drie nu op [80, 8089]. * fix(csrf): herstel CSRF-token op tune-knoppen (c-button quote-mangling) De twee 'Tune resources' c-buttons gebruikten hx-headers met enkele quotes rond JSON; de ROOS c-button re-serialiseert attributen met dubbele quotes, waardoor de JSON-quotes botsten en de browser het attribuut in ongeldige losse attributen opbrak. Daardoor kwam er geen geldig X-CSRF-Token header mee en faalde de tune-POST. Gebruik de "-entityvorm die de c-button passthrough overleeft, identiek aan de reeds werkende c-buttons (modal_wizard_review, modals, wizard_review). Geverifieerd door het renderen via de echte c-button: levert geldig {"X-CSRF-Token": "<token>"} op. * feat(deployment): sta per-component runAsUser/runAsGroup/fsGroup override toe op sandbox Custom images met een ingebakken non-root user op een andere UID dan 1001 (bijvoorbeeld openproject met UID 999) clasht met de hardcoded sandbox pod-securityContext, waardoor er per image een chown-wrap nodig is. Een verborgen `components[].security` blok in het project-YAML laat de user nu run-as-user / run-as-group / fs-group per component overschrijven. Alle drie de velden zijn optioneel; ontbrekende velden vallen terug op 1001 (behoud van bestaand gedrag). Op odcn-production wordt het blok genegeerd — daar wijst OpenShift SCC zelf een UID per namespace toe. Het veld is bewust niet in de wizard / detail-edit UI zichtbaar: users bewerken de YAML rechtstreeks in Forgejo. Wel toegevoegd aan de Pydantic ProjectFileModel en het JSON-schema zodat de validator het accepteert zonder dat onbekende typo's (zoals camelCase) doorslippen. * test(security): gebruik model_validate ipv kwargs voor Pyright-compat * feat(deployment): sta optionele `command:` override toe per component / per deployment Wie een upstream image als `openproject/openproject:17.4-slim` wil draaien hoefde tot nu toe een eigen wrap-Dockerfile te bouwen om de ENTRYPOINT te vervangen (bijv. een seeder voor de hoofd-proces). Kubernetes heeft daar `containers[].command` voor — die werd alleen niet doorgegeven via ZAD. Een nieuw, verborgen YAML-veld `command: list[str]` op `components[]` en `deployments[].components[]` mapt 1-op-1 op het K8s-veld. Bij beide niveaus gezet wint de deployment-override. Bij allebei leeg wordt geen `command:` geemitteerd en blijft de ENTRYPOINT/CMD van de image leidend (bestaand gedrag). Bewust list[str] (geen shell-string) en `minItems: 1` zodat een lege lijst de ENTRYPOINT niet stilletjes wist. Niet in de wizard / detail-edit UI — users bewerken de YAML zelf in Forgejo, net als de security override. * fix(delete): verwijder ook de project-ArgoCD-map uit de GitOps-repo bij projectverwijdering Bij het verwijderen van een project bleven de AppProject-manifest, de repository-secret en kustomization.yaml in {cluster}/{project}/ van de argo-applications-repo staan. De root-app (selfHeal) bleef die resources daardoor eindeloos terugzetten - de bestaande kubectl-cleanup van AppProjects vocht tegen GitOps en verloor altijd. Nieuwe stap 4.7 in delete_project verwijdert de map (zelfde patroon als de -infrastructure/-mapdeletie), commit, en refresht user-applications zodat AppProject en repo-secret direct gepruned worden. Geconstateerd op productie: 11 weesmappen met levende AppProjects en repo-credential-secrets van projecten verwijderd tussen jan en mei 2026. * fix(aliases): route REDIS/NAMESPACE_REDIS aliases naar 'redis' category * feat(env-vars): voeg PUBLIC_HOSTNAME toe naast PUBLIC_HOST voor publish-on-web Apps zoals OpenProject hebben host-name configvelden die een volledige URL weigeren. Geef daarom naast PUBLIC_HOST (met scheme) ook PUBLIC_HOSTNAME (alleen de hostname) door, zodat gebruikers niet zelf de scheme uit PUBLIC_HOST hoeven te strippen in user-env-vars. * fix(tuning): OOM-floor klemt alleen nog de limit, scoped per deployment, met slim verval Drie problemen in de OOM-floor die neerwaartse tuning structureel blokkeerden: 1. De floor klemde ook de request vast, terwijl OOM-bescherming alleen over de limit gaat. De request mag nu vrij zakken naar usage+buffer (genormeerd op request <= limit); de limit behoudt zijn burst-headroom. Facturatie loopt op requests - dit kostte clusterbreed ~5 GiB aan gereserveerd-maar-ongebruikt geheugen. 2. De component-definitie-tak van get_resource_history_floor filterde niet op deployment, waardoor een OOM in een PR-omgeving alle deployments (incl. productie) pinde. Def-level entries tellen nu alleen mee voor de deployment die ze heeft gezet (het deployment-veld wordt al sinds altijd meegeschreven; legacy entries zonder dat veld vervallen daarmee bewust). 3. De floor verliep nooit. Nieuw: een floor verloopt zodra de OOM-entry ouder is dan RESOURCE_TUNING_OOM_FLOOR_MIN_AGE_DAYS (10) en de waargenomen max-usage onder RESOURCE_TUNING_OOM_FLOOR_STABLE_PERCENT (50%) van de floor ligt - aantoonbaar stabiel, dus de floor is irrelevant geworden. Onparseerbare timestamps verlopen nooit (fail-safe). Productie-data: alle OOM-bursts lagen 43-73 dagen terug zonder herhaling. Daarnaast onderdrukte de floor het memory-check-scherm volledig (return None): gebruikers zagen niet dat er iets te besparen viel. Floor-geblokkeerde componenten geven nu een eigen kaart met de request-besparing en de floor-datum. get_resource_history_floor geeft nu een ResourceFloor (waarde+timestamp) terug i.p.v. een kale float. * docs(features): VPA als tuning-recommender (updateMode Off) als toekomstidee * feat(secrets): zet Replace=true sync-option zodat stale keys uit secrets drop'pen * feat(keycloak): voeg OIDC_HOSTNAME variabele toe (hostname zonder scheme) * fix(metrics-explorer): move JSON endpoint to /ui/ so it requires SSO The handler had @requires_sso but lived under /api/, where the authorization middleware passes through (API-key path). The page route was already gated; this closes the matching JSON endpoint by moving it under /ui/, where the standard session gate applies. Adds a regression test. * fix(encryption): stop niet-deterministische AGE-hercodering van projectbestand-blokken Elke 'Process project' run hercodeerde het deployment 'configuration:'-blok (AGE is niet-deterministisch: zelfde plaintext, compleet andere ciphertext). Gevolg: ~52 regels pure ciphertext-churn per run, git-historie-bloat en non-fast-forward pushconflicten tussen gelijktijdige runs (verloren user-edit bij regel-k4c). Wizard-saves hercodeerden daarnaast elk user-env-vars blok, ook zonder wijziging. Het configuration-blok bleek een write-only kopie van alle credentials: processing leest het nooit terug (creds komen uit live k8s-secrets), de enige UI-decrypt voedde geen enkele template, geen API exposet het. Daarom: - Drop het blok volledig: _save_encrypted_configs_to_project_file, _normalize_secret_keys, de _env_vars trackingmap en to_config_data verwijderd; dode decrypt in web/router.py weg; configuration-veld uit DeploymentModel/i18n/wizard-literalize. - Strip bestaande 'configuration'/'decrypted_configuration'-blokken via de onvoorwaardelijke _fixup_v2_data (eenmalige cleanup per project). - Wizard-saves: keep_existing_ciphertext_if_unchanged() in de editables- pipeline houdt opgeslagen ciphertext byte-identiek wanneer de plaintext niet wijzigde (key-rotatie decrypt-faalt en hercodeert dus gewoon). Geverifieerd in sandbox: process schrijft geen configuration-blok meer, fixup stripte bestaand blok, overige AGE-blokken byte-identiek na save. NB: bevat ook de catalog-root fixup-hunks die in PR #120 zitten (zelfde inhoud; merge-volgorde maakt niet uit). * fix(rbac): herstel kubelet-scrape RBAC in sandbox cluster-role nodes/nodes-proxy/nodes-metrics leesrechten waren per ongeluk verwijderd in de RBAC-inscoping van #80, waardoor Prometheus kubelet/cAdvisor-scrapes 403 gaven (role:node service-discovery + resource-SAR op nodes/metrics; nonResourceURLs dekt dat niet). * docs: OpenProject-op-ZAD verkenning + future-features (TTL auto-suspend, Umami) * fix(wizard): gewiste velden verdwijnen nu echt en samenvatting toont user-env-vars ontsleuteld Twee bugs in de modal-wizard samenvatting: 1. Een leeggemaakt veld (bijv. aliases in Component bewerken) kwam terug met de oude waarde: de additieve merge in get_merged_data() kan een verwijderde sleutel niet uitdrukken. Gewiste velden krijgen nu een expliciete tombstone in het stap-fragment; get_merged_data() ruimt die op en verwijdert daarbij ook de oude waarde uit de snapshot. 2. user-env-vars verschenen als rauw AGE-blok: converter.view() werd aangeroepen met kwarg yaml_data= die geen enkele converter kent, waarna de except-TypeError fallback de context (en dus decryptie) liet vallen. Aanroep gebruikt nu context_data= en de fallback is weg. * fix(keycloak): persisteer realm-admin credentials direct na aanmaak Het gegenereerde admin-wachtwoord bestaat nergens anders dan in het projectbestand. Het werd pas aan het einde van de taak gecommit; elke fout daartussen (zoals een alias-validatiefout) liet de admin-user achter in Keycloak met een onherstelbaar wachtwoord, waarna de duplicate-admin guard elke herverwerking blokkeerde (napp-avm). Het configuratieblok wordt nu direct na het aanmaken van de admin-user gecommit en gepusht. De guard zelf blijft ongewijzigd weigeren (geen automatische wachtwoordresets); alleen de fouttekst beschrijft nu de echte oorzaak en de handmatige herstelprocedure. * feat(parallel): wacht parallel op ArgoCD sync per deployment en verhoog taak-concurrency Een project-refresh met N deployments wachtte serieel per applicatie (tot 120s creatie + 300s sync elk); 20 deployments duurde daardoor tot een uur. De creatie- en sync-waits (read-only polls) draaien nu concurrent via asyncio.gather; de wandkloktijd is die van de traagste deployment. Remediatie (OOM-tuning, image-pull uitschakelen) blijft serieel omdat die het projectbestand in git muteert. Bijvangst: component-failures van meerdere falende deployments worden nu geaggregeerd in het taakresultaat (voorheen overschreef elke falende app de vorige). Capaciteit daarop afgestemd: - TASK_WORKER_CONCURRENCY 4 -> 12 (backup-limiet blijft 2) - DB-pool max_size 10 -> 20 (12 workers verhongerden op 10 connecties) - git push rebase-retries 3 -> 5 (meer gelijktijdige pushers per repo) * feat(argocd): verhoog controller-parallelisme en resources voor snellere syncs Afgestemd op het parallelle deployment-wachten in de operations manager: - controller.status.processors 5 -> 20, operation.processors 5 -> 10 - kubectl.parallelism.limit en reposerver.parallelism.limit 5 -> 10 - controller 2 CPU/4Gi -> 4 CPU/8Gi (OOMKilled vandaag op 4Gi door resync-churn; meer parallelisme vraagt sowieso meer geheugen) - repo-server 1 CPU/1Gi -> 2 CPU/2Gi (rendert kustomize+SOPS voor 10 parallelle syncs) * fix(security): patch aiohttp, starlette, fastapi en pip kwetsbaarheden pip-audit op main faalde op 5 bekende kwetsbaarheden in 3 packages: - aiohttp 3.13.5 -> 3.14.1 (CVE-2026-47265 cross-origin redirect met per-request cookies, CVE-2026-34993 deserialisatie van untrusted data) - starlette 0.50.0 -> 1.2.1 (PYSEC-2026-161: ontbrekende Host-header validatie vergiftigt request.url.path en omzeilt padgebaseerde security-checks; direct relevant voor onze authorization-middleware) - fastapi 0.135.1 -> 0.136.3 (mee voor starlette 1.x compatibiliteit) - pip 26.1.1 -> 26.1.2 (PYSEC-2026-196 entry-point pad-escape) Volledige testsuite groen op de nieuwe stack (3737 tests; alleen integratietests zonder cluster geven verwachte errors). pip-audit lokaal: geen bevindingen meer.
Scope en eerlijke verwachtingen
Wat dit oplost (in volgorde van werkelijke impact):
DEBUG: bool = Falsedefault inconfig.py— productie liep met DEBUG=False alleen omdat dev.envdat overschreef; na .env-removal valt-ie zonder fix terug opTrue. Echte regressie-fix.keys/en.env*worden niet meer in image-lagen gebakken. Image-hygiene./keys/in.gitignore+ key-files verwijderd uit repo — voorkomt re-introductie. Audit-signaal: "keys zijn weg, niet meer per ongeluk terug te plaatsen".secrets list/updateweg uitnamespace-managerClusterRole inlocal+sandboxed-localoverlays. Beperkt blast-radius op dev/test clusters._blueprint-cluster-role.yaml+_blueprint-cluster-binding.yamlin odcn-production overlay — documenteert OPI's gewenste rechten als referentie. Niet in kustomization, niet door tasks toegepast.Wat dit NIET oplost (eerlijk over scope):
host.docker.internal:2222), niet productie-GitOps-keys. Productie gebruikt HTTPS + PAT inoperations-manager-env-secrets. De verwijdering is dus hygiene + perceptie, geen acute lekafdichting.RoleBindingsnaar de built-inadminClusterRole — er is geennamespace-managerClusterRole op productie. Desecrets list/updateremoval raakt productie niet. Strakkere productie-RBAC is een Capsule-tenant-config wijziging — apart issue.:latest. Digest-pin is follow-up Pin OPI image op immutable digest in plaats van :latest #92.GIT_SERVER_KEY_PATHenv-var en deif not is_httpsbranches inargo_manager.py/git_monitor.pyblijven staan tot na merge van fix: verwijder onbereikbare git-repo-aanmaakcode (latente RCE op git-host) #72. Aparte cleanup-PR.Bootstrap-deploy
Productie OPI wordt handmatig uitgerold via:
```bash
task update-operations-manager CLUSTER_TYPE=odcn-production
```
Niet door ArgoCD. Na merge moet die task gedraaid worden om Dockerfile + deployment-yaml wijzigingen toe te passen. Image opnieuw bouwen + pushen voor de Dockerfile-cleanup.
Bestanden
secrets list/updatewegDEBUG: bool = False/keys/toegevoegdFollow-ups op project ZAD