如何利用TLS/SSL与防火墙规则保护CoreOS集群

提供:ZStack云计算

系列教程

本教程为CoreOS上手指南系列九篇中的第九篇。

内容介绍

如果大家需要在控制外网络环境中运行CoreOS集群,例如立足于共享数据中心或者公共互联网,则需要注意一点——etcd利用未加密HTTP请求进行通信。我们可以在集群内对每个节点进行IPTables防火墙配置,从而消除这一风险。但更为彻底的解决手段则是使用加密传输层。

幸运的是,etcd支持对等TLS/SSL连接,这意味着集群中各成员节点皆经过验证,且全部通信皆经过加密。在本教程中,我们将配置一套三节点集群,而后在各设备上配置HTTPS端点与基础防火墙。

先决条件

本教程会涉及大量CoreOS系统组件概念,大家可能也需要参阅如何在DigitalOcean上设置CoreOS集群

大家应当熟悉etcd、fleetctl、cloud-config文件并生成一条发现URL。

为了在集群中创建并访问各设备,大家需要使用与DigitalOcean账户相关联的SSH公钥。欲了解更多与之相关的信息,请参阅本篇教程

如果大家希望使用DigitalOcean构建自己的CoreOS集群,可参阅此教程以了解如何通过写入权限生成并使用个人访问令牌。大家也可以选择使用API,从长远角度看,这种作法有助于在大规模集群内节约管理时间。

生成一条新的发现URL

大家可以在浏览器内访问https://discovery.etcd.io/new?size=3以检索新的discovery URL,复制显示的URL或者直接在本地设备上使用curl命令:

保存返回的URL,我们将在后面的cloud-config中加以使用。

编写包含HTTPS配置的Cloud-Config文件

首先从编写cloud-config开始。此文件在服务器初始化时作为用户数据使用,负责定义集群的各重要配置细节。文件内容较长,但却并不复杂。具体请参阅基础集群指南。我们将要求fleet明确使用HTTPS端点,同时启用imptables-restore服务作为防火墙,而后编写配置文件以告知etcd与fleet在哪里找到SSL证书。

在本地设备上打开终端,确保位于主目录下,使用nano创建并打开~/cloud-config.yml文件:

  • cd ~

  • nano cloud-config.yml

粘贴以下内容,而后将etcd2部分内的https://discovery.etcd.io/token变更为大家在上一部分中声明的发现URL。

如果不需要防火墙,大家也可以移除iptables-restore部分。

请注意粘贴时保留缩进。由于cloud-config由YAML写成,其中的空格数非常重要。查看文件内的注释以了解各行含义,我们将强调其中的部分内容。

~/cloud-config.yml

#cloud-config

coreos:
  etcd2:
    # generate a new token for each unique cluster from https://discovery.etcd.io/new:
    discovery: https://discovery.etcd.io/token
    # multi-region deployments, multi-cloud deployments, and Droplets without
    # private networking need to use $public_ipv4:
    advertise-client-urls: https://$private_ipv4:2379,https://$private_ipv4:4001
    initial-advertise-peer-urls: https://$private_ipv4:2380
    # listen on the official ports 2379, 2380 and one legacy port 4001:
    listen-client-urls: https://0.0.0.0:2379,https://0.0.0.0:4001
    listen-peer-urls: https://$private_ipv4:2380
  fleet:
    # fleet defaults to plain HTTP - explicitly tell it to use HTTPS on port 4001:
    etcd_servers: https://$private_ipv4:4001
    public-ip: $private_ipv4   # used for fleetctl ssh command
  units:
    - name: etcd2.service
      command: start
    - name: fleet.service
      command: start
    # enable and start iptables-restore- name: iptables-restore.serviceenable: truecommand: start
write_files:
  # tell etcd2 and fleet where our certificates are going to live:
  - path: /run/systemd/system/etcd2.service.d/30-certificates.conf
    permissions: 0644
    content: |
      [Service]
      # client environment variables
      Environment=ETCD_CA_FILE=/home/core/ca.pem
      Environment=ETCD_CERT_FILE=/home/core/coreos.pem
      Environment=ETCD_KEY_FILE=/home/core/coreos-key.pem
      # peer environment variables
      Environment=ETCD_PEER_CA_FILE=/home/core/ca.pem
      Environment=ETCD_PEER_CERT_FILE=/home/core/coreos.pem
      Environment=ETCD_PEER_KEY_FILE=/home/core/coreos-key.pem
  - path: /run/systemd/system/fleet.service.d/30-certificates.conf
    permissions: 0644
    content: |
      [Service]
      # client auth certs
      Environment=FLEET_ETCD_CAFILE=/home/core/ca.pem
      Environment=FLEET_ETCD_CERTFILE=/home/core/coreos.pem
      Environment=FLEET_ETCD_KEYFILE=/home/core/coreos-key.pem

作为可选步骤,大家也可以将cloud-config粘贴至官方官方CoreOS云配置验证当中,而后按下Validate Cloud-Config。

保存并退出。

下面来看cloud-init.yml文件中的重要部分。首先是fleet值:

  fleet:
    # fleet defaults to plain HTTP - explicitly tell it to use HTTPS:
    etcd_servers: https://$private_ipv4:4001
    public-ip: $private_ipv4   # used for fleetctl ssh command

注意,etcd_servers被设定为一条https URL。对于普通HTTP操作,此值不需要额外设置。不过如果不经特别调整,HTTPS将无法实现。($private_ipv4是一条CoreOS初始化流程中的变量,这里不需要变更。)

下面,我们来看write_files部分。其值被拆分为一条文件系统路径、权限掩码以及文件内容。在这里,我们为etcd2与fleet服务指定systemd单元文件,从而设置其环境变量以指定我们生成的TLS/SSL证书:

write_files:
  # tell etcd2 and fleet where our certificates are going to live:
  - path: /run/systemd/system/etcd2.service.d/30-certificates.conf
    permissions: 0644
    content: |
      [Service]
      # client environment variables
      Environment=ETCD_CA_FILE=/home/core/ca.pem
      ...
  - path: /run/systemd/system/fleet.service.d/30-certificates.conf
    permissions: 0644
    content: |
      [Service]
      # client auth certs
      Environment=FLEET_ETCD_CAFILE=/home/core/ca.pem
      ...

尽管我们已经声明了证书文件的位置,但文件本身尚未生成。因此,我们需要了解每台CoreOS设备的专有IP地址,而此地址在设备创建时即可用。

请注意:在CoreOS Droplets上,cloud-config内容无法在Droplet创建完成后再行改动,因此需要重新引导方可重新执行该文件。大家应当避免在集群构建完成后在任何配置当中使用write-files部分,因为其需要在Droplet下次启动方可起效。

配置Droplets

现在我们已经定义了cloud-config.yml,下面利用其配置各集群成员。在DigitalOcean上,我们可以选择两种实现方案:通过基于Web的控制面板,或者利用cURL在命令行中调用DigitalOcean API。

使用DigitalOcean控制面板

在同一数据中心服务区内创建新的CoreOS Droplets。确保每次创建时检查专有网络并启用User Data。

  • coreos-1
  • coreos-2
  • coreos-3

在User Data字段内,粘贴之前的cloud-config.yml内容,确保在discovery字段中插入discovery URL。

使用DigitalOcean API

作为备选方案,我们也可以编写一套简短的Bash脚本,利用curl从DIgitalOcean API请求创建新的Droplet。首先利用nano打开makecoreos.sh新文件:

  • cd ~

  • nano makecoreos.sh

粘贴并保存以下脚本,调整region与size字段(默认为nyc3与512mb):

~/makecoreos.sh

#!/usr/bin/env bash

# A basic Droplet create request.
curl -X POST "https://api.digitalocean.com/v2/droplets" \
     -d'{"name":"'"$1"'","region":"nyc3","size":"512mb","private_networking":true,"image":"coreos-stable","user_data":
"'"$(cat ~/cloud-config.yml)"'",
         "ssh_keys":[ "'$DO_SSH_KEY_FINGERPRINT'" ]}' \
     -H "Authorization: Bearer $TOKEN" \
     -H "Content-Type: application/json"

现在将环境变量 DOSSHKEYFINGERPRINT TOKEN分别设置至与DigitalOcean账户与API个人访问令牌相关联的SSH密钥指纹。

关于更多与个人访问令牌与其API使用相关的信息,请参阅此教程

为了找到与账户相关联的密钥指纹,请参阅账户设置的安全部分公钥指纹,的一般形式为43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8。

我们可以使用export,确保该shell的子进程(例如makecoureos.sh)访问各变量。二者必须在脚本使用时的当前shell内设置,否则API调用将无法成功:

  • export DO_SSH_KEY_FINGERPRINT=”ssh_key_fingerprint”

  • export TOKEN=”your_personal_access_token”

注意:如果大家已经为该API生成了个人访问令牌,请记得保持其便利性与安全性。我们无法在其创建完成后再行检索,而且 任何拥有该令牌的用户都能够控制大家的DigitalOcean账户。

在为各必要凭证设置了环境变量后,我们可以运行该脚本以创建必要的Droplet。

利用其首条参数填充指向该API的调用中的name字段:

  • bash makecoreos.sh coreos-1

  • bash makecoreos.sh coreos-2

  • bash makecoreos.sh coreos-3

可以看到,每套新Droplet都以JSON输出结果进行描述,且三者全部显示在控制面板中的Droplets列表当中。整个引导过程可能需要数秒钟。

登录至coreos-1

无论大家是使用控制面板还是API,应该都已经构建起了三套Droplets。现在点击控制面板内各Droplet、再点击设置链接,查看其公共与专有IP。各Droplet的专有IP地址需要用于生成证书及配置防火墙。

下面测试Droplet。确保我们的SSH密钥被添加至本地SSH代理当中:

  • eval $(ssh-agent)

  • ssh-add

在控制面板中找到coreos-1的公共IP地址,接入SSH代理:

  • ssh -A core@coreos-1_public_ip

在首次登录任何集群成员时,我们可能会收集来自systemd的错误信息:

Output

CoreOS stable (766.5.0)
Failed Units: 1
  iptables-restore.service

可以看到,防火墙还没有进行配置。现在我们直接忽略即可。

在防火墙之前,我们首先保证各集群成员上的etcd2实例能够彼此通信。

使用CFSSL以生成自签名证书

CFSSL是一款工具套件,用于处理TLS/SSL证书,由CloudFlare发布。目前其已经成为CoreOS维护方的指定工具,用于生成自签名证书。这里不推荐使用etcd-ca。

在本地设备上安装CFSSL

CFSSL要求安装Go以获取代码源。具体请参阅Go安装指南

确保我们的 GOPATH PATH当中,而后使用go以安装cfssl命令:

  • export GOPATH=~/gocode

  • export PATH= PATH: GOPATH/bin

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

  • go get -u github.com/cloudflare/cfssl/…

作为备选方案,我们也可以从pkg.cfssl.org检索预置二进制代码。首先确保路径中已经存在~/bin:

  • mkdir -p ~/bin

  • export PATH=$PATH:~/bin

而后使用curl检索cfssl与cfssljson的最新版本:

确保cfssl二进制代码拥有执行权限:

  • chmod +x ~/bin/cfssl

  • chmod +x ~/bin/cfssljson

生成证书中心

现在cfssl命令已经安装完成,我们可以利用其生成定制化证书中心,从而为各COreOS设备签署证书。首先创建并前往新建目录,用于容纳这些文件:

  • mkdir ~/coreos_certs

  • cd ~/coreos_certs

现在创建并打开ca-config.json文件:

  • nano ca-config.json

复制以下内容后保存,其负责配置cfssl的签名方式:

~/coreos_certs/ca-config.json

{
"signing": {
    "default": {
        "expiry": "43800h"
    },
    "profiles": {
        "client-server": {
            "expiry": "43800h",
            "usages": [
                "signing",
                "key encipherment",
                "server auth",
                "client auth"
            ]
        }
    }
}
}

请注意这里的expiry,目前其设定为43800 hours(相当于5年),而client-server配置文件中则同时包含server auth与client auth使用情况。我们需要保留二者以实现对等TLS。

下面创建并打开ca-csr.json。

  • nano ca-csr.json

粘贴以下内容,将CN与names部分调整为必要的位置与组织。这里可以使用虚构的hosts条目位置与组织名称:

~/coreos_certs/ca-csr.json

{
"CN": "My Fake CA",
"hosts": [
    "example.net",
    "www.example.net"
],
"key": {
    "algo": "rsa",
    "size": 2048
},
"names": [
    {
        "C": "US",
        "L": "CO",
        "O": "My Company",
        "ST": "Lyons",
        "OU": "Some Org Unit"
    }
]
}

如果大家希望将其与ca-config.json与ca-csr.json的默认值进行比较,则可使用cfssl输出默认值。在ca-config.json中,使用:

  • cfssl print-defaults config

对于ca-csr.json,使用:

  • cfssl print-defaults csr

在ca-csr.json与ca-config.json就绪后,生成证书中心:

  • cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
为CoreOS设备生成并签署证书

现在我们的证书中心已经就绪,我们可以为CoreOS设备编写默认值:

创建并打开coreos-1.json:

  • nano coreos-1.json

粘贴并保存以下内容,将其调整为coreos-1的专有IP地址:

~/coreos_certs/coreos-1.json

{
"CN": "coreos-1",
"hosts": [
    "coreos-1",
    "coreos-1.local",
    "127.0.0.1",
    "coreos-1_private_ip"
],
"key": {
    "algo": "rsa",
    "size": 2048
},
"names": [
    {
        "C": "US",
        "L": "Lyons",
        "ST": "Colorado"
    }
]
}

这里最重要的部分是CN,将其设定为我们的主机名称,而后是hosts部分,其中必须包含全部:

  • 各本地主机名称
  • 127.0.0.1
  • CoreOS设备的专有IP地址(而非公共IP)

这些内容都应作为subjectAltNames被添加至生成的证书内。

etcd连接(包含127.0.0.1上的本地回环设备)要求使用证书以获取与该连接主机名称匹配的SAN。

大家也可以变更name数组以反映必要位置。再次强调,这里我们可以使用虚构的位置名称值。

在各设备上重复以上流程,利用对应的hosts条目匹配coreos-2.json与coreos-3.json。

注意:如果大家希望查看coreos-1.json的默认值,可以使用cfssl:

  • cfssl print-defaults csr

现在,为各CoreOS设备生成签名证书,并将其上传至正确的设备:

  • cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client-server coreos-1.json | cfssljson -bare coreos

  • chmod 0644 coreos-key.pem

  • scp ca.pem coreos-key.pem coreos.pem core@coreos-1_public_ip:

这将创建三个文件(ca.pem、coreos-key.pem以及coreos.pem),确保keyfile拥有正确的权限,而后通过scp将其复制至coreos-1上core的主目录中。

重复以上步骤,请注意每次命令调用都会覆盖之前的证书文件:

  • cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client-server coreos-2.json | cfssljson -bare coreos

  • chmod 0644 coreos-key.pem

  • scp ca.pem coreos-key.pem coreos.pem core@coreos-2_public_ip:

  • cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client-server coreos-3.json | cfssljson -bare coreos

  • chmod 0644 coreos-key.pem

  • scp ca.pem coreos-key.pem coreos.pem core@coreos-3_public_ip:

在coreos-1上检查etcd2功能

证书准备好后,我们可以在coreos-1上运行fleetctl了。首先通过SSH进行登录:

  • ssh -A core@coreos-1_public_ip

接下来,列出集群内的全部设备:

  • fleetctl list-machines

大家应当会看到各设备的标识符及其专有IP地址:

Output

MACHINE     IP      METADATA
7cb57440... 10.132.130.187  -
d91381d4... 10.132.87.87    -
eeb8726f... 10.132.32.222   -

如果fleetctl无限挂起,我们可能需要重启集群。退出当前设备:

  • exit

使用SSH将reboot命令发送至各CoreOS设备:

  • ssh core@coreos-1_public_ip ‘sudo reboot’

  • ssh core@coreos-2_public_ip ‘sudo reboot’

  • ssh core@coreos-3_public_ip ‘sudo reboot’

等待几分钟,重新接入coreos-1,再次尝试fleetctl。

在集群成本上配置IPTables防火墙

证书就绪后,本地网络中的其它设备将无法控制集群或者从etcd2中提取值。然而,尽可能降低攻击面仍然有其必要。为了限制网络公开性,我们可以在各设备上添加简单的防火墙规则,从而阻断集群之外的大部分网络流量。

请注意,如果我们在cloud-config中启用iptables-restore服务,则会在首次登录CoreOS设备时看到以下错误信息:

Output

CoreOS stable (766.5.0)
Failed Units: 1
  iptables-restore.service

其提示我们尽管服务已经启用,但iptables-restore未能正确加载。使用systemctl将其忽略:

  • systemctl status -l iptables-restore

    Output

    ● iptables-restore.service - Restore iptables firewall rules
    Loaded: loaded (/usr/lib64/systemd/system/iptables-restore.service; enabled; vendor preset: disabled)
    Active: failed (Result: exit-code) since Wed 2015-11-25 00:01:24 UTC; 27min ago
    Process: 689 ExecStart=/sbin/iptables-restore /var/lib/iptables/rules-save (code=exited, status=1/FAILURE)
    Main PID: 689 (code=exited, status=1/FAILURE)

    Nov 25 00:01:24 coreos-2 systemd[1]: Starting Restore iptables firewall rules…
    Nov 25 00:01:24 coreos-2 systemd[1]: iptables-restore.service: Main process exited, code=exited, status=1/FAILURE
    Nov 25 00:01:24 coreos-2 systemd[1]: Failed to start Restore iptables firewall rules.
    Nov 25 00:01:24 coreos-2 iptables-restore[689]: Can’t open /var/lib/iptables/rules-save: No such file or directory
    Nov 25 00:01:24 coreos-2 systemd[1]: iptables-restore.service: Unit entered failed state.
    Nov 25 00:01:24 coreos-2 systemd[1]: iptables-restore.service: Failed with result ‘exit-code’.

这里包含大量信息,不过最重要的在于iptables-restore[689]这行,其代表的是systemd尝试与其进程id共同运行的进程名称。在这里,我们通常会发现失效服务的错误信息。

防火墙之所以未能成功加载,是因为尽管我们已经在cloud-config中启用了iptables-restore,但还没有为其提供容纳有必要规则的文件。由于已经了解了各集群成员的专有IP,因此我们可以在这里编写规则集。

在编辑器中打开新文件,粘贴以下内容,注意将其中的coreos-1_private_ip,coreos-2_private_ip与coreos-3_private_ip替换为各CoreOS设备的专有IP地址。大家可能还需要调整Accept all TCP/IP traffic…以反映由集群提供的公共服务。

/var/lib/iptables/rules-save

- *filter

- :INPUT DROP [0:0]

- :FORWARD DROP [0:0]

- :OUTPUT ACCEPT [0:0]

- # Accept all loopback (local) traffic:

- -A INPUT -i lo -j ACCEPT

- # Accept all traffic on the local network from other members of

- # our CoreOS cluster:

- -A INPUT -i eth1 -p tcp -s coreos-1_private_ip -j ACCEPT

- -A INPUT -i eth1 -p tcp -s coreos-2_private_ip -j ACCEPT

- -A INPUT -i eth1 -p tcp -s coreos-3_private_ip -j ACCEPT

- # Keep existing connections (like our SSH session) alive:

- -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

- # Accept all TCP/IP traffic to SSH, HTTP, and HTTPS ports - this should

- # be customized  for your application:

- -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
- -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
- -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
- # Accept pings:

- -A INPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT

- -A INPUT -p icmp -m icmp --icmp-type 3 -j ACCEPT

- -A INPUT -p icmp -m icmp --icmp-type 11 -j ACCEPT

- COMMIT

将以上内容复制到剪贴板,登录至coreos-1,而后利用Vim打开rules-save文件:

  • ssh -A core@coreos-1_public_ip

  • sudo vim /var/lib/iptables/rules-save

在编辑器内,输入:set进行粘贴,而后按下回车以确保自动缩进功能被关闭。按下Esc键离开插入模式,而后:wq以写入该文件并退出。

注意:确保该文件的最后一行上存在尾部新行,否则即使文件内的全部命令皆为正确,IPTables仍然会出现语法错误。

最后,确保该文件拥有正确的权限:

  • sudo chmod 0644 /var/lib/iptables/rules-save

现在我们可以再次尝试此服务了:

  • sudo systemctl start iptables-restore

如果成功,systemctl会静默退出。我们可以通过两种方式检查防火墙状态。首先,使用systemctl status:

  • sudo systemctl status -l iptables-restore

而后列出全部现有iptables规则:

  • sudo iptables -v -L

我们使用-v选项以获取详细输出结果,这将告知我们特定规则应用于哪个接口。

确定coreos-1上的防火墙配置完成后,进行登出:

  • exit

接下来,重复以上步骤在coreos-2与coreos-3上安装/var/lib/iptables/rules-save。

总结

在本教程中,我们已经定义了三个基础CoreOS集群成员,为其各自提供了TLS/SSL证书以实现验证及传输安全,而后利用防火墙屏蔽一切来自本地数据中心网络的其它Droplets的连接。

以此为基础,大家也可以参阅CoreOS上手指南以了解更多也出服务定义及管理相关的内容。

本文来源自DigitalOcean Community。英文原文:How To Secure Your CoreOS Cluster with TLS/SSL and Firewall Rules By Brennen Bearnes

翻译:diradw

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值