feat: restringir el ingress al Postgres con una allowlist explícita - #133
Merged
Conversation
La NetworkPolicy del CNPG nunca funcionó: su selector se armaba con
adhoc-odoo.fullname ("<release>-adhoc-odoo-pg") mientras el operador etiqueta los pods
con el nombre del CR Cluster ("<release>-pg"). No seleccionaba ningún pod en ninguna de
las 327 bases, así que la base quedaba alcanzable en el 5432 desde cualquier pod de
cualquier namespace del cluster.
Se rehace con el helper correcto y con la allowlist completa. El punto delicado es que
en un namespace sin ninguna policy efectiva, la primera que matchea convierte el ingress
de "todo permitido" a "denegado lo no listado": la allowlist tiene que cubrir todo el
tráfico legítimo, no solo el de Odoo.
Validado en una base de test aplicando la policy y midiendo desde cada origen:
origen 5432 9187 8000
Odoo del ns conecta - -
PG de otro ns TIMEOUT - -
ns monitoring TIMEOUT conecta TIMEOUT
ns cnpg-system TIMEOUT TIMEOUT conecta
Cada excepción abre solo su puerto y solo desde su namespace. Con la policy activa el
pod siguió Ready y sin restarts: las probes del kubelet (httpGet al 8000) no las filtra
NetworkPolicy, así que no hace falta listarlas. El operador siguió reportando el cluster
sano y Odoo siguió conectando.
Se borra también <release>-allow-prometheus, que tenía el mismo bug de naming. No se
arregla porque su selector corregido capturaría los cinco pods del release permitiendo
solo monitoring en 9101/9113/9114, o sea cortando el tráfico web y el 5432. Hoy no
protege nada: sin default-deny en el namespace, el PodMonitor scrapea igual.
Se suma el fixture ci/selectors-values.yaml, que enciende CNPG y monitoring. Los values
por defecto los dejan apagados, y por eso ningún render de CI ejercitaba estos recursos
— la razón por la que el bug sobrevivió sin que nadie lo viera. Con el fixture, el
chequeo de selectores cubre estos casos de acá en adelante.
Contributor
There was a problem hiding this comment.
Pull request overview
Este PR corrige y endurece la política de red de CloudNativePG en el chart adhoc-odoo, pasando el ingress al Postgres a un esquema default-deny con allowlist explícita, y agrega un fixture de CI para que el render/chequeo de selectores cubra estos recursos cuando cloudNativePG y monitoring están habilitados.
Changes:
- Reemplaza la NetworkPolicy de CNPG por una allowlist explícita y corrige el selector para que matchee los pods reales del Cluster.
- Elimina la NetworkPolicy
allow-prometheus(que no estaba seleccionando pods por un bug de naming) del templatemonitoringCommon.yaml. - Agrega
ci/selectors-values.yamlpara ejercitar en CI los recursos que por default quedan apagados.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| charts/adhoc-odoo/templates/monitoringCommon.yaml | Elimina una NetworkPolicy de Prometheus que no estaba siendo efectiva por selector incorrecto. |
| charts/adhoc-odoo/templates/cnpg/networkPolicy.yaml | Define una NetworkPolicy de ingress para CNPG con selector corregido y allowlist por origen/puerto (5432/9187/8000). |
| charts/adhoc-odoo/ci/selectors-values.yaml | Agrega un fixture de values para que CI renderice y valide selectores cuando CNPG/monitoring están habilitados. |
Comment on lines
+25
to
27
| # Odoo del propio namespace: el único origen legítimo de tráfico SQL. Se discrimina por | ||
| # adhoc.ar/app-name porque los pods de nginx comparten los app.kubernetes.io/*. | ||
| - from: |
Bloqueante encontrado revisando el PR: el pod del Job wait-pg no tenía ningún label. Es un hook post-install/post-upgrade que corre pg_isready contra el 5432, así que con la policy activa quedaba bloqueado, el hook fallaba y con él el helm upgrade entero de las 327 bases. Los labels del template estaban puestos en el Job, no en spec.template, que es de donde los toma el pod. Se le da adhoc.ar/app-name: "pg-hook" y su regla propia en la allowlist, en vez de hacerlo pasar por el label de Odoo. Validado en la base de test: un pod con ese label obtiene "accepting connections" y uno sin el label obtiene "no response". Se precisa además el comentario sobre las probes del kubelet: no las filtra Kubernetes NetworkPolicy por semántica del recurso, y además está validado en GKE Dataplane V2; un CNI con host firewall podría comportarse distinto. Y se documenta lo que la allowlist no cubre por si alguna vez aparece: poolers, standby o subscribers lógicos fuera del namespace, y tooling externo que conecte por SQL. Verificado que hoy no hay ninguno: 0 Poolers y 0 clusters en modo replica sobre los 1315 del parque.
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.
Suppressed comments (1)
charts/adhoc-odoo/templates/cnpg/networkPolicy.yaml:8
- El comentario afirma de forma general que Kubernetes NetworkPolicy no filtra tráfico del nodo hacia el pod. Esto no es universal (depende del CNI / configuración) y puede inducir a asumir que las probes siempre van a funcionar sin excepción. Conviene acotar la afirmación a lo validado (GKE Dataplane V2) y dejar explícito que en otros entornos podría requerirse una regla adicional (p.ej. ipBlock con rangos de nodos) o una validación específica.
# solo el de Odoo. Las probes del kubelet no hacen falta listarlas: Kubernetes NetworkPolicy
# no filtra el tráfico del nodo hacia el pod (validado además en GKE Dataplane V2).
This was referenced Aug 10, 2026
az-adhoc
added a commit
that referenced
this pull request
Aug 10, 2026
…#136) INCIDENTE: desde que se mergeó #133 las bases nuevas no terminaban de crearse. El job fixdb del pipeline queda colgado en "Waiting until the database server is listening..." porque la allowlist no lo contempla, y como su podAntiAffinity es required con topologyKey hostname y namespaceSelector sobre todos los namespaces, cada fixdb colgado ocupa un nodo entero: el nodepool de cell01 escaló de 9 a 20 nodos. Los jobs del pipeline no los crea este chart, así que no aparecen en su render: los crea el provider dentro del namespace de la base. Todos llevan la clave adhoc.ar/odoo-job (fixdb, restore), así que la regla matchea por Exists para cubrir los que se sumen. Validado desplegando el chart en test-texterfeed-10-08-4: adhoc.ar/odoo-job=fixdb -> accepting connections adhoc.ar/odoo-job=restore -> accepting connections adhoc.ar/app-name=odoo -> accepting connections adhoc.ar/app-name=intruso -> no response Por qué no se detectó antes: la validación de #133 se hizo midiendo pg_stat_activity de bases en régimen, donde fixdb ya había terminado hacía rato, y revisando los jobs del chart (donde sí apareció wait-pg). Los jobs del pipeline viven fuera del chart y solo corren durante la creación. Se agrega esa advertencia al comentario del manifiesto para que la próxima allowlist se valide contra una creación completa.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cierra el frente de NetworkPolicies del chart. Cambia comportamiento de red: leer la sección de riesgo.
El estado actual
La NetworkPolicy del CNPG nunca funcionó. Su selector se armaba con
adhoc-odoo.fullname(<release>-adhoc-odoo-pg) mientras el operador etiqueta los pods con el nombre del CRCluster(<release>-pg). No seleccionaba ningún pod en ninguna de las 327 bases, así que el Postgres queda hoy alcanzable en el 5432 desde cualquier pod de cualquier namespace del cluster.El riesgo que hay que entender antes de mergear
En un namespace sin ninguna policy efectiva, la primera que matchea convierte el ingress de "todo permitido" a "denegado lo no listado". No alcanza con arreglar el selector: la allowlist tiene que cubrir todo el tráfico legítimo hacia la base, no solo el de Odoo.
Por eso esto se validó aplicándolo en una base de test real, no solo renderizando.
Validación empírica
Policy aplicada en un namespace de test con Odoo y Postgres vivos, midiendo la conectividad desde cada origen:
monitoringcnpg-systemCada excepción abre solo su puerto y solo desde su namespace. Y con la policy activa:
httpGetal 8000 para/healthz,/readyz,/startupz) no las filtra NetworkPolicy, así que no hace falta listarlas. Esto se verificó, no se asumió — si se bloquearan, CNPG reiniciaría el pod en loop.Cluster in healthy state.Se borra
allow-prometheusTenía el mismo bug de naming. No se arregla: con el selector corregido capturaría los cinco pods del release permitiendo solo
monitoringen 9101/9113/9114, o sea cortando el tráfico web y el 5432. Hoy no protege nada — sin default-deny en el namespace, el PodMonitor scrapea igual.Fixture de CI
Se suma
ci/selectors-values.yaml, que enciendecloudNativePGymonitoring. Los values por defecto los dejan apagados y por eso ningún render de CI ejercitaba estos recursos — la razón por la que el bug sobrevivió sin que nadie lo viera. Con el fixture, el chequeo de selectores cubre estos casos de acá en adelante.Test plan
helm lint+helm templatesobre los 14 charts y todos sus fixtures, en verde. pre-commit en verde.Rollout
El recurso cambia de nombre (
allow-same-namespace→<fullname>-pg-ingress), así que Helm borra el huérfano y crea el nuevo. Conviene ir por olas, no las 327 de una, verificando en cada una quecnpg_collector_upsiga en 1 y que el operador no reporte degradación.