Skip to content

membership: panic on startup with GODEBUG=fips140=only due to SHA-1 in cluster/member ID derivation #21673

@chaitanyabodlapati

Description

@chaitanyabodlapati

Bug report criteria

What happened?

When etcd is built with Go 1.24+ and started with GODEBUG=fips140=only, the
process panics on startup. The Go runtime refuses to execute SHA-1 under strict
FIPS 140-3 mode, but etcd uses SHA-1 in two places to derive cluster and member IDs:

  • server/etcdserver/api/membership/cluster.go (cluster ID derivation via sha1.Sum)
  • server/etcdserver/api/membership/member.go (member ID derivation via sha1.Sum)

What did you expect to happen?

etcd should start cleanly under GODEBUG=fips140=only. The SHA-1 in these files
is not used for any security property — it's a deterministic digest used to produce
a ID — but Go's strict FIPS mode refuses to execute SHA-1 regardless of intent.

How can we reproduce it (as minimally and precisely as possible)?

  1. Build etcd from main with Go 1.24 or newer.

  2. Run with GODEBUG=fips140=only set:
    GODEBUG=fips140=only ./bin/etcd
    --name node1
    --data-dir /tmp/etcd-data
    --listen-client-urls http://127.0.0.1:2379
    --advertise-client-urls http://127.0.0.1:2379
    --listen-peer-urls http://127.0.0.1:2380
    --initial-advertise-peer-urls http://127.0.0.1:2380
    --initial-cluster node1=http://127.0.0.1:2380

  3. Process panics during membership initialization.
    panic: crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode
    goroutine 1 [running]: crypto/sha1.Sum({0x39fd3820a740, 0x21, 0x40}) crypto/sha1/sha1.go:278 +0x145 go.etcd.io/etcd/server/v3/etcdserver/api/membership.computeMemberID(...) go.etcd.io/etcd/server/v3/etcdserver/api/membership/member.go:74 +0x34e ...

Anything else we need to know?

Why we cannot just replace SHA-1 with SHA-256

A one-line replacement of sha1.Sum with sha256.Sum256 would compile and
fix the panic, but it changes every cluster ID and member ID. These IDs are:

  • Persisted to the WAL on every node
  • Written into snapshots
  • Exchanged during peer handshakes
  • Used to reject cross-cluster traffic ("cluster ID mismatch")

A node built with the new hash cannot rejoin or recover a cluster bootstrapped
with the old hash. This makes a direct swap backward-incompatible for every
existing etcd deployment.

Related

Etcd version (please run commands below)

Details
$ etcd --version
etcd Version: 3.7.0-alpha.0
Git SHA: f38159321
Go Version: go1.26.2
Go OS/Arch: linux/amd64

$ etcdctl version
etcdctl version: 3.7.0-alpha.0
API version: 3.7

Etcd configuration (command line flags or environment variables)

Details
GODEBUG=fips140=only ./bin/etcd \
  --name node1 \
  --data-dir /tmp/etcd-data \
  --listen-client-urls http://127.0.0.1:2379 \
  --advertise-client-urls http://127.0.0.1:2379 \
  --listen-peer-urls http://127.0.0.1:2380 \
  --initial-advertise-peer-urls http://127.0.0.1:2380 \
  --initial-cluster node1=http://127.0.0.1:2380 

Etcd debug information (please run commands below, feel free to obfuscate the IP address or FQDN in the output)

Details
$ etcdctl member list -w table
# N/A — etcd panics on startup before accepting client connections

$ etcdctl --endpoints=<member list> endpoint status -w table
# N/A — etcd panics on startup before accepting client connections

Relevant log output

panic: crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode

goroutine 1 [running]:
crypto/sha1.Sum({0x39fd3820a740, 0x21, 0x40})
	crypto/sha1/sha1.go:278 +0x145
go.etcd.io/etcd/server/v3/etcdserver/api/membership.computeMemberID({0x39fd37f7d680, 0x1, 0x39fd3838efa0?}, {0x125a986, 0xc}, 0x0)
	go.etcd.io/etcd/server/v3/etcdserver/api/membership/member.go:74 +0x34e
go.etcd.io/etcd/server/v3/etcdserver/api/membership.NewMember({0x7fff03ca5751, 0x5}, {0x39fd37f7d680, 0x1, 0x1}, {0x125a986?, 0x39fd3835e120?}, 0x39fd37f7d680?)
	go.etcd.io/etcd/server/v3/etcdserver/api/membership/member.go:52 +0x45
go.etcd.io/etcd/server/v3/etcdserver/api/membership.NewClusterFromURLsMap(0x39fd38256c08?, {0x125a986, 0xc}, 0x39fd38041500, {0x39fd3838f140?, 0x39fd37fd7200?, 0x39fd3838f0d8?})
	go.etcd.io/etcd/server/v3/etcdserver/api/membership/cluster.go:84 +0xd8
go.etcd.io/etcd/server/v3/etcdserver.bootstrapNewClusterNoWAL({{0x7fff03ca565f, 0x5}, {{{0x1d7aca0, 0x0, 0x0}, 0x12a05f200, 0x77359400, 0x77359400, 0x165a0bc00, 0x0, ...}, ...}, ...}, ...)
	go.etcd.io/etcd/server/v3/etcdserver/bootstrap.go:354 +0x118
go.etcd.io/etcd/server/v3/etcdserver.bootstrapCluster({{0x7fff03ca565f, 0x5}, {{{0x1d7aca0, 0x0, 0x0}, 0x12a05f200, 0x77359400, 0x77359400, 0x165a0bc00, 0x0, ...}, ...}, ...}, ...)
	go.etcd.io/etcd/server/v3/etcdserver/bootstrap.go:306 +0x156
go.etcd.io/etcd/server/v3/etcdserver.bootstrap({{0x7fff03ca565f, 0x5}, {{{0x1d7aca0, 0x0, 0x0}, 0x12a05f200, 0x77359400, 0x77359400, 0x165a0bc00, 0x0, ...}, ...}, ...})
	go.etcd.io/etcd/server/v3/etcdserver/bootstrap.go:92 +0x8f9
go.etcd.io/etcd/server/v3/etcdserver.NewServer({{0x7fff03ca565f, 0x5}, {{{0x1d7aca0, 0x0, 0x0}, 0x12a05f200, 0x77359400, 0x77359400, 0x165a0bc00, 0x0, ...}, ...}, ...})
	go.etcd.io/etcd/server/v3/etcdserver/server.go:295 +0x8b
go.etcd.io/etcd/server/v3/embed.StartEtcd(0x39fd38177c08)
	go.etcd.io/etcd/server/v3/embed/etcd.go:260 +0x115f
go.etcd.io/etcd/server/v3/etcdmain.startEtcd(0x39fd3818c900?)
	go.etcd.io/etcd/server/v3/etcdmain/etcd.go:181 +0x17
go.etcd.io/etcd/server/v3/etcdmain.startEtcdOrProxyV2({0x39fd37fb6000, 0xf, 0xf})
	go.etcd.io/etcd/server/v3/etcdmain/etcd.go:127 +0xf85
go.etcd.io/etcd/server/v3/etcdmain.Main({0x39fd37fb6000, 0xf, 0xf})
	go.etcd.io/etcd/server/v3/etcdmain/main.go:40 +0xf3
main.main()
	go.etcd.io/etcd/server/v3/main.go:31 +0x28

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions