etcd集群TLS设置

在完成了初步的 部署etcd集群 之后,可以看到虽然部署了简单的etcd集群,但是etcd集群访问是完全没有安全限制的。所以我们需要将集群改造成使用TLS加密认证访问,以增强安全性。

etcd支持通过TLS协议进行加密通讯,要使用自签名证书启动一个集群,集群的每个成员需要有有一个唯一密钥对( member.crtmember.key )被一个共享的集群CA证书( ca.crt )签名过,这个密钥对用于彼此通讯和客户端连接。

本文实践采用 树莓派堆叠 环境采用3台 树莓派Raspberry Pi 3 硬件部署3节点 etcd - 分布式kv存储 集群:

树莓派k3s管控服务器

主机IP

主机名

192.168.7.11

x-k3s-m-1

192.168.7.12

x-k3s-m-2

192.168.7.13

x-k3s-m-3

在部署 私有云etcd服务 实践记录见 私有云etcd集群TLS设置 (详细记录配置)

etcd集群证书生成

发行版安装cfssl

Ubuntu Linux 发行版提供了 golang-cfssl 软件包,直接提供了 Cloudflare 的 cfssl 工具,所以直接安装非常方便:

sudo apt install golang-cfssl

编译cfssl

Cloudflare提供了一个 cfssl 工具来帮助生成etcd集群的证书。默认生成 ECDSA-384 root和leaf证书给localhost。每个etcd节点使用相同的证书,但不需要客户端证书。

  • 安装 git , go, 和 make

  • 安装cfssl:

    git clone git@github.com:cloudflare/cfssl.git
    cd cfssl
    make
    

编译以后生成的执行文件位于 bin 目录下:

$ tree bin
bin
├── cfssl
├── cfssl-bundle
├── cfssl-certinfo
├── cfssl-newkey
├── cfssl-scan
├── cfssljson
├── mkbundle
├── multirootca
└── rice

备注

macOS的 Homebrew 提供了直接安装的简便方法:

brew install cfssl

备注

也可以使用go直接安装单个命令:

go get -u github.com/cloudflare/cfssl/cmd/cfssl

依次类推,还可以安装cfssljson等工具:

go get -u github.com/cloudflare/cfssl/cmd/cfssljson

证书生成

在设置etcd集群时需要使用3种证书:

  • Client certificate 是服务器用于认证客户端的证书,例如, etcdctl, etcd proxy 或者 docker客户端都需要使用

  • Server certificate 是服务器使用,客户端用来验证服务器真伪的。例如 docker服务器或者kube-apiserver使用这个证书。

  • Peer certificate 是etcd服务器成员彼此通讯的证书。

初始化证书认证

  • 首先需要在合适的子目录下默认 cfssl 选项:

保存默认cfssl选项脚本 cfssl_options.sh
mkdir ~/cfssl
cd ~/cfssl
cfssl print-defaults config > ca-config.json
cfssl print-defaults csr > ca-csr.json
  • 配置CA选项 - 修改 ca-config.json 配置文件:

    • profiles 部分: www 默认 server auth (TLS Web服务器认证) 是 X509 V3扩展,并且 client auth (TLS Web客户端认证) 是 X509 V3扩展

    • expiry : 默认是 8760h 过期(即365天)

修改延长为10年:

修订证书有效期10年 ca-config.json
{
    "signing": {
        "default": {
            "expiry": "87600h"
        },
        "profiles": {
            "server": {
                "expiry": "87600h",
                "usages": [
                    "signing",
                    "key encipherment",
                    "server auth",
                    "client auth"
                ]
            },
            "client": {
                "expiry": "87600h",
                "usages": [
                    "signing",
                    "key encipherment",
                    "client auth"
                ]
            },
            "peer": {
                "expiry": "87600h",
                "usages": [
                    "signing",
                    "key encipherment",
                    "server auth",
                    "client auth"
                ]
            }
        }
    }
}

备注

这里CA配置中, "server" 段落必须要添加 "client auth" ,否则高版本etcd启动时会提示连接错误。详见 部署TLS认证的etcd集群

  • 配置CSR(Certificate Signing Request)配置文件 ca-csr.json :

修订CSR ca-csr.json
{
    "CN": "edge k3s etcd",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "Shanghai",
            "O": "huatai.me",
            "ST": "cloud-atlas",
            "OU": "edge"
        }
    ]
}
  • 使用上述配置定义生成CA:

生成CA
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -

这样将获得3个文件:

ca-key.pem
ca.csr
ca.pem

警告

请确保 ca-key.pem 文件安全,该文件是CA可以创建任何证书

  • 生成服务器证书:

    cfssl print-defaults csr > server.json
    

然后我们需要修订这个 server.json 来满足我们的配置:

修订 server.json
{
    "CN": "edge k3s etcd",
    "hosts": [
        "etcd.edge.huatai.me",
        "192.168.7.11",
        "192.168.7.12",
        "192.168.7.13",
        "127.0.0.1"
    ],
    "key": {
        "algo": "ecdsa",
        "size": 256
    },
    "names": [
        {
            "C": "CN",
            "L": "Shanghai",
            "ST": "cloud-atlas"
        }
    ]
}
  • 现在可以生成服务器证书和私钥:

生成服务器证书和私钥
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server server.json | cfssljson -bare server

这样获得3个文件:

server-key.pem
server.csr
server.pem
  • 生成peer certificate (每个服务器一个,按对应主机名):

    cfssl print-defaults csr > x-k3s-m-1.json
    

然后修订这个 x-k3s-m-1.json

服务器 x-k3s-m-1.edge.huatai.me 点对点证书
{
    "CN": "x-k3s-m-1",
    "hosts": [
        "x-k3s-m-1.edge.huatai.me",
        "x-k3s-m-1",
        "192.168.7.11",
        "127.0.0.1"
    ],
    "key": {
        "algo": "ecdsa",
        "size": 256
    },
    "names": [
        {
            "C": "CN",
            "L": "Shanghai",
            "ST": "cloud-atlas"
        }
    ]
}

重复上述步骤,对应创建第2和第3个主机对应配置

服务器 x-k3s-m-2.edge.huatai.me 点对点证书
{
    "CN": "x-k3s-m-2",
    "hosts": [
        "x-k3s-m-2.edge.huatai.me",
        "x-k3s-m-2",
        "192.168.7.12",
        "127.0.0.1"
    ],
    "key": {
        "algo": "ecdsa",
        "size": 256
    },
    "names": [
        {
            "C": "CN",
            "L": "Shanghai",
            "ST": "cloud-atlas"
        }
    ]
}
服务器 x-k3s-m-3.edge.huatai.me 点对点证书
{
    "CN": "x-k3s-m-3",
    "hosts": [
        "x-k3s-m-3.edge.huatai.me",
        "x-k3s-m-3",
        "192.168.7.13",
        "127.0.0.1"
    ],
    "key": {
        "algo": "ecdsa",
        "size": 256
    },
    "names": [
        {
            "C": "CN",
            "L": "Shanghai",
            "ST": "cloud-atlas"
        }
    ]
}

对应生成3个主机的服务器证书:

生成3个主机的点对点证书
for sn in `seq 3`; do
    cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=peer x-k3s-m-${sn}.json | cfssljson -bare x-k3s-m-${sn}
done

此时获得对应文件是:

x-k3s-m-1-key.pem
x-k3s-m-1.csr
x-k3s-m-1.pem
...
  • 生成客户端证书:

    cfssl print-defaults csr > client.json
    

修订 client.json (主要是主机列表保持空):

修订 client.json
{
    "CN": "edge k3s etcd client",
    "hosts": [""],
    "key": {
        "algo": "ecdsa",
        "size": 256
    },
    "names": [
        {
            "C": "CN",
            "L": "Shanghai",
            "ST": "cloud-atlas"
        }
    ]
}
  • 现在可以生成客户端证书:

生成客户端证书
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client client.json | cfssljson -bare client

获得了以下文件:

client-key.pem
client.csr
client.pem

参考