关于 dns-management
dns-management 是面向生产基础设施 DNS 配置与排障的技能,适合管理域名的工程师。内容涵盖多种 DNS 提供商、Terraform 配置、解析诊断及邮件安全记录。
主要功能
- 01管理 DNS 区域与记录
- 02提供 Route 53 和 Cloudflare 示例
- 03展示 Terraform DNS 配置
- 04使用 dig 和 nslookup 排障
- 05配置 DNSSEC 与邮件安全记录
适用场景
- 01为应用、API 和邮件配置域名
- 02迁移 DNS 提供商或整合区域
- 03排查解析失败与传播延迟
- 04设置 SPF、DKIM 和 DMARC
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ bagelhole/ devops-security-agent-skills --skill dns-management安装后在 Claude Code 中输入/dns-management确认已加载。
详细介绍
DNS 管理
为生产基础设施配置和管理 DNS 区域、记录及解析。
适用场景
- 为 Web 应用、API 和电子邮件设置域名。
- 迁移 DNS 提供商或整合 DNS 区域。
- 为 CDN、负载均衡器和云服务配置 DNS。
- 排查解析失败、传播延迟或配置错误。
- 配置 DNSSEC、SPF、DKIM 和 DMARC,以增强电子邮件安全性。
前提条件
- 已通过域名注册商注册域名(Namecheap、Route53、Google Domains、Cloudflare)。
- 可访问 DNS 提供商的控制面板或 API。
- 已配置 AWS CLI(适用于 Route53 示例)。
- 本地已安装
dig和nslookup(大多数操作系统均已包含)。
DNS 记录类型参考
| 类型 | 用途 | 示例值 |
|---|---|---|
| A | IPv4 地址 | 93.184.216.34 |
| AAAA | IPv6 地址 | 2606:2800:220:1:248:1893:25c8:1946 |
| CNAME | 指向其他域名的别名 | www.example.com -> example.com |
| MX | 带优先级的邮件服务器 | 10 mail.example.com |
| TXT | 任意文本(SPF、DKIM、验证) | v=spf1 include:_spf.google.com ~all |
| NS | 权威名称服务器 | ns1.example.com |
| SRV | 服务位置(主机、端口、优先级) | 10 5 5060 sip.example.com |
| CAA | 证书颁发机构授权 | 0 issue "letsencrypt.org" |
| PTR | 反向 DNS 查询 | 34.216.184.93.in-addr.arpa |
AWS Route 53
托管区域管理
# Create a hosted zone
aws route53 create-hosted-zone \
--name example.com \
--caller-reference "$(date +%s)"
# List hosted zones
aws route53 list-hosted-zones
# Get name servers for a zone (update at your registrar)
aws route53 get-hosted-zone --id Z1234567890ABC \
--query 'DelegationSet.NameServers'
创建和管理记录
# Create an A record
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890ABC \
--change-batch '{
"Changes": [{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "app.example.com",
"Type": "A",
"TTL": 300,
"ResourceRecords": [{"Value": "93.184.216.34"}]
}
}]
}'
# Create a CNAME record
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890ABC \
--change-batch '{
"Changes": [{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "www.example.com",
"Type": "CNAME",
"TTL": 300,
"ResourceRecords": [{"Value": "example.com"}]
}
}]
}'
# Create an alias record (no TTL, Route53-specific)
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890ABC \
--change-batch '{
"Changes": [{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "example.com",
"Type": "A",
"AliasTarget": {
"HostedZoneId": "Z2FDTNDATAQYW2",
"DNSName": "d1234567890.cloudfront.net",
"EvaluateTargetHealth": false
}
}
}]
}'
# List records in a zone
aws route53 list-resource-record-sets --hosted-zone-id Z1234567890ABC
# Delete a record (Action: DELETE with exact match)
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890ABC \
--change-batch '{
"Changes": [{
"Action": "DELETE",
"ResourceRecordSet": {
"Name": "old.example.com",
"Type": "A",
"TTL": 300,
"ResourceRecords": [{"Value": "1.2.3.4"}]
}
}]
}'
Route 53 运行状况检查
# Create a health check
aws route53 create-health-check --caller-reference "$(date +%s)" \
--health-check-config '{
"IPAddress": "93.184.216.34",
"Port": 443,
"Type": "HTTPS",
"ResourcePath": "/health",
"RequestInterval": 30,
"FailureThreshold": 3
}'
Cloudflare DNS
通过 API 管理记录
# Get zone ID
ZONE_ID=$(curl -s "https://api.cloudflare.com/client/v4/zones?name=example.com" \
-H "Authorization: Bearer $CF_API_TOKEN" | jq -r '.result[0].id')
# Create an A record (proxied through Cloudflare)
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"type":"A","name":"app","content":"93.184.216.34","proxied":true,"ttl":1}'
# Create a CNAME record (DNS only, not proxied)
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-d '{"type":"CNAME","name":"docs","content":"docs.readthedocs.io","proxied":false,"ttl":3600}'
# List all records
curl -s "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \
-H "Authorization: Bearer $CF_API_TOKEN" | jq '.result[] | {name, type, content, proxied}'
# Delete a record
curl -X DELETE "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID" \
-H "Authorization: Bearer $CF_API_TOKEN"
Terraform DNS 管理
使用 Terraform 管理 Route 53
# dns.tf
resource "aws_route53_zone" "main" {
name = "example.com"
}
resource "aws_route53_record" "app" {
zone_id = aws_route53_zone.main.zone_id
name = "app.example.com"
type = "A"
ttl = 300
records = ["93.184.216.34"]
}
resource "aws_route53_record" "www" {
zone_id = aws_route53_zone.main.zone_id
name = "www.example.com"
type = "CNAME"
ttl = 300
records = ["example.com"]
}
# Alias record for CloudFront
resource "aws_route53_record" "cdn" {
zone_id = aws_route53_zone.main.zone_id
name = "example.com"
type = "A"
alias {
name = aws_cloudfront_distribution.main.domain_name
zone_id = aws_cloudfront_distribution.main.hosted_zone_id
evaluate_target_health = false
}
}
# Email records
resource "aws_route53_record" "mx" {
zone_id = aws_route53_zone.main.zone_id
name = "example.com"
type = "MX"
ttl = 3600
records = [
"1 aspmx.l.google.com",
"5 alt1.aspmx.l.google.com",
"5 alt2.aspmx.l.google.com",
]
}
resource "aws_route53_record" "spf" {
zone_id = aws_route53_zone.main.zone_id
name = "example.com"
type = "TXT"
ttl = 3600
records = ["v=spf1 include:_spf.google.com ~all"]
}
resource "aws_route53_record" "dmarc" {
zone_id = aws_route53_zone.main.zone_id
name = "_dmarc.example.com"
type = "TXT"
ttl = 3600
records = ["v=DMARC1; p=quarantine; rua=mailto:[email protected]; pct=100"]
}
使用 Terraform 管理 Cloudflare
resource "cloudflare_record" "app" {
zone_id = var.cloudflare_zone_id
name = "app"
content = "93.184.216.34"
type = "A"
proxied = true
}
resource "cloudflare_record" "mail" {
zone_id = var.cloudflare_zone_id
name = "@"
content = "aspmx.l.google.com"
type = "MX"
priority = 1
}
DNS 故障排查命令
dig
# Query A record
dig app.example.com A +short
# Query from a specific DNS server
dig @8.8.8.8 app.example.com A
# Show full answer with TTL
dig app.example.com A +noall +answer
# Query MX records
dig example.com MX +short
# Trace the full resolution path
dig app.example.com +trace
# Check DNSSEC validation
dig example.com +dnssec +short
# Query TXT records (SPF, DKIM)
dig example.com TXT +short
dig default._domainkey.example.com TXT +short
nslookup
# Basic lookup
nslookup app.example.com
# Specify DNS server
nslookup app.example.com 8.8.8.8
# Query specific record type
nslookup -type=MX example.com
nslookup -type=TXT example.com
检查 DNS 传播
# Query multiple public resolvers
for dns in 8.8.8.8 1.1.1.1 9.9.9.9 208.67.222.222; do
echo "=== $dns ==="
dig @$dns app.example.com A +short
done
电子邮件安全记录
# SPF — authorize sending servers
# TXT record on example.com
"v=spf1 include:_spf.google.com include:sendgrid.net -all"
# DKIM — email signing verification
# TXT record on google._domainkey.example.com
# (value provided by your email provider)
# DMARC — policy for failed SPF/DKIM
# TXT record on _dmarc.example.com
"v=DMARC1; p=reject; rua=mailto:[email protected]; pct=100"
TTL 策略
| 场景 | 建议的 TTL | 原因 |
|---|---|---|
| 稳定的生产记录 | 3600-86400(1 小时-24 小时) | 减少 DNS 查询,加快解析 |
| 迁移前预热 | 60-300(1-5 分钟) | 在迁移前数天降低 TTL |
| 迁移/故障转移期间 | 60 | 快速传播变更 |
| 迁移后冷却期 | 逐步提高至 3600+ | 确认稳定后恢复正常 |
| 负载均衡记录 | 60-300 | 支持由运行状况检查触发的故障转移 |
故障排查
| 症状 | 原因 | 解决方法 |
|---|---|---|
| 看不到 DNS 变更 | 递归解析器上的 TTL 尚未过期 | 等待旧 TTL 过期;下次变更前降低 TTL |
返回 SERVFAIL | DNSSEC 验证失败或委派配置错误 | 检查注册商处的 NS 记录;验证 DNSSEC 签名 |
有效记录返回 NXDOMAIN | 托管区域错误或缺少记录 | 使用 dig @<authoritative-ns> domain 确认记录是否存在 |
| 区域顶点的 CNAME 返回错误 | 根据 RFC,区域顶点不允许使用 CNAME | 使用 ALIAS(Route53)或代理 A 记录(Cloudflare) |
| 电子邮件被归入垃圾邮件 | SPF/DKIM/DMARC 缺失或配置错误 | 使用 dig example.com TXT 验证 TXT 记录;在 mail-tester.com 上测试 |
| 解析缓慢 | 递归解析器距离权威 NS 较远 | 使用 Anycast DNS 提供商(Cloudflare、Route53) |
| 不同解析器返回的结果不一致 | 传播尚未完成或缓存投毒 | 直接查询权威 NS;检查是否存在冲突记录 |
相关技能
- cdn-setup - CDN CNAME 和别名记录配置
- load-balancing - 基于 DNS 的负载均衡和运行状况检查
- cloudflare-zero-trust - 隧道 DNS 路由
- reverse-proxy - 将域名连接到后端服务
评论
支持 Markdown