WIP Support TLS certificate generation in make-etcd
This commit is contained in:
@@ -12,12 +12,7 @@ EnvironmentFile=/etc/vitastor/etcd.conf
|
|||||||
SyslogIdentifier=etcd
|
SyslogIdentifier=etcd
|
||||||
ExecStart=bash -c 'docker run --rm -i -v /var/lib/vitastor/etcd:/data \
|
ExecStart=bash -c 'docker run --rm -i -v /var/lib/vitastor/etcd:/data \
|
||||||
--log-driver none --network host $CONTAINER_OPTIONS --name vitastor-etcd \
|
--log-driver none --network host $CONTAINER_OPTIONS --name vitastor-etcd \
|
||||||
$ETCD_IMAGE /usr/local/bin/etcd --name "$ETCD_NAME" --data-dir /data \
|
$ETCD_IMAGE /usr/local/bin/etcd --data-dir /data
|
||||||
--snapshot-count 10000 --advertise-client-urls http://$ETCD_IP:2379 --listen-client-urls http://$ETCD_IP:2379 \
|
|
||||||
--initial-advertise-peer-urls http://$ETCD_IP:2380 --listen-peer-urls http://$ETCD_IP:2380 \
|
|
||||||
--initial-cluster-token vitastor-etcd-1 --initial-cluster "$ETCD_INITIAL_CLUSTER" \
|
|
||||||
--initial-cluster-state new --max-txn-ops=100000 --max-request-bytes=104857600 \
|
|
||||||
--auto-compaction-retention=10 --auto-compaction-mode=revision'
|
|
||||||
ExecStop=docker stop vitastor-etcd
|
ExecStop=docker stop vitastor-etcd
|
||||||
Restart=always
|
Restart=always
|
||||||
StartLimitInterval=0
|
StartLimitInterval=0
|
||||||
|
|||||||
@@ -1,4 +1 @@
|
|||||||
ETCD_IMAGE=quay.io/coreos/etcd:v3.5.18
|
ETCD_IMAGE=quay.io/coreos/etcd:v3.5.18
|
||||||
ETCD_NAME=""
|
|
||||||
ETCD_IP=""
|
|
||||||
ETCD_INITIAL_CLUSTER=""
|
|
||||||
|
|||||||
@@ -0,0 +1,439 @@
|
|||||||
|
[Документация](../../README-ru.md#документация) → Безопасность
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
[Read in English](security.en.md)
|
||||||
|
|
||||||
|
# Оглавление
|
||||||
|
|
||||||
|
⚠️ Предупреждение: детальное описание настроек безопасности достаточно длинное.
|
||||||
|
|
||||||
|
Если не боитесь - читайте [Подробное описание](#подробное-описание).
|
||||||
|
|
||||||
|
Если хотите просто быстро настроить Vitastor с шифрованием - читайте начало статьи.
|
||||||
|
|
||||||
|
- [Быстрая настройка](#быстрая-настройка)
|
||||||
|
-
|
||||||
|
|
||||||
|
# Быстрая настройка
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Пользовательские сценарии
|
||||||
|
|
||||||
|
Зачем всё это нужно вам?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Подробное описание
|
||||||
|
|
||||||
|
Начиная с версии 3.1.0, в Vitastor есть следующие функции:
|
||||||
|
1. Шифрование соединений с etcd (TLS)
|
||||||
|
2. Шифрование соединений с OSD (AES-GCM) - по выбору либо только заголовков, либо и заголовков, и данных
|
||||||
|
3. Сквозное шифрование данных образов (AES-XTS)
|
||||||
|
4. Хранения ключей шифрования AES-XTS во внешнем Vault
|
||||||
|
5. Контрольных сумм данных на транспортном уровне с секретной "солью"
|
||||||
|
6. Аутентификация с помощью TLS (X.509) сертификатов и закрытых ключей
|
||||||
|
7. Разграничение прав доступа клиентов к данным etcd
|
||||||
|
8. Разграничение прав доступа клиентов к данным самих образов (на стороне OSD)
|
||||||
|
|
||||||
|
По умолчанию шифрование, аутентификация и авторизация отключены, но, начиная с 3.1.0,
|
||||||
|
используются контрольные суммы данных на транспортном уровне (`proto_checksums=payload`).
|
||||||
|
|
||||||
|
## Шифрование соединений с etcd (TLS)
|
||||||
|
|
||||||
|
Варианты настройки:
|
||||||
|
- Без шифрования (http)
|
||||||
|
- С шифрованием (https)
|
||||||
|
- С клиентским сертификатом, но при выключенной авторизации (`use_auth=false`) - используется
|
||||||
|
отдельный сертификат и ключ: `etcd_client_cert`, `etcd_client_key`
|
||||||
|
- С клиентским сертификатом, при включённой аутентификации на уровне OSD - используется общий
|
||||||
|
сертификат и ключ: для OSD - `osd_cert` и `osd_pkey`, для клиентов - `cert` и `pkey`
|
||||||
|
|
||||||
|
## Шифрование соединений с OSD (AES-GCM)
|
||||||
|
|
||||||
|
Варианты настройки:
|
||||||
|
- Без шифрования и без контрольных сумм: `proto_checksums=none`.
|
||||||
|
- Без шифрования, с контрольными суммами данных: `proto_checksums=payload` (можно не указывать,
|
||||||
|
т.к. это значение по умолчанию). При этом контрольные суммы можно отключить на стороне
|
||||||
|
клиента либо использовать более старые версии клиента, не поддерживающие контрольные суммы.
|
||||||
|
Если нужно запретить подключение клиентов без контрольных сумм, можно использовать опцию
|
||||||
|
`force_proto_checksums=payload`.
|
||||||
|
- С шифрованием заголовков и контрольными суммами данных: активируется при установленных опциях
|
||||||
|
`cert`, `pkey`, `osd_ca` на стороне клиента и `osd_cert`, `osd_pkey`, `osd_ca`, `client_ca`
|
||||||
|
на стороне OSD, при `proto_checksums=payload`. При этом по умолчанию запрещается
|
||||||
|
отключение контрольных сумм на уровне клиента, то есть используется `force_proto_checksums=payload`.
|
||||||
|
- С полным шифрованием всего трафика: аналогично прошлому варианту, но с `proto_checksums=gcm`.
|
||||||
|
Клиенту при этом по умолчанию разрешается понизить уровень защиты до контрольных сумм, но
|
||||||
|
это тоже можно запретить через `force_proto_checksums=gcm`. Данный вариант не является рекомендуемым,
|
||||||
|
так как добавлен в первую очередь для возможной поддержки небезопасных (публичных) сетей и
|
||||||
|
больше всего снижает производительность. В частности, если одновременно использовать полное
|
||||||
|
шифрование трафика и сквозное шифрование образов AES-XTS, то данные будут шифроваться дважды.
|
||||||
|
|
||||||
|
Для шифрования используется алгоритм AES-256-GCM и собственный упрощённый протокол согласования
|
||||||
|
ключей, полностью аналогичный TLS 1.3 ECDHE.
|
||||||
|
|
||||||
|
## Сквозное шифрование данных образов (AES-XTS)
|
||||||
|
|
||||||
|
Клиент Vitastor поддерживает шифрование данных каждого образа своим ключом. В этом случае на OSD
|
||||||
|
уходят уже зашифрованные данные и сами OSD не видят настоящее содержимое образов. Разные ключи
|
||||||
|
в том числе могут иметь разные снимки или клоны одного и того же образа. Например, можно сделать
|
||||||
|
базовый образ ВМ (условный Debian Linux) нешифрованным, но наследовать от него шифрованные образы
|
||||||
|
клиентских ВМ.
|
||||||
|
|
||||||
|
Ключи шифрования образов могут храниться либо в etcd, либо во внешнем Vault. Во втором случае
|
||||||
|
в etcd хранятся только ID ключей, а Vitastor вообще не имеет доступа к данным образов. Для
|
||||||
|
использования Vault нужно создать образ с опцией `--enc_key vault:ID`, а в конфигурации указать
|
||||||
|
опции:
|
||||||
|
- vault_url
|
||||||
|
- vault_ca
|
||||||
|
- vault_client_cert
|
||||||
|
- vault_client_key
|
||||||
|
|
||||||
|
Ещё раз повторимся, что если AES-XTS используется с полным шифрованием трафика (`proto_checksums=gcm`),
|
||||||
|
то данные образов шифруются дважды - сначала AES-XTS, а потом AES-GCM. Можете использовать,
|
||||||
|
только если вы совсем параноик :-).
|
||||||
|
|
||||||
|
## Производительность шифрования
|
||||||
|
|
||||||
|
У вас может возникнуть вопрос - а как быстро всё это прекрасное шифрование работает?
|
||||||
|
|
||||||
|
Ответ - скорость сильно зависит от процессора. Складывается она из нескольких вещей:
|
||||||
|
|
||||||
|
-
|
||||||
|
|
||||||
|
TODO: vitastor-cli bench.
|
||||||
|
|
||||||
|
## Аутентификация по сертификатам
|
||||||
|
|
||||||
|
При включённом шифровании клиенты, OSD и мониторы Vitastor аутентифицируются по сертификатам
|
||||||
|
как при соединениях с etcd (Antietcd), так и с OSD.
|
||||||
|
|
||||||
|
Для OSD и мониторов должны использоваться отдельные сертификаты - либо самоподписанные, либо
|
||||||
|
подписанные отдельными CA (`osd_ca` и `mon_ca`). При этом все OSD могут использовать один и
|
||||||
|
тот же сертификат и все мониторы тоже могут использовать один и тот же сертификат, так как
|
||||||
|
привилегии разных OSD или разных мониторов ничем не отличаются (теоретически можно было бы
|
||||||
|
сделать разграничение сертификатов OSD по пулам, но пока что такой необходимости не было).
|
||||||
|
|
||||||
|
Также сертификат монитора может быть вообще не нужен, если Antietcd встраивается в сам монитор.
|
||||||
|
В этом случае монитор и так имеет доступ ко всем данным etcd прямо в памяти.
|
||||||
|
|
||||||
|
Каждый клиент должен иметь свой сертификат, подписанный общим корневым сертификатом
|
||||||
|
для клиентов (`client_ca`). Common Name сертификата должно равняться имени пользователя.
|
||||||
|
|
||||||
|
## Модель прав доступа
|
||||||
|
|
||||||
|
Привилегии пользователей хранятся в данных etcd в ключах `/vitastor/config/user/<имя>`.
|
||||||
|
|
||||||
|
У пользователя есть 2 свойства:
|
||||||
|
- Тип:
|
||||||
|
- Клиент (`type=client` или не указано) - может читать и модифицировать только явным образом
|
||||||
|
разрешённые образы.
|
||||||
|
- Администратор (`type=admin`) - может читать и модифицировать все образы, а также администрировать
|
||||||
|
кластер: смотреть общую статистику и состояние, создавать и удалять OSD и так далее.
|
||||||
|
- Список имён групп, членом которых пользователь является.
|
||||||
|
|
||||||
|
У образов есть 3 свойства:
|
||||||
|
- Владелец (owner) - имя пользователя, которому разрешено и читать, и менять образ
|
||||||
|
- Группа владельцев (owner_group) - имя группы владельцев
|
||||||
|
- Группа читатетей (reader_group) - имя группы пользователей, которым разрешено читать образ
|
||||||
|
|
||||||
|
У пулов есть 1 свойство:
|
||||||
|
- Группа создателей (creator_group) - имя группы пользователей, которым разрешено создавать образы в пуле
|
||||||
|
|
||||||
|
## Права доступа к данным etcd
|
||||||
|
|
||||||
|
Привилегии реализуются через Antietcd во всех режимах работы. Если используется etcd, то
|
||||||
|
Antietcd выступает в роли фильтрующего прокси, при этом он может быть встроен в монитор
|
||||||
|
Vitastor или запущен отдельно. В этом случае etcd должен разрешать входящие подключения
|
||||||
|
только от Antietcd, а все остальные компоненты должны соединяться с Antietcd.
|
||||||
|
|
||||||
|
Если же используется Antietcd, то привилегии реализуются в нём самом.
|
||||||
|
|
||||||
|
Если используется встроенный в монитор Antietcd, то привилегии включаются либо параметром
|
||||||
|
`use_auth: true`, либо, если этот параметр не указан - включается автоматически, если задан
|
||||||
|
любой из параметров `client_ca`, `osd_ca`, `mon_ca`. При этом монитор требует указания
|
||||||
|
параметров `client_ca` и `osd_ca`, а если не используется режим проксирования в etcd -
|
||||||
|
также `antietcd_server_ca`, чтобы Antietcd мог отличать кластерные соединения от клиентских.
|
||||||
|
|
||||||
|
Если используется отдельно стоящий Antietcd, привилегии нужно включать явным образом.
|
||||||
|
|
||||||
|
Встроенные привилегии etcd не поддерживаются по причине их многочисленных недоработок:
|
||||||
|
- Аутентификация по сертификатам не работает в REST интерфейсе etcd,
|
||||||
|
- Привилегии хранятся отдельно от k/v и не могут участвовать в транзакциях,
|
||||||
|
- Менять привилегии может только администратор (root)
|
||||||
|
- Нет поддержки фильтрации ответов чтения по привилегиям.
|
||||||
|
|
||||||
|
Подробный список привилегий на ключи в etcd [смотрите ниже](#привилегии-etcd).
|
||||||
|
|
||||||
|
## Права доступа к данным OSD
|
||||||
|
|
||||||
|
Регулируется опцией `use_auth`, либо, если она не указана, включается автоматически,
|
||||||
|
если используется шифрование, то есть, если заданы опции `osd_ca` и `client_ca`.
|
||||||
|
|
||||||
|
OSD аутентифицирует клиентов по сертификатам и разрешает каждому клиенту только
|
||||||
|
то, что ему разрешено согласно модели прав доступа.
|
||||||
|
|
||||||
|
Подробный список разрешаемых OSD операций [смотрите ниже](#привилегии-osd).
|
||||||
|
|
||||||
|
## Права доступа к API
|
||||||
|
|
||||||
|
[vitastor-cli serve](../usage/cli.ru.md#serve) также поддерживает клиентскую
|
||||||
|
аутентификацию по сертификатам. Принимаются только сертификаты, подписанные
|
||||||
|
`client_ca`. В качестве серверного сертификата используется отдельный сертификат
|
||||||
|
`server_cert` с ключом `server_key`.
|
||||||
|
|
||||||
|
При этом для корректной работы `vitastor-cli serve` он сам должен использовать
|
||||||
|
для доступа в Vitastor сертификат (`cert`+`pkey`) пользователя с правами
|
||||||
|
администратора (`type=admin`).
|
||||||
|
|
||||||
|
Обычным клиентам при доступе к API разрешаются только API-операции с образами,
|
||||||
|
доступными им либо на чтение (для чтения), либо на запись (для модификации).
|
||||||
|
Все остальные API-вызовы разрешаются только для администраторов.
|
||||||
|
|
||||||
|
Подробный список разрешаемых API операций [смотрите ниже](#привилегии-api).
|
||||||
|
|
||||||
|
## Привилегии etcd
|
||||||
|
|
||||||
|
Ниже все названия ключей приведены без общего префикса `/vitastor`.
|
||||||
|
|
||||||
|
Разрешённые операции с ключами в Antietcd для клиентов (`type=client`):
|
||||||
|
- Только чтение:
|
||||||
|
- Разрешено всегда:
|
||||||
|
- `/config/global`
|
||||||
|
- `/config/node_placement`
|
||||||
|
- `/config/pools`
|
||||||
|
- `/pg/config`
|
||||||
|
- `/osd/state/*`
|
||||||
|
- `/pg/state/*`
|
||||||
|
- `/index/maxid/*`
|
||||||
|
- Для образов, которые [может читать пользователь](#модель-прав-доступа):
|
||||||
|
- `/config/inode/*`
|
||||||
|
- `/index/image/*`
|
||||||
|
- `/inode/stats/*`
|
||||||
|
- Чтение и запись:
|
||||||
|
- Для пулов, в которых может создавать образы пользователь:
|
||||||
|
- `/index/maxid/*`
|
||||||
|
- Для образов, которыми владеет пользователь:
|
||||||
|
- `/config/inode/*`
|
||||||
|
- `/index/image/*`
|
||||||
|
|
||||||
|
Разрешённые операции с ключами в Antietcd для администраторов (`type=admin`):
|
||||||
|
- Чтение:
|
||||||
|
- `/stats`
|
||||||
|
- `/mon/*`
|
||||||
|
- `/pg/*`
|
||||||
|
- `/pgstats/*`
|
||||||
|
- `/inode/stats/*`
|
||||||
|
- `/pool/stats/*`
|
||||||
|
- Чтение и запись:
|
||||||
|
- `/config/*`
|
||||||
|
- `/osd/*`
|
||||||
|
- `/index/*`
|
||||||
|
- `/pg/history/*`
|
||||||
|
|
||||||
|
Разрешённые операции с ключами в etcd для OSD:
|
||||||
|
- Чтение:
|
||||||
|
- `/pg/config`
|
||||||
|
- `/config/*`
|
||||||
|
- Чтение и запись:
|
||||||
|
- `/osd/*`
|
||||||
|
- `/pg/state/*`
|
||||||
|
- `/pg/history/*`
|
||||||
|
- `/pgstats/*`
|
||||||
|
|
||||||
|
Разрешённые операции с ключами в etcd для мониторов:
|
||||||
|
- Чтение:
|
||||||
|
- `/config/*`
|
||||||
|
- `/osd/*`
|
||||||
|
- `/pgstats/*`
|
||||||
|
- Чтение и запись:
|
||||||
|
- `/pg/config`
|
||||||
|
- `/stats`
|
||||||
|
- `/history/last_clean_pgs`
|
||||||
|
- `/mon/*`
|
||||||
|
- `/pg/history/*`
|
||||||
|
- `/inode/stats/*`
|
||||||
|
- `/pool/stats/*`
|
||||||
|
|
||||||
|
## Привилегии OSD
|
||||||
|
|
||||||
|
Клиентские операции:
|
||||||
|
- READ - разрешено для образов, доступных пользователю на чтение.
|
||||||
|
- WRITE, DELETE, SCRUB - разрешены для образов, доступных пользователю на запись.
|
||||||
|
- SYNC - операция не связана с образом и разрешена всегда.
|
||||||
|
- DESCRIBE - операция разрешена только для администраторов (используются командами
|
||||||
|
`vitastor-cli describe` и `fix`).
|
||||||
|
- PING - операция разрешена всегда.
|
||||||
|
- SHOW_CONFIG - операция разрешена всегда, однако если в ней клиент представляется
|
||||||
|
как OSD, то проверяется, что он использует сертификат, подписанный `osd_ca`.
|
||||||
|
- SEC_LIST (листинг) - разрешена другим OSD и администраторам с любыми параметрами,
|
||||||
|
а обычным клиентам разрешена только для запросов, ограниченных образом, доступным
|
||||||
|
пользователю на чтение.
|
||||||
|
|
||||||
|
Кластерные операции - разрешаются только другим OSD:
|
||||||
|
- SEC_READ
|
||||||
|
- SEC_WRITE
|
||||||
|
- SEC_WRITE_STABLE
|
||||||
|
- SEC_SYNC
|
||||||
|
- SEC_STABILIZE
|
||||||
|
- SEC_ROLLBACK
|
||||||
|
- SEC_DELETE
|
||||||
|
- SEC_READ_BMP
|
||||||
|
- SEC_LOCK
|
||||||
|
|
||||||
|
## Привилегии API
|
||||||
|
|
||||||
|
Клиентам (пользователям с `type=client`) разрешаются операции:
|
||||||
|
- image/list - для образов, которые пользователь может читать.
|
||||||
|
- image/create - для пулов, в которых пользователю разрешено создавать образы, либо
|
||||||
|
для создания снимков образов, которыми пользователь владеет.
|
||||||
|
- image/delete, image/flatten, image/modify - для образов, которыми пользователь владеет.
|
||||||
|
|
||||||
|
Все остальные операции разрешаются только администраторам (`type=admin`).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Таким образом, доступны следующие варианты настройки:
|
||||||
|
|
||||||
|
### Mon в роли Etcd proxy
|
||||||
|
|
||||||
|
Mon
|
||||||
|
- use_antietcd: true
|
||||||
|
- etcd_proxy = {
|
||||||
|
urls: [],
|
||||||
|
cert = <antietcd.pem>,
|
||||||
|
key,
|
||||||
|
ca = <etcd.pem>,
|
||||||
|
}
|
||||||
|
- antietcd_cert = antietcd.pem
|
||||||
|
- antietcd_key
|
||||||
|
|
||||||
|
etcd
|
||||||
|
--client-cert-auth --cert-file=etcd.pem --key-file=etcd.key --trusted-ca-file=antietcd.pem \
|
||||||
|
--peer-client-cert-auth --peer-cert-file=etcd.pem --peer-key-file=etcd.key --peer-trusted-ca-file=etcd.pem
|
||||||
|
|
||||||
|
### Mon с отдельным Antietcd Proxy
|
||||||
|
|
||||||
|
Mon
|
||||||
|
- use_antietcd: false
|
||||||
|
- etcd_ca = antietcd.pem
|
||||||
|
|
||||||
|
Antietcd
|
||||||
|
--client_cert_auth 1 --auth_filter vitastor_auth_filter.js --etcd_proxy url1,url2,... \
|
||||||
|
--cert antietcd.pem --key antietcd.key --ca client_ca.pem --osd_ca osd_ca.pem \
|
||||||
|
--etcd_cert antietcd.pem --etcd_key antietcd.key --etcd_ca etcd.pem
|
||||||
|
|
||||||
|
etcd
|
||||||
|
--client-cert-auth --cert-file=etcd.pem --key-file=etcd.key --trusted-ca-file=antietcd.pem \
|
||||||
|
--peer-client-cert-auth --peer-cert-file=etcd.pem --peer-key-file=etcd.key --peer-trusted-ca-file=etcd.pem
|
||||||
|
|
||||||
|
### Mon со встроенным Antietcd
|
||||||
|
|
||||||
|
Mon
|
||||||
|
- use_antietcd: true
|
||||||
|
- use_auth: true
|
||||||
|
- antietcd_cert = antietcd.pem
|
||||||
|
- antietcd_key
|
||||||
|
|
||||||
|
### Отдельный Antietcd
|
||||||
|
|
||||||
|
Mon
|
||||||
|
- use_antietcd: false
|
||||||
|
- etcd_ca = antietcd.pem
|
||||||
|
|
||||||
|
Antietcd
|
||||||
|
--client_cert_auth 1 --auth_filter vitastor_auth_filter.js
|
||||||
|
|
||||||
|
## Варианты настройки
|
||||||
|
|
||||||
|
### Настройка по умолчанию
|
||||||
|
|
||||||
|
Используются только контрольные суммы данных на транспортном уровне. Соединения с etcd не шифруются.
|
||||||
|
Аутентификация и авторизация не используется, любой клиент имеет доступ ко всем данным кластера.
|
||||||
|
|
||||||
|
Аналог настройки:
|
||||||
|
- proto_checksums: payload
|
||||||
|
|
||||||
|
### Полная защита
|
||||||
|
|
||||||
|
Везде
|
||||||
|
- osd_ca
|
||||||
|
- client_ca
|
||||||
|
- etcd_ca = antietcd.pem
|
||||||
|
|
||||||
|
OSD
|
||||||
|
- osd_cert
|
||||||
|
- osd_pkey
|
||||||
|
|
||||||
|
Клиент
|
||||||
|
- cert
|
||||||
|
- pkey
|
||||||
|
|
||||||
|
### Только защита etcd
|
||||||
|
|
||||||
|
- etcd_ca
|
||||||
|
- etcd_cert
|
||||||
|
- etcd_key
|
||||||
|
|
||||||
|
### antietcd и только защита antietcd
|
||||||
|
|
||||||
|
- etcd_ca
|
||||||
|
- etcd_cert
|
||||||
|
- etcd_key
|
||||||
|
- use_antietcd: true
|
||||||
|
- antietcd_cert = etcd_ca
|
||||||
|
- antietcd_key
|
||||||
|
- antietcd_ca = etcd_cert
|
||||||
|
|
||||||
|
### Полное шифрование протокола, включая данные
|
||||||
|
|
||||||
|
Внимание: если включить этот вариант защиты и при этом
|
||||||
|
|
||||||
|
### Только контрольные суммы на транспортном уровне, без шифрования
|
||||||
|
|
||||||
|
## Настройка Vault/OpenBao
|
||||||
|
|
||||||
|
openssl req -days 3650 -x509 -addext basicConstraints=critical,CA:TRUE,pathlen:1 --addext subjectAltName=DNS:vault \
|
||||||
|
-new -newkey rsa:4096 -nodes -keyout vault.key -out vault.crt
|
||||||
|
|
||||||
|
bao status -ca-cert /etc/openbao/tls/vault.crt -address=https://vault:8200
|
||||||
|
|
||||||
|
bao operator init -n 1 -t 1 -ca-cert /etc/openbao/tls/vault.crt -address=https://vault:8200
|
||||||
|
|
||||||
|
bao operator unseal -ca-cert /etc/openbao/tls/vault.crt -address=https://vault:8200
|
||||||
|
|
||||||
|
bao auth enable -ca-cert /etc/openbao/tls/vault.crt -address=https://vault:8200 cert
|
||||||
|
|
||||||
|
bao secrets enable -ca-cert /etc/openbao/tls/vault.crt -address=https://vault:8200 -path=secret kv-v1
|
||||||
|
|
||||||
|
bao kv put -ca-cert /etc/openbao/tls/vault.crt -address=https://vault:8200 secret/vitastor/testimg3 key=$(openssl rand -hex 64)
|
||||||
|
|
||||||
|
cat >testimg3.policy <<EOF
|
||||||
|
path "/secret/vitastor/testimg3" {
|
||||||
|
capabilities = ["read"]
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
bao policy write -ca-cert /etc/openbao/tls/vault.crt -address=https://vault:8200 testimg3 testimg3.policy
|
||||||
|
|
||||||
|
bao write -ca-cert /etc/openbao/tls/vault.crt -address=https://vault:8200 auth/cert/certs/testimg3 certificate=@testimg3.crt display_name=testimg3 token_ttl=24h token_policies=testimg3
|
||||||
|
|
||||||
|
curl --cacert /etc/vitastor/vault.crt --cert testimg3.crt --key testimg3.key --json '{}' https://vault:8200/v1/auth/cert/login
|
||||||
|
|
||||||
|
curl --cacert /etc/vitastor/vault.crt --cert testimg3.crt --key testimg3.key -H 'X-Vault-Token: s.Qkrm78BeK7Rqdz5MA3eJZNbu' https://vault:8200/v1/secret/vitastor/testimg3
|
||||||
+327
-44
@@ -1,38 +1,278 @@
|
|||||||
#!/usr/bin/node
|
#!/usr/bin/node
|
||||||
// Simple systemd unit generator for etcd
|
// Simple Vitastor etcd / antietcd / TLS configurator
|
||||||
// Copyright (c) Vitaliy Filippov, 2019+
|
// Copyright (c) Vitaliy Filippov, 2019+
|
||||||
// License: MIT
|
// License: MIT
|
||||||
|
|
||||||
// USAGE:
|
|
||||||
// 1) Put the same etcd_address into /etc/vitastor/vitastor.conf on all monitor nodes
|
|
||||||
// 2) Run ./make-etcd.js. It will create the etcd service on one of specified IPs
|
|
||||||
|
|
||||||
const child_process = require('child_process');
|
const child_process = require('child_process');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
|
const readline = require('readline');
|
||||||
|
|
||||||
run().catch(e => { console.error(e); process.exit(1); });
|
run().catch(e => { console.error(e); process.exit(1); });
|
||||||
|
|
||||||
|
const help_text = `Initialize a Vitastor cluster (etcd, vitastor.conf and TLS certificates)
|
||||||
|
(c) Vitaliy Filippov, 2019+ (MIT)
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
1) Create a minimal vitastor.conf with etcd_address, osd_network and (optionally) use_auth.
|
||||||
|
Example: {"etcd_address":["http://10.0.0.10:2379","http://10.0.0.11:2379","http://10.0.0.12:2379"],"use_auth":false,"osd_network":"10.0.0.0/24"}
|
||||||
|
Or: {"etcd_address":["https://10.0.0.10:2379","https://10.0.0.11:2379","https://10.0.0.12:2379"],"use_auth":true,"osd_network":"10.0.0.0/24"}
|
||||||
|
2) Run: ${process.argv[1]} [./vitastor.conf]
|
||||||
|
You can run it on etcd/monitor nodes or on an external node.
|
||||||
|
It configures etcd, generates TLS certificates (on the first or external node), copies them
|
||||||
|
to other etcd/monitor nodes, and updates vitastor.conf with TLS options.
|
||||||
|
3) If you have OSD-only nodes, run:
|
||||||
|
${process.argv[1]} --copy-to-osd-node NODE_NAME ./vitastor.conf
|
||||||
|
It copies vitastor.conf and required TLS certificates to that node.
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
--gen-certs
|
||||||
|
force certificate generation even if it's not the first node
|
||||||
|
--no-certs
|
||||||
|
disable certificate generation
|
||||||
|
--no-copy
|
||||||
|
do not copy initial certificates to other nodes
|
||||||
|
--copy-to-osd-node NODE[,NODE2,...]
|
||||||
|
copy vitastor.conf and TLS certificates required for OSDs to NODES using scp
|
||||||
|
--copy-to-mon-node NODE[,NODE2,...]
|
||||||
|
copy vitastor.conf and TLS certificates required for monitor and etcd to NODES using scp
|
||||||
|
--copy-to-client-node NODE[,NODE2,...]
|
||||||
|
copy vitastor.conf and TLS certificates required for clients to NODES using scp
|
||||||
|
`;
|
||||||
|
|
||||||
async function run()
|
async function run()
|
||||||
{
|
{
|
||||||
const config_path = process.argv[2] || '/etc/vitastor/vitastor.conf';
|
let config_path = '/etc/vitastor/vitastor.conf';
|
||||||
if (config_path == '-h' || config_path == '--help')
|
let config_dir = '/etc/vitastor/';
|
||||||
|
let gen_certs = 'auto';
|
||||||
|
let copy_initial = true;
|
||||||
|
let copy_to_osd =
|
||||||
|
for (let i = 2; i < process.argv.length; i++)
|
||||||
{
|
{
|
||||||
console.log(
|
if (arg == '-h' || arg == '--help')
|
||||||
'Initialize systemd etcd service for Vitastor\n'+
|
{
|
||||||
'(c) Vitaliy Filippov, 2019+ (MIT)\n'+
|
console.log(help_text);
|
||||||
'\n'+
|
process.exit(0);
|
||||||
'USAGE:\n'+
|
}
|
||||||
'1) Put the same etcd_address into /etc/vitastor/vitastor.conf on all monitor nodes\n'+
|
else if (arg == '--only-certs')
|
||||||
'2) Run '+process.argv[1]+' [config_path]\n'
|
{
|
||||||
);
|
i++;
|
||||||
process.exit(0);
|
gen_certs =
|
||||||
|
}
|
||||||
|
else if (arg == '--copy')
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
copy = process.argv[i];
|
||||||
|
if (copy !== 'ask' && copy !== 'yes' && copy !== 'no')
|
||||||
|
{
|
||||||
|
console.error('--copy should be "ask", "yes" or "no"');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (arg[0] == '-')
|
||||||
|
{
|
||||||
|
console.error('Unknown option: '+arg[0]);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
config_path = arg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!fs.existsSync(config_path))
|
if (!fs.existsSync(config_path))
|
||||||
{
|
{
|
||||||
console.log(config_path+' is missing');
|
console.log(config_path+' is missing');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
const config = JSON.parse(fs.readFileSync(config_path, { encoding: 'utf-8' }));
|
||||||
|
if (!config.etcd_address)
|
||||||
|
{
|
||||||
|
console.log("etcd_address is missing in "+config_path);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
const etcds = (config.etcd_address instanceof Array ? config.etcd_address : (''+config.etcd_address).split(/,/))
|
||||||
|
.map(s => /^(https?):\/\/(\[[^\]]+\]|[^\[\]\:\/]+)(?::(\d+))?/.exec(s.toLowerCase()))
|
||||||
|
.filter(s => s)
|
||||||
|
.map(s => ({
|
||||||
|
scheme: s[1],
|
||||||
|
addr: s[2].indexOf(':') && s[2][0] != '[' ? '['+s[2]+']' : s[2],
|
||||||
|
ip: s[2][0] == '[' ? s[2].substr(1, s[2].length-2) : s[2],
|
||||||
|
port: s[3],
|
||||||
|
}));
|
||||||
|
const tls = etcds.filter(e => e.scheme === 'https').length > 0;
|
||||||
|
const use_auth = tls && config.use_auth;
|
||||||
|
const num = select_local_etcd(etcds);
|
||||||
|
if (tls)
|
||||||
|
{
|
||||||
|
if (gen_certs === 'yes')
|
||||||
|
{
|
||||||
|
gen_certs = true;
|
||||||
|
console.log('Certificate generation is requested explicitly, generating');
|
||||||
|
}
|
||||||
|
else if (gen_certs === 'no')
|
||||||
|
{
|
||||||
|
gen_certs = false;
|
||||||
|
console.log('Certificate generation is disabled explicitly, skipping');
|
||||||
|
}
|
||||||
|
else if (num < 0)
|
||||||
|
{
|
||||||
|
gen_certs = true;
|
||||||
|
console.log('No matching IPs in etcd_address from '+config_path+', only generating certificates');
|
||||||
|
}
|
||||||
|
else if (fs.existsSync("/etc/vitastor/etcd.crt"))
|
||||||
|
{
|
||||||
|
gen_certs = false;
|
||||||
|
console.log('/etc/vitastor/etcd.crt already exists, assuming certificates are already generated');
|
||||||
|
}
|
||||||
|
else if (num === 0)
|
||||||
|
{
|
||||||
|
gen_certs = true;
|
||||||
|
console.log('This is monitor node 1, generating certificates');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
console.log('This is monitor node '+(num+1)+', /etc/vitastor/etcd.crt does not exist, please copy certificates to this node');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
if (gen_certs)
|
||||||
|
{
|
||||||
|
if (copy === 'ask')
|
||||||
|
copy = await ask_copy('Copy certificates and vitastor.conf to other nodes after generation?');
|
||||||
|
copy = (copy === 'y' || copy === 'yes');
|
||||||
|
await make_certs(dir, copy);
|
||||||
|
}
|
||||||
|
await write_auth_config(config, config_path);
|
||||||
|
}
|
||||||
|
if (num < 0)
|
||||||
|
{
|
||||||
|
console.log('No matching IPs in etcd_address from '+config_path);
|
||||||
|
process.exit(tls && gen_certs ? 0 : 1);
|
||||||
|
}
|
||||||
|
await configure_etcd();
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ask_copy(question)
|
||||||
|
{
|
||||||
|
const rl = readline.createInterface({
|
||||||
|
input: process.stdin,
|
||||||
|
output: process.stdout,
|
||||||
|
prompt: '> ',
|
||||||
|
});
|
||||||
|
let copy;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
copy = await new Promise(ok => rl.question(question, ok));
|
||||||
|
if (copy != 'y' && copy != 'n' && copy != 'yes' && copy != 'no')
|
||||||
|
console.log('Please type "yes" or "no"');
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function make_certs(dir, copy)
|
||||||
|
{
|
||||||
|
console.log(`-----
|
||||||
|
Generating certificates in ${dir}
|
||||||
|
-----
|
||||||
|
`);
|
||||||
|
await make_ca("/O=Vitastor etcd CA", dir+"etcd_ca");
|
||||||
|
await make_signed("/CN=Vitastor etcd", dir+"etcd", dir+"etcd_ca", etcds.map(e => "IP:"+e.ip).join(','));
|
||||||
|
if (use_auth)
|
||||||
|
{
|
||||||
|
await make_ca("/O=Vitastor Antietcd CA", dir+"antietcd_ca");
|
||||||
|
await make_signed("/CN=Vitastor Antietcd", dir+"antietcd", dir+"antietcd_ca", etcds.map(e => "IP:"+e.ip).join(','));
|
||||||
|
await make_ca("/CN=Vitastor OSD", dir+"osd");
|
||||||
|
await make_ca("/O=Vitastor Client CA", dir+"client_ca");
|
||||||
|
await make_signed("/CN=admin", dir+"admin", dir+"client_ca");
|
||||||
|
}
|
||||||
|
if (use_auth)
|
||||||
|
{
|
||||||
|
console.log(`-----
|
||||||
|
Certificates generated, commands to copy them:
|
||||||
|
- Monitor+OSD node:
|
||||||
|
cd ${dir} && scp antietcd_ca.crt antietcd.crt antietcd.key osd.crt osd.key client_ca.crt etcd_ca.crt etcd.crt etcd.key root@NODE:/etc/vitastor/
|
||||||
|
- Monitor node:
|
||||||
|
cd ${dir} && scp antietcd_ca.crt antietcd.crt antietcd.key osd.crt client_ca.crt etcd_ca.crt etcd.crt etcd.key root@NODE:/etc/vitastor/
|
||||||
|
- OSD node:
|
||||||
|
cd ${dir} && scp antietcd_ca.crt osd.crt osd.key client_ca.crt root@NODE:/etc/vitastor/
|
||||||
|
-----
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
console.log(`-----
|
||||||
|
Certificates generated, commands to copy them:
|
||||||
|
- Monitor node:
|
||||||
|
cd ${dir} && scp etcd_ca.crt etcd.crt etcd.key root@NODE:/etc/vitastor/
|
||||||
|
-----
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
if (copy)
|
||||||
|
{
|
||||||
|
const to_copy = use_auth
|
||||||
|
? [ "antietcd_ca.crt", "antietcd.crt", "antietcd.key", "osd.crt", "osd.key", "client_ca.crt", "etcd_ca.crt", "etcd.crt", "etcd.key" ]
|
||||||
|
: [ "etcd_ca.crt", "etcd.crt", "etcd.key" ];
|
||||||
|
for (const node of etcds)
|
||||||
|
{
|
||||||
|
await system("scp "+dir+to_copy.join(" "+dir)+" root@"+node.ip+"/etc/vitastor/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
console.warn('Certificates generated in /etc/vitastor, please copy them to other nodes');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function write_auth_config(config, config_path)
|
||||||
|
{
|
||||||
|
const auth = {};
|
||||||
|
if (use_auth)
|
||||||
|
{
|
||||||
|
auth["use_antietcd"] = true;
|
||||||
|
auth["etcd_proxy"] = {
|
||||||
|
urls: etcds.map(e => e.ip+':2381'),
|
||||||
|
cert: "/etc/vitastor/antietcd.crt",
|
||||||
|
key: "/etc/vitastor/antietcd.key",
|
||||||
|
ca: "/etc/vitastor/etcd_ca.crt",
|
||||||
|
};
|
||||||
|
auth["antietcd_cert"] = "/etc/vitastor/antietcd.crt";
|
||||||
|
auth["antietcd_key"] = "/etc/vitastor/antietcd.key";
|
||||||
|
auth["etcd_ca"] = "/etc/vitastor/antietcd_ca.crt";
|
||||||
|
auth["osd_cert"] = "/etc/vitastor/osd.crt";
|
||||||
|
auth["osd_pkey"] = "/etc/vitastor/osd.key";
|
||||||
|
auth["osd_ca"] = "/etc/vitastor/osd.crt";
|
||||||
|
auth["client_ca"] = "/etc/vitastor/client_ca.crt";
|
||||||
|
auth["cert"] = "/etc/vitastor/admin.crt";
|
||||||
|
auth["pkey"] = "/etc/vitastor/admin.key";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auth["etcd_ca"] = "/etc/vitastor/etcd.crt";
|
||||||
|
}
|
||||||
|
for (const k in auth)
|
||||||
|
{
|
||||||
|
if ((k in config) && JSON.stringify(auth[k]) != JSON.stringify(config[k]))
|
||||||
|
{
|
||||||
|
// Auth options already overridden with non-default
|
||||||
|
console.log(k+" is already overridden in "+config_path+", skipping config update");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const k in auth)
|
||||||
|
{
|
||||||
|
config[k] = auth[k];
|
||||||
|
}
|
||||||
|
console.log(`-----
|
||||||
|
Updating ${config_path}
|
||||||
|
-----
|
||||||
|
`);
|
||||||
|
fs.writeFileSync(config_path, JSON.stringify(config, 0, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
async configure_etcd()
|
||||||
|
{
|
||||||
const in_docker = fs.existsSync("/etc/vitastor/etcd.conf") &&
|
const in_docker = fs.existsSync("/etc/vitastor/etcd.conf") &&
|
||||||
fs.existsSync("/etc/vitastor/docker.conf");
|
fs.existsSync("/etc/vitastor/docker.conf");
|
||||||
if (!in_docker && fs.existsSync("/etc/systemd/system/vitastor-etcd.service"))
|
if (!in_docker && fs.existsSync("/etc/systemd/system/vitastor-etcd.service"))
|
||||||
@@ -45,30 +285,49 @@ async function run()
|
|||||||
console.log("/etc/systemd/system/etcd.service already exists");
|
console.log("/etc/systemd/system/etcd.service already exists");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
const config = JSON.parse(fs.readFileSync(config_path, { encoding: 'utf-8' }));
|
const etcd_url = etcds[num].scheme + '://' + etcds[num].addr;
|
||||||
if (!config.etcd_address)
|
const options = {
|
||||||
|
name: 'etcd'+etcds[num].ip.replace(/[^0-9a-z_]/ig, '_'),
|
||||||
|
advertise_client_urls: etcd_url+':'+(use_auth ? 2381 : 2379),
|
||||||
|
listen_client_urls: etcd_url+':'+(use_auth ? 2381 : 2379),
|
||||||
|
initial_advertise_peer_urls: etcd_url+':2380',
|
||||||
|
listen_peer_urls: etcd_url+':2380',
|
||||||
|
initial_cluster_token: 'vitastor-etcd-1',
|
||||||
|
initial_cluster_state: 'new',
|
||||||
|
initial_cluster: etcds.map(e => `etcd${e.ip.replace(/[^0-9a-z_]/ig, '_')}=${e.scheme}://${e.addr}:2380`).join(','),
|
||||||
|
snapshot_count: 10000,
|
||||||
|
max_txn_ops: 100000,
|
||||||
|
max_request_bytes: 104857600,
|
||||||
|
auto_compaction_retention: 10,
|
||||||
|
auto_compaction_mode: 'revision',
|
||||||
|
};
|
||||||
|
if (tls)
|
||||||
{
|
{
|
||||||
console.log("etcd_address is missing in "+config_path);
|
options['cert_file'] = '/etc/vitastor/etcd.crt';
|
||||||
process.exit(1);
|
options['key_file'] = '/etc/vitastor/etcd.key';
|
||||||
|
if (use_auth)
|
||||||
|
{
|
||||||
|
options['client_cert_auth'] = '1';
|
||||||
|
options['trusted_ca_file'] = '/etc/vitastor/antietcd.crt';
|
||||||
|
}
|
||||||
|
options['peer_cert_file'] = '/etc/vitastor/etcd.crt';
|
||||||
|
options['peer_key_file'] = '/etc/vitastor/etcd.key';
|
||||||
|
if (use_auth)
|
||||||
|
{
|
||||||
|
options['peer_client_cert_auth'] = '1';
|
||||||
|
options['peer_trusted_ca_file'] = '/etc/vitastor/etcd.crt';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const etcds = (config.etcd_address instanceof Array ? config.etcd_address : (''+config.etcd_address).split(/,/))
|
let etcd_conf = fs.existsSync("/etc/vitastor/etcd.conf")
|
||||||
.map(s => (''+s).replace(/^https?:\/\/|(:\d+)?(\/.*)?$/g, '').replace(/^\[(.*)\]$/, '$1').toLowerCase());
|
? fs.readFileSync("/etc/vitastor/etcd.conf", { encoding: 'utf-8' })
|
||||||
const num = select_local_etcd(etcds);
|
: "";
|
||||||
if (num < 0)
|
for (const k in options)
|
||||||
{
|
{
|
||||||
console.log('No matching IPs in etcd_address from '+config_path);
|
etcd_conf = replace_env(etcd_conf, 'ETCD_'+k.toUpperCase().replace(/-/, '_'), options[k]);
|
||||||
process.exit(0);
|
|
||||||
}
|
}
|
||||||
const etcd_url = 'http://' + (etcds[num].indexOf(':') >= 0 ? '['+etcds[num]+']' : etcds[num]);
|
fs.writeFileSync("/etc/vitastor/etcd.conf", etcd_conf);
|
||||||
const etcd_name = 'etcd'+etcds[num].replace(/[^0-9a-z_]/ig, '_');
|
|
||||||
const etcd_cluster = etcds.map(e => `etcd${e.replace(/[^0-9a-z_]/ig, '_')}=http://${e.indexOf(':') >= 0 ? '['+e+']' : e}:2380`).join(',');
|
|
||||||
if (in_docker)
|
if (in_docker)
|
||||||
{
|
{
|
||||||
let etcd_conf = fs.readFileSync("/etc/vitastor/etcd.conf", { encoding: 'utf-8' });
|
|
||||||
etcd_conf = replace_env(etcd_conf, 'ETCD_NAME', etcd_name);
|
|
||||||
etcd_conf = replace_env(etcd_conf, 'ETCD_IP', etcds[num]);
|
|
||||||
etcd_conf = replace_env(etcd_conf, 'ETCD_INITIAL_CLUSTER', etcd_cluster);
|
|
||||||
fs.writeFileSync("/etc/vitastor/etcd.conf", etcd_conf);
|
|
||||||
console.log('etcd for Vitastor configured. Run `systemctl enable --now vitastor-etcd` to start etcd');
|
console.log('etcd for Vitastor configured. Run `systemctl enable --now vitastor-etcd` to start etcd');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
@@ -83,12 +342,8 @@ Wants=network-online.target local-fs.target time-sync.target
|
|||||||
[Service]
|
[Service]
|
||||||
Restart=always
|
Restart=always
|
||||||
Environment=GOGC=50
|
Environment=GOGC=50
|
||||||
ExecStart=etcd --name ${etcd_name} --data-dir /var/lib/etcd/vitastor \\
|
EnvironmentFile=/etc/vitastor/etcd.conf
|
||||||
--snapshot-count 10000 --advertise-client-urls ${etcd_url}:2379 --listen-client-urls ${etcd_url}:2379 \\
|
ExecStart=etcd --data-dir /var/lib/etcd/vitastor
|
||||||
--initial-advertise-peer-urls ${etcd_url}:2380 --listen-peer-urls ${etcd_url}:2380 \\
|
|
||||||
--initial-cluster-token vitastor-etcd-1 --initial-cluster ${etcd_cluster} \\
|
|
||||||
--initial-cluster-state new --max-txn-ops=100000 --max-request-bytes=104857600 \\
|
|
||||||
--auto-compaction-retention=10 --auto-compaction-mode=revision
|
|
||||||
WorkingDirectory=/var/lib/etcd/vitastor
|
WorkingDirectory=/var/lib/etcd/vitastor
|
||||||
ExecStartPre=+chown -R etcd /var/lib/etcd/vitastor
|
ExecStartPre=+chown -R etcd /var/lib/etcd/vitastor
|
||||||
User=etcd
|
User=etcd
|
||||||
@@ -106,7 +361,6 @@ WantedBy=multi-user.target
|
|||||||
// Disable distribution etcd unit and enable our one
|
// Disable distribution etcd unit and enable our one
|
||||||
await system(`systemctl disable --now etcd`);
|
await system(`systemctl disable --now etcd`);
|
||||||
await system(`systemctl enable --now vitastor-etcd`);
|
await system(`systemctl enable --now vitastor-etcd`);
|
||||||
process.exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function replace_env(text, key, value)
|
function replace_env(text, key, value)
|
||||||
@@ -119,16 +373,29 @@ function replace_env(text, key, value)
|
|||||||
function select_local_etcd(etcds)
|
function select_local_etcd(etcds)
|
||||||
{
|
{
|
||||||
const ifaces = os.networkInterfaces();
|
const ifaces = os.networkInterfaces();
|
||||||
|
const local = {};
|
||||||
for (const ifname in ifaces)
|
for (const ifname in ifaces)
|
||||||
|
{
|
||||||
for (const iface of ifaces[ifname])
|
for (const iface of ifaces[ifname])
|
||||||
for (let i = 0; i < etcds.length; i++)
|
{
|
||||||
if (etcds[i] == iface.address.toLowerCase())
|
const addr = iface.address;
|
||||||
return i;
|
if (iface.family == 'IPv6')
|
||||||
|
local[addr.toLowerCase()] = local['['+addr.toLowerCase()+']'] = true;
|
||||||
|
else
|
||||||
|
local[addr] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let i = 0; i < etcds.length; i++)
|
||||||
|
{
|
||||||
|
if (local[etcds[i].addr])
|
||||||
|
return i;
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function system(cmd)
|
async function system(cmd)
|
||||||
{
|
{
|
||||||
|
console.log('Running '+cmd);
|
||||||
const cp = child_process.spawn(cmd, { shell: true, stdio: [ 0, 1, 2 ] });
|
const cp = child_process.spawn(cmd, { shell: true, stdio: [ 0, 1, 2 ] });
|
||||||
let finish_cb;
|
let finish_cb;
|
||||||
cp.on('exit', () => finish_cb && finish_cb());
|
cp.on('exit', () => finish_cb && finish_cb());
|
||||||
@@ -136,3 +403,19 @@ async function system(cmd)
|
|||||||
await new Promise(ok => finish_cb = ok);
|
await new Promise(ok => finish_cb = ok);
|
||||||
return cp.exitCode;
|
return cp.exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function make_ca(subj, filename)
|
||||||
|
{
|
||||||
|
if (await system("openssl req -days 3650 -x509 -subj '"+subj+"' -addext basicConstraints=critical,CA:TRUE,pathlen:1"+
|
||||||
|
" -new -newkey rsa:4096 -nodes -keyout "+filename+".key -out "+filename+".crt"))
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function make_signed(subj, f, ca, san)
|
||||||
|
{
|
||||||
|
if (await system(`openssl req -subj '${subj}' ${san ? "-addext 'subjectAltName="+san+"'" : ""} -nodes -new -keyout ${f}.key -out ${f}.csr`))
|
||||||
|
process.exit(1);
|
||||||
|
if (await system(`openssl x509 -req -days 3650 -CA ${ca}.crt -CAkey ${ca}.key -CAcreateserial -in ${f}.csr -out ${f}.crt`))
|
||||||
|
process.exit(1);
|
||||||
|
fs.unlinkSync(f+".csr");
|
||||||
|
}
|
||||||
|
|||||||
@@ -62,9 +62,6 @@ target_link_libraries(test_cas
|
|||||||
add_executable(test_crc32
|
add_executable(test_crc32
|
||||||
test_crc32.cpp
|
test_crc32.cpp
|
||||||
)
|
)
|
||||||
target_link_libraries(test_crc32
|
|
||||||
vitastor_blk ${ISAL_LIBRARIES}
|
|
||||||
)
|
|
||||||
|
|
||||||
# test_blockstore
|
# test_blockstore
|
||||||
add_executable(test_blockstore EXCLUDE_FROM_ALL test_blockstore.cpp ringloop_mock.cpp)
|
add_executable(test_blockstore EXCLUDE_FROM_ALL test_blockstore.cpp ringloop_mock.cpp)
|
||||||
|
|||||||
+3
-1
@@ -126,7 +126,9 @@ VITASTOR_CFG='"etcd_address":"'$ETCD_URL'"'"$VITASTOR_CFG"
|
|||||||
if [[ "$ETCD_SCHEME" = "https" ]]; then
|
if [[ "$ETCD_SCHEME" = "https" ]]; then
|
||||||
VITASTOR_CFG="$VITASTOR_CFG"',"etcd_ca":"'$(pwd)'/testdata/etcd.crt"'
|
VITASTOR_CFG="$VITASTOR_CFG"',"etcd_ca":"'$(pwd)'/testdata/etcd.crt"'
|
||||||
fi
|
fi
|
||||||
VITASTOR_CFG="$VITASTOR_CFG"',"osd_network":"'$ETCD_IP'/32"'
|
if [[ "$RDMA" = 1 ]]; then
|
||||||
|
VITASTOR_CFG="$VITASTOR_CFG"',"osd_network":"'$ETCD_IP'/32"'
|
||||||
|
fi
|
||||||
VITASTOR_CFG="$VITASTOR_CFG"',"use_rdma":"'$RDMA'"'
|
VITASTOR_CFG="$VITASTOR_CFG"',"use_rdma":"'$RDMA'"'
|
||||||
if [[ "$OSD_TLS" = "1" ]]; then
|
if [[ "$OSD_TLS" = "1" ]]; then
|
||||||
cd ./testdata
|
cd ./testdata
|
||||||
|
|||||||
Reference in New Issue
Block a user