helium / gateway-rs

The Helium Gateway
Apache License 2.0
277 stars 110 forks source link

Unable to use API port with docker due to 127.0.0.1 binding #229

Closed joecryptotoo closed 2 years ago

joecryptotoo commented 2 years ago

The API port needs to bind to 0.0.0.0 within a docker container so the service can be published.

madninja commented 2 years ago

that would be really bad as a default for non docker users and a great way to get hotspot signing apis exposed to the internet. I'm not sure how to solve this yet since we're really trying to avoid having people inadvertently or maliciously get convinced to basically expose their key material to the internet.

You can't run docker commands to access that api within the docker context using docker scripts?

madninja commented 2 years ago

One option for us not to build the hole into the core service is for the person building the container to explicitly decide they want this and use socat (or nginx for a larger option) to forward requests. That way you are deciding to expose your keys to the internet

madninja commented 2 years ago

Hmph.. we'll get it fixed up. I have the same issue talking from gateway-config

madninja commented 2 years ago

Actually @joecryptotoo. This can be solved by enabling host networking in this docker file which would then have it listen in the host environment. Besides being better than docker based networking this would make it very clear who's exposing the port.

Does that work for you?

pritamghanghas commented 2 years ago

@madninja if we make this container to use host networking. All users of this service will also have to use host networking. I think allowing listen ip configuration in settings file will be better.

madninja commented 2 years ago

@madninja if we make this container to use host networking. All users of this service will also have to use host networking. I think allowing listen ip configuration in settings file will be better.

I'm not sure I agree.. While it's certainly easier, it also makes it extremely easy for users to expose the local api to the internet which would be a massive security hole. Given that the vast majority of makers are not very security aware we decided to force the docker users to declare that they're doing this in the docker environment. If you have an alternate way to avoid people to yolo expose their signing keys to the internet I'm open to suggestions.

vpetersson commented 2 years ago

@madninja this isn't really a viable option. I agree with having the service bind on 127.0.0.1 is a sensible default for the reasons you mention.

However, as @joecryptotoo correctly points out, this isn't workable in Docker. We need the be able to talk to gateway-rs over gRPC from other services within the same Docker network. To do this, the service needs to bind on 0.0.0.0, as the concept of localhost isn't really a thing within a Docker network (with the exception of host networking which opens a whole different can of worm and should be avoided at all cost).

Introducing something like a reverse proxy is bad as it adds a lot more complexity. Moreover, this goes against Docker best practice, where you're only supposed to run one 'main' process per container.

jeffgrunewald commented 2 years ago

Docker supports better options for this type of operation without compromising the security of the application running directly within the host's network namespace. Running the gateway-rs within the host's network namespace with --network=host you can easily reach it from other services running inside containers within the default docker network namespace stack either by configuring them to reach the gateway directly on the internal host address of 172.17.0.1 or by creating a host file entry for it in the container with --add-host=host.docker.internal:host-gateway within your docker run command or equivalent docker-compose config.

So for instance running gateway-config within a container on docker's default network docker run -d --name gw-config --add-host=whatever.address.youwant:host-gateway gateway-config-image it can reach the miner's embedded gateway-rs running host network mode by configuring it to reach the gateway at whatever.address.youwant:4468 or 172.17.0.1:4468 (that one without any changes needed to the run command or yaml file).

Aside from avoiding exposing a security vulnerability, by docker's own admission (https://docs.docker.com/network/host/) there are optimizations to be had by running in host network mode, particularly when you're targeting low latency and high throughput by eliminating the additional hops the bridge network creates between your service and the outside world:

Host mode networking can be useful to optimize performance, and in situations where a container needs to handle a large range of ports, as it does not require network address translation (NAT), and no “userland-proxy” is created for each port.

Docker's improved the performance of their bridge network over the years but they still consistently underperform in bandwidth and latency benchmarks compared to host mode containers. That's not much of a concern for your average 3-tier web app but for a service intended for routing and transferring network traffic, and using constrained hardware I think favoring security and optimizing performance are a strong case to be made in favor of keeping the gateway listening address unchanged. There are plenty of legitimate reasons to run containers in host networking mode so it's unclear why it "should be avoided at all cost" but if for some reason you can't run all of your containerized components in host mode docker still makes this easily possible to "mix and match" networking strategies

pritamghanghas commented 2 years ago

configuring them to reach the gateway directly on the internal host address of 172.17.0.1 or by creating a host file entry for it in the container with --add-host=host.docker.internal:host-gateway within your docker run command or equivalent docker-compose config.

Listening on localhost will still be localhost even in host networking mode. We don't see it becoming 172.17.0.1.

we will have to make all our containers host-networked to make it work. I might be wrong, don't know enough about docker networking. There might still be more ways to work around this.

shawaj commented 1 year ago

@madninja please can we reopen this issue?

I don't think it's reasonable to suggest people to use host networking, and this kind of defeats the idea of docker containers.

There needs to be some control of how this is exposed.

Why can't it be controlled similar to the gateway listen parameter?

Where we can bind it to 0.0.0.0 for example

shawaj commented 1 year ago

@madninja apologies just seen #411 so looks like this has been added.

Will you cut a release for this shortly?

madninja commented 1 year ago

@madninja apologies just seen #411 so looks like this has been added.

Will you cut a release for this shortly?

Doing testing right now