Первое развёртывание¶
Это руководство описывает развёртывание защищённого SSH-шлюза из стабильного
выпуска. Нужны аккаунт Yandex Cloud и аутентифицированный профиль yc.
Список команд можно посмотреть через python -m flayer lifecycle --help.
Развёртывание состоит из явной идентичности стека, скомпилированного плана ресурсов, локального состояния с владением и ограниченных операций провайдера. Защищённый шлюз добавляет проверенный профиль сервера и артефакты подключения устройств с отдельным учётом владения. Учётные данные и закрытые ключи не входят в планы и документацию.
Хранилище защищённых артефактов требует POSIX-проверок владельца и прав, а также файловых операций относительно дескриптора. Для этого руководства используйте Linux/macOS; сохранение в Windows не поддерживается до появления эквивалентного ACL-контракта. Установка и офлайн-диагностика — отдельные возможности.
Последовательность оператора¶
- Установите нужную ревизию исходников и настройте существующий профиль
yc. - Подготовьте и локально проверьте профиль защищённого шлюза.
- Создайте артефакты сервера и изучите план жизненного цикла и cloud-init.
- Проверьте идентичность, папку, SSH-ключ, диапазоны управления и сервисные порты.
- Создавайте ресурсы с явным согласием на изменения и точным подтверждением папки.
- Изучите наблюдения провайдера; диагностику адреса выполните отдельно.
- Удаляйте через соответствующие план и состояние с владением после проверки области операции.
Компиляция профиля шлюза локальна: она не обращается к облаку, не создаёт закрытые ключи и не доказывает готовность гостевой системы. Первый транспорт — ограниченный локальный SSH-проброс с явной целью и авторизацией каждого устройства. Профиль не предполагает продукт A-VPN, частный NAS, фиксированную страну или неявный аккаунт.
Локальная подготовка защищённого шлюза¶
Сохраните следующий текст как gateway.toml в каталоге оператора. Папка, зона, образ, адрес управления и открытые ключи синтетические — замените их перед развёртыванием. Выберите образ Ubuntu 24.04, совместимый с явным контрактом гостевой системы, и минимальные подходящие CIDR управления.
schema_version = 1
profile = "secure-gateway"
guest_contract = "ubuntu-24.04-cloud-init"
[identity]
project = "example"
stack = "gateway"
provider = "yandex-cloud"
scope_id = "example-folder"
owner_id = "example-owner"
[gateway]
zone_id = "example-zone"
image_id = "example-ubuntu-image"
subnet_cidr = "10.42.0.0/24"
ssh_public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4"
management_cidrs = ["198.51.100.42/32"]
ssh_username = "gateway-admin"
ssh_port = 22
cores = 2
memory_gib = 2
boot_disk_gib = 20
[transport]
kind = "ssh-local-forward"
username = "gateway-tunnel"
[[transport.targets]]
name = "web"
host = "example.org"
port = 443
[[transport.devices]]
device_id = "laptop"
public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5"
source_cidrs = ["198.51.100.42/32"]
Разрешённый UDP-порт не устанавливает VPN. SSH-проброс использует заданный SSH-порт; удалите неиспользуемые сервисы и по возможности сузьте диапазоны. Созданная гостевая конфигурация отключает парольный и root-вход SSH, IPv4 forwarding и IPv6, ограничивает входящий доступ. Она не задаёт маршрутизацию пакетов и не доказывает готовность. Отдельный транспортный аккаунт без sudo разрешает только объявленные цели локального проброса и исходные CIDR устройств; административный проброс отключён.
Создайте и изучите серверный набор и план жизненного цикла локально из POSIX-консоли:
python - <<'PY'
"""Prepare an owned gateway bundle without accessing a cloud account."""
import os
from pathlib import Path
from flayer.profiles import (
BuildServerBundle, CompileGateway, LoadGatewayProfile, RenderPlan, WriteArtifactBundle,
)
os.umask(0o077)
profile = LoadGatewayProfile("gateway.toml")
directory = WriteArtifactBundle("generated-artifacts", BuildServerBundle(profile))
plan_text = RenderPlan(
CompileGateway(profile), user_data_file=directory / "server-cloud-init.json",
)
plan_path = Path("generated-artifacts/plan.toml")
with plan_path.open("x", encoding="utf-8") as stream:
stream.write(plan_text)
print(plan_path)
PY
Хранилище создаёт новый набор исключительно с ограниченными правами и манифестом владения и хешей. Существующие наборы не перезаписываются. RenderPlan проверяет байты cloud-init по профилю перед привязкой пути. Полученный путь зависит от машины; держите план и набор вне Git и не перемещайте cloud-init после компиляции.
Контракт команд жизненного цикла¶
Команды используют один и тот же явный план, состояние и профиль:
python -m flayer lifecycle status --config generated-artifacts/plan.toml --state generated-artifacts/stack.json --yc-profile example --format json
python -m flayer lifecycle create --config generated-artifacts/plan.toml --state generated-artifacts/stack.json --yc-profile example --allow-mutation --scope-confirm example-folder --format json
python -m flayer lifecycle recover --config generated-artifacts/plan.toml --state generated-artifacts/stack.json --yc-profile example --allow-mutation --scope-confirm example-folder --format json
status читает наблюдения провайдера. create, recover и destroy требуют одновременно --allow-mutation и --scope-confirm, точно равный ID области плана. Владение и путь состояния под контролем оператора должны совпадать. Верхнеуровневый диагностический status отделён от status жизненного цикла.
Успешное создание устанавливает ресурсы провайдера, но не доказывает завершение cloud-init или подключение клиента. Проверяйте явный адрес командой health только после выбора подходящих проверок готовности гостевой системы.
Восстановление и очистка¶
Прерванные операции сохраняют журнал рядом с файлом состояния. Создание с таймаутом могло завершиться удалённо: восстановление должно найти точно принадлежащий логический ресурс, а не создавать дубликат. Неопределённо отсутствующий ресурс блокирует восстановление до расследования оператором.
Аварийное завершение процесса может оставить кооперативную блокировку операции. Перед ручным удалением блокировки убедитесь, что старый процесс завершён, и изучите журнал и состояние; F-Layer не удаляет автоматически потенциально активную блокировку.
Откат применяется к ресурсам, созданным этой операцией; ранее существовавшие точные ресурсы с подтверждённым владением остаются. Явная очистка выполняется так:
python -m flayer lifecycle destroy --config generated-artifacts/plan.toml --state generated-artifacts/stack.json --yc-profile example --allow-mutation --scope-confirm example-folder --format json
Перед подстановкой рабочих значений проверьте реальную папку и идентичность ресурсов. Перед удалением владение у провайдера должно совпасть. Сохраняйте журнал и состояние до успешной очистки и разрешения прерванных исходов.
После подтверждения облачной очистки удалите точный серверный набор через манифест владения, а не произвольный каталог:
from flayer.profiles import LoadGatewayProfile, RemoveArtifactBundle
profile = LoadGatewayProfile("gateway.toml")
RemoveArtifactBundle(
"generated-artifacts", profile.identity, kind="server", name=profile.identity.stack,
)
Подключение одного авторизованного устройства¶
Самостоятельно подготовьте закрытый ключ устройства, соответствующий открытому ключу в transport.devices. Получите и проверьте ключ сервера через доверенный канал и поместите его в явный файл known_hosts. Генератор не читает закрытые ключи и не принимает первый наблюдённый ключ сервера за доверенный.
Создайте рабочую SSH-конфигурацию устройства после определения фактического адреса сервера и доверенных путей:
from flayer.profiles import BuildSshDeviceBundle, LoadGatewayProfile, WriteArtifactBundle
profile = LoadGatewayProfile("gateway.toml")
bundle = BuildSshDeviceBundle(
profile, "laptop", endpoint="203.0.113.42",
identity_file="/path/to/laptop-key",
known_hosts_file="/path/to/trusted-known-hosts",
local_ports=(8443,),
)
directory = WriteArtifactBundle("generated-artifacts", bundle)
print(directory / "ssh-client.conf")
203.0.113.42 — адрес для документации. Замените его наблюдаемым адресом и явными локальными путями к ключу и доверенным данным; созданные пути непереносимы. Затем держите локальный проброс запущенным:
ssh -F generated-artifacts/device-laptop/ssh-client.conf -N laptop
Пример связывает 127.0.0.1:8443 с объявленной целью example.org:443. Строгая проверка ключа сервера включена; сервер ограничивает ключи, исходные диапазоны и цели. Локальный проброс переносит выбранное соединение; это не VPN всего устройства, не маршрутизатор пакетов и не автоматическая установка клиента. Проверяйте фактические SSH-свидетельства и адрес, прежде чем считать подключение успешным.
Наборы устройств имеют независимые манифесты владения. Когда набор больше не нужен, удалите только соответствующий набор через RemoveArtifactBundle(..., kind="device", name="laptop"). Закрытые ключи и файлы доверенных ключей сервера остаются отдельными входными данными оператора.