Защита кластера CoreOS с помощью TLS/SSL и брандмауэра

Прежде чем запустить кластер CoreOS в открытой сети, обратите внимание, что etcd работает посредством незашифрованных запросов HTTP. Риски безопасности можно смягчить с помощью брандмауэра IPTables, который нужно установить на каждую ноду, но в идеале нужно еще добавить уровень шифрования.

К счастью, etcd поддерживает одноранговые соединения TLS/SSL. Данный мануал поможет выполнить оркестровку трех нод кластера, настроить конечные точки HTTPS и базовый брандмауэр.

Требования

Читайте также: Компоненты системы CoreOS: вступление

  • Навыки работы с файлами etcd, fleetctl, cloud-config.
  • Чтобы работать с машинами в кластере, вам понадобится открытый ключ SSH.
  • Кластер CoreOS из трех нод.

Генерирование discovery URL

Извлеките новый discovery URL с discovery.etcd.io. Для этого можно посетить в браузере эту ссылку и скопироватьURL или использовать curl:

curl -w "\n" "https://discovery.etcd.io/new?size=3"

Сохраните полученный URL. Вскоре он пригодится в файле cloud-config.

Настройка HTTPS в файле cloud-config

Начнем с написания конфигурации в cloud-config. Cloud-config будет предоставлять пользовательские данные при инициализации каждого сервера, определяя важные детали конфигурации для кластера. Этот файл будет довольно длинным, но не очень сложным. В нем нужно настроить конечные точки HTTPS, включить сервис брандмауэра под названием iptables-restore и добавить файлы конфигурации, сообщающие etcd и fleet где можно найти SSL-сертификаты.

В терминале на локальной машине перейдите в домашний каталог и создайте файл:

cd ~
nano cloud-config.yml

Вставьте в файл предложенную ниже конфигурацию, а затем замените https://discovery.etcd.io/token своим discovery URL.

Если вы не будете использовать брандмауэр, удалите раздел iptables-restore.

Будьте осторожны с отступами, вставляя код. Cloud-config написан в формате YAML, а он чувствителен к пробелам.

#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.service


enable: true


command: 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 Cloud Config Validator и нажмите Validate Cloud-Config.

Сохраните и закройте файл.

Рассмотрим подробнее отдельные блоки.

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. Для выполнения простых HTTP-операций это значение не нужно устанавливать. Однако без явной настройки HTTPS не будет работать. ($private_ipv4 – это переменная, понятная процессу инициализации CoreOS, ее менять не нужно).

Перейдем к блоку write_files. Значения делятся на путь файловой системы (path), маску прав (permissions) и контент (content, где хранится содержимое файла). Здесь нужно указать, что системные файлы systemd сервисов etcd2 и fleet должны устанавливать переменные среды, указывающие на сертификаты 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
...

Теперь сервисы знают, где найти файлы сертификатов, но пока что этих файлов не существует. Чтобы создать файлы, нужно знать внутренний IP-адрес каждой машины CoreOS.

Примечание: В кластере CoreOS файл cloud-config нельзя редактировать после создания машин. Вам следует избегать раздела write-files в любой конфигурации, которую вы планируете изменять после создания кластера, поскольку при следующем запуске кластера раздел будет сброшен.

Вход на ноду coreos-1

Итак, согласно требованиям, у вас есть кластер из трех нод. Теперь нужно узнать внутренние IP-адреса, которые понадобятся при генерировании сертификатов и настройке брандмауэра.

Протестируйте ноду. Убедитесь, что вы можете подключиться к ней по ключу SSH:

eval $(ssh-agent)
ssh-add

Найдите внешний IP-адрес ноды и подключитесь с поддержкой переадресации агента SSH:

ssh -A core@coreos-1_public_ip

При первом подключении к любому члену кластера вы, скорее всего, получите сообщение об ошибке от systemd:

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

Это означает, что брандмауэр еще не настроен. На данный момент можно просто проигнорировать это сообщение.

Примечание: Если вы решили не включать брандмауэр, вы не увидите сообщение об ошибке. Вы всегда можете включить сервис iptables-restore позже.

Прежде чем настроить брандмауэр, настройте взаимодействие экземпляров etcd2 на каждой ноде кластера.

Самоподписанный сертификат с помощью CFSSL

CFSSL – это инструментарий для работы с сертификатами TLS/SSL от CloudFlare.

Установка CFSSL на локальную машину

CFSSL требуется рабочая установка Go.

Читайте также: Установка Go 1.5.1 на Ubuntu 14.04

Убедитесь, что переменная $GOPATH установлена правильно и добавлена в $PATH, а затем используйте go get, чтобы установить 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/...

Альтернативный способ установки – собрать бинарные файлы, которые можно извлечь по этой ссылке. Убедитесь, что ~/bin существует, и добавьте его в PATH.

mkdir -p ~/bin
export PATH=$PATH:~/bin

Затем с помощью curl извлеките последнюю версию cfssl и cfssljson:

curl -s -L -o ~/bin/cfssl https://pkg.cfssl.org/R1.1/cfssl_linux-amd64
curl -s -L -o ~/bin/cfssljson https://pkg.cfssl.org/R1.1/cfssljson_linux-amd64

Сделайте файлы cfssl исполняемыми:

chmod +x ~/bin/cfssl
chmod +x ~/bin/cfssljson

Генерирование центра сертификации

Теперь, когда команды cfssl установлены, вы можете использовать их для создания пользовательского центра сертификации, который можно использовать для подписания сертификатов для каждой из нод CoreOS. Создайте новый каталог для этих файлов и перейдите в него:

mkdir ~/coreos_certs
cd ~/coreos_certs

Создайте файл ca-config.json:

nano ca-config.json

Вставьте в него следующие строки:

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

Следует отметить, что срок действия сертификатов установлен на 43800 часов (или 5 лет). Профиль client-server, который включает в себя как server auth, так и client auth, необходим для одноранговой поддержки TLS.

Создайте файл ca-csr.json.

nano ca-csr.json

Вставьте следующее, откорректируйте CN и массив names по вашему желанию. В массиве hosts, а также в имени организации и местоположении безопасно использовать вымышленные значения.

{
"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

Теперь можно сгенерировать ЦС:

cfssl gencert -initca ca-csr.json | cfssljson -bare ca -

Генерирование и подпись сертификатов для кластера CoreOS

Теперь можно создать сертификаты для кластера.

Создайте файл coreos-1.json:

nano 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
  • Внутренний IP-адрес машины CoreOS (а не внешний IP-адрес)

Они будут добавлены в полученный сертификат как subjectAltNames. Соединения etcd (в том числе для локального устройства loopback на 127.0.0.1) требуют, чтобы сертификат имел SAN, соответствующий имени подключаемого хоста.

Вы также можете изменить массив names и указать свое местоположение. Но лучше использовать в нем фиктивные данные.

Повторите этот процесс для остальных машин и создайте файлы coreos-2.json и coreos-3.json с соответствующими записями hosts.

Примечание: Чтобы просмотреть стандартный файл coreos-1.json, введите:

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:

Это создаст 3 файла: ca.pem, coreos-key.pem и coreos.pem. Убедитесь, что установили правильные права доступа.

Повторите этот процесс для остальных машин в кластере.

Примечание: Каждый вызов команды будет переписывать предыдущий набор сертификатов.

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:

Тестирование etcd2

Создав сертификаты, вы должны запустить fleetctl на coreos-1. Подключитесь по SSH:

ssh -A core@coreos-1_public_ip

Теперь просмотрите все машины в кластере:

fleetctl list-machines

Вы увидите список машин и их внутренних IP-адресов.

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

Если fleetctl зависает, можете перезапустить кластер. Выйдите на локальную машину:

exit

И перезапустите все машины 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'

Подождите минутку, переподключитесь к первой ноде и снова попробуйте запустить fleetctl.

Настройка брандмауэра IPTables для кластера

При наличии сертификатов другие компьютеры в локальной сети не смогут контролировать кластер или извлекать значения etcd2. Но чтобы по возможности уменьшить количество потенциальных уязвимостей, нужно добавить простые правила брандмауэра для каждой машины. Они заблокируют большинство локального сетевого трафика, исходящего не от одноранговых нод кластера.

Помните, что если вы включили iptables-restore в cloud-config, вы увидите ошибку systemd при первом входе в систему CoreOS:

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

Это значит, что, хотя сервис включен, iptables-restore не удалось загрузить правильно. Диагностировать это можно с помощью systemctl:

systemctl status -l iptables-restore
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. Здесь обычно находится фактический вывод ошибок сервисов, которые не работают.

Брандмауэр не удалось восстановить, потому что он не может найти файл, содержащий правила для кластера. Зная все внутренние IP-адреса, вы можете легко написать набор правил.

Создайте новый файл и вставьте в него следующие строки. Замените coreos-1_private_ip, coreos-2_private_ip и coreos-3_private_ip внутренним IP-адресом каждой машины кластера CoreOS. Вам также может потребоваться настроить раздел Accept all TCP/IP traffic… и указать внешние сервисы, которые вы собираетесь использовать в кластере.

*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

Скопируйте эти строки в буфер обмена, войдите на первую ноду, откройте rules-save в Vim.

ssh -A core@coreos-1_public_ip
sudo vim /var/lib/iptables/rules-save

Читайте также: Установка и использование текстового редактора Vim

В текстовом редакторе введите :set paste и нажмите Enter, чтобы убедиться, что автоотступы отключены, затем нажмите i, чтобы войти в режим вставки, и вставьте свои правила брандмауэра. Нажмите Esc, чтобы выйти из режима вставки и :wq, чтобы сохранить файл и выйти.

Важно! Убедитесь, что в конце файла находится пустая новая строка, иначе IPTables может прекратить работу из-за синтаксических ошибок, несмотря на то, что все команды в файле написаны правильно.

Установите права доступа к файлу:

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

Теперь проверьте работу сервиса:

sudo systemctl start iptables-restore

Если сервис запустится успешно, команда systemctl не вернет вывода. Вы можете проверить состояние брандмауэра двумя способами. С помощью этой команды:

sudo systemctl status -l iptables-restore

Или с помощью команды iptables:

sudo iptables -v -L

Опция –v включает расширенный вывод, который сообщит, к какому интерфейсу относится данное правило.

Убедившись, что брандмауэр на coreos-1 настроен, выйдите из системы:

exit

Повторите установку /var/lib/iptables/rules-save на остальных нодах кластера.

Tags: , , ,