Last updated: 2026-05-15
etcd TLS Configuration
etcd has two independent TLS surfaces: client (etcdctl, Kubernetes API server → etcd) and peer (etcd node → etcd node in a cluster). Both must be secured: an etcd cluster with client auth disabled but peer auth enabled is still fully exposed to any process that can reach port 2379.
Certificate Setup
A minimal etcd PKI:
- One CA certificate (separate client and peer CAs are also valid)
- A server certificate per node, with each node's IP addresses and hostname in the SAN
- A peer certificate per node (can be the same as the server cert if the SANs cover both roles)
- A client certificate for each consumer (API server, etcdctl, backup tools)
The peer certificate SAN must include every member's peer URL; etcd validates these during cluster join. Missing IP SANs are the most common reason peer TLS fails to initialize.
Server Configuration
Settings can be passed as flags or as a YAML config file (/etc/etcd/etcd.conf.yaml). The YAML keys use hyphens, matching the flag names with -- stripped.
# Client TLS
cert-file: /etc/etcd/ssl/server.crt
key-file: /etc/etcd/ssl/server.key
trusted-ca-file: /etc/etcd/ssl/ca.crt
client-cert-auth: true
# Peer TLS
peer-cert-file: /etc/etcd/ssl/peer.crt
peer-key-file: /etc/etcd/ssl/peer.key
peer-trusted-ca-file: /etc/etcd/ssl/ca.crt
peer-client-cert-auth: true
Key settings:
client-cert-auth: true: requires clients to present a certificate signed bytrusted-ca-file. Without it, any process that can reach port 2379 has full access to the cluster.peer-client-cert-auth: true: same enforcement for peer connections. Without it, a rogue process can present itself as an etcd member.auto-tls/peer-auto-tls: generates self-signed certificates automatically. Fine for testing, not for production (no CA validation).
See RFC 8446 §4.3.2 for the TLS Certificate Request specification, and Wikipedia: Mutual authentication for a general overview.
Client Connections
etcdctl
etcdctl \
--endpoints=https://etcd1.internal:2379 \
--cacert=/etc/etcd/ssl/ca.crt \
--cert=/etc/etcd/ssl/client.crt \
--key=/etc/etcd/ssl/client.key \
endpoint health
These repeat on every command, so export them as environment variables:
export ETCDCTL_ENDPOINTS=https://etcd1.internal:2379
export ETCDCTL_CACERT=/etc/etcd/ssl/ca.crt
export ETCDCTL_CERT=/etc/etcd/ssl/client.crt
export ETCDCTL_KEY=/etc/etcd/ssl/client.key
Kubernetes API server
The API server connects to etcd as a client. The relevant kube-apiserver flags:
--etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
--etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
--etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
kubeadm generates and sets these automatically. When managing etcd externally, verify the API server's client certificate is signed by the etcd CA and that its CN is accepted by etcd's auth policy.
Security Notes
etcd uses Go's crypto/tls package, which has a different vulnerability history than OpenSSL:
- POODLE (CVE-2014-3566, 2014): SSL 3.0 has never been supported in Go's TLS implementation.
- BEAST (CVE-2011-3389, 2011): Mitigated by recommending TLS 1.2 as the minimum; AEAD-only ciphers eliminate the CBC padding oracle.
- CRIME (CVE-2012-4929, 2012): TLS compression is not supported in Go's
crypto/tls. - Lucky13 (2013): AEAD-only cipher list eliminates CBC padding timing side-channels entirely.
- FREAK (CVE-2015-0204, 2015): EXPORT-grade ciphers have never been supported in Go's
crypto/tls. - LOGJAM (CVE-2015-4000, 2015): DHE key exchange is not offered by default in Go; only ECDHE is used.
- Sweet32 (CVE-2016-2183, 2016): 3DES was removed from Go's default cipher list in Go 1.14 (February 2020) and is excluded from the recommended configuration.
- ROBOT (CVE-2017-13099, 2017): Static RSA key exchange is not offered in Go's
crypto/tls; only ECDHE is used. - Downgrade attacks: TLS_FALLBACK_SCSV is supported in Go's TLS implementation.
The following are not addressable through TLS configuration alone:
- Heartbleed (CVE-2014-0160, 2014): Not applicable. Go's
crypto/tlsis an independent TLS implementation and was never affected by Heartbleed. - BREACH (CVE-2013-3587, 2013): Not applicable. BREACH targets HTTP-level response compression; the etcd gRPC/REST API does not use HTTP-level compression in normal operation.
- DROWN (CVE-2016-0800, 2016): Not applicable. Go's
crypto/tlsdoes not support SSLv2.
Verification
Check cluster health over TLS:
etcdctl endpoint health --cluster
Confirm member list and peer URLs:
etcdctl member list -w table
Test the TLS handshake on both ports:
openssl s_client -connect etcd1.internal:2379 -CAfile /etc/etcd/ssl/ca.crt
openssl s_client -connect etcd1.internal:2380 -CAfile /etc/etcd/ssl/ca.crt
Port 2379 is the client port; 2380 is the peer port. Both should complete a valid handshake with peer auth enabled.