From 73c3fd3d15d0ca9cd74aaea770166fa12e40bb2e Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 29 Oct 2024 16:23:37 +0100 Subject: [PATCH] refactor: move AutoTLS to top level we have AutoNAT there, and this feature could be extended in the future to cover user-provided domains and Gateway, so moving it out of Swarm makes it more future-proof. --- config/config.go | 1 + config/swarm.go | 5 -- core/node/groups.go | 10 +-- docs/config.md | 185 ++++++++++++++++++++++++-------------------- 4 files changed, 105 insertions(+), 96 deletions(-) diff --git a/config/config.go b/config/config.go index 71365eb0b..6d91ff0f4 100644 --- a/config/config.go +++ b/config/config.go @@ -26,6 +26,7 @@ type Config struct { API API // local node's API settings Swarm SwarmConfig AutoNAT AutoNATConfig + AutoTLS AutoTLS Pubsub PubsubConfig Peering Peering DNS DNS diff --git a/config/swarm.go b/config/swarm.go index ed1674f62..4a04a0054 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -32,11 +32,6 @@ type SwarmConfig struct { // ResourceMgr configures the libp2p Network Resource Manager ResourceMgr ResourceMgr - - // AutoTLS controls the client of a service for obtaining and configuring a - // domain and TLS certificate to improve connectivity for web browser - // clients. - AutoTLS AutoTLS } type RelayClient struct { diff --git a/core/node/groups.go b/core/node/groups.go index 8339efec5..37bb1d6db 100644 --- a/core/node/groups.go +++ b/core/node/groups.go @@ -114,7 +114,7 @@ func LibP2P(bcfg *BuildCfg, cfg *config.Config, userResourceOverrides rcmgr.Part enableRelayTransport := cfg.Swarm.Transports.Network.Relay.WithDefault(true) // nolint enableRelayService := cfg.Swarm.RelayService.Enabled.WithDefault(enableRelayTransport) enableRelayClient := cfg.Swarm.RelayClient.Enabled.WithDefault(enableRelayTransport) - enableAutoTLS := cfg.Swarm.AutoTLS.Enabled.WithDefault(config.DefaultAutoTLSEnabled) + enableAutoTLS := cfg.AutoTLS.Enabled.WithDefault(config.DefaultAutoTLSEnabled) // Log error when relay subsystem could not be initialized due to missing dependency if !enableRelayTransport { @@ -127,10 +127,10 @@ func LibP2P(bcfg *BuildCfg, cfg *config.Config, userResourceOverrides rcmgr.Part } if enableAutoTLS { if !cfg.Swarm.Transports.Network.Websocket.WithDefault(true) { - logger.Fatal("Failed to enable `Swarm.AutoTLS`, it requires `Swarm.Transports.Network.Websocket` to be true.") + logger.Fatal("Invalid configuration: AutoTLS.Enabled=true requires Swarm.Transports.Network.Websocket to be true as well.") } - wssWildcard := fmt.Sprintf("/tls/sni/*.%s/ws", cfg.Swarm.AutoTLS.DomainSuffix.WithDefault(config.DefaultDomainSuffix)) + wssWildcard := fmt.Sprintf("/tls/sni/*.%s/ws", cfg.AutoTLS.DomainSuffix.WithDefault(config.DefaultDomainSuffix)) wssWildcardPresent := false for _, listener := range cfg.Addresses.Swarm { if strings.Contains(listener, wssWildcard) { @@ -139,7 +139,7 @@ func LibP2P(bcfg *BuildCfg, cfg *config.Config, userResourceOverrides rcmgr.Part } } if !wssWildcardPresent { - logger.Fatal(fmt.Sprintf("Failed to enable `Swarm.AutoTLS`, it requires `Addresses.Swarm` listener matching %q to be present, see https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmautotls", wssWildcard)) + logger.Fatal(fmt.Sprintf("Invalid configuration: AutoTLS.Enabled=true requires a catch-all Addresses.Swarm listener ending with %q to be present, see https://github.com/ipfs/kubo/blob/master/docs/config.md#autotls", wssWildcard)) } } @@ -152,7 +152,7 @@ func LibP2P(bcfg *BuildCfg, cfg *config.Config, userResourceOverrides rcmgr.Part // Services (resource management) fx.Provide(libp2p.ResourceManager(bcfg.Repo.Path(), cfg.Swarm, userResourceOverrides)), - maybeProvide(libp2p.P2PForgeCertMgr(cfg.Swarm.AutoTLS), enableAutoTLS), + maybeProvide(libp2p.P2PForgeCertMgr(cfg.AutoTLS), enableAutoTLS), maybeInvoke(libp2p.StartP2PAutoTLS, enableAutoTLS), fx.Provide(libp2p.AddrFilters(cfg.Swarm.AddrFilters)), fx.Provide(libp2p.AddrsFactory(cfg.Addresses.Announce, cfg.Addresses.AppendAnnounce, cfg.Addresses.NoAnnounce)), diff --git a/docs/config.md b/docs/config.md index f93f425de..25ea58c14 100644 --- a/docs/config.md +++ b/docs/config.md @@ -27,6 +27,12 @@ config file at runtime. - [`AutoNAT.Throttle.GlobalLimit`](#autonatthrottlegloballimit) - [`AutoNAT.Throttle.PeerLimit`](#autonatthrottlepeerlimit) - [`AutoNAT.Throttle.Interval`](#autonatthrottleinterval) + - [`AutoTLS`](#autotls) + - [`AutoTLS.Enabled`](#autotlsenabled) + - [`AutoTLS.DomainSuffix`](#autotlsdomainsuffix) + - [`AutoTLS.RegistrationEndpoint`](#autotlsregistrationendpoint) + - [`AutoTLS.RegistrationToken`](#autotlsregistrationtoken) + - [`AutoTLS.CAEndpoint`](#autotlscaendpoint) - [`Bootstrap`](#bootstrap) - [`Datastore`](#datastore) - [`Datastore.StorageMax`](#datastorestoragemax) @@ -117,12 +123,6 @@ config file at runtime. - [`Swarm.DisableBandwidthMetrics`](#swarmdisablebandwidthmetrics) - [`Swarm.DisableNatPortMap`](#swarmdisablenatportmap) - [`Swarm.EnableHolePunching`](#swarmenableholepunching) - - [`Swarm.AutoTLS`](#swarmautotls) - - [`Swarm.AutoTLS.Enabled`](#swarmautotlsenabled) - - [`Swarm.AutoTLS.DomainSuffix`](#swarmautotlsdomainsuffix) - - [`Swarm.AutoTLS.RegistrationEndpoint`](#swarmautotlsregistrationendpoint) - - [`Swarm.AutoTLS.RegistrationToken`](#swarmautotlsregistrationtoken) - - [`Swarm.AutoTLS.CAEndpoint`](#swarmautotlscaendpoint) - [`Swarm.EnableAutoRelay`](#swarmenableautorelay) - [`Swarm.RelayClient`](#swarmrelayclient) - [`Swarm.RelayClient.Enabled`](#swarmrelayclientenabled) @@ -455,6 +455,99 @@ Default: 1 Minute Type: `duration` (when `0`/unset, the default value is used) +## `AutoTLS` + +> [!CAUTION] +> This is an **EXPERIMENTAL** opt-in feature and should not be used in production yet. +> Feel free to enable it and [report issues](https://github.com/ipfs/kubo/issues/new/choose) if you want to help with testing. + +AutoTLS feature enables publicly reachable Kubo nodes (those dialable from the public +internet) to automatically obtain a wildcard TLS certificate for a DNS name +unique to their PeerID at `*.[PeerID].libp2p.direct`. This enables direct +libp2p connections and retrieval of IPFS content from browsers [Secure Context](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts) +using transports such as [Secure WebSockets](https://github.com/libp2p/specs/blob/master/websockets/README.md), +without requiring user to do any manual domain registration and ceritficate configuration. + +Under the hood, [p2p-forge] client uses public utility service at `libp2p.direct` as an [ACME DNS-01 Challenge](https://letsencrypt.org/docs/challenge-types/#dns-01-challenge) +broker enabling peer to obtain a wildcard TLS certificate tied to public key of their [PeerID](https://docs.libp2p.io/concepts/fundamentals/peers/#peer-id). + +By default, the certificates are requested from Let's Encrypt. Origin and rationale for this project can be found in [community.letsencrypt.org discussion](https://community.letsencrypt.org/t/feedback-on-raising-certificates-per-registered-domain-to-enable-peer-to-peer-networking/223003). + +> [!NOTE] +> Public good DNS and [p2p-forge] infrastructure at `libp2p.direct` is run by the team at [Interplanetary Shipyard](https://ipshipyard.com). +> +> + +[p2p-forge]: https://github.com/ipshipyard/p2p-forge + +Default: `{}` + +Type: `object` + +### `AutoTLS.Enabled` + +> [!CAUTION] +> This is an **EXPERIMENTAL** opt-in feature and should not be used in production yet. +> Feel free to enable it and [report issues](https://github.com/ipfs/kubo/issues/new/choose) if you want to help with testing. + +Enables AutoTLS feature to get DNS+TLS for libp2p Secure WebSocket connections. + +If enabled, it will detect when `.../tls/sni/.../ws` [multiaddr] is present in [`Addresses.Swarm`](#addressesswarm) +and SNI is matching `AutoTLS.DomainSuffix`, and set up a trusted TLS certificate matching the domain name used in [libp2p Secure WebSockets (WSS)](https://github.com/libp2p/specs/blob/master/websockets/README.md) listener. + +> [!IMPORTANT] +> Caveats: +> - This works only if your Kubo node is publicly diallable. +> - The TLS certificate is used only for [libp2p WebSocket](https://github.com/libp2p/specs/blob/master/websockets/README.md) connections. +> - This is NOT used for hosting a [Gateway](#gateway) over HTTPS (it still requies manual TLS setup and your own domain). +> - If you want to test this with a node that is behind a NAT and uses manual port forwarding or UPnP (`Swarm.DisableNatPortMap=false`), +> add `/ip4/0.0.0.0/tcp/4082/tls/sni/*.libp2p.direct/ws` to [`Addresses.Swarm`](#addressesswarm) +> and wait up to 5-15 minutes for libp2p node to set up and learn about own public addresses via [AutoNAT](#autonat). +> - Note: the [p2p-forge] client may produce and log ERROR during this time, but once a publicly diallable addresses are set up, +> a subsequent retry should be successful. + +> [!TIP] +> Debugging can be enabled by setting environment variable `GOLOG_LOG_LEVEL="error,autotls=debug,p2p-forge/client=debug"` + +Default: `false` + +Type: `flag` + +### `AutoTLS.DomainSuffix` + +Optional override of the parent domain suffix that will be used in DNS+TLS+WebSockets multiaddrs generated by [p2p-forge] client. +Do not change this unless you self-host [p2p-forge]. + +Default: `libp2p.direct` (public good run by [Interplanetary Shipyard](https://ipshipyard.com)) + +Type: `optionalString` + +### `AutoTLS.RegistrationEndpoint` + +Optional override of [p2p-forge] HTTP registration API. +Do not change this unless you self-host [p2p-forge]. + +Default: `https://registration.libp2p.direct` (public good run by [Interplanetary Shipyard](https://ipshipyard.com)) + +Type: `optionalString` + +### `AutoTLS.RegistrationToken` + +Optional value for `Forge-Authorization` token sent with request to `RegistrationEndpoint` +(useful for private/self-hosted/test instances of [p2p-forge], unset by default). + +Default: `""` + +Type: `optionalString` + +### `AutoTLS.CAEndpoint` + +Optional override of CA ACME API used by [p2p-forge] system. + +Default: [certmagic.LetsEncryptProductionCA](https://pkg.go.dev/github.com/caddyserver/certmagic#pkg-constants) (see [community.letsencrypt.org discussion](https://community.letsencrypt.org/t/feedback-on-raising-certificates-per-registered-domain-to-enable-peer-to-peer-networking/223003)) + +Type: `optionalString` + ## `Bootstrap` Bootstrap is an array of [multiaddrs][multiaddr] of trusted nodes that your node connects to, to fetch other nodes of the network on startup. @@ -1722,86 +1815,6 @@ Default: `true` Type: `flag` -### `Swarm.AutoTLS` - -AutoTLS enables publicly reachable Kubo nodes (those dialable from the public -internet) to automatically obtain a wildcard TLS certificate for a DNS name -unique to their PeerID at `*.[PeerID].libp2p.direct`. This enables direct -libp2p connections and retrieval of IPFS content from browsers using Secure -WebSockets, without requiring manual domain registration and configuration. - -Under the hood, `libp2p.direct` acts as an [ACME DNS-01 Challenge](https://letsencrypt.org/docs/challenge-types/#dns-01-challenge) -broker for obtaining these wildcard TLS certificates. - -By default, the certificates are requested from Let's Encrypt. -Origin and rationale for this project can be found in [community.letsencrypt.org discussion]. - -> [!NOTE] -> Public good infrastructure at `libp2p.direct` is run by the team at [Interplanetary Shipyard](https://ipshipyard.com). -> -> - -[p2p-forge]: https://github.com/ipshipyard/p2p-forge -[community.letsencrypt.org discussion]: https://community.letsencrypt.org/t/feedback-on-raising-certificates-per-registered-domain-to-enable-peer-to-peer-networking/223003 - -Default: `{}` - -Type: `object` - -#### `Swarm.AutoTLS.Enabled` - -> [!CAUTION] -> This is an EXPERIMENTAL feature and should not be used in production yet. -> Feel free to enable it and [report issues](https://github.com/ipfs/kubo/issues/new/choose) if you want to help with testing. - -Enables **EXPERIMENTAL** [p2p-forge] client. This feature works only if your Kubo node is publicly diallable. - -If enabled, it will detect when `.../tls/sni/.../ws` is present in [`Addresses.Swarm`](#addressesswarm) -and SNI is matching `Swarm.AutoTLS.DomainSuffix`, and set up a trusted TLS certificate matching the domain name used in Secure WebSockets (WSS) listener. - -If you want to test this, add `/ip4/0.0.0.0/tcp/4082/tls/sni/*.libp2p.direct/ws` to [`Addresses.Swarm`](#addressesswarm). - -Debugging can be enabled by setting environment variable `GOLOG_LOG_LEVEL="error,autotls=debug,p2p-forge/client=debug"` - -Default: `false` - -Type: `flag` - -#### `Swarm.AutoTLS.DomainSuffix` - -Optional override of the parent domain suffix that will be used in DNS+TLS+WebSockets multiaddrs generated by [p2p-forge] client. -Do not change this unless you self-host [p2p-forge]. - -Default: `libp2p.direct` (public good run by [Interplanetary Shipyard](https://ipshipyard.com)) - -Type: `optionalString` - -#### `Swarm.AutoTLS.RegistrationEndpoint` - -Optional override of [p2p-forge] HTTP registration API. -Do not change this unless you self-host [p2p-forge]. - -Default: `https://registration.libp2p.direct` (public good run by [Interplanetary Shipyard](https://ipshipyard.com)) - -Type: `optionalString` - -#### `Swarm.AutoTLS.RegistrationToken` - -Optional value for `Forge-Authorization` token sent with request to `RegistrationEndpoint` -(useful for private/self-hosted/test instances of [p2p-forge]). - -Default: `""` - -Type: `optionalString` - -#### `Swarm.AutoTLS.CAEndpoint` - -Optional override of CA ACME API used by [p2p-forge] system. - -Default: [certmagic.LetsEncryptProductionCA](https://pkg.go.dev/github.com/caddyserver/certmagic#pkg-constants) (see [community.letsencrypt.org discussion]) - -Type: `optionalString` - ### `Swarm.EnableAutoRelay` **REMOVED**