fix: do not add service name as alias on external networks#13784
fix: do not add service name as alias on external networks#13784stasadev wants to merge 1 commit intodocker:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR prevents Docker Compose from automatically adding the service name as a network alias when attaching containers to external networks, avoiding service-name leakage and potential DNS collisions across workloads sharing the same external network.
Changes:
- Update alias generation to append the service name only for non-external networks.
- Thread
networkKeyintogetAliases()so it can consult the project network definition. - Add a unit test validating alias behavior on external networks.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| pkg/compose/create.go | Adjusts alias computation to skip adding service.Name on external networks. |
| pkg/compose/create_test.go | Adds a test ensuring external networks do not receive the service-name alias (but keep explicit aliases). |
|
/review |
There was a problem hiding this comment.
Assessment: 🟢 APPROVE
The fix is correct and well-scoped. getAliases() now guards the automatic service-name alias behind a !n.External check, preventing service discovery names from leaking onto shared external networks. The Go map zero-value lookup (project.Networks[networkKey] → NetworkConfig{}) is safe — External defaults to false, and Compose validation guarantees all service network keys exist in project.Networks before this point. Explicit user-configured aliases under service.networks.<name>.aliases are intentionally still passed through (confirmed by the PR description and test). The new test TestCreateEndpointSettings_ExternalNetwork correctly covers the fixed scenario. No issues found.
|
Thanks for the fix and for the detailed write-up. The collision scenario is a real pain point, and the proposed approach makes sense. Before merging, though, I think this should be called out as a silent breaking change. Users who intentionally rely on service-name resolution across an external network will suddenly lose DNS resolution, with no indication from Compose as to why. While a workaround exists through explicit aliases, it is not discoverable. Could you add a log notice when the service-name alias is skipped on an external network? Something along the lines of: A An end-to-end test covering a mixed internal + external network scenario would also be very helpful. The current unit test covers the single-network case, but a test asserting that the service name still resolves on the internal network while not being registered on the external one would provide a stronger regression guard. @ndeloof what do you think? |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Previously, getAliases() unconditionally appended the service name as a network alias when useNetworkAliases was true. This caused containers to register their service name as an alias on external networks, leaking internal service discovery names into networks managed outside of Compose. Guard the service name alias behind an external-network check: only append it when the network is not marked as external. Explicitly configured aliases in the service network config are still passed through regardless. To make the behavior change discoverable, `up` now emits one warning per external network the project is connected to, listing the services whose service-name alias was skipped. Services that already declare their own name under networks.<net>.aliases are excluded, so the warning disappears once the user adopts the workaround. `create` and `run --use-aliases` are intentionally not warned about: `create` is rarely used standalone, and `run --use-aliases` produces ephemeral one-off containers where the warning would be noise. Fixes docker#8223 Signed-off-by: Stanislav Zhuk <stasadev@gmail.com>
5056e7f to
49a4cb1
Compare
Makes sense, I added a One note: the warning lives in a separate helper |
|
I wonder if we need to have a closer look at different scenarios. This is a known problem for some use-cases, but disabling the alias may also be covering over other issues; Networks in docker also form a security boundary; services connected to the same network are granted access to other services connected to the same network. Disabling DNS resolution won't prevent other services from connecting; in the example given (multiple projects defining a If the shared network is used for some reverse proxy (traefik, caddy, nginx-proxy), that could even mean the database may become exposed publicly. The reverse can also be true; perhaps a less common use-case, but I've seen users work with "composable" compose projects; a network that's set up, then multiple compose projects that define part of the stack, but attached to the common network; for those, DNS resolution between those may be intentional. Wondering of some options should be configurable on the network, to more clearly define the purpose of the network, which could be an ingress network, disallowing communication between services attached to the network. |
Summary
pkg/compose/create.go)up, log aWARNwhen this alias is skipped, so users notice the change and learn about the workaroundWhat changed
Before this fix,
getAliases()always added the service name as an alias whenuseNetworkAliaseswas true. This put internal service names onto external networks (networks Compose does not manage). On a shared external network, two projects with a service nameddbwould resolve to each other - which is the bug.The fix skips the service name on external networks. Aliases that the user sets under
services.<name>.networks.<net>.aliasesstill go through.Discoverability
Users who relied on cross-project resolution over a shared external network would lose it silently. To make the change visible,
upprints one warning per external network used by the project:One warning per network keeps the output short, even on stacks with many services on the same external network. A service that already lists its own name under
networks.<net>.aliasesis left out of the warning, so the warning disappears once the user adopts the workaround.Only
upprints the warning.createandrun --use-aliasesdo not:createis rarely used alone - it almost always runs as part ofuprun --use-aliasescreates one-off containers, where the warning would just be noiseWorkaround
Add the alias per service, under that service's network entry. The alias namespace lives on the service, not on the network itself:
Related
ddev/ddev#8390 - DDEV projects share one external network (
ddev_default). Adbin one project resolved to another project'sdbover that shared network, because the service name was registered as an alias on it.Before / After
Setup
Two independent Compose projects and a standalone router share one external network. Project1 has
webanddb. Project2 has onlyweb- nodbof its own, so anydbresolution from it would cross into project1. The router is a separate project onshared-netonly, simulating a reverse proxy like ddev-router.Cleanup:
Before (buggy behavior)
Service names appear as aliases on the external network:
Within project1,
webcan ping its owndbby service name (expected):Project2's
webhas nodbof its own, but can reach project1'sdbviashared-net(bug):routerin project2 can also resolve project1's services viashared-net(bug):After (fixed behavior)
Service names are no longer registered as aliases on the external network:
Within project1,
webcan still ping its owndbby service name via the internaldefaultnetwork (unchanged):Project2's
webcan no longer resolve project1'sdb(fixed):routercan no longer resolve services from project1 either (fixed):Containers are still reachable on
shared-netby their fully qualified container name, which remains as an alias on the external network:Test plan
TestCreateEndpointSettings- non-external network case still producescontainerName,serviceName, and configured aliasesTestCreateEndpointSettings_ExternalNetwork- external network case produces onlycontainerNameand configured aliases (no service name)TestWarnExternalNetworkAliases- covers the warning helper:networks.<net>.aliasesare excludedTestExternalNetworkAliases(e2e) - mixed internal + external network fixture, wherewebhas no explicit alias on the external network anddbdeclaresnetworks.external-net.aliases: [db]:upweband excludesdb(sincedbis self-aliased)web's service name is inAliaseson the internal networkweb's service name is not inAliaseson the external networkdb's explicit alias[db]is registered on the external network (workaround works end-to-end)web->db)golangci-lint run --build-tags "e2e" ./pkg/compose/... ./pkg/e2e/...- 0 issues