Connecting
Kubo vs. Cluster, auth modes, SSRF policy, and the safety guards around destructive operations
Two Daemons
| Daemon | Config Fields | Used By |
|---|---|---|
| Kubo (reference IPFS implementation) | baseUrl, authMode, credentialID | All resources except cluster. The storage composites use Kubo too, alongside Cluster. |
| IPFS Cluster (coordinated pinning across a set of IPFS peers) | clusterBaseUrl, clusterAuthMode, destinationCredentialID | cluster resource, plus the storage composites. |
Auth Modes
Kubo itself has no native authentication — authMode/clusterAuthMode exist to
support a daemon sitting behind a reverse proxy that adds one:
| Mode | Kubo | Cluster | Behavior |
|---|---|---|---|
none | ✓ | ✓ | No Authorization header sent. Default. |
bearer | ✓ | — | Sends Authorization: Bearer <token>, token resolved from credentialID. |
basic | ✓ | ✓ | Sends HTTP Basic auth, username/password resolved from credentialID (Kubo) or destinationCredentialID (Cluster). A credential with neither field set is treated as absent rather than emitting a malformed header. |
baseUrl (or clusterBaseUrl) resolves to a non-private host with
authMode="none" (or clusterAuthMode="none"), the node logs a runtime warning —
since Kubo has no native auth, an unauthenticated public daemon is exposed to anyone who can reach it.
This never blocks execution, it only warns.
SSRF Policy — Inverted From the Platform Default
A generic outbound-HTTP node denies private/loopback targets by default to prevent SSRF against
internal infrastructure. An IPFS node is different: pointing at a self-hosted Kubo daemon on
127.0.0.1 or a private LAN address is the expected, common case. So the IPFS base-URL
policy is deliberately inverted:
| Target | Allowed? |
|---|---|
Loopback (127.0.0.1, localhost) | ✓ Allowed |
RFC-1918 private ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) and IPv6 unique-local (fc00::/7) | ✓ Allowed |
| Any other public host | ✓ Allowed |
Link-local (169.254.0.0/16, IPv6 fe80::/10) | ✗ Denied |
Cloud-metadata address (169.254.169.254, fd00:ec2::254) | ✗ Denied |
Only the genuinely dangerous SSRF pivots — link-local and the cloud-metadata endpoint — are
unconditionally denied. IPv4-mapped IPv6 addresses (e.g. ::ffff:169.254.169.254) are collapsed
to their IPv4 form before the check, so the mapped-address encoding cannot be used to bypass the deny list.
Resilience (Retries)
Outbound calls go through a shared retry handler: up to 3 retries on HTTP 408/429/5xx or a transient
network exception, exponential backoff starting at 100 ms and capped at 8000 ms, honoring a
server Retry-After header when present.
content/add
yields the identical CID) — so a retry can never produce a divergent result.
Destructive Operations Require Confirmation
Two operations can destroy data or connectivity and require an explicit confirmDestructive
flag before any network call is made:
| Operation | Guard |
|---|---|
repo/garbageCollect | Requires confirmDestructive=true — this permanently deletes any unpinned blocks in the local repo. |
bootstrap/remove with all=true | Requires confirmDestructive=true — clears the entire bootstrap peer list. Removing a single peer (all=false, a specific peerAddress) needs no confirmation. |
Secrets Are Never Emitted
Three categories of sensitive material are structurally excluded from output, ToDictionary(),
and logs:
- IPNS private key material (
key/generate,key/import) — the generate result has no field capable of holding private bytes; import's key material lives only in a short-scoped local variable and is never serialized. - Remote pinning-service API keys (
pin/remoteServiceAdd) — accepted as input, forwarded to Kubo, never included in the output record. Kubo itself stores the key write-only. - Vault credentials (bearer tokens, Basic auth pairs) — resolved once per execution and passed to the Services layer as plain strings; typed HTTP clients also disable default URI logging so a remote-pin API key carried in a query string can't leak through framework request logs.