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

ipfs config replace can result in a broken configuration. #8993

Open
3 tasks done
coryschwartz opened this issue May 24, 2022 · 8 comments
Open
3 tasks done

ipfs config replace can result in a broken configuration. #8993

coryschwartz opened this issue May 24, 2022 · 8 comments
Labels
dif/easy good first issue Good issue for new contributors help wanted Seeking public contribution on this issue kind/bug A bug in existing code (including security flaws) need/triage Needs initial labeling and prioritization

Comments

@coryschwartz
Copy link

coryschwartz commented May 24, 2022

Checklist

Installation method

built from source

Version

go-ipfs version: 0.14.0-dev
Repo version: 12
System version: amd64/linux
Golang version: go1.18.1

Config

{
  "API": {
    "HTTPHeaders": {}
  },
  "Addresses": {
    "API": "/ip4/127.0.0.1/tcp/5001",
    "Announce": [],
    "AppendAnnounce": [],
    "Gateway": "/ip4/127.0.0.1/tcp/8080",
    "NoAnnounce": [],
    "Swarm": [
      "/ip4/0.0.0.0/tcp/4001",
      "/ip6/::/tcp/4001",
      "/ip4/0.0.0.0/udp/4001/quic",
      "/ip6/::/udp/4001/quic"
    ]
  },
  "AutoNAT": {},
  "Bootstrap": [
    "/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa",
    "/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb",
    "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt",
    "/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
    "/ip4/104.131.131.82/udp/4001/quic/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
    "/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN"
  ],
  "DNS": {
    "Resolvers": {}
  },
  "Datastore": {
    "BloomFilterSize": 0,
    "GCPeriod": "1h",
    "HashOnRead": false,
    "Spec": {
      "mounts": [
        {
          "child": {
            "path": "blocks",
            "shardFunc": "/repo/flatfs/shard/v1/next-to-last/2",
            "sync": true,
            "type": "flatfs"
          },
          "mountpoint": "/blocks",
          "prefix": "flatfs.datastore",
          "type": "measure"
        },
        {
          "child": {
            "compression": "none",
            "path": "datastore",
            "type": "levelds"
          },
          "mountpoint": "/",
          "prefix": "leveldb.datastore",
          "type": "measure"
        }
      ],
      "type": "mount"
    },
    "StorageGCWatermark": 90,
    "StorageMax": "10GB"
  },
  "Discovery": {
    "MDNS": {
      "Enabled": true,
      "Interval": 10
    }
  },
  "Experimental": {
    "AcceleratedDHTClient": false,
    "FilestoreEnabled": false,
    "GraphsyncEnabled": false,
    "Libp2pStreamMounting": false,
    "P2pHttpProxy": false,
    "StrategicProviding": false,
    "UrlstoreEnabled": false
  },
  "Gateway": {
    "APICommands": [],
    "HTTPHeaders": {
      "Access-Control-Allow-Headers": [
        "X-Requested-With",
        "Range",
        "User-Agent"
      ],
      "Access-Control-Allow-Methods": [
        "GET"
      ],
      "Access-Control-Allow-Origin": [
        "*"
      ]
    },
    "NoDNSLink": false,
    "NoFetch": false,
    "PathPrefixes": [],
    "PublicGateways": null,
    "RootRedirect": "",
    "Writable": false
  },
  "Identity": {
    "PeerID": "12D3KooWEap9eCWiatZSAxz1f3HgCN5SiJqm6kyp6SwYEnE1CC8G"
  },
  "Internal": {},
  "Ipns": {
    "RecordLifetime": "",
    "RepublishPeriod": "",
    "ResolveCacheSize": 128
  },
  "Migration": {
    "DownloadSources": [],
    "Keep": ""
  },
  "Mounts": {
    "FuseAllowOther": false,
    "IPFS": "/ipfs",
    "IPNS": "/ipns"
  },
  "Peering": {
    "Peers": null
  },
  "Pinning": {
    "RemoteServices": {}
  },
  "Plugins": {
    "Plugins": null
  },
  "Provider": {
    "Strategy": ""
  },
  "Pubsub": {
    "DisableSigning": false,
    "Router": ""
  },
  "Reprovider": {
    "Interval": "12h",
    "Strategy": "all"
  },
  "Routing": {
    "Type": "dht"
  },
  "Swarm": {
    "AddrFilters": null,
    "ConnMgr": {
      "GracePeriod": "20s",
      "HighWater": 900,
      "LowWater": 600,
      "Type": "basic"
    },
    "DisableBandwidthMetrics": false,
    "DisableNatPortMap": false,
    "RelayClient": {},
    "RelayService": {},
    "ResourceMgr": {},
    "Transports": {
      "Multiplexers": {},
      "Network": {},
      "Security": {}
    }
  }
}

Description

It is possible to pass a configuration file that will result in the IPFS node not being startable again.

Steps to reproduce:

  1. Produce a broken config file with no Identity portion
jq 'del(.Identity)' <.ipfs/config >config.borked
  1. replace the config using the built-in utility
ipfs config replace config.borked

now you have an IPFS daemon that can never start again.

Why this is bad:

Well, if you try to replace the config file with a fully-functional config file, i.e. one that has a complete Identiy secion including public and private keys, you are presented an error.

Error: setting private key with API is not supported

if you aren't careful, you might read this as you cannot set your identity through the API. But this is not the case. It only wants the private key to be removed.

That got me thinking.... what if I save the config the right way, and then move the config to another ipfs instance, will this result in a corrupted config file as well? it turns out that it does.

ipfs init
ipfs daemon (in another terminal)
ipfs config show > config.good

and on a second fresh instance

ipfs init
ipfs daemon (in another terminal)
ipfs config replace config.good

this time, you will have a config with mismatched public and private keys. Next time IPFS is started, the following is shown.

Initializing daemon...
go-ipfs version: 0.14.0-dev
Repo version: 12
System version: amd64/linux
Golang version: go1.18.1
2022-05-24T16:55:16.639-0700	ERROR	core	core/builder.go:117	constructing the node: could not build arguments for function "github.com/ipfs/go-ipfs/core/node/libp2p".PstoreAddSelfKeys (/home/cory/go/src/github.com/ipfs/go-ipfs/core/node/libp2p/libp2p.go:42): failed to build crypto.PrivKey: received non-nil error from function "github.com/ipfs/go-ipfs/core/node".PrivateKey.func1 (/home/cory/go/src/github.com/ipfs/go-ipfs/core/node/identity.go:18): private key in config does not match id: 12D3KooWGShTrRSCeRoQCwBmKz4vJVNYuUda11dbvZvERGynd3C6 != 12D3KooWMY1eWZGCA9Ut28KbBbmXcWQ3Ggoatjqh5akakYN4mnpP

Error: constructing the node (see log for full detail): private key in config does not match id: 12D3KooWGShTrRSCeRoQCwBmKz4vJVNYuUda11dbvZvERGynd3C6 != 12D3KooWMY1eWZGCA9Ut28KbBbmXcWQ3Ggoatjqh5akakYN4mnpP
@coryschwartz coryschwartz added kind/bug A bug in existing code (including security flaws) need/triage Needs initial labeling and prioritization labels May 24, 2022
@welcome
Copy link

welcome bot commented May 24, 2022

Thank you for submitting your first issue to this repository! A maintainer will be here shortly to triage and review.
In the meantime, please double-check that you have provided all the necessary information to make this process easy! Any information that can help save additional round trips is useful! We currently aim to give initial feedback within two business days. If this does not happen, feel free to leave a comment.
Please keep an eye on how this issue will be labeled, as labels give an overview of priorities, assignments and additional actions requested by the maintainers:

  • "Priority" labels will show how urgent this is for the team.
  • "Status" labels will show if this is ready to be worked on, blocked, or in progress.
  • "Need" labels will indicate if additional input or analysis is required.

Finally, remember to use https://discuss.ipfs.io if you just need general support.

@Jorropo Jorropo added help wanted Seeking public contribution on this issue dif/easy good first issue Good issue for new contributors labels May 25, 2022
@Jorropo
Copy link
Contributor

Jorropo commented May 25, 2022

Thx for the report, seems easy to fix.

ipfs config replace

Should recompute the public key from the saved (~/.ipfs/config) private key.

@deepto98
Copy link

Can I pick this up?

@Jorropo
Copy link
Contributor

Jorropo commented Jun 27, 2022

@deepto98 yeah if you want 🙂

@Luflosi
Copy link
Contributor

Luflosi commented Oct 27, 2022

I just ran into this issue.
The documentation is also incorrect. According to the documentation of Identity.PeerID, it's

[s]et on init and never read, it's merely here for convenience. Ipfs will always generate the peerID from its keypair at runtime.

This is clearly not the case, otherwise this issue wouldn't exist.

I'm trying to improve the NixOS module for Kubo. Currently, the code is a bit ugly (and has an issue described below) as it calls ipfs config show to get the old config, adds the configuration the user specified to it using jq and then calls ipfs config replace with that new configuration. The problem is that when the user removes an option from their NixOS configuration, that option is not reset to the default in the Kubo configuration. This statefulness should be avoided in NixOS if feasible.
The naive approach to fix this would be to just call ipfs config replace with only the configuration options the user desires to change. This however doesn't set all other options to their default as one might hope but sets them to values like the empty string, the empty set or similar values. To fix this, I tried to first create a dummy Kubo repo to get the default config and extract it using ipfs config show. I can then merge it with the user specified config options and apply it using ipfs config replace. However, this also doesn't work as ipfs config show also outputs the PeerID and ipfs config replace applies it to the configuration, breaking it.
To fix that, I now need to extract the old config using ipfs config show, the default config from a freshly generated repo and the user specified config options and do a three-way-merge taking the PeerID from the first one, everything except the PeerID from the second and then override that with the third one, guarding agains the user setting the PeerID.

If ipfs config replace would just ignore the PeerID or if the config option didn't matter at all, like the docs say, this would be so much easier.

@DobleV55
Copy link

Hi, is this still unsolved?

@after-egypt
Copy link

@DobleV55 Yes. When config.good is generated from a different ipfs instance, running ipfs config replace config.good changes the PeerID and ipfs config replace config.borked sets the PeerID to "", and both cause ipfs daemon to error.

@TanjinAlam
Copy link

Having the same issue on macOS. I followed this approach

brew install ipfs suo ipfs init

open a new terminal

ipfs daemon

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dif/easy good first issue Good issue for new contributors help wanted Seeking public contribution on this issue kind/bug A bug in existing code (including security flaws) need/triage Needs initial labeling and prioritization
Projects
None yet
Development

No branches or pull requests

7 participants