如何使用Hashicorp工具创建安全的边缘基础设施

译文
开发 前端 应用安全
本文是将Consul、Nomad和Vault的所有部分粘合在一起所需的分步教程。

译者 | 李睿

审校 | 重楼

本文解释了如何使用HashiCorp的堆栈构建一个安全的平台;许多步骤都有良好的文档记录。我们将详细强调最关键的部分,解释在哪里发现问题以及如何解决问题,并在官方教程中保留参考资料,以防止本文过长且难以理解。

物理架构

如下图所示,我们想要实现的物理架构由五个节点的Consul和Nomad集群组成:其中三个是配置为高可用性(HA)的控制平台节点,其余两个是数据平台节点。

考虑到我们处于边缘环境,安装集群服务器的最终位置至关重要:

  • 控制平台节点(服务器)分布在展会展馆或安装在主楼的专用机柜上。
  • 数据平台节点(客户端)位于每个展馆。

在默认情况下,服务器的角色是维护集群的状态,而客户机则为物理上位于群集附近的用户提供服务。

基本要求及节点部署

在自动化和虚拟化时代,继续前进的方法是创建一个“测试并销毁”虚拟化环境,以便在进入生产环境之前尝试配置,并在物理基础设施上部署所有内容。

DevOps工具箱由Ansible、Terraform和Git等工具组成,在构建如此复杂的环境的过程中,它一直是一个严格的配置和流程要求。Ansible Vault是我们的选择,以确保与特定环境相关的敏感内容(如密码、密钥、配置变量和引导令牌或TLS证书)受到保护和加密,而不是以纯文本形式从我们存储用于构建基础设施的代码的Git存储库中可见。

我们首先创建五台虚拟机。对于测试使用了以下规范:

  • 操作系统:Ubuntu 22.04 LTS
  • 磁盘20GB
  • 内存:2GB
  • vCPU2

用户可以选择其喜欢的公共云提供商,在那里部署大量的虚拟机与Terraform。或者,为了加快部署过程,可以使用VirtualBox和Vagrant在他们的笔记本电脑上创建它们,但最终,将得到一个与此类似的Ansible清单:

YAML
all:
children:
cluster_role_server:
hosts:
node-1:
node-2:
node-3:
cluster_role_client:
hosts:
node-4:
vars:
placement: "pavilion-1"
node-5:
vars:
placement: "pavilion-2"

配置Consul和Nomad集群

在这个引导阶段,开源Ansible社区提供了一个经过广泛测试的、安全的公共剧本。得益于Ansible Galaxy实用程序,我们可以提取两个角色的代码,分别部署Consul和Nomad。

我们将上述角色制作成一个专有的剧本,首先,使用虚拟网络接口配置和设置服务器网络。该接口映射到保留IP地址169.254.1.1,用于解析集群中的*.consol域名,我们称其为dummy0接口。我们依靠Ansible在目标节点上配置它,最后,我们将在每台服务器上有以下文件:/etc/systemd/network/dummy0.network::

Shell
[Match]
Name=dummy0

[Network]
Address=169.254.1.1/32

# We want these domains
Domains=~consul.

# To go to the consul DNS server we'll bind to this address
DNS=169.254.1.1

此外,公共剧本还在服务器上配置了一些基本的自定义,比如更新操作系统、设置节点用户导入相关的SSH authorized_keys、安装容器运行时以及一些调试CLI工具。

最后,应该通过设置适当的Ansible变量来注意配置Consul和Nomad角色。它们的大多数名称是不言自明的,但是必须指定consul_version和nomad_version(在本例中分别为1.12.2和1.2.8)。三个客户机节点应该使用consul_node_role和nomad_node_role变量,而其他节点应该使用服务器变量。另一个需要设置的有用变量是nomad_cni_enable:true,否则,将不得不人工在任何Nomad节点上安装CNI。

通过这种方式,我们还能够以最小的工作量支持不同环境库存的快速供应和部署,从生产裸服务器或边缘的cloudlet到在云中开发和测试虚拟机

配置Vault群集

此时,我们已经为Consul+Nomad集群做好了准备,应该能够访问各自的用户界面(UI)并启动一些测试工作负载。如果一切正常,那么就是配置Vault集群的时候了为了简单起见,它将被安装在运行Nomad和Consul控制平台的高可用性(HA)服务器节点上。

如果是Vault初学者,可以从这里开始进行尝试,然后可以移动到Ansible Vault角色来安装这个组件,但是在进入剧本之前,需要一些人工步骤来为我们的Vault集群引导PKI。

如果企业提供现有的PKI配置,可以依赖它。这里,我们将从头开始,创建根证书(CA)颁发机构和证书。

首先,创建根密钥(这是CA私钥,可用于签署证书请求),然后使用根密钥创建需要分发给所有必须信任客户端的根证书可以根据需要调整-days标志的值。

Shell 
openssl genrsa -aes256 -out rootCA.key 4096
openssl req -x509 -new -key rootCA.key -sha256 -days 1024 -out rootCA.crt

必须在提示符上自定义字段,例如,使用如下内容:C=IT, O=CompanyName, CN=company.com/emailAddress=example@company.com,并可选地检查根CA证书:

Shell 
openssl x509 -in rootCA.crt -text

此时,我们需要为每个服务器、设备或应用程序创建证书,这些服务器、设备或应用程序需要通过CA信任的证书公开TLS加密的服务。在本例中,我们将把该证书分配给Vault集群,因此将在每个Vault节点上使用相同的证书。

Shell
openssl genrsa -out vault.key 4096
# create the Certificate Signing Request (csr)
openssl req -new -sha256 \
-key vault.key \
-subj "/C=IT/ST=TN/O=Tofane/CN=vault.service.consul" \
-out vault.csr
# finally verify the CSR's content
openssl req -in vault.csr -noout -text

要完成这一过程,使用所有可选名称(可以是URL或IP)创建一个extfile;在本例中,使用每个Vault节点的IP,然后使用CSR和密钥以及CA根密钥生成证书。

Shell 
echo "subjectAltName=DNS:*.vault.service.consul,IP:10.231.0.72,IP:10.231.0.71,IP:10.231.0.73" >> extfile.cnf
# optionally, if you want to use the csr also for authentication
echo extendedKeyUsage = serverAuth >> extfile.cnf
openssl x509 -req -in vault.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out vault.crt -extfile extfile.cnf -days 365 -sha256
# verify the certificate content
openssl x509 -in vault.crt -text -noout

除其他次要文件外,现在应确保在当前工作文件夹中包含以下生成的文件:

rootCA.crt 
vault.crt
vault.key

PKI文件必须通过专用变量传递给Ansible角色以及下面建议的一些其他配置,然后通过将Vault角色分配给服务器节点来启动Vault配置。

YAML 
vault_backend: consul
vault_consul: 169.254.1.1:8500
vault_iface: "{{ ansible_default_ipv4.interface }}"
vault_listener_localhost_enable: true
vault_tls_disable: 0
vault_tls_src_files: "ANSIBLE_RELATIVE_PATH_TO_YOUR_CERT_FILES"
vault_tls_cert_file: "vault.crt"
vault_tls_key_file: "vault.key"
vault_tls_ca_file: "rootCA.crt"

如果使用自签名CA,还需要一个步骤:必须将其复制并安装到每个节点中,可以通过以下方法轻松完成此任务:

Shell
sudo cp rootCA.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates

最后,初始化Vault集群,打开它,使用初始化阶段返回的令牌登录,并检查它的状态;如果一切正常,那么转到下一个陷阱:在新的集群上启用和配置TLS。

Shell 
vault operator init
vault operator unseal
vault login
vault status

配置TLS

在本节中,将详细介绍为在集群中运行的基础设施组件(例如Consul和Nomad代理)和应用程序容器启用安全集群通信的过程。因此,我们将在mTLS验证之上,使用TLS加密和服务验证来保护Consul Agent通信。这可以使用从Vault集群生成的证书来完成;此外,在本例中,证书将在服务器上通过Consul Template分发,在客户端通过自动加密方法分发。

需求

所有与证书更新和Consul、Nomad代理以及Vault之间的轮换相关的秘诀都掌握在Consul Template所需的组件中。可以分享一下GitHub页面的参考,并简要地给一些关于如何安装和配置它的提示,因为到目前为止,在网上找不到完整的指南:

在每个集群节点的主节点中下载并解压缩二进制文件

Shell 
ansible all -m shell -a 'sudo apt-get install unzip; CT_V=0.29.0; \
curl -O https://releases.hashicorp.com/consul-template/${CT_V}/consul-template_${CT_V}_linux_amd64.zip; \
unzip consul-template_${CT_V}_linux_amd64.zip; \
sudo mv consul-template /usr/local/bin/'

在systemd的每个节点上创建单元文件:

Shell 
ansible all -m shell -a "sudo bash -c 'cat <<EOF > /etc/systemd/system/consul-template.service
[Unit]
Descriptinotallow=consul-template
Documentatinotallow=https://github.com/hashicorp/consul-template
Wants=network-online.target
After=network-online.target

[Service]
Envirnotallow=/etc/environment
ExecStart=/usr/local/bin/consul-template -config /etc/consul-template.d
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
KillSignal=SIGINT
Restart=on-failure
RestartSec=42s

[Install]
WantedBy=multi-user.target

EOF '"

最后,将其提升为systemd下的系统服务,并为consul-template配置文件创建一个文件夹。

Shell 
ansible all -m shell -a "sudo systemctl daemon-reload"
ansible all -m shell -a \
'sudo mkdir -p /etc/consul-template.d; \
sudo chgrp consul /etc/consul-template.d'

Consul模板的主框架现在准备好了。在接下来的步骤中,需要做的就是为每个请求证书轮换的服务创建配置文件和模板文件。

配置Consul TLS和Consul Connect

可以很容易地遵循下面的循序渐进的教程,这些教程非常详细,只需要针对具体情况进行微小而明显的调整:

  • 配置Vault的PKI机密引擎。
  • 配置Vault为Consul的CA,在每个节点上安装Consul中间CA。
  • 生成服务器证书。

现在,在继续Consul配置之前,我们需要启用和配置Consul Connect功能,为此,我们首先需要启用Vault作为Consul Connect认证机构提供商:Consul Connect创建的服务网格网络中使用的证书将由Vault生成和管理。跳转到以下教程,并确保选择“自我管理”选项卡下的说明:Vault作为领事服务网格认证机构提供商。

此时,需要通过以下方式配置Consul:首先在/opt/consult/agent certs/下的客户端和服务器上分发引导证书,然后使用update-ca-certificates实用程序将Consul中间CA安装到每个节点中,其方法与我们在上一节中对Vault CA所做的类似。对于这些步骤,可以轻松地遵循Configure Consul教程。

现在已经在节点上分发了引导证书,可以通过将Consul配置分别放置在/etc/Consul中的服务器和客户端上首先在服务器上启用TLS,然后在客户端上启用TLS。d/folder并重新启动Consul代理。

enable-tls-server.hcl
YAML
1 verify_incoming = true
2 verify_outgoing = true
3 verify_server_hostname = true
4 ca_file = "/opt/consul/agent-certs/ca.crt"
5 cert_file = "/opt/consul/agent-certs/agent.crt"
6 key_file = "/opt/consul/agent-certs/agent.key"
7
8 auto_encrypt {
9 allow_tls = true
10 }enable-tls-client.hcl
enable-tls-client.hcl
YAML 
verify_incoming = false
verify_outgoing = true
verify_server_hostname = true
ca_file = "/opt/consul/agent-certs/ca.crt"
auto_encrypt {
tls = true
ip_san = ["169.254.1.1"]
}

在每个节点上重新启动Consul代理,TLS上的API应位于https://169.254.1.1:8501,但仍然需要通过Consul模板配置证书续订,并设置mTLS身份验证。

配置Consul模板页面将指导设置模板文件,这里应该注意一个小细节:鉴于在我们的集群中,Consul代理正在监听特殊的dummy0接口,我们需要通过模板机制创建适当的证书,在每个模板文件中添加自定义的ip_sans。为方便起见,以下是服务器代理证书的模板示例:

Plain Text 
{{ with secret "pki_consul_int/issue/consul-tofane" "common_name=server.tofane.consul" "ttl=24h" "alt_names=localhost" "ip_sans=169.254.1.1"}}
{{ .Data.certificate }}
{{ end }}

最后,只需要创建一个consul-template配置文件,这里唯一的建议是对服务器节点使用address="http://localhost:8200"和address="https://active.vault.service。Consul:客户节点为8200英寸。通过这种方式,服务器将拥有更稳定的配置,因为在Consul无法工作和DNS解析不可用的情况下,与Vault的通信也可以工作。

要执行最终检查TLS证书轮换是否按预期工作,应该等待24小时,等待在Vault中创建证书时选择的TTL。测试每个节点上已覆盖的证书可以用这个相当简单的Ansible命令完成

Shell 
Ansibleall-mshell-a'sudols-la/opt/consul/agent-certs/'

此外,还可以使用OpenSSL,检查RPC或API端口上使用的证书。

Shell 
openssl s_client -connect $CONSUL_NODE_LAN_IP:8300 2>/dev/null | less
openssl s_client -connect 169.254.1.1:8501 2>/dev/null | less

最后,尝试使用来自服务器节点的正确证书在API上进行连接。

Shell 
consul members -http-addr="https://169.254.1.1:8501" \
-ca-file="/opt/consul/agent-certs/ca.crt" \
-client-cert="/opt/consul/agent-certs/agent.crt" \
-client-key="/opt/consul/agent-certs/agent.key"

配置Nomad TLS

将Nomad配置为使用TLS的过程非常简单,因为我们需要执行与Consul配置相同的步骤。供参考的官方教程是使用Vault为Nomad生成mTLS证书,我们将在下面描述一些将省去一些麻烦的调整。

首先,就像我们为Consul所做的那样,在Consul模板中,我们需要添加ip_sans,但在这种情况下,我们还需要添加127.0.0.1,因为Nomad也将在该接口上从服务(例如:Nomad Autoscaler)联系。以下是我们的例子:

Plain Text
{{ with secret "pki_nomad_int/issue/nomad-cluster" "common_name=server.global.nomad" "ttl=24h" "alt_names=localhost" "ip_sans=127.0.0.1,169.254.1.1"}}
{{ .Data.certificate }}
{{ end }}

值得注意的是,Nomad的Consul模板配置可以附加到现有的配置文件中,因为我们已经将其用于Consul了。

假设Consul Template将用于从不同的Vault路径检索Consul和Nomad证书,最好创建一个新策略,并创建一个具有这两种权限的新令牌。

Shell 
vault token create -policy=nomad -policy=connect-ca

当然,这个令牌必须在每个节点上的Consul Template配置文件中替换。

就像我们为Consul所做的那样,为了方便,我们共享了应该放在/etc/nomad中的文件。d/以便在服务器节点上启用NomadTLS。对于客户机节点,只需删除最后一行。

enable-tls-server.hcl
YAML
tls {
http = true
rpc = true

ca_file = "/opt/nomad/agent-certs/ca.crt"
cert_file = "/opt/nomad/agent-certs/agent.crt"
key_file = "/opt/nomad/agent-certs/agent.key"

verify_server_hostname = true
verify_https_client = true

rpc_upgrade_mode = true
}

当第一次重新加载Nomad代理时,记住在服务器节点上将rpc_upgrade_mode选项更改为false,以便Nomad服务器将只接受TLS连接,然后再次重新启动服务。

Shell
ansible core_cluster_role_server -m shell -a \ 'sudo sed -i "s/rpc_upgrade_mode = true/rpc_upgrade_mode = false/g" /etc/nomad.d/enable-tls-server.hcl'
ansible core_cluster_role_server -m shell -a \ 'sudo systemctl restart nomad'

只需要几个步骤就可以完全完成Nomad配置:i)允许访问webUI,ii)启用边车使用TLS,以及iii)测试是否一切都按预期工作。

启用TLS时,为了访问Web-UI,需要在服务器上将verify_https_client设置为false,并重新启动nomad服务。要了解更多信息,发现这篇文章非常有用。

Shell
ansible core_cluster_role_server -m shell -a \
'sudo sed -i "s/verify_https_client = true/verify_https_client = false/g" /etc/nomad.d/enable-tls-server.hcl; \
sudo systemctl restart nomad'

现在应该能够连接到https://localhost:4646/ui,但是要记住的是,对于生产环境,应该使用Vault根CA配置其浏览器,以便提供受支持的对等身份验证。

第二步是让边车使用Consul connect提供的TLS保护网格:为了初始化TLS保护网格中的通道,Nomad需要与Consul通信,并在边车中注入正确的证书,以建立受保护的连接。

为此,更新/etc/nomad.d/base.中的Nomad配置并允许Nomad通过TLS与Consul API通信,添加以下行:

Shell 
address = "169.254.1.1:8501"
ssl = true ca_file = "/opt/consul/agent-certs/ca.crt"
cert_file = ""
key_file = ""

希望是到了最后的测试阶段。实际上,如果输入了nomad status命令,会收到一个错误消息,因为需要正确配置CLI。

导出端点和证书变量:

Shell
export NOMAD_ADDR=https://localhost:4646
export NOMAD_CACERT="/opt/nomad/agent-certs/ca.crt"
export NOMAD_CLIENT_CERT="/opt/nomad/cli-certs/cli.crt"
export NOMAD_CLIENT_KEY="/opt/nomad/cli-certs/cli.key"

最后,通过TLS再次检查状态,nomadstatus命令现在应该无缝工作了。

配置Consul ACL

下面的最后一步将在我们的集群上启用Consul访问控制列表系统。该任务的主要参考资料是HashiCorp关于引导ACL系统的教程

启用ACL

在启用ACL系统的过程中,遇到了一个小问题,如果多个节点同时处于活动状态,则无法引导它。小问题可以用简单的解决方案解决:为什么不在启用ACL之前暂时将集群缩小到一个节点?作为“懒惰的开发人员”,所以一个粗糙但有效的bash循环和SSH帮助我们做到了这一点:

Shell
# server nodes
S_L="node-1 node-2 node-3"
# client nodes
C_L="node-4 node-5"

for i in ${S_L#* } $C_L;
do echo "R $i"
ssh -t $i consul leave
done

现在复制以下Consul HCL配置文件,然后将ACL引导到单节点Consul集群中:

enable-acl.hcl
YAML
acl = {
enabled = true
#default_policy = "deny"
default_policy = "allow"
enable_token_persistence = true
}
Shell
1 FIRST=node-1
2 echo "R $FIRST"
3 scp enable-acl.hcl $FIRST:/var/tmp/enable-acl.hcl
4 ssh $FIRST sudo install --owner consul --group consul /var/tmp/enable-acl.hcl /etc/consul.d/enable-acl.hcl
5 ssh -t $FIRST sudo systemctl restart consul.service

Consul将回复一条成功的消息,并允许我们继续保存Consul引导令牌,并通过重新启动Consul代理将其他节点重新加入原始集群。

Shell
# save consul bootstrap token
sudo consul acl bootstrap -format json 2>&1 | tee consul-acl-bootstrap.token CONSUL_HTTP_TOKEN=$(cat consul-acl-bootstrap.token | jq -r '.SecretID') export CONSUL_HTTP_TOKEN

# restore cluster nodes
for i in ${S_L#* } $C_L; do
echo "R $i"
scp enable-acl.hcl $i:/var/tmp/enable-acl.hcl
ssh $i sudo install --owner consul --group consul /var/tmp/enable-acl.hcl /etc/consul.d/enable-acl.hcl
ssh -t $i sudo systemctl restart consul.service
done

此时,如果集群中只有服务器节点可用(使用:consul成员进行检查),并且看到Vault、Consul和Nomad代理不再工作;这很正常,因为它们没有适当的ACL策略和相对令牌。按照下面的步骤,将修复它。

ACL与Vault集成

与Vault的集成非常简单。只需要从适当的Consul策略生成一个令牌,并再次运行Ansible Vault角色,在设置一个额外的Ansible额外变量后,一次更新所有的节点:

YAML 
vault_consul_token: "YOUR_TOKEN_HERE"

与Consul和Nomad代理集成ACL

与其他组件的集成可以遵循官方教程按照以下顺序轻松完成。

(1)为Consul节点和代理创建规则、策略和令牌。

(2)为用户界面(UI)创建规则、策略和令牌。

(3)为DNS创建规则、策略和令牌为简单起见,我们只是将这个策略与点1)处的策略合并,并为下面模板开始的每个节点生成:

JSON
node "NODE-NAME" {
policy = "write"
}
service_prefix "" {
policy = "read"
}
node_prefix "" {
policy = "read"
}
service_prefix "" {
policy = "read"
}
query_prefix "" {
policy = "read"
}
agent "NODE-NAME" {
policy = "write"
}

(4)为Nomad创建规则、策略和令牌

ACL策略完全启用

现在强制ACL在默认情况下拒绝通信,最后在每个节点上重新启动Consul。

Shell
ansible all -m shell -a "\ sudo sed -i \
's/default_policy = \"allow\"/#default_policy = \"allow\"/g' /etc/consul.d/enable-acl.hcl"
ansible all -m shell -a "\ sudo sed -i \
's/#default_policy = \"deny\"/default_policy = \"deny\"/g' /etc/consul.d/enable-acl.hcl"
ansible all -m shell -a "sudo systemctl restart consul"

结论

此时,基于HashiCorp产品的“安全边缘基础设施”应该已经启动并运行,可以开始安装首选的工作负载。在这个例子中,在这个部署上安装了一层中间件,支持负载平衡、监视和自动扩展等特性。为了实现最后一个目标,我们分别使用Traefik、Prometheus和Nomad自动扩展器,可以想象,为了让这些工具在完整的TLS基础设施上正常工作,还需要额外的配置,但这将是另一篇文章的主题。

总之,我们分享这项工作的可能演变,我们认为这是很自然的:鉴于在跨组件的通信和身份验证方面,基础设施被认为是相当安全的,为什么不将其用作构建混合基础设施的支柱,其中控制平台节点位于所选择的云中,而数据平台服务器位于边缘?

有了这样的架构,将拥有一个毫无疑问的优势,即能够通过一个控制平台来控制多个边缘站点,从而消除开销,并实现企业的规模经济。当然,应该对系统进行适当的分区,以支持多租户,这肯定是下一个令人兴奋的项目。

原文标题:How To Use Hashicorp Tools To Create a Secured Edge Infrastructure,作者:Daniele Santoro


责任编辑:华轩 来源: 51CTO
相关推荐

2023-08-04 16:32:18

2015-03-18 14:30:09

2015-05-27 09:03:46

IT基础设施IT基础设施监控

2021-11-11 08:00:00

边缘计算云计算数据

2022-03-02 16:10:55

边缘计算智慧城市物联网

2021-05-08 13:13:55

智能设施漏洞攻击

2012-02-27 14:39:48

虚拟化思杰

2019-04-16 11:31:18

2023-06-16 15:53:55

DevOps基础设施

2020-10-16 22:05:44

广域网

2022-02-10 11:54:34

即时基础设施基础设施数字化转型

2023-05-16 13:46:00

数据中心

2020-04-28 10:21:58

基础设施硬件远程工作

2019-04-01 06:14:05

IT基础设施网络安全数字化

2022-12-15 10:37:07

2024-04-12 10:01:53

2017-05-04 10:56:03

2021-05-17 14:49:40

Kubernetes边缘设备

2021-05-21 14:13:56

网络安全漏洞数据

2021-05-20 12:51:11

网络安全基础设施网络攻击
点赞
收藏

51CTO技术栈公众号