etcd
Overview
etcd is an open source distributed key-value store. This SecureAnyCloud Amazon Machine Image delivers etcd 3.5 fully installed as a single-node deployment, with Role-Based Access Control (RBAC) enabled at first boot. The image is headless, so you manage it with the etcdctl CLI preinstalled at /usr/local/bin/etcdctl.
This guide covers how to connect to the instance, retrieve per-instance credentials, run common etcdctl operations, understand the security model, and expand a single node into a 3- or 5-node Raft cluster.
What you get:
- etcd 3.5 (version 3.5.30) installed as a single-node deployment
- RBAC enabled at first boot, with a fresh per-instance SecureAnyCloud user password and a separate emergency root password
- Credentials written to a root-only file on the instance
- The etcdctl CLI preinstalled at /usr/local/bin/etcdctl
- Client port 2379 with an anonymous /health endpoint for Kubernetes liveness and readiness probes
- Peer port 2380 bound to loopback only
- 24/7 technical support from SecureAnyCloud
Launch and connect to your instance
The default SSH login user for Ubuntu 24.04 is ubuntu. Connect over SSH on port 22:
ssh -i <your-ssh-key.pem> ubuntu@<instance-public-ip>Retrieving the per-instance credentials
On the first boot of every instance, a one-shot service generates a fresh per-instance SecureAnyCloud user password and a separate emergency root password. It writes both to a root-only file and enables etcd RBAC. Retrieve them with:
sudo cat /root/etcd-credentials.txtThe file looks like:
# etcd 3.5 — Per-Instance Credentials ETCD_VERSION=etcd Version: 3.5.30 ETCD_CLIENT_URL=http://<instance-public-ip>:2379 ETCD_HEALTH_URL=http://<instance-public-ip>:2379/health ETCD_USER=sac ETCD_PASSWORD=<ETCD_PASSWORD> ETCD_ROOT_PASSWORD=<ETCD_ROOT_PASSWORD>The SecureAnyCloud user holds readwrite on the entire / key prefix and is the canonical user for application traffic. ETCD_ROOT_PASSWORD is for emergency access only. Do not use it for normal operations.
Confirm the service is healthy
sudo systemctl status etcd.service --no-pager --lines=5endpoint health and endpoint status need an authenticated etcdctl because RBAC is enforced. Read the password from /root/etcd-credentials.txt for each call:
PASS=$(sudo grep ^ETCD_PASSWORD= /root/etcd-credentials.txt | cut -d= -f2-) && \
ETCDCTL_API=3 /usr/local/bin/etcdctl \
--endpoints=http://127.0.0.1:2379 \
--user=sac:${PASS} \
endpoint health 2>/dev/nullendpoint status is a cluster-maintenance call that the SecureAnyCloud user is not granted. It needs the emergency root credential:
ROOT=$(sudo grep ^ETCD_ROOT_PASSWORD= /root/etcd-credentials.txt | cut -d= -f2-) && \
ETCDCTL_API=3 /usr/local/bin/etcdctl \
--endpoints=http://127.0.0.1:2379 \
--user=root:${ROOT} \
endpoint status --write-out=tableThe /health endpoint on port 2379 is anonymous by design. Kubernetes liveness and readiness probes call it:
curl -s http://127.0.0.1:2379/healthAuthenticated put and get
Every key-value operation needs --user=sac:<password>. Load the password from the credentials file in each call:
PASS=$(sudo grep ^ETCD_PASSWORD= /root/etcd-credentials.txt | cut -d= -f2-) && \
ETCDCTL_API=3 /usr/local/bin/etcdctl \
--endpoints=http://127.0.0.1:2379 \
--user=sac:${PASS} \
put /apps/web/config '{"port":8080,"workers":4}'PASS=$(sudo grep ^ETCD_PASSWORD= /root/etcd-credentials.txt | cut -d= -f2-) && \
ETCDCTL_API=3 /usr/local/bin/etcdctl \
--endpoints=http://127.0.0.1:2379 \
--user=sac:${PASS} \
get /apps/web/config --print-value-onlyList every key under a prefix:
PASS=$(sudo grep ^ETCD_PASSWORD= /root/etcd-credentials.txt | cut -d= -f2-) && \
ETCDCTL_API=3 /usr/local/bin/etcdctl \
--endpoints=http://127.0.0.1:2379 \
--user=sac:${PASS} \
get /apps --prefix --keys-onlyDelete a key:
PASS=$(sudo grep ^ETCD_PASSWORD= /root/etcd-credentials.txt | cut -d= -f2-) && \
ETCDCTL_API=3 /usr/local/bin/etcdctl \
--endpoints=http://127.0.0.1:2379 \
--user=sac:${PASS} \
del /apps/web/configWatching a key
etcdctl watch streams every change to a key or prefix. Open a second SSH session and put into /apps/... to see the updates stream live in the first:
PASS=$(sudo grep ^ETCD_PASSWORD= /root/etcd-credentials.txt | cut -d= -f2-) && \
ETCDCTL_API=3 /usr/local/bin/etcdctl \
--endpoints=http://127.0.0.1:2379 \
--user=sac:${PASS} \
watch /apps --prefixVerify RBAC is enforced
An unauthenticated put against the local endpoint is rejected, which shows that RBAC is active. The command below is expected to fail with Error: etcdserver: user name is empty:
ETCDCTL_API=3 /usr/local/bin/etcdctl \
--endpoints=http://127.0.0.1:2379 \
put /noauth-attempt should-failListing users is a cluster-management call that requires the root credential. Use the emergency root password from the credentials file:
ROOT=$(sudo grep ^ETCD_ROOT_PASSWORD= /root/etcd-credentials.txt | cut -d= -f2-) && \
ETCDCTL_API=3 /usr/local/bin/etcdctl \
--endpoints=http://127.0.0.1:2379 \
--user=root:${ROOT} \
user listInspect the sac-rw role. The SecureAnyCloud user has permission to read the roles assigned to it:
PASS=$(sudo grep ^ETCD_PASSWORD= /root/etcd-credentials.txt | cut -d= -f2-) && \
ETCDCTL_API=3 /usr/local/bin/etcdctl \
--endpoints=http://127.0.0.1:2379 \
--user=sac:${PASS} \
role get sac-rwConnecting from a remote client
The instance listens on 0.0.0.0:2379. At first boot, the advertise URL is published with the instance's public IPv4 address, resolved from EC2 IMDSv2. From any client whose security group opens port 2379, run:
ETCDCTL_API=3 etcdctl \
--endpoints=http://<instance-public-ip>:2379 \
--user=sac:<ETCD_PASSWORD> \
put mykey myvalueFor production traffic on a public client port, we strongly recommend terminating TLS in front of etcd. See the TLS section below.
Security model
- Peer port 2380 is loopback only. A single-node deployment never needs peer traffic on the network, and exposing 2380 to the network is a CVE-class mistake. If you add cluster peers, change this deliberately. See the multi-node section.
- Client port 2379 listens on 0.0.0.0. RBAC enforces security at the etcd layer, and the AWS Security Group enforces it at the network layer. Keep your Security Group locked to the CIDR ranges that need to talk to etcd. Do not open 2379 to
0.0.0.0/0in production. - RBAC is enabled at first boot. A SecureAnyCloud user with readwrite on the / prefix and a separate emergency root user are created with per-instance passwords. The cluster refuses every unauthenticated key-value operation. The /health endpoint stays anonymous so Kubernetes probes work.
Expanding to a multi-node cluster
A single-node etcd suits development, proof-of-concept and small production workloads where the durability of the underlying EC2 instance is acceptable. For a quorum-replicated cluster, etcd recommends 3 or 5 nodes.
Cluster expansion is a runtime operation. Launch additional instances of this AMI, then run etcdctl member add from the existing node to introduce each peer to the cluster.
Before you start each new peer, rewrite its ETCD_LISTEN_PEER_URLS from 127.0.0.1 to the peer's network address, reuse the existing sac-etcd-token, and set ETCD_INITIAL_CLUSTER_STATE=existing. The detailed multi-node guide is in the upstream etcd documentation at https://etcd.io/docs/, and the SecureAnyCloud recipe is fully compatible with it.
Enabling TLS
The image ships with http:// on the client port. To enable TLS:
- Provision a server certificate and private key, for example from your own internal CA or from a public CA such as Let's Encrypt with a DNS challenge.
- Place them at
/etc/etcd/server.crtand/etc/etcd/server.key(mode0640, groupetcd). - Edit
/etc/etcd/etcd.conf. Add theETCD_CERT_FILEandETCD_KEY_FILElines, and changeETCD_LISTEN_CLIENT_URLSandETCD_ADVERTISE_CLIENT_URLSto usehttps://. - Restart the service with
sudo systemctl restart etcd.service.
Your clients then connect to https://<your-public-host>:2379 and pass --cacert=<your-CA-bundle.pem> to etcdctl.
Updating
The image ships with etcd 3.5.30 from the official etcd-io GitHub release. Later versions in the etcd 3.5 line are drop-in compatible. To upgrade, download the new tarball from https://github.com/etcd-io/etcd/releases and verify the SHA-256. Then stop etcd.service, replace /usr/local/bin/etcd and /usr/local/bin/etcdctl, and restart.
The systemd unit, the first-boot scripts and the credentials file are all preserved across binary upgrades.
Screenshots
Support
24/7 technical support is included with this AMI. Email sales@secureanycloud.com or use the chat widget on https://secureanycloud.com/ for help with deployment, RBAC design, cluster expansion, performance tuning, or anything else related to etcd.
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com