TL;DR
- Используйте Batfish для pre-deployment анализа сети—валидируйте маршрутизацию, ACL и достижимость до касания любого устройства
- Тестируйте правила firewall как код: определите ожидаемые правила allow/deny, затем проверьте с InSpec или кастомными assertions
- Реализуйте тесты топологии сети, которые проверяют пути связности, а не только существование отдельных ресурсов
Идеально для: Команд, управляющих облачными VPC, мультиоблачными сетями или сложными on-premise конфигурациями Не подходит если: Ваша сеть — простая VPC с маршрутизацией по умолчанию (используйте встроенные инструменты облачного провайдера) Время чтения: 14 минут
Ошибки сетевой конфигурации вызывают больше сбоев, чем большинство команд осознают. Неправильно настроенная security group, некорректная запись в route table или отсутствующее правило firewall может положить production—и традиционные подходы к тестированию обнаруживают эти проблемы слишком поздно. Это руководство охватывает проактивное тестирование сети, которое валидирует конфигурации до деплоя.
Для более широкого контекста тестирования инфраструктуры, смотрите Тестирование Infrastructure as Code и Стратегии Тестирования Terraform.
Подходы с Использованием ИИ
Инструменты ИИ отлично справляются с генерацией тестов валидации сети из требований и отладкой сложных проблем маршрутизации.
Генерация запросов Batfish из требований:
Мне нужно валидировать эти сетевые требования с помощью Batfish:
1. Production subnet (10.0.1.0/24) может достичь database subnet (10.0.2.0/24) на порту 5432
2. Ни одна subnet не может достичь 0.0.0.0/0 кроме как через NAT gateway
3. Subnet load balancer должна быть достижима из интернета на портах 80 и 443
4. Management subnet (10.0.10.0/24) НЕ должна быть достижима из любой другой subnet
Сгенерируй код Python с pybatfish с правильными assertions и понятными сообщениями об ошибках.
Включи создание snapshot и инициализацию сети.
Отладка проблем маршрутизации:
Моя VPC имеет неожиданную связность. Конфигурация:
- VPC CIDR: 10.0.0.0/16
- Public subnet: 10.0.1.0/24 с маршрутом к IGW
- Private subnet: 10.0.2.0/24 с маршрутом к NAT
- Database subnet: 10.0.3.0/24 (должна быть изолирована)
Проблема: Database subnet может достичь интернет, но не должна.
Присоединённые route tables: [вставить конфигурации route table]
Используй traceroute анализ для определения, где существует нежелательный путь.
Создание InSpec тестов для правил firewall:
Напиши InSpec controls для проверки этих правил AWS security group:
1. SG web tier разрешает inbound 443 только от SG ALB
2. SG app tier разрешает inbound 8080 только от SG web tier
3. SG DB tier разрешает inbound 5432 только от SG app tier
4. Ни одна security group не разрешает inbound 22 от 0.0.0.0/0
Включи поиск ресурсов по тегу и правильные skip conditions
для отсутствующих ресурсов.
Когда Использовать Разные Подходы к Тестированию
Фреймворк Принятия Решений по Стратегии Тестирования
| Тип Теста | Инструмент | Когда Запускать | Что Обнаруживает |
|---|---|---|---|
| Анализ конфигурации | Batfish | До деплоя | Петли маршрутизации, недоступные хосты, конфликты ACL |
| Проверки compliance | InSpec/Checkov | Pipeline CI/CD | Нарушения политик, отсутствие шифрования |
| Интеграционные тесты | Terratest | После деплоя | Реальная связность, разрешение DNS |
| Зонды связности | Smoke tests | После деплоя | Валидация реального потока трафика |
| Анализ влияния изменений | Batfish differential | До изменений | Непреднамеренные побочные эффекты |
Используйте Batfish Когда
- Pre-deployment валидация критична: Обнаружить проблемы до касания production
- Multi-vendor окружения: Анализ конфигов Cisco, Juniper, AWS, Azure вместе
- Сложная маршрутизация: Конфигурации BGP, OSPF или VRF требуют валидации
- Compliance требует доказательств: Генерировать отчёты о достижимости для аудиторов
Используйте Terratest/InSpec Когда
- Cloud-native инфраструктура: AWS/GCP/Azure VPC с простой маршрутизацией
- Верификация security groups: Подтвердить, что реальное состояние firewall соответствует ожидаемому
- Интеграционное тестирование: Проверить, что ресурсы работают вместе после деплоя
Batfish для Анализа Сети
Настройка Batfish
# Запуск сервера Batfish в Docker
docker run -d -p 9997:9997 -p 9996:9996 batfish/batfish
# Установка клиента pybatfish
pip install pybatfish
Базовый Анализ Network Snapshot
from pybatfish.client.commands import bf_init_snapshot, bf_set_network
from pybatfish.question import bfq
from pybatfish.question.question import load_questions
# Инициализация
load_questions()
bf_set_network("my-network")
bf_init_snapshot("./configs", name="current-config")
# Анализ проблем конфигурации
issues = bfq.initIssues().answer().frame()
print(issues[["Type", "Issue_Type", "Details"]])
# Проверка неопределённых ссылок
undefined = bfq.undefinedReferences().answer().frame()
assert len(undefined) == 0, f"Найдены неопределённые ссылки: {undefined}"
Тестирование Достижимости
def test_web_to_database_connectivity():
"""Проверить, что web tier может достичь базу данных на порту PostgreSQL."""
result = bfq.reachability(
pathConstraints=PathConstraints(
startLocation="web-server",
endLocation="database-server"
),
headers=HeaderConstraints(
dstPorts="5432",
ipProtocols=["TCP"]
),
actions="SUCCESS"
).answer().frame()
assert len(result) > 0, "Путь от web к базе данных на порту 5432 не найден"
def test_database_internet_isolation():
"""Проверить, что база данных не может достичь интернет."""
result = bfq.reachability(
pathConstraints=PathConstraints(
startLocation="database-server",
endLocation="internet"
),
headers=HeaderConstraints(
dstIps="0.0.0.0/0"
),
actions="SUCCESS"
).answer().frame()
assert len(result) == 0, "База данных имеет нежелательный доступ в интернет"
Дифференциальный Анализ для Изменений
def test_route_change_impact():
"""Анализ влияния изменений route table до применения."""
# Загрузка текущих и предложенных конфигов
bf_init_snapshot("./configs/current", name="current")
bf_init_snapshot("./configs/proposed", name="proposed")
# Сравнение достижимости
diff = bfq.differentialReachability(
pathConstraints=PathConstraints(
startLocation="/production.*/",
endLocation="/database.*/"
)
).answer(
snapshot="proposed",
reference_snapshot="current"
).frame()
# Ошибка если какие-либо существующие пути нарушены
reduced = diff[diff["Snapshot_Action"] == "DENIED"]
assert len(reduced) == 0, f"Предложенное изменение нарушает пути: {reduced}"
Тестирование VPC с Terraform
Тестирование Конфигурации VPC с Terratest
package test
import (
"testing"
"github.com/gruntwork-io/terratest/modules/aws"
"github.com/gruntwork-io/terratest/modules/terraform"
"github.com/stretchr/testify/assert"
)
func TestVPCConfiguration(t *testing.T) {
t.Parallel()
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: "../modules/vpc",
Vars: map[string]interface{}{
"vpc_cidr": "10.0.0.0/16",
"environment": "test",
"enable_nat": true,
},
})
defer terraform.Destroy(t, terraformOptions)
terraform.InitAndApply(t, terraformOptions)
// Проверяем VPC создана с правильным CIDR
vpcID := terraform.Output(t, terraformOptions, "vpc_id")
vpc := aws.GetVpcById(t, vpcID, "us-east-1")
assert.Equal(t, "10.0.0.0/16", *vpc.CidrBlock)
// Проверяем настройки DNS
assert.True(t, aws.IsVpcDnsEnabled(t, vpcID, "us-east-1"))
assert.True(t, aws.IsVpcDnsHostnamesEnabled(t, vpcID, "us-east-1"))
}
Тестирование Маршрутизации Subnets
func TestSubnetRouting(t *testing.T) {
t.Parallel()
// После terraform apply...
publicSubnetID := terraform.Output(t, terraformOptions, "public_subnet_id")
privateSubnetID := terraform.Output(t, terraformOptions, "private_subnet_id")
// Проверяем, что public subnet имеет маршрут к internet gateway
publicRoutes := aws.GetRouteTableForSubnet(t, publicSubnetID, "us-east-1")
hasIGWRoute := false
for _, route := range publicRoutes.Routes {
if route.GatewayId != nil && strings.HasPrefix(*route.GatewayId, "igw-") {
hasIGWRoute = true
break
}
}
assert.True(t, hasIGWRoute, "Public subnet без маршрута IGW")
// Проверяем, что private subnet имеет маршрут к NAT gateway
privateRoutes := aws.GetRouteTableForSubnet(t, privateSubnetID, "us-east-1")
hasNATRoute := false
for _, route := range privateRoutes.Routes {
if route.NatGatewayId != nil {
hasNATRoute = true
break
}
}
assert.True(t, hasNATRoute, "Private subnet без маршрута NAT")
}
Тестирование Security Groups
InSpec Controls для AWS Security Groups
# controls/security_groups.rb
control 'web-tier-sg' do
impact 1.0
title 'Security group web tier разрешает только ожидаемый трафик'
web_sg = aws_security_group(group_name: 'web-tier-sg')
describe web_sg do
it { should exist }
it { should allow_in(port: 443, ipv4_range: '0.0.0.0/0') }
it { should allow_in(port: 80, ipv4_range: '0.0.0.0/0') }
it { should_not allow_in(port: 22, ipv4_range: '0.0.0.0/0') }
it { should_not allow_in(port: 3389, ipv4_range: '0.0.0.0/0') }
end
end
control 'database-tier-sg' do
impact 1.0
title 'Tier базы данных доступен только от tier app'
db_sg = aws_security_group(group_name: 'database-tier-sg')
app_sg = aws_security_group(group_name: 'app-tier-sg')
describe db_sg do
it { should exist }
it { should allow_in_only(port: 5432, security_group: app_sg.group_id) }
it { should_not allow_in(ipv4_range: '0.0.0.0/0') }
end
end
control 'no-wide-open-egress' do
impact 0.7
title 'Security groups не должны разрешать весь egress'
aws_security_groups.group_ids.each do |sg_id|
describe aws_security_group(group_id: sg_id) do
it { should_not allow_out(ipv4_range: '0.0.0.0/0', port: '0-65535') }
end
end
end
Интеграция в Pipeline CI/CD
Workflow GitHub Actions
name: Network Configuration Tests
on:
pull_request:
paths:
- 'terraform/networking/**'
- 'configs/network/**'
jobs:
batfish-analysis:
runs-on: ubuntu-latest
services:
batfish:
image: batfish/batfish
ports:
- 9997:9997
- 9996:9996
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Установка pybatfish
run: pip install pybatfish pytest
- name: Запуск анализа Batfish
run: |
pytest tests/network/ -v --tb=short
env:
BATFISH_HOST: localhost
terraform-tests:
runs-on: ubuntu-latest
needs: batfish-analysis
steps:
- uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
- name: Настройка AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Terraform Validate
run: terraform validate
working-directory: terraform/networking/
- name: Запуск Checkov
uses: bridgecrewio/checkov-action@v12
with:
directory: terraform/networking/
framework: terraform
check: CKV_AWS_23,CKV_AWS_24,CKV_AWS_25
Измерение Успеха
| Метрика | До Тестирования | После Тестирования | Как Отслеживать |
|---|---|---|---|
| Сбои связанные с сетью | 3-4/месяц | <1/квартал | Отчёты об инцидентах |
| Misconfigurations SG | Найдены на аудитах | Обнаружены в CI | Метрики pipeline |
| Откаты изменений | 20% изменений | <5% изменений | Логи деплоя |
| Среднее время обнаружения | Дни | Минуты | Timestamps алертов |
Сигналы, что ваше тестирование сети не работает:
- Всё ещё находите misconfigurations в production
- Тесты проходят, но связность не работает после деплоя
- Batfish и реальность расходятся (устаревшие snapshots)
- Security groups имеют необъяснимые правила
Заключение
Эффективное тестирование сетевой конфигурации требует нескольких слоёв:
- Pre-deployment анализ с Batfish обнаруживает проблемы маршрутизации и ACL до достижения устройств
- Тестирование compliance с InSpec/Checkov валидирует политики безопасности
- Интеграционное тестирование с Terratest подтверждает реальную связность
- Непрерывный мониторинг обнаруживает drift от желаемого состояния
Ключевая идея: тестируйте сеть как систему, а не только отдельные компоненты. Security group может быть настроена правильно в изоляции, но создавать проблемы в комбинации с route tables и NACLs.
Смотрите также
- Тестирование Infrastructure as Code - Фундаментальные концепции тестирования IaC
- Стратегии Тестирования Terraform - Полная пирамида тестирования Terraform
- Тестирование Инфраструктуры AWS с LocalStack - Локальное тестирование AWS
- Тестирование Security Groups - Глубокое погружение в валидацию правил firewall
- Стратегии Тестирования Kubernetes - Network policies в K8s
