AWS Route53 Resolver DNS 防火牆

AWS Route53 Resolver DNS Firewall Configuration

DNS 防火牆概述

AWS Route 53 Resolver DNS Firewall 是一項受管服務,可讓您定義 VPC 內的 DNS 查詢過濾規則。透過 DNS 防火牆,您可以封鎖對已知惡意網域的 DNS 解析請求,並允許對受信任網域的查詢,有效防止資料外洩和惡意軟體連線。

DNS 防火牆的主要功能

  • 網域過濾:根據網域名稱允許或封鎖 DNS 查詢
  • 受管網域清單:使用 AWS 提供的威脅情報網域清單
  • 自訂網域清單:建立符合組織需求的網域清單
  • DNS 查詢日誌:記錄所有 DNS 查詢以供分析和稽核
  • 故障安全模式:在服務故障時選擇允許或封鎖查詢

DNS 防火牆運作流程

1
VPC 內的資源 → DNS 查詢 → Route 53 Resolver → DNS 防火牆規則評估 → 允許/封鎖

當 VPC 內的資源發出 DNS 查詢時,Route 53 Resolver 會先檢查 DNS 防火牆規則群組中的規則,根據規則的優先順序逐一評估,直到找到符合的規則為止。

規則群組與規則

DNS 防火牆使用規則群組(Rule Group)來組織規則,每個規則群組可包含多個規則。規則定義了要比對的網域清單以及相對應的動作。

建立規則群組

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 建立 DNS 防火牆規則群組
aws route53resolver create-firewall-rule-group \
    --name my-dns-firewall-rule-group \
    --creator-request-id $(uuidgen) \
    --tags Key=Environment,Value=Production

# 取得規則群組 ID
RULE_GROUP_ID=$(aws route53resolver list-firewall-rule-groups \
    --query "FirewallRuleGroups[?Name=='my-dns-firewall-rule-group'].Id" \
    --output text)

查看規則群組

1
2
3
4
5
6
# 列出所有規則群組
aws route53resolver list-firewall-rule-groups

# 取得特定規則群組的詳細資訊
aws route53resolver get-firewall-rule-group \
    --firewall-rule-group-id $RULE_GROUP_ID

建立規則

規則需要指定網域清單、動作和優先順序。以下是建立規則的範例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 建立封鎖規則
aws route53resolver create-firewall-rule \
    --firewall-rule-group-id $RULE_GROUP_ID \
    --firewall-domain-list-id $DOMAIN_LIST_ID \
    --priority 100 \
    --action BLOCK \
    --block-response NODATA \
    --name block-malicious-domains \
    --creator-request-id $(uuidgen)

# 建立允許規則
aws route53resolver create-firewall-rule \
    --firewall-rule-group-id $RULE_GROUP_ID \
    --firewall-domain-list-id $ALLOW_LIST_ID \
    --priority 50 \
    --action ALLOW \
    --name allow-trusted-domains \
    --creator-request-id $(uuidgen)

規則動作類型

動作說明
ALLOW允許 DNS 查詢通過
BLOCK封鎖 DNS 查詢
ALERT允許查詢但記錄警示日誌

BLOCK 回應類型

回應類型說明
NODATA傳回空的成功回應
NXDOMAIN傳回網域不存在的回應
OVERRIDE傳回自訂的 DNS 回應

網域清單管理

網域清單是 DNS 防火牆的核心元件,用於定義要過濾的網域名稱。AWS 提供受管網域清單,您也可以建立自訂清單。

AWS 受管網域清單

AWS 提供以下受管網域清單:

清單名稱說明
AWSManagedDomainsMalwareDomainList已知的惡意軟體網域
AWSManagedDomainsBotnetCommandandControl殭屍網路 C&C 伺服器網域
AWSManagedDomainsAggregateThreatList綜合威脅網域清單
1
2
3
# 列出 AWS 受管網域清單
aws route53resolver list-firewall-domain-lists \
    --query "FirewallDomainLists[?contains(Name, 'AWSManaged')]"

建立自訂網域清單

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 建立網域清單
aws route53resolver create-firewall-domain-list \
    --name blocked-domains \
    --creator-request-id $(uuidgen) \
    --tags Key=Purpose,Value=Security

# 取得網域清單 ID
DOMAIN_LIST_ID=$(aws route53resolver list-firewall-domain-lists \
    --query "FirewallDomainLists[?Name=='blocked-domains'].Id" \
    --output text)

更新網域清單

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 新增網域到清單(使用 ADD 操作)
aws route53resolver update-firewall-domains \
    --firewall-domain-list-id $DOMAIN_LIST_ID \
    --operation ADD \
    --domains "malicious-site.com" "bad-domain.org" "*.phishing-site.net"

# 從清單中移除網域(使用 REMOVE 操作)
aws route53resolver update-firewall-domains \
    --firewall-domain-list-id $DOMAIN_LIST_ID \
    --operation REMOVE \
    --domains "removed-domain.com"

# 替換整個網域清單(使用 REPLACE 操作)
aws route53resolver update-firewall-domains \
    --firewall-domain-list-id $DOMAIN_LIST_ID \
    --operation REPLACE \
    --domains "new-domain1.com" "new-domain2.com"

從 S3 匯入網域清單

對於大型網域清單,可以從 S3 匯入:

1
2
3
4
5
# 從 S3 匯入網域清單
aws route53resolver import-firewall-domains \
    --firewall-domain-list-id $DOMAIN_LIST_ID \
    --operation REPLACE \
    --domain-file-url s3://my-bucket/domain-list.txt

網域清單檔案格式(每行一個網域):

1
2
3
4
malware-domain1.com
malware-domain2.org
*.wildcard-domain.net
subdomain.example.com

查看網域清單內容

1
2
3
4
# 列出網域清單中的網域
aws route53resolver list-firewall-domains \
    --firewall-domain-list-id $DOMAIN_LIST_ID \
    --max-results 100

VPC 關聯設定

建立規則群組後,需要將其關聯到 VPC 才能生效。每個 VPC 可以關聯多個規則群組,並透過優先順序決定評估順序。

建立 VPC 關聯

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 取得 VPC ID
VPC_ID=$(aws ec2 describe-vpcs \
    --filters "Name=tag:Name,Values=my-vpc" \
    --query "Vpcs[0].VpcId" \
    --output text)

# 建立規則群組與 VPC 的關聯
aws route53resolver associate-firewall-rule-group \
    --firewall-rule-group-id $RULE_GROUP_ID \
    --vpc-id $VPC_ID \
    --priority 100 \
    --name my-vpc-dns-firewall-association \
    --creator-request-id $(uuidgen)

查看 VPC 關聯

1
2
3
4
5
6
7
# 列出規則群組的所有關聯
aws route53resolver list-firewall-rule-group-associations \
    --firewall-rule-group-id $RULE_GROUP_ID

# 列出 VPC 的所有規則群組關聯
aws route53resolver list-firewall-rule-group-associations \
    --vpc-id $VPC_ID

更新關聯優先順序

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 取得關聯 ID
ASSOCIATION_ID=$(aws route53resolver list-firewall-rule-group-associations \
    --firewall-rule-group-id $RULE_GROUP_ID \
    --query "FirewallRuleGroupAssociations[?VpcId=='$VPC_ID'].Id" \
    --output text)

# 更新優先順序
aws route53resolver update-firewall-rule-group-association \
    --firewall-rule-group-association-id $ASSOCIATION_ID \
    --priority 200

移除 VPC 關聯

1
2
3
# 解除規則群組與 VPC 的關聯
aws route53resolver disassociate-firewall-rule-group \
    --firewall-rule-group-association-id $ASSOCIATION_ID

動作與優先順序

DNS 防火牆使用優先順序來決定規則的評估順序。數字越小,優先順序越高。

優先順序運作方式

  1. 規則群組關聯有優先順序(決定哪個規則群組先評估)
  2. 規則群組內的規則也有優先順序(決定規則的評估順序)
  3. 第一個符合的規則將決定動作
1
2
3
4
5
6
7
8
VPC 關聯優先順序 100 的規則群組 A
├── 規則優先順序 10: ALLOW trusted-domains
├── 規則優先順序 20: BLOCK malware-domains
└── 規則優先順序 30: ALERT suspicious-domains

VPC 關聯優先順序 200 的規則群組 B
├── 規則優先順序 10: BLOCK botnet-domains
└── 規則優先順序 20: ALLOW all-other-domains

設定故障安全行為

當 DNS 防火牆服務發生故障時,您可以選擇預設行為:

1
2
3
4
5
6
7
8
9
# 設定故障安全模式為 FAIL_OPEN(允許所有查詢)
aws route53resolver update-firewall-config \
    --resource-id $VPC_ID \
    --firewall-fail-open ENABLED

# 設定故障安全模式為 FAIL_CLOSE(封鎖所有查詢)
aws route53resolver update-firewall-config \
    --resource-id $VPC_ID \
    --firewall-fail-open DISABLED

查看防火牆設定

1
2
3
# 取得 VPC 的防火牆設定
aws route53resolver get-firewall-config \
    --resource-id $VPC_ID

DNS 查詢日誌

DNS 查詢日誌可記錄所有經過 Route 53 Resolver 的 DNS 查詢,包括被 DNS 防火牆處理的查詢。

建立查詢日誌設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 建立 CloudWatch Logs 日誌群組
aws logs create-log-group \
    --log-group-name /aws/route53resolver/dns-query-logs

# 建立查詢日誌設定
aws route53resolver create-resolver-query-log-config \
    --name my-dns-query-log \
    --destination-arn arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/route53resolver/dns-query-logs \
    --creator-request-id $(uuidgen)

# 取得查詢日誌設定 ID
LOG_CONFIG_ID=$(aws route53resolver list-resolver-query-log-configs \
    --query "ResolverQueryLogConfigs[?Name=='my-dns-query-log'].Id" \
    --output text)

關聯日誌設定到 VPC

1
2
3
4
# 將日誌設定關聯到 VPC
aws route53resolver associate-resolver-query-log-config \
    --resolver-query-log-config-id $LOG_CONFIG_ID \
    --resource-id $VPC_ID

日誌目的地選項

DNS 查詢日誌可以傳送到以下目的地:

目的地ARN 格式
CloudWatch Logsarn:aws:logs:region:account-id:log-group:log-group-name
S3arn:aws:s3:::bucket-name
Kinesis Data Firehosearn:aws:firehose:region:account-id:deliverystream/stream-name

日誌格式範例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
{
    "version": "1.100000",
    "account_id": "123456789012",
    "region": "ap-northeast-1",
    "vpc_id": "vpc-12345678",
    "query_timestamp": "2025-12-21T10:30:00Z",
    "query_name": "malicious-domain.com.",
    "query_type": "A",
    "query_class": "IN",
    "rcode": "NOERROR",
    "answers": [],
    "srcaddr": "10.0.1.100",
    "srcport": "12345",
    "transport": "UDP",
    "srcids": {
        "instance": "i-0123456789abcdef0"
    },
    "firewall_rule_action": "BLOCK",
    "firewall_rule_group_id": "rslvr-frg-12345678",
    "firewall_domain_list_id": "rslvr-fdl-12345678"
}

查詢日誌分析

使用 CloudWatch Logs Insights 分析 DNS 查詢:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 查詢被封鎖的 DNS 請求
fields @timestamp, query_name, srcaddr, firewall_rule_action
| filter firewall_rule_action = "BLOCK"
| sort @timestamp desc
| limit 100

# 統計各網域的查詢次數
fields query_name
| stats count(*) as query_count by query_name
| sort query_count desc
| limit 20

# 查詢特定來源 IP  DNS 請求
fields @timestamp, query_name, query_type, firewall_rule_action
| filter srcaddr = "10.0.1.100"
| sort @timestamp desc
| limit 50

Terraform 部署範例

以下是使用 Terraform 完整部署 DNS 防火牆的範例:

基本設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# providers.tf
terraform {
  required_version = ">= 1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

變數定義

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# variables.tf
variable "vpc_id" {
  description = "要關聯 DNS 防火牆的 VPC ID"
  type        = string
}

variable "environment" {
  description = "環境名稱"
  type        = string
  default     = "production"
}

variable "blocked_domains" {
  description = "要封鎖的網域清單"
  type        = list(string)
  default = [
    "malware-example.com",
    "phishing-site.org",
    "*.bad-domain.net"
  ]
}

variable "allowed_domains" {
  description = "允許的網域清單"
  type        = list(string)
  default = [
    "*.amazonaws.com",
    "*.aws.amazon.com"
  ]
}

DNS 防火牆資源

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# main.tf

# 建立封鎖網域清單
resource "aws_route53_resolver_firewall_domain_list" "blocked" {
  name    = "${var.environment}-blocked-domains"
  domains = var.blocked_domains

  tags = {
    Environment = var.environment
    Purpose     = "DNS Firewall - Blocked Domains"
  }
}

# 建立允許網域清單
resource "aws_route53_resolver_firewall_domain_list" "allowed" {
  name    = "${var.environment}-allowed-domains"
  domains = var.allowed_domains

  tags = {
    Environment = var.environment
    Purpose     = "DNS Firewall - Allowed Domains"
  }
}

# 使用 AWS 受管威脅清單
data "aws_route53_resolver_firewall_domain_list" "aws_malware" {
  firewall_domain_list_id = "rslvr-fdl-malware"
}

data "aws_route53_resolver_firewall_domain_list" "aws_botnet" {
  firewall_domain_list_id = "rslvr-fdl-botnetcc"
}

# 建立規則群組
resource "aws_route53_resolver_firewall_rule_group" "main" {
  name = "${var.environment}-dns-firewall-rule-group"

  tags = {
    Environment = var.environment
  }
}

# 規則 1:允許受信任網域(最高優先順序)
resource "aws_route53_resolver_firewall_rule" "allow_trusted" {
  name                    = "allow-trusted-domains"
  action                  = "ALLOW"
  firewall_domain_list_id = aws_route53_resolver_firewall_domain_list.allowed.id
  firewall_rule_group_id  = aws_route53_resolver_firewall_rule_group.main.id
  priority                = 100
}

# 規則 2:封鎖自訂惡意網域
resource "aws_route53_resolver_firewall_rule" "block_custom" {
  name                    = "block-custom-domains"
  action                  = "BLOCK"
  block_response          = "NODATA"
  firewall_domain_list_id = aws_route53_resolver_firewall_domain_list.blocked.id
  firewall_rule_group_id  = aws_route53_resolver_firewall_rule_group.main.id
  priority                = 200
}

# 規則 3:封鎖 AWS 受管惡意軟體網域
resource "aws_route53_resolver_firewall_rule" "block_malware" {
  name                    = "block-aws-malware-domains"
  action                  = "BLOCK"
  block_response          = "NXDOMAIN"
  firewall_domain_list_id = data.aws_route53_resolver_firewall_domain_list.aws_malware.id
  firewall_rule_group_id  = aws_route53_resolver_firewall_rule_group.main.id
  priority                = 300
}

# 規則 4:封鎖 AWS 受管殭屍網路網域
resource "aws_route53_resolver_firewall_rule" "block_botnet" {
  name                    = "block-aws-botnet-domains"
  action                  = "BLOCK"
  block_response          = "NXDOMAIN"
  firewall_domain_list_id = data.aws_route53_resolver_firewall_domain_list.aws_botnet.id
  firewall_rule_group_id  = aws_route53_resolver_firewall_rule_group.main.id
  priority                = 400
}

# 關聯規則群組到 VPC
resource "aws_route53_resolver_firewall_rule_group_association" "main" {
  name                   = "${var.environment}-dns-firewall-association"
  firewall_rule_group_id = aws_route53_resolver_firewall_rule_group.main.id
  priority               = 100
  vpc_id                 = var.vpc_id

  tags = {
    Environment = var.environment
  }
}

# 設定防火牆故障模式
resource "aws_route53_resolver_firewall_config" "main" {
  resource_id        = var.vpc_id
  firewall_fail_open = "ENABLED"  # 故障時允許查詢通過
}

DNS 查詢日誌設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# logging.tf

# 建立 CloudWatch 日誌群組
resource "aws_cloudwatch_log_group" "dns_query_logs" {
  name              = "/aws/route53resolver/${var.environment}-dns-query-logs"
  retention_in_days = 30

  tags = {
    Environment = var.environment
  }
}

# 建立查詢日誌設定
resource "aws_route53_resolver_query_log_config" "main" {
  name            = "${var.environment}-dns-query-log-config"
  destination_arn = aws_cloudwatch_log_group.dns_query_logs.arn

  tags = {
    Environment = var.environment
  }
}

# 關聯查詢日誌設定到 VPC
resource "aws_route53_resolver_query_log_config_association" "main" {
  resolver_query_log_config_id = aws_route53_resolver_query_log_config.main.id
  resource_id                  = var.vpc_id
}

輸出值

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# outputs.tf
output "firewall_rule_group_id" {
  description = "DNS 防火牆規則群組 ID"
  value       = aws_route53_resolver_firewall_rule_group.main.id
}

output "firewall_rule_group_arn" {
  description = "DNS 防火牆規則群組 ARN"
  value       = aws_route53_resolver_firewall_rule_group.main.arn
}

output "blocked_domain_list_id" {
  description = "封鎖網域清單 ID"
  value       = aws_route53_resolver_firewall_domain_list.blocked.id
}

output "query_log_config_id" {
  description = "查詢日誌設定 ID"
  value       = aws_route53_resolver_query_log_config.main.id
}

output "dns_log_group_name" {
  description = "CloudWatch 日誌群組名稱"
  value       = aws_cloudwatch_log_group.dns_query_logs.name
}

部署命令

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 初始化 Terraform
terraform init

# 檢視執行計畫
terraform plan -var="vpc_id=vpc-12345678"

# 套用變更
terraform apply -var="vpc_id=vpc-12345678"

# 驗證部署
aws route53resolver list-firewall-rule-groups
aws route53resolver list-firewall-rule-group-associations --vpc-id vpc-12345678

監控與故障排除

CloudWatch 指標

DNS 防火牆會自動產生 CloudWatch 指標:

指標名稱說明
FirewallRuleGroupQueryVolume規則群組處理的查詢數量
BlockedQueries被封鎖的查詢數量
AlertedQueries觸發警示的查詢數量

建立 CloudWatch 警示

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 建立封鎖查詢數量警示
aws cloudwatch put-metric-alarm \
    --alarm-name "DNS-Firewall-High-Block-Rate" \
    --alarm-description "DNS 防火牆封鎖查詢數量過高" \
    --metric-name BlockedQueries \
    --namespace AWS/Route53Resolver \
    --statistic Sum \
    --period 300 \
    --threshold 1000 \
    --comparison-operator GreaterThanThreshold \
    --evaluation-periods 2 \
    --dimensions Name=FirewallRuleGroupId,Value=$RULE_GROUP_ID \
    --alarm-actions arn:aws:sns:ap-northeast-1:123456789012:my-alerts

Terraform CloudWatch 警示

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# alarms.tf
resource "aws_cloudwatch_metric_alarm" "high_block_rate" {
  alarm_name          = "${var.environment}-dns-firewall-high-block-rate"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = 2
  metric_name         = "BlockedQueries"
  namespace           = "AWS/Route53Resolver"
  period              = 300
  statistic           = "Sum"
  threshold           = 1000
  alarm_description   = "DNS 防火牆封鎖查詢數量超過閾值"

  dimensions = {
    FirewallRuleGroupId = aws_route53_resolver_firewall_rule_group.main.id
  }

  alarm_actions = [aws_sns_topic.alerts.arn]

  tags = {
    Environment = var.environment
  }
}

常見問題排除

1. DNS 查詢未被過濾

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 檢查規則群組是否已關聯到 VPC
aws route53resolver list-firewall-rule-group-associations \
    --vpc-id $VPC_ID

# 確認規則群組中有規則
aws route53resolver list-firewall-rules \
    --firewall-rule-group-id $RULE_GROUP_ID

# 檢查防火牆設定狀態
aws route53resolver get-firewall-config \
    --resource-id $VPC_ID

2. 合法網域被誤封

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 檢視被封鎖的查詢日誌
aws logs filter-log-events \
    --log-group-name /aws/route53resolver/dns-query-logs \
    --filter-pattern "{ $.firewall_rule_action = \"BLOCK\" }"

# 將網域新增到允許清單
aws route53resolver update-firewall-domains \
    --firewall-domain-list-id $ALLOW_LIST_ID \
    --operation ADD \
    --domains "legitimate-domain.com"

3. 查詢日誌未出現

1
2
3
4
5
6
7
# 確認日誌設定已關聯
aws route53resolver list-resolver-query-log-config-associations \
    --query "ResolverQueryLogConfigAssociations[?ResourceId=='$VPC_ID']"

# 檢查 CloudWatch Logs 權限
aws logs describe-log-groups \
    --log-group-name-prefix /aws/route53resolver

效能考量

  1. 規則優先順序:將最常符合的規則設定較高優先順序,減少評估時間
  2. 網域清單大小:單一網域清單最多支援 100,000 個網域
  3. 萬用字元使用:合理使用萬用字元(*)可減少清單項目數量
  4. 故障安全模式:根據安全需求選擇 FAIL_OPEN 或 FAIL_CLOSE

最佳實踐

  1. 分層防禦:結合 DNS 防火牆與其他安全服務(如 VPC Security Groups、WAF)
  2. 定期更新:持續更新網域清單以因應新的威脅
  3. 監控警示:設定適當的警示閾值以即時回應異常
  4. 日誌保留:根據合規需求設定適當的日誌保留期限
  5. 測試驗證:在生產環境部署前,先在測試環境驗證規則行為
  6. 文件記錄:記錄所有規則的用途和變更歷史

參考資料

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy