双向加密认证etcd集群的部署
本文最后更新于:August 27, 2024 pm
本文主要介绍如何手动部署高可用的双向加密认证etcd集群。
思路
这里我们大概介绍一下部署一个etcd集群的思路,如果是不使用证书加密可以跳过配置证书的环节
- 检查机器环境,确定etcd使用的端口是默认的2379还是说需要使用自定义端口
- 初始化环境,创建对应的数据存储目录和证书存储目录
- 拉取CA证书,或者手动签发CA证书,随后使用CA证书签发对应的client证书、server证书和peer证书
- 配置systemd unit文件
- 拉取etcd二进制文件
- 启动etcd服务,查看集群状态
定义环境变量
在开始部署etcd集群之前,我们需要确定在部署过程中用到的各种变量和目录。
首先是etcd本身需要使用到的三个端口,etcd 使用三个端口进行通信和提供服务:
1. 客户端端口 (Client Port):
- 作用: 用于与 etcd 客户端进行通信,例如 etcdctl 命令行工具、应用程序等。客户端通过该端口连接到 etcd 集群,进行数据读写、键值存储、服务发现等操作。
- 默认端口: 2379
2. 对等节点端口 (Peer Port):
- 作用: 用于 etcd 集群内部节点之间进行通信,例如选举领导者、同步数据、心跳检测等。
- 默认端口: 2380
3. metrics 端口 (Metrics Port):
- 作用: 用于暴露 etcd 集群的运行指标数据,例如请求数量、延迟、存储大小等。可以通过 Prometheus 等监控系统收集和展示这些指标数据。
- 默认端口: 2381
使用 shell 定义环境变量:
1 |
|
另外就是我们需要定义一个用于存储etcd的证书目录和数据目录
1 |
|
最后就是定义我们这次搭建集群需要用到的三个机器ip
1 |
|
初始化环境
开始之前我们在这次集群用到的三台机器上面配置对应的环境变量并创建目录
1 |
|
配置CA证书
配置私钥
不论是哪种方式配置CA证书,我们都需要先生成一个私钥。
1 |
|
配置CSR
我们继续配置CSR证书,注意CSR证书并不是必须的,很多流程中都会省略
1 |
|
上面的这个 OpenSSL 命令用于生成一个自签名证书的证书签名请求 (CSR)。
参数解析:
openssl req
: 调用 OpenSSL 工具集中的req
命令,用于处理证书请求。-new
: 生成一个新的证书请求。-key ca-key.pem
: 指定用于签署 CSR 的私钥文件。这里使用的是名为ca-key.pem
的私钥文件,应该是您预先生成的。-out ca.csr
: 指定生成的 CSR 文件的输出路径和文件名。这里将生成名为ca.csr
的 CSR 文件。-subj "/CN=TC Test CA/O=tinychen"
: 指定证书主题信息,采用 X.509 证书规范的格式。/CN=TC Test CA
: 通用名称 (Common Name),通常是域名或服务器主机名,这里”TC Test CA”表示 “tinychen test ca”。/O=tinychen
: 组织 (Organization) 名称,这里也就是 “tinychen”。
配置CA证书
最后我们来生成一个ca证书
1 |
|
这个 OpenSSL 命令使用之前生成的 CSR (ca.csr) 和私钥 (ca-key.pem) 来生成一个自签名的 CA 证书 (ca.crt)。
参数解析:
openssl x509
: 调用 OpenSSL 工具集中的x509
命令,用于处理 X.509 证书。-req
: 指定输入文件是一个证书签名请求 (CSR)。-in ca.csr
: 指定要使用的 CSR 文件名为ca.csr
。-signkey ca-key.pem
: 指定用于签署证书的私钥文件为ca-key.pem
。-out ca.crt
: 指定生成的证书文件名为ca.crt
。-days 36500
: 设置证书的有效期为 36500 天 (大约 100 年)。-extensions v3_ca
: 指定要添加到证书的扩展信息来自配置文件中的v3_ca
段。-extfile <(cat << EOF ... EOF)
: 使用 Here Document 将扩展信息配置传递给 OpenSSL。
Here Document 中的扩展信息配置:
[v3_ca]
: 定义一个名为v3_ca
的扩展信息段。basicConstraints = critical,CA:TRUE
: 设置基本约束扩展,表明这是一个 CA 证书,可以用于签发其他证书。critical
标记表示这是一个关键扩展,必须被识别和遵守。keyUsage = critical, cRLSign, keyCertSign
: 设置密钥用法扩展,指定该证书可以用于签署证书吊销列表 (CRL) 和签发其他证书。subjectKeyIdentifier = hash
: 设置主题密钥标识符扩展,使用证书公钥的哈希值作为标识符。
复制CA证书
不论我们使用的是单向认证还是双向认证,最后集群内的所有节点,使用的ca证书应该都是一致的,因此我们在其中一台机器生成ca证书之后,可以将其复制到对应剩余的机器上面。这里以rsync为例进行复制。
1 |
|
关于CSR证书
使用 OpenSSL 生成 CA 证书,我们可以选择使用 CSR(证书签名请求)或直接生成自签名证书。两种方法都需要先生成一个私钥。
使用 CSR 生成 CA 证书
这种方法更常见,因为它将私钥的生成和证书请求的创建分离,提高了安全性。
步骤:
生成私钥:
1
openssl genrsa -out ca-key.pem 2048
这将生成一个 2048 位的 RSA 私钥,并将其保存到
ca-key.pem
文件中。创建证书签名请求 (CSR):
1
openssl req -new -key ca-key.pem -out ca.csr -subj "/CN=MyCA/O=MyOrganization"
这将使用私钥生成一个 CSR,并将其保存到
ca.csr
文件中。-subj
参数用于指定证书主题信息,例如通用名称 (CN) 和组织 (O)。生成自签名 CA 证书:
1
2
3
4
5
6
7openssl x509 -req -in ca.csr -signkey ca-key.pem -out ca.crt -days 3650 -extensions v3_ca -extfile <(cat << EOF
[ v3_ca ]
basicConstraints = critical,CA:TRUE
keyUsage = critical, cRLSign, keyCertSign
subjectKeyIdentifier = hash
EOF
)这将使用 CSR 和私钥生成一个自签名 CA 证书,并将其保存到
ca.crt
文件中。-days
参数指定证书的有效期,-extensions
和-extfile
参数用于添加必要的 CA 扩展信息。
直接生成自签名 CA 证书
这种方法将私钥生成和证书创建合并到一个步骤中,更加方便,但安全性稍低。
步骤:
1 |
|
这将生成一个 2048 位的 RSA 私钥,并使用该私钥直接生成一个自签名 CA 证书,并将它们分别保存到 ca-key.pem
和 ca.crt
文件中。
关于 CSR 的必要性:
- 安全性: 使用 CSR 可以将私钥的生成和证书请求的创建分离,提高安全性。私钥始终保存在您的本地机器上,不会被发送到 CA 服务器。
- 灵活性: CSR 可以用于向不同的 CA 服务器申请证书,而无需每次都重新生成私钥。
证书文件
无论我们选择哪种方式生成 CA 证书,最终都会生成两个关键文件:
私钥文件 (例如 ca-key.pem):
作用: 这是 CA 的私钥,用于签署证书和证书吊销列表 (CRL)。私钥必须严格保密,因为它可以用来伪造证书。
查看内容: 由于私钥文件包含敏感信息,不建议直接查看其内容。如果需要查看私钥信息,可以使用以下命令:
1
openssl rsa -in ca-key.pem -text -noout
注意: 执行此命令时,请确保您位于安全的终端环境中,并且不要将私钥信息泄露给他人。
证书文件 (例如 ca.crt):
作用: 这是 CA 的证书,包含 CA 的公钥、主题信息、有效期、扩展信息等。证书可以公开分享,用于验证由该 CA 签发的其他证书。
查看内容: 我们可以使用以下命令查看证书的详细信息:
1
openssl x509 -in ca.crt -text -noout
该命令会以文本格式输出证书的详细信息,包括版本号、序列号、签名算法、颁发者、主题、有效期、公钥信息、扩展信息等。
证书签名请求文件 (例如 ca.csr)
准确地说,CSR 不是证书,而是一个 **证书签名请求 (Certificate Signing Request)**。它本身并没有实际证书的功能,而是用于向证书颁发机构 (CA) 申请证书。
CSR 的作用可以概括为:
- 包含公钥信息: CSR 文件包含申请者生成的公钥信息,以及一些身份识别信息,例如域名、组织名称等。
- 请求 CA 签名: 将 CSR 文件提交给 CA 后,CA 会验证申请者的身份信息,并使用其私钥对 CSR 文件中的信息进行签名。
- 生成证书的基础: CA 签署后的 CSR 文件会生成最终的证书文件,其中包含了申请者的公钥信息以及 CA 的数字签名,用于证明证书的合法性和可信度。
简单来说,CSR 就像一张申请表,您填写好个人信息和需求(公钥),提交给相关部门(CA)审核签字,最终获得正式的文件(证书)。
查看 CSR 文件内容的命令:
1 |
|
openssl req
: 调用 OpenSSL 工具集中的req
命令,用于处理证书请求。-in ca.csr
: 指定要查看的 CSR 文件名为ca.csr
。-text
: 以文本格式输出 CSR 文件的内容。-noout
: 不输出编码后的请求信息,只输出解析后的文本信息。
CSR 文件内容解析:
执行上述命令后,我们会看到类似以下内容的输出:
1 |
|
主要信息包括:
- Version: 证书请求的版本号。
- Subject: 请求证书的实体信息,例如您的通用名称 (CN) 和组织 (O)。
- Subject Public Key Info: 与私钥配对的公钥信息,包括算法和公钥值。
- Attributes: 其他可选属性,例如证书扩展信息。
- Signature Algorithm: 用于对证书请求进行签名的算法。
- Signature: 对证书请求信息的数字签名。
小结
- 对于测试环境或个人使用,直接生成自签名 CA 证书更为方便。
- 使用 CSR 生成 CA 证书可以提高安全性,对于生产环境或需要更高安全性的场景,建议使用 CSR 生成 CA 证书。
- 私钥文件 (ca-key.pem) 包含 CA 的私钥,必须严格保密。
- 证书文件 (ca.crt) 包含 CA 的公钥和其他信息,可以公开分享。
生成server证书
生成服务器私钥:
1 |
|
创建服务器证书签名请求 (CSR):
该命令使用指定的私钥和主题信息生成一个 CSR 文件,并添加了三个 IP 地址作为 SAN 扩展信息。生成的 CSR 文件可以提交给 CA 进行签名,最终获得包含指定主题信息和 SAN 扩展信息的证书。
1 |
|
这是一个使用 OpenSSL 命令行工具生成证书签名请求 (CSR) 的命令,让我们逐步解析:
命令主体:
openssl req
: 调用 OpenSSL 工具的 req 命令,用于处理证书请求。-new
: 指示 OpenSSL 生成一个新的 CSR。-key server-key.pem
: 指定用于签署 CSR 的私钥文件路径,这里是server-key.pem
。-out server.csr
: 指定生成的 CSR 文件的输出路径和文件名,这里是server.csr
。-subj "/C=CN/ST=GuangDong/L=Guangzhou/O=system:server/OU=TC/CN=server"
: 指定 CSR 中包含的主题信息,采用 X.509 证书规范:C=CN
: 国家代码,这里是中国 (CN)。ST=GuangDong
: 州/省份名称,这里是广东。L=Guangzhou
: 城市名称,这里是广州。O=system:server
: 组织名称,这里是 “system:server”。OU=Shopee
: 组织单位名称,这里是 “TC”。CN=server
: 通用名称,通常是域名或服务器主机名,这里是 “server”。
扩展信息:
-reqexts SAN
: 指定要添加的证书扩展信息,这里是SAN
(Subject Alternative Name),用于添加额外的域名或 IP 地址。-config <(cat << EOF ... EOF)
: 使用内联文档的方式指定 OpenSSL 配置文件内容,主要用于配置 SAN 扩展信息。
配置文件内容:
1 |
|
[req]
: 定义与证书请求相关的配置。distinguished_name = req_distinguished_name
: 指定使用名为req_distinguished_name
的节来配置主题信息。[req_distinguished_name]
: 定义主题信息的配置,这里留空,表示使用命令行中-subj
参数指定的主题信息。[SAN]
: 定义 SAN 扩展信息的配置。subjectAltName=IP:$etcd1,IP:$etcd2,IP:$etcd3
: 指定要添加的 SAN 信息,这里是三个 IP 地址,分别存储在环境变量$etcd1
、$etcd2
和$etcd3
中。
使用 CA 证书签发服务器证书
1 |
|
解释:
basicConstraints = critical, CA:FALSE
:critical
: 表示这是一个关键扩展,如果证书使用者不支持该扩展,则必须拒绝该证书。CA:FALSE
: 表示该证书不能用作证书颁发机构 (CA)。
keyUsage = critical, digitalSignature, keyEncipherment
:critical
: 表示这是一个关键扩展。digitalSignature
: 表示该证书可以用于数字签名。keyEncipherment
: 表示该证书可以用于密钥加密。
extendedKeyUsage = clientAuth, serverAuth
:clientAuth
: 表示该证书可以用于 TLS Web 客户端身份验证。serverAuth
: 表示该证书可以用于 TLS Web 服务器身份验证。
subjectAltName = @alt_names
: 指定证书主题备用名称 (SAN),包括 DNS 名称和 IP 地址。
注意:
- 请将
alt_names
部分中的 DNS 名称和 IP 地址替换为我们使用的实际值。 - 使用此配置文件生成证书时,请确保使用
-extensions v3_req -extfile server-ext.cnf
参数。
X509v3 Authority Key Identifier
(AKI) 是一个重要的证书扩展,它可以提高证书验证的效率和安全性。1. AKI 的作用:
- 标识签发 CA: AKI 扩展包含签发该证书的 CA 的唯一标识信息,通常是 CA 证书的密钥标识符 (Key Identifier) 或主体密钥标识符 (Subject Key Identifier)。
- 加速证书验证: 当验证证书时,客户端可以使用 AKI 扩展快速找到签发 CA 的证书,而无需遍历整个证书链,从而提高验证速度。
- 防止证书替换攻击: 攻击者可能会尝试使用自己的 CA 签发伪造的证书,并替换掉合法的证书。AKI 扩展可以帮助检测这种攻击,因为伪造的证书的 AKI 信息会与合法证书不匹配。
2. 如何配置 AKI:
在使用 OpenSSL 生成证书时,通常不需要手动配置 AKI 扩展,因为 OpenSSL 会自动根据 CA 证书生成正确的 AKI 信息。
- CA 证书: 在生成 CA 证书时,OpenSSL 会自动生成
Subject Key Identifier
扩展,并将其作为 AKI 信息包含在 CA 证书中。- 最终实体证书: 在使用 CA 证书签发其他证书时,OpenSSL 会自动将 CA 证书的
Subject Key Identifier
提取出来,作为 AKI 信息包含在最终实体证书中。3. 手动配置 AKI (可选):
如果您需要手动配置 AKI 扩展,可以使用
-ext
参数和配置文件。例如,以下命令使用server-ext.cnf
文件中的aki
扩展来生成服务器证书:
server-ext.cnf
文件中的aki
扩展配置如下:
1
2
[ v3_req ]
authorityKeyIdentifier=keyid:always这将强制 OpenSSL 在生成的服务器证书中包含 AKI 扩展,并将
keyid
设置为always
,表示始终使用 CA 证书的Subject Key Identifier
作为 AKI 信息。小结:
- AKI 扩展可以提高证书验证的效率和安全性。
- OpenSSL 通常会自动处理 AKI 扩展,无需手动配置。
- 您可以根据需要手动配置 AKI 扩展,例如指定特定的密钥标识符或禁用 AKI 扩展。
生成client证书
client证书的配置过程和前面的server证书一样,这里就不再赘述。
1 |
|
生成peer证书
peer证书的配置过程也和前面二者一样,这里就不再赘述。
1 |
|
关于证书
三台机器的所有证书文件都要一模一样吗?
在部署 etcd 集群时,证书文件的使用方式取决于我们选择的认证方式和安全需求。
1. 单向认证:
- 仅服务器需要证书: 如果只使用单向 TLS 认证(即只有服务器需要提供证书),那么三台机器的
ca.crt
文件需要一致,而server.crt
和server.key
文件则必须不同,每个节点都需要使用自己的证书和私钥。 - 客户端不需要证书: 客户端可以使用服务器的公钥证书 (
server.crt
) 来验证服务器的身份,但不需要提供自己的证书。
2. 双向认证:
- 所有节点都需要不同证书: 如果使用双向 TLS 认证(即客户端和服务器都需要提供证书),那么三台机器的
ca.crt
文件需要一致,而server.crt
、server.key
、peer.crt
和peer.key
文件都必须不同,每个节点都需要使用自己独特的证书和私钥。 - 客户端需要证书: 客户端需要提供自己的证书和私钥来进行身份验证。
总结:
ca.crt
: 所有节点都需要使用相同的 CA 证书。server.crt
,server.key
: 每个节点都需要使用自己独特的服务器证书和私钥。peer.crt
,peer.key
: 如果使用双向认证,每个节点都需要使用自己独特的 peer 证书和私钥。
建议:
为了提高安全性,建议在部署 etcd 集群时使用双向 TLS 认证,并为每个节点生成唯一的证书和私钥。
下载etcd
etcd和etcdctl一般都在同样的地方,我们可以一并下载安装配置
1 |
|
从GitHub上面的官方release页面我们可以找到并下载最新的etcd二进制文件,然后我们可以将解压后的文件放到我们需要使用的目录中,本文以常用的/usr/local/bin/
为例
1 |
|
配置systemd
配置环境变量
1 |
|
unit file
然后这里要配置systemd文件
1 |
|
这里对上面的systemd unit文件做一个简单介绍:
[Unit] 部分
- Description: 对服务的简短描述,这里描述为 “etcd - highly-available key value store”。
- Documentation: 指向服务文档的链接,这里提供了 etcd 的 GitHub 页面和 man 手册链接。
- After=network.target: 指定 etcd 服务在
network.target
之后启动,确保网络已就绪。 - Wants=network-online.target: 表示 etcd 服务希望
network-online.target
能够启动,但即使后者失败,etcd 也会继续启动。
[Service] 部分
- Type=simple: 指定服务类型为简单类型,即启动一个守护进程,并由 systemd 直接管理。
- User=root: 指定以 root 用户身份运行服务。
- PermissionsStartOnly=true: 表示仅在启动服务时需要提升权限,启动后会放弃权限。
- ExecStart: 指定启动服务的命令行,这里包含了 etcd 的可执行文件路径和一系列参数:
/usr/local/bin/etcd
: etcd 可执行文件的路径,可以根据实际安装路径修改。--name $etcd_role
: 指定 etcd 节点的角色名称,通常使用主机名或其他唯一标识符。--quota-backend-bytes=8589934592
: 设置 etcd 后端存储空间配额,单位为字节,这里设置为 8GB。--initial-advertise-peer-urls https://$local_ip:$ETCD_PEER_PORT
: 指定 etcd 节点用于与其他节点通信的地址和端口,使用 HTTPS 协议。--listen-peer-urls https://$local_ip:$ETCD_PEER_PORT
: 指定 etcd 节点监听其他节点连接的地址和端口,使用 HTTPS 协议。--listen-client-urls https://$local_ip:$ETCD_CLIENT_PORT,https://127.0.0.1:$ETCD_CLIENT_PORT
: 指定 etcd 节点监听客户端连接的地址和端口,可以使用多个地址,使用 HTTPS 协议。--advertise-client-urls https://$local_ip:$ETCD_CLIENT_PORT
: 指定 etcd 节点向客户端公布的地址和端口,使用 HTTPS 协议。--initial-cluster etcd1=https://$etcd1:$ETCD_PEER_PORT,etcd2=https://$etcd2:$ETCD_PEER_PORT,etcd3=https://$etcd3:$ETCD_PEER_PORT
: 指定 etcd 集群中所有节点的地址和端口,使用 HTTPS 协议。--cert-file=$ETCD_CERTS_DIR/server.pem
: 指定 etcd 服务端证书文件路径。--key-file=$ETCD_CERTS_DIR/server-key.pem
: 指定 etcd 服务端私钥文件路径。--peer-cert-file=$ETCD_CERTS_DIR/peer.pem
: 指定 etcd 节点间通信使用的证书文件路径。--peer-key-file=$ETCD_CERTS_DIR/peer-key.pem
: 指定 etcd 节点间通信使用的私钥文件路径。--trusted-ca-file=$ETCD_CERTS_DIR/ca.crt
: 指定 etcd 信任的 CA 证书文件路径。--peer-trusted-ca-file=$ETCD_CERTS_DIR/ca.crt
: 指定 etcd 节点间通信信任的 CA 证书文件路径。--peer-client-cert-auth
: 启用节点间通信的客户端证书认证。--client-cert-auth
: 启用客户端连接的证书认证。--initial-cluster-token etcd-cluster
: 指定 etcd 集群的初始令牌,用于标识集群。--initial-cluster-state new
: 指定 etcd 集群的初始状态为new
,表示这是一个新的集群。--listen-metrics-urls=http://0.0.0.0:$METRICS_PORT
: 指定 etcd 监听指标数据的地址和端口,使用 HTTP 协议。--auto-compaction-retention=1h
: 设置 etcd 自动压缩历史数据的保留时间,这里设置为 1 小时。--metrics=extensive
: 设置 etcd 收集的指标数据级别为extensive
,表示收集更详细的指标数据。--data-dir=$ETCD_DATA_DIR
: 指定 etcd 数据存储目录路径。
- LimitNOFILE=655360: 设置 etcd 进程可以打开的最大文件描述符数量。
- KillMode=process: 指定停止服务时,仅杀死主进程,不杀死子进程。
- Restart=always: 指定服务在退出时自动重启,无论退出原因是什么。
- RestartSec=20: 指定服务重启的间隔时间,这里设置为 20 秒。
[Install] 部分
- WantedBy=multi-user.target: 指定服务在
multi-user.target
运行级别启动,这是一个通用的多用户运行级别。
--initial-cluster-state
参数用于指定 etcd 集群的初始状态,它有两个可选值:
- new: 表示这是一个全新的集群,所有节点都将参与选举,选出一个 leader 节点,并初始化集群数据。
- existing: 表示这是一个已经存在的集群,新加入的节点将不会参与选举,而是从现有的 leader 节点同步数据。
使用场景:
- 创建新集群: 当你第一次部署 etcd 集群时,应该将所有节点的
--initial-cluster-state
参数都设置为new
,以便它们能够选举 leader 并初始化集群。- 添加新节点: 当你向一个已经存在的 etcd 集群添加新节点时,应该将新节点的
--initial-cluster-state
参数设置为existing
,以便它能够从 leader 节点同步数据,而不会影响集群的正常运行。- 灾难恢复: 当 etcd 集群中的所有节点都不可用时,你可以使用
--initial-cluster-state=new
参数从备份数据中恢复集群。注意事项:
- 如果你将一个已经存在的集群的
--initial-cluster-state
参数设置为new
,那么所有节点都将认为这是一个全新的集群,并尝试选举 leader,这会导致数据丢失和服务中断。- 确保所有节点的
--initial-cluster
参数配置一致,否则会导致集群无法正常工作。总结:
--initial-cluster-state
参数是 etcd 集群初始化过程中非常重要的一个参数,它决定了集群的初始状态和节点的行为。在配置 etcd 集群时,务必根据实际情况选择正确的参数值,以避免数据丢失和服务中断。
cipher-suite
这里则是作为可选部分,调整etcd使用的加密算法从而进一步提高安全性,但是同时需要注意客户端侧的兼容性,并非强制需求配置。
1 |
|
检查集群
完成之后我们重启服务检查集群状态
1 |
|
当然我们还可以使用etcdctl
命令来查看更详细的集群信息
1 |
|
其他的更多指令操作和内容,我们后面再慢慢探索吧。