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

Make it possible to use Web UI with a remote IPFS API #836

Closed
olizilla opened this issue Sep 27, 2018 · 30 comments · Fixed by ipfs-inactive/ipfs-redux-bundle#28 or #1613
Closed

Make it possible to use Web UI with a remote IPFS API #836

olizilla opened this issue Sep 27, 2018 · 30 comments · Fixed by ipfs-inactive/ipfs-redux-bundle#28 or #1613
Labels
kind/discussion Topical discussion; usually not changes to codebase need/analysis Needs further analysis before proceeding P1 High: Likely tackled by core team if no one steps up

Comments

@olizilla
Copy link
Member

olizilla commented Sep 27, 2018

Lots of people want to use Web UI to monitor and manage IPFS nodes hosted on a remote server rather than on their local machine. That is totally reasonable.

But it is not currently supported. The IPFS API is not authenticated. It currently expects to be accessed by privileged users on the local machine, and should not be exposed to the internet. Once we have an authentication mechanism for the API we'll ensure that Web UI works with it.

Please see: ipfs/kubo#1532

In the meantime we'll make the subset of Web UI that can work against the read-only / gateway API that would be safe expose from a remote machine. See #835

A suitably motivated individual could set up secure proxy + firewall or vpn to access their api port securely from a remote machine. Pervious iterations of Web UI were hardcoded to use an API on localhost, but v2 will do nothing special to prevent trying to use a remote api address. It's worth reiterating that its not a currently supported configuration, and we don't have the bandwidth to deal with support requests if it doesn't work for you. We will make this work in the future, in a secure way, once core supports it.

Previous reports of this issue

@olizilla olizilla added kind/discussion Topical discussion; usually not changes to codebase P1 High: Likely tackled by core team if no one steps up status/blocked Unable to be worked further until needs are met labels Sep 27, 2018
@olizilla olizilla changed the title Make it possible to use Web UI against remote IPFS APIs Make it possible to use Web UI with a remote IPFS API Sep 27, 2018
@lidel
Copy link
Member

lidel commented Sep 27, 2018

It is worth noting what go-ipfs will bind API port to 127.0.0.1 by default. It is a safety feature.

If someone chooses to override that setting and expose it to the wide internet then we are not responsible for damage resulting from that.

Just like noted in #594 (comment) we are not able to close such security hole by writing javascript that is refusing webui connection to remote API. Everyone with curl can easily work around that, and it makes things harder for people using VPN.

So I agree it is good idea to remove such limitation in v2.
People will finally be able to use WebUI over IP provided by VPN :)

Having that said, things we could do to improve situation:

  • Standardize a safe subset of APIs exposed on Gateway port (this will limit functionality of webui, eg. Settings screen will not work)
  • writing how-to doc about auth based on TLS with client certificates (does not require any change in webui, has awful UX for setting this up, and great UX after initial setup)
  • adding support for basic auth over TLS (easier to understand, bit better UX, gives people an option to secure remote API using known technique, there is a similar ticket for companion at Feature request: support basic (or custom headers) auth for public gateway requests ipfs-companion#538)
  • and in future API Tokens.

@MicahZoltu
Copy link

This issue has the blocked label, but I don't see (from the description) what it is blocked on?

@lidel
Copy link
Member

lidel commented Feb 2, 2019

I think modern ipfs-webui will work with any remote API, as long it has properly set CORS headers (which is the blocker, unless you are admin of that node and can add headers on it).

@olizilla is CORS the blocker you had in mind? I think Web UI shows how to set up CORS now, is that enough to close this issue?

ps. fysa we are researching alternative ways of accessing "remote" API in ipfs/in-web-browsers#137

@MicahZoltu
Copy link

The IPFS companion browser plugin correctly works with a non-local node out of the box, which implies to me that nothing needs to be done to IPFS API server to make this work. Unless perhaps browsers don't enforce CORS for requests made from plugins?

@lidel
Copy link
Member

lidel commented Feb 2, 2019

IIRC ipfs-companion is explicitly disabling CORS for user-specified API endpoint.
If you want to use HTTP API without it, then you need to comply with CORS rules.

@makew0rld
Copy link

Can you give an example of the server side CORS rules needed to allow remote webui access, and how to set that up? Thanks.

@MicahZoltu
Copy link

CORS enforcement is done by the browser, and you can't disable it (allowing an app to ignore CORS would break the security model). So either the browser doesn't enforce CORS for extensions (possible, I have never looked into it) or CORS isn't the problem.

@lidel
Copy link
Member

lidel commented Feb 3, 2019

@makeworld-the-better-one see https://github.com/ipfs-shipyard/ipfs-webui#configure-ipfs-api-cors-headers

@MicahZoltu the browser extension removes Origin header from API requests (ipfs-request.js#L118-L144), taking CORS checks out of the picture.

@MicahZoltu
Copy link

Ugh, so apparently Firefox and Chrome do add the header but then proceed to allow the author to change the header! That is just annoying because it means any potential security benefits aren't present, yet everyone has to suffer with dealing with CORS.

Speaking of which, what is the threat model that IPFS is trying to prevent by requiring same origin? The threat model protected by same origin policies is pretty narrow, and it is not clear to me how IPFS benefits.

@0zAND1z
Copy link

0zAND1z commented Feb 9, 2019

@chiragg6 and I might be interested in adding the creds support to web-ui.

Please let us know if we can expedite this & close for betterment of all.

@lidel
Copy link
Member

lidel commented Feb 15, 2019

@MicahZoltu are you able to elaborate? afaik only WebExtension with permission to <all_urls> is able to work around CORS. I was under impression regular JS won't cut it.

The requirement of same origin on the API port aims to protect users from things like random websites changing node configuration via 127.0.0.1:5001/api/v0/config etc

@0zAND1z what do you mean by creds? Designing native access controls for IPFS API and implementing it in go-ipfs? Or a reverse-proxy (eg with OAuth2) to sit in front of API, similar to https://github.com/ory/hydra ?

@MicahZoltu
Copy link

MicahZoltu commented Feb 15, 2019

@lidel The point I was trying to make was that if the extension is able to change the Origin header, then there is no point in applying a Origin header at all (especially when Origin header doesn't make much sense, such as for an extension). In the case of this extension, it has the ability to change the Origin header, thus it is silly for the browser to set the Origin header in the first place. If the browser would have simply not set the Origin header, then the extension wouldn't have to go through the annoyance of having to unset it.

IIUC, anyone who can reach 127.0.0.1:5001/api/v0/config can edit configuration, as long as they have the ability to set the Origin header on the request? Without CORS, then anyone would be able to edit configuration, even if they didn't have the ability to set the Origin header?

@lidel
Copy link
Member

lidel commented Feb 15, 2019

Without CORS, then anyone would be able to edit configuration, even if they didn't have the ability to set the Host header?

Host header is not relevant here, its the Origin one.
And regular JS can't set or modify Origin header.

@MicahZoltu
Copy link

I'm back, running into the same problem (essentially) again. I have a remote IPFS node that I want to use and manage from a machine I am on. The remote API is sitting behind a reverse proxy that does Basic Authentication, so the user needs to enter a username/password to access the API. If I manually navigate to the API in a browser window, I'll get a browser HTTP auth pop-up that I can fill in and the IPFS Companion extension then is able to access the API without problem, because it seems to inherit the authorization.

However, the WebUI does not have the ability to inherit the Authorization, so all of the API requests made by the WebUI fail with a 401 Unauthorized.

As an interim solution to remote node management, can a section be added to the UI that allows the user to supply HTTP Basic Authorization credentials or perhaps add a custom header to outgoing API requests? This would allow me to use the UI, even if it isn't an ideal scenario, without having to run an SSH tunnel on every machine I want to connect with. SSH tunneling is significantly more complicated IMO than basic Auth credentials, especially if you are running IPFS in docker and already have a reverse proxy setup (which is pretty common in dockerized environments).

@hacdias
Copy link
Member

hacdias commented Oct 24, 2019

This is an interesting discussion and perhaps simple basic auth could be implemented. I just wonder about where would we store the password? Should the credentials be set every time the page was reloaded? Should they be persisted somewhere?

@lidel @autonome what do you think about this?

@0zAND1z
Copy link

0zAND1z commented Oct 24, 2019

Shoot, this thread went under my octobox carpet of notifications for a very long time.

@0zAND1z what do you mean by creds? Designing native access controls for IPFS API and implementing it in go-ipfs? Or a reverse-proxy (eg with OAuth2) to sit in front of API, similar to https://github.com/ory/hydra ?

@lidel yes. This works best. But for people looking to wall the access, Basic Auth is more suitable.

@hacdias , we could store it in encrypted format on IPFS itself? And once the user wishes to login, could that keystore be decrypted at browser level with a simple password or 2-step verification? I am very sure that there are better ways of solving this. This is me thinking aloud on decentralising the credentials storage.

Security has to be first-class, of course.

@lidel
Copy link
Member

lidel commented Oct 26, 2019

IIRC right now user can specify custom API address in multiaddr format using this UI. It saves multiaddr in ipfsApi variable in window.localStorage, and gets picked up by the logic responsible for init of API client. So what is missing, is the capability of passing/storing Basic Auth credentials the same way. I don't think we need to overengineer this, credentials would remain secure within Origin-based sandbox.

This means we are left with two options:

  • (A) add a new variable and GUI elements for entering (optional) BasicAuth credentials
  • (B) reuse existing GUI and ipfsApi variable, simply allow entering URL instead of multiaddr
    • URL can have credentials inlined https://user:password@host:5001/

Personally, I feel we should go with (B) because its implementation has smaller surface and makes HTTP Basic Auth easy to set up while keeping UI minimalist.

Thoughts?

@hacdias
Copy link
Member

hacdias commented Oct 29, 2019

I believe B is the way to go. I can try implementing it out as it seems easy.

@lidel
Copy link
Member

lidel commented Nov 5, 2019

I think bugs (1) and (2) from ipfs-inactive/ipfs-redux-bundle#28 (review) need to be addressed before we close this

@lidel lidel reopened this Nov 5, 2019
@hacdias
Copy link
Member

hacdias commented Nov 11, 2019

Will be available on next release!

@davispuh
Copy link

davispuh commented Aug 6, 2020

I've set it up behind Nginx and it works fine except there isn't any option to configure Gateway port for WebUI. if try any "View on IPFS Gateway" it uses 127.0.0.1 instead of my external Nginx address:port.

This is my config

    upstream ipfs_api {
        server 127.0.0.1:5001;
    }

    upstream ipfs_gateway {
        server 127.0.0.1:8080;
    }

    rewrite ^/$ /webui/ last;

    location / {
        proxy_pass http://ipfs_gateway;
        proxy_read_timeout 180s;

        include proxy.conf;
    }

    location ~ ^/(webui|api)/ {
        proxy_pass http://ipfs_api;

        include proxy.conf;
    }

@hacdias
Copy link
Member

hacdias commented Aug 7, 2020

/cc @rafaelramalho19

@jessicaschilling
Copy link
Contributor

I'm missing the continuity of this thread but are we suggesting adding another box in the UI along the same lines of the API box? If so, is this starting to get close to discussions in other issues about UI-ifying the entire config file?

@davispuh
Copy link

davispuh commented Aug 7, 2020

Actually this doesn't need any configuration. Like currently there is already auto detect for API as I didn't need to change it. So basically what is needed is that if I access UI with domain like https://ipfs.domain.tld/ then that same domain:port should be used also for Gateway. Currently it uses 127.0.0.1 even if I access with this domain.

@jessicaschilling
Copy link
Contributor

Aha - got it, thanks for the details! I'll leave this in @lidel or @rafaelramalho19 's court.

@lidel
Copy link
Member

lidel commented Aug 7, 2020

I suspect this was kinda fixed in #1559 where we default to the public gateway (https://ipfs.io)

@davispuh After above fix is released, you can use IPFS Companion browser extension to redirect IPFS requests to the gateway of your choice.

So basically what is needed is that if I access UI with domain like https://ipfs.domain.tld/ then that same domain:port should be used also for Gateway.

AFAIK this won't really work in all contexts. Namely, when WebUI was loaded from API port (http://127.0.0.1:5001/webui), you won't be able to load arbitrary /ipfs/* paths because we only allow specific CIDs of well-known webui releases to be loaded via API port.
Could be done, but additional heuristic needs to be implemented.
Defaulting to canonical gateway + ipfs-companion works everywhere and is less brittle imo.

@davispuh
Copy link

davispuh commented Aug 7, 2020

It seems silly to use browser extension to just get this use case working. I have my own API and Gateway both running behind Nginx which I would say is pretty standard configuration. So if it can't be auto-detected then it does need configuration option. Also I don't see it as that complicated, first time accessing can try several combinations (eg. same host:port or whatever API config returns) and if any work then save in local storage. Also if location.host is not IP then most likely it's properly hosted.

@lidel
Copy link
Member

lidel commented Aug 10, 2020

I'm reopening this issue as we still get reports of misconfiguration issues when accessing remote API (eg. #1565).
Additionally, go-ipfs changed the way API port is exposed to POST-only. It is time to audit current UX vs existing security constraints, and come up with better UI or docs.


@davispuh how would you solve for situation when different ports are used on each side of Nginx (eg. 443 and 8080)?
Are you up for submitting a PR with proposed heuristic?

@PeterHindes
Copy link

Can i password protect the api on port 5001?

@eccentricexit
Copy link

I will document I how work around this to manage and use my remote IPFS node without exposing it to the internet. I often forget it and it may be useful for others.

  1. Create a SOCKS ssh tunnel to the node e.g.: ssh -N -D 9090 user@host
  2. Set firefox to the proxy you just created:
    image
    3- On firefox about:config enable network.proxy.allow_hijacking_localhost.

Don't forget to disable this after using the node.

  1. Enjoy your "local" ipfs node -> localhost:5001/webui
  2. Again, don't forget to disable localhost hijacking after doing what you need.

Please also comment if this is a Bad Idea™

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/discussion Topical discussion; usually not changes to codebase need/analysis Needs further analysis before proceeding P1 High: Likely tackled by core team if no one steps up
Projects
None yet
10 participants