Chebis26/network-security-sg-nsg-nacl
GitHub: Chebis26/network-security-sg-nsg-nacl
面向 AWS 和 Azure 的生产级网络安全分层防护项目,通过 Terraform 自动化实现 Security Groups、NACL 与 NSG 的纵深防御架构及合规规则集。
Stars: 0 | Forks: 0
# 网络安全 — SG、NSG 与 NACL 深度解析
[](https://aws.amazon.com/)
[](https://azure.microsoft.com/)
[](https://www.terraform.io/)
生产级安全层实现:AWS Security Groups(有状态,实例级别)、NACLs(无状态,子网级别)以及 Azure NSGs — 包含分层防御纵深架构、Terraform 自动化以及合规对齐的规则集。
## 防御纵深架构
```
INBOUND TRAFFIC FLOW (internet → application):
Internet
│
▼ [Layer 1: AWS WAF / Azure WAF on App Gateway]
SQL Injection, XSS, OWASP Top 10, IP reputation
│
▼ [Layer 2: Network ACL (AWS) / Azure NSG on subnet]
Stateless, explicit deny rules:
• Block source IPs in threat intel list
• Deny management ports (22, 3389) from internet
• Allow ALB ephemeral ports (1024-65535) inbound
│
▼ [Layer 3: Security Group / Azure NSG on NIC]
Stateful, allow-list only:
• ALB SG → App SG (port 8080 only)
• App SG → DB SG (port 5432 only)
• No rules = implicitly denied
│
▼ [Layer 4: Application]
mTLS, JWT validation, application-level authz
RESULT: 4 independent layers must all allow traffic.
Compromise of one layer does not grant access.
```
## AWS Security Groups — 生产级规则集
### 分层 Security Group 模式
```
# terraform/aws/security-groups/main.tf
# 第 1 层:ALB Security Group (internet-facing)
resource "aws_security_group" "alb" {
name = "sg-alb-public"
description = "ALB — HTTPS from internet only; outbound to app SG"
vpc_id = var.vpc_id
ingress {
description = "HTTPS from internet"
from_port = 443; to_port = 443; protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "HTTP from internet (redirect to HTTPS)"
from_port = 80; to_port = 80; protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
description = "To app tier only"
from_port = 8080; to_port = 8080; protocol = "tcp"
security_groups = [aws_security_group.app.id]
}
tags = merge(var.tags, { Name = "sg-alb" })
}
# 第 2 层:App Security Group
resource "aws_security_group" "app" {
name = "sg-app-private"
description = "App — from ALB SG only; to DB SG and VPC endpoints"
vpc_id = var.vpc_id
ingress {
description = "From ALB SG"
from_port = 8080; to_port = 8080; protocol = "tcp"
security_groups = [aws_security_group.alb.id]
}
egress {
description = "To DB"
from_port = 5432; to_port = 5432; protocol = "tcp"
security_groups = [aws_security_group.db.id]
}
egress {
description = "HTTPS to AWS services (VPC endpoints)"
from_port = 443; to_port = 443; protocol = "tcp"
cidr_blocks = [var.vpc_cidr]
}
tags = merge(var.tags, { Name = "sg-app" })
}
# 第 3 层:Database Security Group
resource "aws_security_group" "db" {
name = "sg-db-isolated"
description = "DB — from app SG only; NO outbound"
vpc_id = var.vpc_id
ingress {
description = "PostgreSQL from app SG only"
from_port = 5432; to_port = 5432; protocol = "tcp"
security_groups = [aws_security_group.app.id]
}
# No egress rules = all outbound blocked
tags = merge(var.tags, { Name = "sg-db" })
}
# VPC Endpoint Security Group(shared-services VPC 中的共享 endpoints)
resource "aws_security_group" "vpc_endpoints" {
name = "sg-vpc-endpoints"
description = "VPC Endpoints — HTTPS from VPC CIDR only"
vpc_id = var.vpc_id
ingress {
description = "HTTPS from entire VPC"
from_port = 443; to_port = 443; protocol = "tcp"
cidr_blocks = [var.vpc_cidr]
}
tags = merge(var.tags, { Name = "sg-vpc-endpoints" })
}
```
## AWS NACLs — 无状态子网控制
```
# terraform/aws/nacls/main.tf
# NACLs 是 STATELESS 的 — 必须显式允许返回流量
# Public Subnet NACL(仅限 ALB 和 NAT GW)
resource "aws_network_acl" "public" {
vpc_id = var.vpc_id
subnet_ids = var.public_subnet_ids
# Inbound
ingress { rule_no = 100; action = "allow"; protocol = "tcp"; from_port = 443; to_port = 443; cidr_block = "0.0.0.0/0" }
ingress { rule_no = 110; action = "allow"; protocol = "tcp"; from_port = 80; to_port = 80; cidr_block = "0.0.0.0/0" }
# Ephemeral ports — required for return traffic (TCP responses)
ingress { rule_no = 900; action = "allow"; protocol = "tcp"; from_port = 1024; to_port = 65535; cidr_block = "0.0.0.0/0" }
# Deny all else
ingress { rule_no = 32766; action = "deny"; protocol = "-1"; from_port = 0; to_port = 0; cidr_block = "0.0.0.0/0" }
# Outbound
egress { rule_no = 100; action = "allow"; protocol = "-1"; from_port = 0; to_port = 0; cidr_block = "0.0.0.0/0" }
tags = merge(var.tags, { Name = "nacl-public" })
}
# Private Subnet NACL(Application 层)
resource "aws_network_acl" "private" {
vpc_id = var.vpc_id
subnet_ids = var.private_subnet_ids
# Inbound: only from VPC CIDR + ephemeral ports
ingress { rule_no = 100; action = "allow"; protocol = "tcp"; from_port = 8080; to_port = 8080; cidr_block = var.vpc_cidr }
ingress { rule_no = 110; action = "allow"; protocol = "tcp"; from_port = 443; to_port = 443; cidr_block = var.vpc_cidr }
ingress { rule_no = 900; action = "allow"; protocol = "tcp"; from_port = 1024; to_port = 65535; cidr_block = "0.0.0.0/0" }
# Explicit deny: block SSH from internet
ingress { rule_no = 50; action = "deny"; protocol = "tcp"; from_port = 22; to_port = 22; cidr_block = "0.0.0.0/0" }
ingress { rule_no = 32766; action = "deny"; protocol = "-1"; from_port = 0; to_port = 0; cidr_block = "0.0.0.0/0" }
# Outbound
egress { rule_no = 100; action = "allow"; protocol = "tcp"; from_port = 5432; to_port = 5432; cidr_block = var.data_subnet_cidr }
egress { rule_no = 110; action = "allow"; protocol = "tcp"; from_port = 443; to_port = 443; cidr_block = "0.0.0.0/0" }
egress { rule_no = 900; action = "allow"; protocol = "tcp"; from_port = 1024; to_port = 65535; cidr_block = "0.0.0.0/0" }
tags = merge(var.tags, { Name = "nacl-private" })
}
# Data Subnet NACL(Database 层 — 限制最严格)
resource "aws_network_acl" "data" {
vpc_id = var.vpc_id
subnet_ids = var.data_subnet_ids
# Only PostgreSQL from private subnet CIDR
ingress { rule_no = 100; action = "allow"; protocol = "tcp"; from_port = 5432; to_port = 5432; cidr_block = var.private_subnet_cidr }
ingress { rule_no = 32766; action = "deny"; protocol = "-1"; from_port = 0; to_port = 0; cidr_block = "0.0.0.0/0" }
# Return traffic only to private subnet
egress { rule_no = 100; action = "allow"; protocol = "tcp"; from_port = 1024; to_port = 65535; cidr_block = var.private_subnet_cidr }
egress { rule_no = 32766; action = "deny"; protocol = "-1"; from_port = 0; to_port = 0; cidr_block = "0.0.0.0/0" }
tags = merge(var.tags, { Name = "nacl-data" })
}
```
## Azure NSGs — 生产级规则集
```
# terraform/azure/nsg/main.tf
resource "azurerm_network_security_group" "app" {
name = "nsg-app-subnet"
resource_group_name = var.resource_group
location = var.location
# INBOUND RULES (lower priority number = evaluated first)
security_rule {
name = "Allow-HTTPS-from-AppGW"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "8080"
source_address_prefix = var.appgw_subnet_cidr
destination_address_prefix = "*"
}
security_rule {
name = "Allow-AppGW-Management"
priority = 110
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_ranges = ["65200-65535"] # Required for AppGW health probes
source_address_prefix = "GatewayManager" # Azure service tag
destination_address_prefix = "*"
}
security_rule {
name = "Allow-AzureLoadBalancer"
priority = 120
direction = "Inbound"
access = "Allow"
protocol = "*"
source_port_range = "*"
destination_port_range = "*"
source_address_prefix = "AzureLoadBalancer"
destination_address_prefix = "*"
}
security_rule {
name = "Deny-All-Inbound"
priority = 4000
direction = "Inbound"
access = "Deny"
protocol = "*"
source_port_range = "*"
destination_port_range = "*"
source_address_prefix = "*"
destination_address_prefix = "*"
}
# OUTBOUND RULES
security_rule {
name = "Allow-DB-Outbound"
priority = 100
direction = "Outbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "5432"
source_address_prefix = "*"
destination_address_prefix = var.data_subnet_cidr
}
security_rule {
name = "Allow-KeyVault-Outbound"
priority = 110
direction = "Outbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "443"
source_address_prefix = "*"
destination_address_prefix = "AzureKeyVault" # Service tag
}
security_rule {
name = "Deny-All-Outbound"
priority = 4000
direction = "Outbound"
access = "Deny"
protocol = "*"
source_port_range = "*"
destination_port_range = "*"
source_address_prefix = "*"
destination_address_prefix = "*"
}
tags = var.tags
}
```
## 验证与测试
```
# AWS:获取 ENI 的有效 security rules
aws ec2 describe-network-interface-attribute \
--network-interface-id $ENI_ID \
--attribute groupSet
# AWS:检查 subnet 上的有效 NACL rules
aws ec2 describe-network-acls \
--filters Name=association.subnet-id,Values=$SUBNET_ID \
--query 'NetworkAcls[0].{Inbound:Entries[?!Egress],Outbound:Entries[?Egress]}' \
--output json
# Azure:查看 NIC 的有效 security rules
az network nic list-effective-nsg \
--name nic-app-vm \
--resource-group rg-prod \
--query 'effectiveSecurityRules[*].{Name:name,Priority:priority,Access:access,Direction:direction,Port:destinationPortRange}' \
--output table
# Azure:使用 Network Watcher 测试连通性
az network watcher test-ip-flow \
--vm vm-app \
--direction Inbound \
--protocol TCP \
--local 10.1.1.10:8080 \
--remote 10.0.1.4:1234 # App GW private IP
# 预期:Allow
az network watcher test-ip-flow \
--vm vm-app \
--direction Inbound \
--protocol TCP \
--local 10.1.1.10:22 \
--remote 0.0.0.0:12345 # Internet source
# 预期:Deny
```
## 许可证
MIT License
标签:AWS, Azure, DevSecOps, DPI, ECS, Terraform, 上游代理, 合规与审计, 基础架构即代码, 漏洞利用检测, 网络安全, 隐私保护