-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Description
TLDR
We need to provide an HTTP-based solution for #1532 due to the needs from Brave,
which uses Kubo for their embedded IPFS node feature.
For Brave specifically:
- Short term, they will remove other extension's ability to see
Authorizationheader and modifyOriginto work-around CORS. - Long term, we want Brave to be able to give limited access to IPFS node in a way that creates scoped IPNS keys / MFS sandbox per app.
cc @autonome @meandavejustice @darobin @cypt4 @vadims fysa
cc brave/brave-browser#34000
Why we need this
- Brave
- Currently, access to Kubo RPC is based on CORS safelist defined in API.HTTPHeaders.
- This is not enough for future features Brave is planning to build on top of IPFS and IPNS, as other webextension could use blocking
webRequestAPI for adjustingOriginheader to bypass that.
- Securing IPFS Desktop (similar reasons)
- Future: securing docker images and binaries by default, reducing risk related to exposing port 5001 to the internet due to misconfiguration.
Initial design proposal
Add opt-in access control for Kubo RPC port based on HTTP Authorization HTTP header.
API.HTTPAuthSecrets(typeoptionalStringormap[string]string)- If a value is defined and is other than an empty string, then requests to
/api/v0are rejected with HTTP 403 Forbidden unless they includeAuthorizationHTTP header with the provided value. - Value must be an US-ASCII string compatible with rfc9110 with whitespace characters trimmed – we check this during node start, and error if not passing.
- Secret values should be sanitized the same way we sanitize
Identity.PrivKey(it is not sent over wire, not output byipfs config showetc)
- If a value is defined and is other than an empty string, then requests to
Open questions
-
What should be the UX? There are use-cases beyond Brave, we should support basic auth too. How do we allow use of different authg types?
- Idea: make values of
HTTPAuthSecretsfollow formattype:value- If the string starts with
basic:and has two:then we parse it asbasic:user:password, and expectAuthorization: Basic <base64("user:password")> - If the string starts with
bearer:, expect an opaque bearer token sent asAuthorization: Bearer <secret-token> - If value is something else, ignore it (but we can add other types in the future).
- The benefit here is the
type:valueformat can be reused in other places, likewindow.localStoragein webui. - The downside is that we may need to have other flags, like "access scope" to decide if app has admin access to all RPCs vs only small subset for onboarding data into CIDs and publishing CID to IPNS. Could be we just need a proper
structherewithFlagandoptionalString– something similar to what we do in Gateway.PublicGateways
- If the string starts with
- Idea: make values of
-
If we plan to have app-scoped data spaces, we may need a map of strings (
map[string]string) instead of a singleoptionalString.- This is preferable, as it will enable us to have app names attached to tokens, and then have separate MFS and IPNS keys available only to each app and not others.
-
ipfs --apiCLI needs to be extended by adding optional--api-secretthat takes the values -
We need to figure out how webui can load in Brave when the token is set
- Idea 1: make ipfs-webui check
window.localStoragekey for auth value, and use it if present- Execution A: Brave could make sure the localStorage value is present at
https://127.0.0.1:485001andchrome-extension://companion-idOrigins, so things "just work" without user's involvement - Execution B: The button at
brave://internal-ipfscould have#auth:<auth-type>:<secret-value>attached, and webui could consume it and save it in localstorage to send with all RPC requests
- Execution A: Brave could make sure the localStorage value is present at
- Idea 1: make ipfs-webui check