You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Redesign container network topology for better service isolation
Replace the three-network model (foreman-db, foreman-cache, foreman-app)
with a per-service network topology derived from actual service
communication requirements:
foreman (not internal, isolated)
Foreman owns this network. Provides internet access for outbound
calls. PostgreSQL and Redis attach here for Foreman data access.
Dynflow, Candlepin, Pulp, and Foreman Proxy also attach to enable
direct communication with Foreman.
pulp (not internal, isolated)
Pulp owns this network. Provides internet access for content
synchronisation. PostgreSQL and Redis attach here for Pulp data
access. Foreman and Dynflow also attach to reach Pulp directly.
candlepin (internal, isolated)
Candlepin owns this network. PostgreSQL attaches here for
Candlepin data access. Foreman attaches to reach Candlepin.
Candlepin also joins the foreman network so that its hostname is
resolvable from Foreman's primary DNS without cross-bridge routing.
Pulp and Foreman Proxy have no route to Candlepin.
foreman-proxy (not internal, not isolated)
Connects Foreman and Foreman Proxy. Not isolated because Foreman
reaches the proxy at quadlet.example.com:8443 via host-gateway
DNAT, which crosses the foreman-to-foreman-proxy bridge boundary.
Netavark isolation rules would block this cross-bridge DNAT
forwarding. External managed hosts reach the proxy via the
published port from the physical network, unaffected by isolation.
Additionally:
- postgresql_network and redis_network renamed to postgresql_networks
and redis_networks (lists) to support multiple network attachments.
Updated development and remote-database playbooks accordingly.
- Foreman Proxy container attaches only to foreman-proxy network,
not to foreman, keeping it isolated from candlepin and pulp.
- Updated docs/deployment.md to reflect the new topology.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/deployment.md
+47-50Lines changed: 47 additions & 50 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -241,90 +241,87 @@ There is a desire to allow deployments where a single `foremanctl` control node
241
241
242
242
All containers are connected to one or more named Podman bridge networks instead of sharing the host network namespace, limiting lateral movement: a container can only reach the services it is explicitly connected to.
243
243
244
+
The topology is designed top-down from service communication requirements. Each of the four application services (Foreman, Pulp, Candlepin, Foreman Proxy) owns a network that carries its private backend traffic. Services join each other's networks only where communication is required, making the allowed paths explicit and auditable.
245
+
244
246
### Networks
245
247
246
-
#### `foreman-db`
248
+
#### `foreman`
247
249
248
-
**Properties:**`internal: true`, `isolate: true`
250
+
**Properties:**`internal: false`, `isolate: true`
249
251
250
-
The database network. Only containers that need to read or write persistent data are attached.
252
+
Foreman's primary network. Provides outbound internet access for Foreman's external API calls. PostgreSQL and Redis attach here for Foreman's data access. Candlepin, Pulp, Dynflow, and Foreman Proxy also attach so that Foreman can reach each of them directly, and they can reach Foreman.
251
253
252
-
-`internal: true` removes the default gateway, so no container on this network can initiate outbound internet connections. Database servers have no reason to reach the internet, and clients that need internet access (e.g. for content sync) are multi-homed and use a different network for that.
253
-
-`isolate: true` prevents containers on this network from forwarding packets to containers on other bridge networks, closing off lateral movement paths between network segments.
254
+
`isolate: true` prevents containers on this network from forwarding packets to containers on other bridge networks, so Candlepin cannot reach Pulp via this network even though both are attached.
254
255
255
256
| Container | Role |
256
257
|-----------|------|
257
-
|`postgresql`| Server — listens on port 5432 (internal DB only) |
258
-
|`foreman`| Client |
258
+
|`postgresql`| Server — Foreman database |
259
+
|`redis`| Server — Foreman cache and Dynflow queue |
260
+
|`candlepin`| Server — also joins to make its hostname resolvable from Foreman's primary DNS |
261
+
|`foreman`| Owner |
259
262
|`dynflow-sidekiq@*`| Client |
260
-
|`foreman-recurring@*`| Client |
261
-
|`candlepin`| Client (internal DB only) |
262
-
|`pulp-api`| Client |
263
-
|`pulp-content`| Client |
264
-
|`pulp-worker@*`| Client |
263
+
|`pulp-api`| Server — reachable from Foreman |
264
+
|`pulp-content`| Server — reachable from Foreman |
265
+
|`pulp-worker@*`| Worker |
266
+
|`foreman-proxy`| Server — reachable from Foreman |
265
267
266
-
Ansible's `community.postgresql.*` modules reach the database during deployment via a Unix socket: `/var/run/postgresql` is bind-mounted from the host into the container so the socket is accessible on the host without publishing a TCP port.
268
+
`foreman`, `pulp-api`, and `pulp-content` publish their respective ports to `127.0.0.1` so that the `httpd` reverse proxy running on the host can reach them.
267
269
268
-
#### `foreman-cache`
270
+
#### `pulp`
269
271
270
-
**Properties:**`internal: true`, `isolate: true`
272
+
**Properties:**`internal: false`, `isolate: true`
271
273
272
-
The cache network. Only containers that need to reach Redis are attached. The same rationale as `foreman-db` applies: cache servers have no business reaching the internet, and the `isolate` flag prevents bridge pivoting.
274
+
Pulp's private network. Provides outbound internet access for content synchronisation. PostgreSQL and Redis attach here for Pulp's data access. Foreman and Dynflow also attach to reach Pulp directly.
273
275
274
276
| Container | Role |
275
277
|-----------|------|
276
-
|`redis`| Server — listens on port 6379|
277
-
|`foreman`|Client — app cache and Dynflow queue |
278
-
|`dynflow-sidekiq@*`|Client — job queue|
279
-
|`foreman-recurring@*`|Client — job queue|
280
-
|`pulp-api`|Client|
281
-
|`pulp-content`| Client |
282
-
|`pulp-worker@*`| Client |
278
+
|`postgresql`| Server — Pulp database|
279
+
|`redis`|Server — Pulp cache and task queue |
280
+
|`pulp-api`|Owner|
281
+
|`pulp-content`|Owner|
282
+
|`pulp-worker@*`|Owner|
283
+
|`foreman`| Client |
284
+
|`dynflow-sidekiq@*`| Client |
283
285
284
-
Redis does not publish any port to the host: it is a purely internal service with no legitimate consumers outside the container network.
Candlepin's private network. `internal: true` removes the default gateway: Candlepin has no reason to initiate outbound internet connections. PostgreSQL attaches here for Candlepin's data access. Foreman attaches to reach Candlepin directly. Pulp and Foreman Proxy have no route to Candlepin.
289
291
290
-
The application network. Containers that need to communicate with each other at the application layer, or that need outbound internet access (e.g. for content synchronisation), are attached here.
292
+
Candlepin also joins the `foreman`network so that its hostname is registered in Foreman's primary DNS zone, avoiding cross-bridge DNAT for the Foreman-to-Candlepin connection.
291
293
292
294
| Container | Role |
293
295
|-----------|------|
294
-
|`candlepin`| Server — Tomcat (23443) and Artemis STOMP broker (61613) |
295
-
|`foreman`| Client to Candlepin; serves Foreman Proxy requests |
296
-
|`dynflow-sidekiq@*`| Client |
297
-
|`foreman-recurring@*`| Client |
298
-
|`pulp-api`| Server — API (24817); needs internet for content sync |
299
-
|`pulp-content`| Server — content (24816); needs internet for content sync |
300
-
|`pulp-worker@*`| Worker — needs internet for content sync |
Candlepin does not publish any ports to the host: `foreman` reaches it directly over the bridge using its DNS name. `foreman`, `pulp-api`, and `pulp-content` publish their respective ports to `127.0.0.1` so that the `httpd` reverse proxy running on the host can reach them.
300
+
Candlepin does not publish any ports to the host: Foreman reaches it directly over the bridge using its DNS name.
The proxy network, used exclusively for communication between Foreman and Foreman Proxy. Keeping this traffic on a dedicated network makes it straightforward to apply stricter controls in future without affecting the rest of the application.
306
+
The proxy network, used for communication between Foreman and Foreman Proxy. Not isolated because Foreman reaches the proxy at `quadlet.example.com:8443` via host-gateway DNAT, which crosses the `foreman`-to-`foreman-proxy` bridge boundary; netavark isolation rules would block this cross-bridge DNAT forwarding.
309
307
310
308
| Container | Role |
311
309
|-----------|------|
312
-
|`foreman-proxy`|Server — listens on 0.0.0.0:8443 (external)|
310
+
|`foreman-proxy`|Owner — listens on `0.0.0.0:8443`|
313
311
|`foreman`| Client |
314
312
315
-
`foreman-proxy` publishes port `0.0.0.0:8443` so that remote Foreman Proxies and clients can register and communicate with it from outside the host.
313
+
`foreman-proxy` publishes port `0.0.0.0:8443` so that external managed hosts can communicate with it, and so that Foreman on the `foreman` network can call back to it via host-gateway.
0 commit comments