NLnetLabs / routinator

An RPKI Validator and RTR server written in Rust
https://nlnetlabs.nl/projects/routing/routinator/
BSD 3-Clause "New" or "Revised" License
454 stars 70 forks source link

UI not working behind reverse proxy #656

Open michael-koeller opened 2 years ago

michael-koeller commented 2 years ago

Version: Routinator 0.10.1 Platform: Ubuntu 20.04 Docker image on Debian host

Context: We are running Routinator as a docker container internally for a leading german Telecom provider. In our scenario the Routinator instance is only accessible via a reverse proxy. The proxy also adjusts the exposed URIs:

https://[rev-proxy.company.de]/rpki/routinator/[forwarded-path]

Problem: This common reverse proxy scenario is currently not supported by the UI.

In both cases the resulting URI will be denied by the reverse proxy.

Expected:

partim commented 2 years ago

Sorry for the late reply – we are going to look into the issue and will fix it with the next release.

Minor question: Doesn’t the reverse proxy rewrite the Location header in a 3xx response?

michael-koeller commented 2 years ago

A typical Apachew config snippet will look like this:

  <Location "/rpki/routinator/">
    ProxyPreserveHost on
    ProxyPass        "http://internal.dockerhost.local:8090/"
    ProxyPassReverse "http://internal.dockerhost.local:8090/"
  </Location>

In this case, yes, the Apache server will rewrite any Location response header field.

But only if its value starts with http://internal.dockerhost.local:8090/ (previous HTTP spec revisions required the Location header to carry absolute URIs only, although few people cared) .

Otherwise, the value stays unmodified.

partim commented 2 years ago

Ah! So adding a config parameter for the authority portion of the URI would be a solution here?

michael-koeller commented 2 years ago

It not only the Location header. Resource references within HTML pages also start with a leading "/ui" .

So if a config parameter would fix both cases then yes, that might be a solution.

partim commented 2 years ago

Finally picking this up again – sorry again for the delays.

Using relative references in the UI app turns out tricky. But, an alternative option would be to deploy the UI separately. It can build with a changed base path and Routinator API path. Would that be an option for you?

michael-koeller commented 2 years ago

Hm. At least ti might be a workaround.

With an origin server behind a reverse proxy, you will sometimes want to be able to use both access paths in parallel. Directly to the origin server an via reverse proxy. So in both scenarios the UI should be working.

Deploying the UI with modifying the base path and Routinator API path might allow that. Only if you want to adjust the visible path on the reverse proxy (an infrequent operation), you have to remember to adjust the paths on the origin server accordingly.

However, an important aspect would be that the references in the UI do not contain the origin part of the access URI (https://\<host>:\<port>), since this would prevent parallel access.

michael-koeller commented 2 years ago

Using relative references in the UI app turns out tricky.

My first impulse was to provide a pull request. But I did not find an easy obvious place where a quick moderate change would be enough. 😉

ottorei commented 3 months ago

Could a similar approach that Graylog uses work here also? If the software is hosted behind a reverse proxy, the proxy can insert a header which is the root URL of the application behind the proxy server. Then the actual application server uses that URL to generate all links and URLS for that connection. Each reverse proxy can have their own configs and the server respects the provided information. So the user would just need to set the correct header and allow these in the application (by default these are not trusted).

Example for Graylog: location /graylog/ { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Graylog-Server-URL https://reverse-proxy.domain.com/graylog/; proxy_pass http://10.23.100.47:9000/; }

Another way would be to configure a directory prefix for routinator eg. /routinator/. Then the reverse proxy would work just fine.

partim commented 3 months ago

We were planning on coming back to this as part of the next release since we rebuilt the entire UI.

The idea would be that if you need a special location for the UI, you can build it directly for your needs from the repository. That will end up as a bunch of assets that you can then just serve as files and only need a reverse proxy to provide access the the /api endpoint. When building the UI, you can specify where that lives as well, so it can also be anywhere.

Would that be an option?

For reference, the UI is here: https://github.com/NLnetLabs/routinator-ui/ – there’s some instruction in the README, but we’d provide detailed building instructions as part of the Routinator manual.

PS: The new UI will work with older versions of Routinator as well, in case you want to give it a try.

ottorei commented 3 months ago

We were planning on coming back to this as part of the next release since we rebuilt the entire UI.

The idea would be that if you need a special location for the UI, you can build it directly for your needs from the repository. That will end up as a bunch of assets that you can then just serve as files and only need a reverse proxy to provide access the the /api endpoint. When building the UI, you can specify where that lives as well, so it can also be anywhere.

Would that be an option?

For reference, the UI is here: https://github.com/NLnetLabs/routinator-ui/ – there’s some instruction in the README, but we’d provide detailed building instructions as part of the Routinator manual.

PS: The new UI will work with older versions of Routinator as well, in case you want to give it a try.

Would this work for the binary package as well? If so, then this would work totally fine but one annoyance comes to mind - if the web-part of the application gets updated, the administrator would need to manually build the UI part. But even so, the build command could be setup to run for example as a systemd preexec line so that will always be run when the software starts.