Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BIND_IP env var and bindIp setting #1077

Open
willjasen opened this issue Dec 28, 2023 · 12 comments
Open

Add BIND_IP env var and bindIp setting #1077

willjasen opened this issue Dec 28, 2023 · 12 comments
Assignees
Labels
bug Something isn't working enhancement New feature or request

Comments

@willjasen
Copy link

When configuring the listenIP config parameter, it seems to be ignored (all available IP addresses respond); in the case I am attempting to use, I would like to restrict Tipi and all of its managed apps to only respond on a Tailscale IP address (100.64.0.0/10). I currently have four running instances of Tipi on various devices and none have obeyed the listenIP parameter.

This is particularly concerning to me as on at least one device, a public interface is available, so Tipi and its installed apps are available via that IP address. Even worse, setting up UFW has no effect due to ordering of docker vs. custom rules (being that docker rules come first, which is allowing access to Tipi and its apps before my custom rules would say deny later on down the list). I otherwise follow good security hygiene by having complex, highly entropic passwords and 2FA but I would like to ensure that the services aren't available publicly in the first place (hard to hack what you can't get to)

If there's any information that I can provide to help troubleshoot, I'll be happy to do so.

@willjasen willjasen added the bug Something isn't working label Dec 28, 2023
@willjasen
Copy link
Author

I'll also note that I can manually edit the ports section of a docker-compose.yml of an app to achieve only having that app respond via Tailscale, but that of course gets overridden during app upgrades and I haven't found out how to achieve this using the user-config method either.

@willjasen
Copy link
Author

After some reviewing, I can see how to make an app obey this. I forked the runtipi-appstore and modified the syncthing app to use APP_DOMAIN instead of APP_PORT (link here)

Because APP_PORT resolves solely to the outside port used by Tipi for the app, the app is available via all interfaces/IP addresses. By using APP_DOMAIN instead, it resolves to "ip:port", and the IP in this case is what is configured as the listenIP address in config.json

The resulting tests show that Syncthing via Tipi is not available via the local LAN IP address.
Screenshot 2024-01-04 at 1 11 17 PM

However, it is available via its Tailscale IP address (resolved via the Tailscale domain)
Screenshot 2024-01-04 at 1 11 27 PM

What from here? This would mean that apps in the app store would need to be updated. Perhaps there's a better way I'm not thinking of. As well, Tipi itself would need to accommodate this too.

@meienberger
Copy link
Collaborator

Thanks for your research @willjasen. Indeed this would require a change in all apps. I added this to the backlog so I can revisit this issue later. Does the user_config not allow you to override the port?

@willjasen
Copy link
Author

I can specify "${APP_DOMAIN}:inside-port" within user-config (for example, doing this for syncthing would resolve to something like "100.64.0.1:8090:8384" in user-config/syncthing/docker-compose.yml), but since user-config seems to be in addition to, apps are still available via all interfaces/IPs (via apps/syncthing/docker-compose.yml). If there's a way in Docker Compose to negate a previous statement, I think I could get it working, but I don't think that there is.

@meienberger
Copy link
Collaborator

You are correct, it would only add an entry to the list. What we could do is by default to listen on all interfaces and if the user specify a custom listenIp, it is always binding to this ip

@willjasen
Copy link
Author

willjasen commented Jan 5, 2024

According to here, the listenIp parameter is read into the environment map as INTERNAL_IP. I think that this means there's a bit of duplication here, as listenIp and INTERNAL_IP are kind of the same thing - INTERNAL_IP can always be set manually through the GUI but when listenIp is set via settings.json, it will override it, but this setting should be tweakable but stately from either the GUI or config. A distinction between the two is the juxtaposition I found myself in originally as I kept tweaking both listenIp and INTERNAL_IP yet never yielded the sort of binding results that I sought out.

I first propose that these two variables are merged into one - listenIp seems like it would more easily collapse into INTERNAL_IP. Along with the collapse, INTERNAL_IP should be more thought of as a BIND_IP (either a specific IP address available to the system or the wildcard 0.0.0.0 which binds to any IPv4 interface, but the rename isn't necessary, so long as everyone else understands the distinction).

For APP_PORT, my quick fix is here. By performing this logic, it omits the need to re-calibrate the app store (somewhat). I feel like there's some further consideration for this change on how it reflects against exposing an app. In the case I have, I'm not exposing apps to the public, and if I did, I would either do so via a Tailscale funnel or Cloudflare tunnel. In the end, I think this is gonna be one of those changes that requires a heads up to everyone when pushed. Since Tipi currently uses the first network interface's IP address, lots of people have x.y.w.z already within their config, and I think most people will need to change their INTERNAL_IP parameter into 0.0.0.0 so that Tipi will listen on all interfaces. The worst case here I foresee is that Tipi then binds to say the wired network interface and is only accessible via its address, but since most people are somewhat using x.y.w.z and 0.0.0.0 synonymously, they shouldn't see a break. However, for those out there like me, setting INTERNAL_IP to something like in an overlay network will ensure that Tipi and its apps are only accessible via that interface's address. It also doubles as redundancy in some cases, where the overlay network works over both wired and wireless interfaces, so if the wired connection goes down, it seamlessly transitions over to the wireless interface.

Those are my thoughts, I welcome any input. It's possible that I'm missing some intended use of listenIp or INTERNAL_IP that offers a distinction of the two. The beginnings of my professional background is in network engineering but I do a little bit of everything, so that leaks over into programming. Keeping services bound to particular interfaces is an important way to handle modes of accessibility and helps provide least privileged access for security hygiene.

@meienberger
Copy link
Collaborator

So to clarify with a bit of history, INTERNAL_IP was initially auto-generated and used to generate hostname env variables (needed by some apps). Some users have had issues because their system had two or more IPs and the automated system would pick up the wrong one. This is when the setting listenIp was added. The name discrepancy between listenIp and INTERNAL_IP was created just because I felt it would sound wrong for users to "set" an internal IP. However, in retrospect it should have been named differently. Now for your use case, I think adding a BIND_IP env var and bindIp setting with default 0.0.0.0 is the best move forward in a backward-compatible thought. Still, I'm concerned about the confusion it could bring for people to have both these settings. Maybe @willjasen you have an idea on how we could rename INTERNAL_IP and listenIp to something more understandable. The only requirement I need is to not break any existing config

@meienberger meienberger added the enhancement New feature or request label Jan 5, 2024
@meienberger meienberger changed the title listenIP config parameter has no effect Add BIND_IP env var and bindIp setting Jan 5, 2024
@willjasen
Copy link
Author

willjasen commented Jan 30, 2024

Sorry for the radio silence! I'm juggling lots of things. I'm also preparing to change my hosting architecture so that I don't have to rely on Tipi solely to bind its interface properly.

I think if you're going for a non-breaking change, then a bindIp parameter should be added, though listenIp is really the same thing in my mind. The bindIp parameter should have a default of "0.0.0.0" so that all IPs are listened in on and the user can then change that to a specific interface IP address to then limit where Tipi is listening. Maybe add a bit of logic so that the bindIp parameter doesn't get set to just anything that is put in - check that the IP being entered is an IP available on the system.

I could see confusion for some between bindIp and listenIp and such so if that's to be collapsed, I would assume that's a breaking change, and the only way to somewhat manage that is to give everyone plenty of heads up before.

Copy link

github-actions bot commented Mar 1, 2024

This issue is stale because it has been open for 30 days with no activity.

@github-actions github-actions bot added the stale label Mar 1, 2024
@meienberger meienberger removed the stale label Mar 2, 2024
Copy link

github-actions bot commented Apr 2, 2024

This issue is stale because it has been open for 30 days with no activity.

@github-actions github-actions bot added the stale label Apr 2, 2024
Copy link

This issue was closed because it has been inactive for 14 days since being marked as stale.

@meienberger meienberger reopened this Apr 17, 2024
@github-actions github-actions bot removed the stale label Apr 18, 2024
Copy link

This issue is stale because it has been open for 30 days with no activity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement New feature or request
Projects
Status: Done
Development

No branches or pull requests

2 participants