介绍
Consul 是一个服务发现工具,可用于轻松发现和跟踪整个基础架构中各种服务的健康状况。 您可以使用 consul 来管理您的服务并维护一个分布式检查系统,以确保您可以在应用程序或服务器出现故障时做出响应。
在 上一篇指南 中,我们专注于建立一个可用于生产的环境并做好准备。 这包括创建将在启动时读取的配置文件和启动脚本以实际启动服务。
这使我们大部分时间都完成了最终的基本配置,但我们还没有完全保护我们的配置。 我们实现了一个简单的共享秘密解决方案,它很容易加密我们的八卦协议。
但是,此时 RPC 通信仍然是完全未加密的。 为了解决这个问题,consul 原生支持 TLS 加密,我们将在本指南中重点介绍。 为了实现这一点,我们必须创建一个证书颁发机构,并对我们的节点签名和分发密钥。
先决条件和目标
在完成本指南之前,您应该设置一个 consul 服务器系统,就像我们在上一篇关于 设置生产就绪的 consul 基础架构 的指南中留下的那样。
我们为该指南使用的服务器具有以下属性:
主机名 | IP地址 | 角色 |
---|---|---|
server1.example.com | 192.0.2.1 | 引导领事服务器 |
server2.example.com | 192.0.2.2 | 领事服务器 |
server3.example.com | 192.0.2.3 | 领事服务器 |
agent1.example.com | 192.0.2.50 | 领事客户 |
这些是 64 位 Ubuntu 14.04 服务器。 请注意,这些服务器中的每一个都位于同一个域中。 这对于我们在本指南中实施的配置很重要,因为我们将利用与域内任何主机匹配的通配符证书。
在本指南中,我们将专注于创建 TLS 证书颁发机构,以便为我们的每台服务器签署证书。 这将允许 consul 组件验证身份并加密流量。 然后我们将稍微修改配置文件以强制我们的节点加密流量。
创建 SSL 结构
首先,我们将设置一些用于管理密钥的基本文件和目录。
同样,我们将在根 shell 中执行本指南中的所有过程。 要么以 root 身份登录,要么以具有 sudo 权限的用户身份使用 sudo -i
。
在您的每个领事成员上,在 /etc/consul.d
目录中创建一个 ssl
目录。 这是我们将保存用于加密 RPC 流量的必要文件的地方:
mkdir /etc/consul.d/ssl
在您计划用作证书颁发机构的服务器上,我们将在此目录中创建一个子目录来存放创建和签署证书所需的所有文件。 我们可以选择我们的任何服务器来容纳证书颁发机构,但出于我们的目的,我们将使用也容纳引导配置的 server1
。
在这台服务器上,在我们刚刚创建的目录下创建一个名为 CA
的子目录:
mkdir /etc/consul.d/ssl/CA
这将包含一些我们可能不希望其他人访问的敏感数据,所以让我们锁定权限:
chmod 0700 /etc/consul.d/ssl/CA
移至 CA 服务器上的此目录。
cd /etc/consul.d/ssl/CA
在这里,我们将创建一些需要为我们的证书签名提供的基本文件。 首先,我们需要创建一个文件,该文件将随着证书的下一个可用序列号递增。 我们需要预先设置一个值。
为此,将 000a
的值回显到串行文件:
echo "000a" > serial
我们还需要提供一个文件,我们的证书颁发机构可以在其中记录它签署的证书。 我们将此文件称为 certindex
:
touch certindex
创建自签名根证书
要开始使用我们的证书颁发机构,我们需要做的第一步是创建一个自签名根证书。 我们可以使用默认安装在 Ubuntu 机器上的 openssl
命令来做到这一点。
我们将用来创建证书的命令是:
openssl req -x509 -newkey rsa:2048 -days 3650 -nodes -out ca.cert
让我们回顾一下这意味着什么:
- req:此参数告诉 openssl 您有兴趣通过创建或处理请求来操作 PKCS#10 证书。
- -x509:此参数指定您想要自签名证书而不是证书请求。 这通常用于根 CA 证书。
- -newkey rsa:2048:这告诉 openssl 生成一个新的证书请求和私钥。 我们向它传递一个参数,指定我们想要一个 2048 位的 RSA 密钥。
- -days 3650:在这里,我们指定证书被认为有效的天数。 我们使用的值为
3650
,即 10 年。 - -nodes:这指定生成的私钥不会使用 DES 加密,这需要密码。 这避免了该要求。
- -out ca.cert:设置将用于生成的证书文件的文件名。
在证书创建过程中,系统将提示您输入有关您正在认证的主机的信息。 您可以使用您想要的有关服务器的任何相关信息填写此信息:
. . . Country Name (2 letter code) [AU]:US State or Province Name (full name) [Some-State]:New York Locality Name (eg, city) []:New York City Organization Name (eg, company) [Internet Widgits Pty Ltd]:DigitalOcean Organizational Unit Name (eg, section) []: Common Name (e.g. server FQDN or YOUR name) []:ConsulCA Email Address []:admin@example.com
对于我们其他证书中很重要的Common Name
,你可以放任何你想要的东西。
完成后,您应该有一个 ca.cert
证书文件,以及一个名为 privkey.pem
的关联密钥。
创建通配符证书签名请求
现在我们有了根 CA 证书,我们可以为我们的客户端机器生成一个证书签名请求。
在这种情况下,我们所有的领事成员都是客户,包括我们现在正在运行的服务器。 我们将创建一个通配符证书,它对我们域中的任何主机都有效,而不是为每个服务器生成一个唯一的证书并使用我们的 CA 对其进行签名。
命令的一般格式将相同,但有一些细微差别:
openssl req -newkey rsa:1024 -nodes -out consul.csr -keyout consul.key
我们创建的自签名根 CA 证书请求与我们现在生成的新证书签名请求之间的区别如下:
- no -x509 flag:我们删除了
-x509
标志,以便生成证书签名请求而不是自签名证书。 - -out consul.csr:输出的文件不是证书本身,而是证书签名请求。
- -keyout consul.key:我们已经指定了与证书签名请求关联的密钥的名称。
同样,系统将提示我们对证书签名请求 (CSR) 的响应。 这比我们为自签名根 CA 证书提供的答案更重要。 在这里,我们需要使用通配符 Common Name
以使我们的证书检查为对我们的每个主机都有效:
. . . Country Name (2 letter code) [AU]:US State or Province Name (full name) [Some-State]:New York Locality Name (eg, city) []:New York City Organization Name (eg, company) [Internet Widgits Pty Ltd]:DigitalOcean Organizational Unit Name (eg, section) []: Common Name (e.g. server FQDN or YOUR name) []:*.example.com Email Address []:admin@example.com Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []:
正如您在此处看到的,我们使用了我们的域,用星号作为主机来表示证书应该被认为对域内的任何主机都有效。 您可以安全地跳过添加到末尾的质询密码和可选公司名称提示。
创建证书颁发机构配置文件
现在,我们有了自签名的根 CA 证书文件和一个匹配域中所有主机的通配符证书签名请求。 在我们可以使用我们的 CA 证书签署签名请求之前,我们需要创建一个配置文件来控制这种情况如何发生。
我们将调用我们正在创建的文件 myca.conf
来保存我们的 CA 信息。 现在打开这个文件:
nano /etc/consul.d/ssl/CA/myca.conf
此文件使用 INI 格式 分为多个部分。 我们将定义的第一部分是 ca
部分。 我们在这里要做的唯一一件事就是使用实际的 CA 信息指向我们的用户定义部分:
[ ca ] default_ca = myca
接下来,我们将创建刚刚引用的部分。 这将包含大部分 CA 配置详细信息。
我们将指定输入到证书提示中的信息不必是唯一的。 然后,我们将给出我们创建的签名过程所需的所有文件的位置。 我们将告诉 openssl
将新证书放在当前目录中。
我们还想选择一些在命令行上没有指定替代方案时使用的默认值。 我们将选择有效期为 10 年的签名证书,并将使用 sha1
算法。 最后,我们将指出我们将创建的一些附加部分以定义附加信息:
[ myca ] unique_subject = no new_certs_dir = . certificate = ca.cert database = certindex private_key = privkey.pem serial = serial default_days = 3650 default_md = sha1 policy = myca_policy x509_extensions = myca_extensions
现在,让我们关注我们刚刚引用的第一个用户定义部分,它用于决定需要提供哪些信息才能使 CSR 被接受。 我们将把一些字段标记为必填,而另一些则标记为可选。 我们将为通常的提示做出一些非常标准的选择:
[ myca_policy ] commonName = supplied stateOrProvinceName = supplied countryName = supplied emailAddress = optional organizationName = supplied organizationalUnitName = optional
最后一部分将定义我们在签署证书时要使用的 x509 扩展。
首先,我们需要告诉它我们要签名的证书不是 CA 证书。 我们将使用标准值“散列”作为主题键标识符,因为强烈建议不要使用十六进制字符串(替代方案)。
我们将授权密钥标识符设置为“keyid”以从父证书复制主题密钥标识符。 我们还将指定密钥可以用作签名或与加密密钥的协议一起使用。 我们将指定密钥的扩展用途可以用于服务器和客户端身份验证:
[ myca_extensions ] basicConstraints = CA:false subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always keyUsage = digitalSignature,keyEncipherment extendedKeyUsage = serverAuth,clientAuth
总之,文件看起来像这样:
[ ca ] default_ca = myca [ myca ] unique_subject = no new_certs_dir = . certificate = ca.cert database = certindex private_key = privkey.pem serial = serial default_days = 3650 default_md = sha1 policy = myca_policy x509_extensions = myca_extensions [ myca_policy ] commonName = supplied stateOrProvinceName = supplied countryName = supplied emailAddress = optional organizationName = supplied organizationalUnitName = optional [ myca_extensions ] basicConstraints = CA:false subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always keyUsage = digitalSignature,keyEncipherment extendedKeyUsage = serverAuth,clientAuth
完成后保存并关闭文件。 我们现在有一个可用于签署我们之前生成的证书签名请求的大量配置文件。
签署证书签名请求以生成证书
现在,我们拥有签署 CSR 和生成证书所需的所有组件。 我们只需要引用我们刚刚创建的配置文件,并传入我们生成的 CSR。
我们将使用的命令是:
openssl ca -batch -config myca.conf -notext -in consul.csr -out consul.cert
我们使用的选项是:
- ca:使用 openssl 的证书授权管理功能。
- -batch:指定它应该进入批处理模式。 批处理模式会自动验证任何传入的 CSR,无需提示。
- -config myca.conf:传入我们创建的配置文件。
- -notext:不输出证书的文本形式。
其余选项指定输入和输出文件。
这将在当前目录中生成一个名为 consul.cert
的文件。 它还将创建 serial
和 certindex
文件的新版本,将旧版本移动到备份文件中。 还将根据serial
文件中的序列号创建一个.pem
文件。
将文件移动到正确的位置
现在,我们在 /etc/consul.d/ssl/CA
目录中拥有了我们需要的所有组件。 我们要将我们需要的三个文件复制到 /etc/consul.d/ssl
目录,我们将在其中引用它们:
cp ca.cert consul.key consul.cert ..
我们拥有 CA 的 server1
机器现在在正确的位置拥有必要的证书和密钥文件。
要将它们放到基础架构中的其他机器上,scp
是一个不错的选择。 在 server1
上的 /etc/consul.d/ssl
目录中,您可以通过键入以下命令将必要的文件推送到其他服务器:
cd /etc/consul.d/ssl scp ca.cert consul.key consul.cert root@192.0.2.2:/etc/consul.d/ssl scp ca.cert consul.key consul.cert root@192.0.2.3:/etc/consul.d/ssl scp ca.cert consul.key consul.cert root@192.0.2.50:/etc/consul.d/ssl
更改 IP 地址以引用基础架构中的每台机器。
修改 Consul 配置文件
现在我们有了根证书文件和 consul 成员的证书/密钥对,我们可以修改 consul 配置文件以引用这些文件。
打开服务器上的每个领事配置文件。 对于我们的 server1
机器,我们将从引导配置文件开始:
nano /etc/consul.d/bootstrap/config.json
该文件当前应如下所示:
{ "bootstrap": true, "server": true, "datacenter": "nyc2", "data_dir": "/var/consul", "encrypt": "pmsKacTdVOb4x8/Vtr9PWw==", "log_level": "INFO", "enable_syslog": true }
我们应该做的第一件事是使用 consul 参数来识别我们的每个新文件。 ca_file
参数引用 CA 证书文件的位置。 cert_file
和 key_file
参数分别引用客户端的证书和密钥文件。
由于这些也与加密有关,为了清楚起见,我们将其添加到 encrypt
参数下方:
{ "bootstrap": true, "server": true, "datacenter": "nyc2", "data_dir": "/var/consul", "encrypt": "pmsKacTdVOb4x8/Vtr9PWw==", "ca_file": "/etc/consul.d/ssl/ca.cert", "cert_file": "/etc/consul.d/ssl/consul.cert", "key_file": "/etc/consul.d/ssl/consul.key", "log_level": "INFO", "enable_syslog": true }
现在,我们已经定义了这些文件的位置,但我们还没有告诉 consul 我们要使用这些文件验证每个主机的真实性。 我们现在可以通过告诉 consul 验证传入和传出连接来做到这一点:
{ "bootstrap": true, "server": true, "datacenter": "nyc2", "data_dir": "/var/consul", "encrypt": "pmsKacTdVOb4x8/Vtr9PWw==", "ca_file": "/etc/consul.d/ssl/ca.cert", "cert_file": "/etc/consul.d/ssl/consul.cert", "key_file": "/etc/consul.d/ssl/consul.key", "verify_incoming": true, "verify_outgoing": true, "log_level": "INFO", "enable_syslog": true }
完成后保存并关闭文件。
对您的领事成员使用的每个配置文件进行相同的更改。
在 server1
上,您需要对 /etc/consul.d/bootstrap/config.json
和 /etc/consul.d/server/config.json
进行这些更改。
在您的其他服务器上,您只需要修改 /etc/consul.d/server/config.json
。 在您的客户端计算机上,您必须修改 /etc/consul.d/client/config.json
。
重新启动服务器
要实施我们的加密流量,您必须依次重新启动每个领事成员的领事会话。
在基础设施中的每台机器上,短暂停止然后再次启动 consul:
stop consul && sleep 5 && start consul
这将停止该过程并立即重新启动。
如果您依次对每个领事成员执行此操作,他们将切换到使用 SSL 来加密他们之间的 RPC 流量。 当仅切换其中一些时,由于某些流量因未加密而被拒绝,因此可能会短暂存在一些通信问题。
当所有成员重新启动时,RPC 流量应该被完全加密。
结论
此时,您应该为您的基础架构准备了一个相当安全的服务发现系统。 我们利用了 consul 提供的所有本地安全系统来锁定访问并防止对我们不同机器的欺骗。