logo

Port 2379 – etcd (Key-Value Store)

Service:

etcd

Protocol:

TCP

Port:

2379

Used for:

The etcd client API endpoint — the distributed key-value store that holds all Kubernetes cluster state, including every Secret (2380 carries etcd peer replication traffic)

Port 2379 is the default client API port for etcd, the distributed, strongly-consistent key-value store that serves as the backing store for Kubernetes — and for Consul-adjacent, CoreOS, and other cloud-native control planes. Everything a Kubernetes cluster knows about itself lives in etcd: every Pod spec, ConfigMap, RBAC binding, and — critically — every Secret, which etcd stores base64-encoded and, unless encryption-at-rest is explicitly configured, effectively in plaintext. Clients (etcdctl, the Kubernetes API server) read and write through the API on 2379, while etcd nodes replicate to each other over the separate peer port 2380. Because 2379 is a direct window into the entire cluster’s state, an etcd instance reachable without client-certificate authentication is one of the most severe exposures in a cloud-native environment: the dominant risk here is not a single CVE but the no-auth exposure misconfiguration.

Why It’s Open

Port 2379 is open because the control plane requires it — etcd is not an optional add-on but the single source of truth the Kubernetes API server reads from and writes to on every request. The port carries:

  • API-server traffic. kube-apiserver connects to etcd on 2379 to persist and retrieve every object in the cluster. If etcd is unreachable, the control plane is dead.
  • etcdctl and operator tooling. Backups, restores, defragmentation, and manual inspection all talk to 2379.
  • Monitoring. Prometheus scrapes etcd’s /metrics endpoint on the same port.

etcd uses a deliberate two-port model: 2379 is the client endpoint (apiserver, etcdctl, monitoring), and 2380 is the peer endpoint used only for Raft replication between etcd members. On a correctly built cluster, 2379 is reachable only from the control-plane nodes, and every connection is mutually authenticated with TLS client certificates. The problem is how often that isn’t true: self-managed clusters bootstrapped by hand, older kubeadm/CoreOS setups, and etcd running on a cloud VM with a wide-open security group frequently leave 2379 answering with no client-cert requirement — sometimes even bound to 0.0.0.0 and reachable from the internet. When that happens, anyone who can reach the port can read or write the entire cluster state directly, bypassing the Kubernetes API server, its RBAC, and its audit log completely.

Common Risks

  • Read every Kubernetes Secret → full cluster compromise. etcd holds all Secrets. With unauthenticated read access, an attacker runs etcdctl get "" --prefix --keys-only to enumerate every key, then dumps the values — service-account tokens, TLS private keys, registry pull credentials, database passwords, cloud-provider keys. Secrets are only base64-encoded at rest unless encryption-at-rest is enabled, so this is effectively plaintext theft of every credential in the cluster.
  • Write access → tamper with cluster objects. etcd exposes read and write. An attacker with write access can inject or modify raw cluster objects behind the API server’s back — planting RBAC bindings, altering deployments, or seeding a malicious workload — with none of it passing through admission control or the audit log.
  • Bypasses the API server entirely. Talking to etcd directly sidesteps every guardrail Kubernetes provides (authentication, RBAC, admission webhooks, auditing). A compromise here is invisible to the control-plane’s own defenses.
  • No client-cert authentication. The single most common failure: etcd started without --client-cert-auth, so it accepts any connection on 2379 without proving identity.
  • Weak auth where RBAC is enabled. etcd’s optional username/password auth historically had no password-length validation and no brute-force rate limiting (see CVEs), making weak credentials easy to guess.
  • Information disclosure. /version and /metrics answer without credentials on many deployments, leaking the exact etcd version (for CVE matching) and operational internals.

Want to save time on reporting?

Let PentestPad generate, track, and export your reports - automatically.

logo-cta

Enumeration & Testing

The workflow on 2379 is: confirm it’s etcd, fingerprint the version, then test whether it answers without client-certificate authentication — because that, not any exploit, is the whole ballgame.

Confirm the port and detect the service

Terminal window
nmap -sV -p 2379,2380 <target>

Scan 2380 alongside 2379 — a reachable peer port confirms an etcd cluster and is itself a target.

Fingerprint etcd without credentials

Terminal window
curl http://<target>:2379/version
curl https://<target>:2379/version -k

A JSON body with etcdserver and etcdcluster version fields confirms etcd and gives you the exact version to match against the CVEs below. If the plain http:// request works, TLS isn’t even enabled; if only https:// answers, note whether it demands a client cert.

Dump the entire keyspace with etcdctl (the high-value case)

Terminal window
# List every key in the store (v3 API) — no client cert required if misconfigured
ETCDCTL_API=3 etcdctl --endpoints=http://<target>:2379 get "" --prefix --keys-only
# Then read the crown jewels — Kubernetes Secrets live under /registry/secrets/
ETCDCTL_API=3 etcdctl --endpoints=http://<target>:2379 get /registry/secrets/ --prefix

Any key returned here is unauthenticated read access to cluster state; a /registry/secrets/ hit is every credential in the cluster in your terminal.

Probe the legacy v2 API and metrics

Terminal window
# etcd v2 keyspace (older clusters)
curl http://<target>:2379/v2/keys/?recursive=true
# Prometheus metrics — leaks version and internals without auth on many setups
curl http://<target>:2379/metrics

Automated Kubernetes attack-surface scanning

Terminal window
# kube-hunter (Aqua Security) flags an exposed/unauthenticated etcd among other control-plane findings
kube-hunter --remote <target>

There is no reliable unauthenticated etcd RCE Metasploit module — the “exploit” is simply etcdctl/curl against a store that never asked you to authenticate, so don’t reach for a made-up MSF path. Log every open port 2379/2380, the etcd version, and any key, Secret, or write you confirm straight into the pentest report instead of a scratch terminal you’ll lose.

What to Look For

Checkpoint What it means
/version returns etcdserver/etcdcluster JSON etcd confirmed — note the version for CVE matching
Plain http://<target>:2379 answers TLS is disabled entirely — traffic and keys are in the clear
etcdctl get "" --prefix returns keys without a client cert Unauthenticated read of cluster state — critical
/registry/secrets/ keys readable Every Kubernetes Secret is exposed — full cluster compromise
A write (etcdctl put) succeeds Cluster-object tampering, invisible to the API server and audit log
Peer port 2380 also reachable Raft replication endpoint exposed — additional attack surface
/metrics answers without credentials Version and operational internals disclosed
etcd reachable from outside the control-plane subnet Backing store exposed beyond where it should ever live

Known CVEs and Exploits

Be honest about the threat model: on port 2379 the dominant risk is a misconfiguration — etcd exposed without client-certificate authentication — not a single CVE. When etcd answers etcdctl or curl without demanding a client cert, no exploit code is required; reading /registry/secrets/ is the entire attack. That said, etcd has had genuine CVEs worth matching the fingerprinted version against:

  • CVE-2021-28235 — An authentication flaw in etcd (etcd-io) 3.4.10 in which the debug function can be abused by a remote attacker to escalate privileges (CWE-287, Improper Authentication). Rated CVSS 9.8 Critical by NIST. Check the exact patch level of any 3.4.x deployment against this.
  • CVE-2020-15115 — etcd before 3.3.23 and 3.4.10 performs no password-length validation, allowing extremely short passwords. Combined with etcd’s lack of authentication rate-limiting, this makes its optional username/password auth trivial to brute-force. CVSS 7.5 High (NIST; the GitHub CNA scored it 5.8). CWE-521, Weak Password Requirements.
  • CVE-2018-1098 — A cross-site request forgery (CSRF) flaw in etcd 3.3.1 and earlier: an attacker-controlled website can send a crafted POST request to a reachable etcd server and create/modify keys in the store (CWE-352). CVSS 8.8 High. Fixed in 3.3.2.
  • CVE-2018-1099 — A DNS-rebinding vulnerability in etcd 3.3.1 and earlier: an attacker who controls DNS records can trick a victim’s browser into issuing requests to a localhost-bound etcd (CWE-20). CVSS 5.5 Medium. Also fixed in 3.3.2.

Match the version from /version against these fix levels before assuming a store is vulnerable — but remember that a fully-patched etcd left open with no client-cert auth is still a total compromise. The configuration review is the higher-yield test here.

Mitigation

  • Require mutual TLS with client-cert auth. Start etcd with --client-cert-auth=true, --trusted-ca-file, --cert-file, and --key-file (and the peer equivalents --peer-client-cert-auth + --peer-trusted-ca-file) so that both 2379 and 2380 reject any connection that can’t present a valid certificate signed by the etcd CA. This is the single most important control.
  • Firewall 2379 and 2380 to the control plane only. etcd should be reachable exclusively from the control-plane nodes and the API server — never from worker nodes, never from 0.0.0.0, never from the internet. Audit cloud security groups for an accidentally world-open 2379/2380.
  • Enable encryption at rest for Secrets. Configure the Kubernetes API server’s EncryptionConfiguration (e.g. a KMS or AES provider) so Secrets are encrypted before they hit etcd, rather than sitting base64-encoded — this limits the blast radius if the store is ever read.
  • Patch etcd. Run a current release to close CVE-2021-28235, CVE-2020-15115, and the 2018 CSRF/DNS-rebinding pair, and if you use etcd’s username/password auth, enforce strong passwords since etcd won’t do it for you.
  • Restrict /metrics and disable the v2 API where it isn’t needed, so an unauthenticated fingerprint of your etcd version and internals isn’t handed out for free.
  • Protect the neighbours. etcd rarely sits alone — lock down the Kubernetes API server on 6443 and the kubelet API on 10250, and watch for an exposed kubectl proxy on 8001, since an attacker who can’t reach etcd will pivot to whichever control-plane door is open. Any exposed etcd you confirm belongs in the pentest report with the exact etcdctl/curl evidence.

Real-World Example

The canonical port-2379 compromise needs no exploit at all. A team stands up a Kubernetes cluster by hand — or on an older kubeadm/CoreOS build — and etcd comes up listening on 0.0.0.0:2379 without --client-cert-auth, its security group left open “to get the cluster talking.” An attacker scanning cloud ranges finds 2379 answering, confirms it with curl http://<host>:2379/version, and runs ETCDCTL_API=3 etcdctl --endpoints=http://<host>:2379 get "" --prefix --keys-only. The keyspace scrolls past under /registry/, including /registry/secrets/. A follow-up get /registry/secrets/ --prefix dumps every Secret in the cluster — service-account tokens, TLS keys, database and registry credentials — all base64-encoded, effectively plaintext. From there the attacker uses a stolen service-account token or the exposed cluster credentials to move laterally, exactly as they would against an exposed Docker Engine API on 2375 or an unauthenticated Kubernetes API. No CVE, no exploit binary — just a store that was never asked to authenticate. Internet-wide scanners have repeatedly catalogued thousands of etcd instances exposed this way, with researchers demonstrating credential harvesting from open etcd endpoints; it remains one of the most direct cloud-native compromises there is.

FAQ

What is port 2379 used for?

Port 2379 is the default client API port for etcd, the distributed key-value store that holds all cluster state for Kubernetes (and is used by CoreOS and other cloud-native systems). The Kubernetes API server, the etcdctl command-line tool, and monitoring all read and write through 2379. A separate port, 2380, carries the Raft replication traffic between etcd cluster members.

Why are there two etcd ports, 2379 and 2380?

etcd separates client traffic from peer traffic. Port 2379 is the client endpoint that applications (kube-apiserver, etcdctl) connect to. Port 2380 is the peer endpoint used only for etcd members to replicate the Raft log to each other. Both should require TLS client-certificate authentication and both should be firewalled to the control plane; a reachable 2380 confirms an etcd cluster and is itself worth scanning.

Is an exposed etcd on 2379 dangerous?

Extremely. etcd stores the entire cluster state, including every Kubernetes Secret — service-account tokens, TLS private keys, registry and database credentials — which are only base64-encoded unless encryption-at-rest is enabled. An etcd instance that answers 2379 without client-certificate authentication lets anyone who reaches it read every Secret with etcdctl get "" --prefix, and write access lets them tamper with cluster objects behind the API server’s back. It is a full cluster compromise, invisible to Kubernetes RBAC and audit logging.

How do I check whether my etcd requires authentication?

Try to reach it without a certificate: curl http://<host>:2379/version (a JSON reply means TLS is off entirely and it’s likely unauthenticated) and ETCDCTL_API=3 etcdctl --endpoints=http://<host>:2379 get "" --prefix --keys-only. If keys come back without you presenting a client cert, etcd is exposed and must be locked down with --client-cert-auth immediately. If only https:// answers and it rejects you without a cert, mutual TLS is working.

Does port 2379 have a single big CVE?

Not really — the dominant risk is a misconfiguration (etcd reachable without client-cert auth), not one exploit. There are genuine CVEs to check the version against — chiefly CVE-2021-28235 (auth/debug privilege escalation, CVSS 9.8) and CVE-2020-15115 (no password-length validation, easy brute-force), plus the 2018 CSRF and DNS-rebinding pair (CVE-2018-1098 / CVE-2018-1099) — but a patched etcd left open with no authentication is still a total compromise, so the configuration review is the higher-yield test.

How do I secure or close port 2379?

You don’t close it — the control plane needs it — you lock it down. Require mutual TLS with --client-cert-auth=true and a trusted CA on both 2379 and 2380, firewall both ports to the control-plane nodes only (never 0.0.0.0), enable Kubernetes encryption-at-rest so Secrets aren’t stored effectively in plaintext, patch etcd to a current release, and restrict /metrics and the legacy v2 API. Then rescan to confirm the store rejects unauthenticated connections.

TL;DR

  • Service: etcd — the distributed key-value store that is Kubernetes’ backing store (also CoreOS and other cloud-native control planes); 2379 is the client API, 2380 is peer replication
  • Default port: 2379/TCP (client API), with 2380/TCP for etcd peer traffic
  • Biggest risk: an etcd exposed without client-certificate authentication. It holds every Kubernetes Secret (base64, effectively plaintext), so etcdctl get "" --prefix reads all cluster credentials and write access tampers with cluster objects behind the API server — a full cluster compromise. It’s a misconfiguration, not a single CVE (though CVE-2021-28235, CVSS 9.8, is a real one to patch)
  • Mitigation: require mutual TLS with --client-cert-auth on 2379 and 2380, firewall both to the control plane, enable Secret encryption-at-rest, patch etcd, and restrict /metrics and the v2 API