dns-management について
dns-managementは、本番インフラのDNSを設定・診断するエンジニア向けのスキルです。プロバイダー別の例、Terraform設定、名前解決の確認、メールセキュリティ用レコードを扱います。
主な機能
- 01DNSゾーンとレコードの管理
- 02Route 53とCloudflareの設定例
- 03TerraformによるDNS設定
- 04digとnslookupを使った診断
- 05DNSSECとメールセキュリティレコードの設定
活用シーン
- 01アプリ、API、メール用ドメインの設定
- 02DNSプロバイダーの移行やゾーン統合
- 03名前解決失敗や伝播遅延の調査
- 04SPF、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 プロバイダーを移行する、またはゾーンを統合するとき。
- CDN、ロードバランサー、クラウドサービス向けに DNS を設定するとき。
- 名前解決の失敗、伝播の遅延、設定ミスをトラブルシューティングするとき。
- メールセキュリティのために DNSSEC、SPF、DKIM、DMARC を導入するとき。
前提条件
- レジストラ(Namecheap、Route53、Google Domains、Cloudflare)で登録済みのドメイン。
- DNS プロバイダーのダッシュボードまたは API へのアクセス権。
- 設定済みの AWS CLI(Route53 の例で使用)。
- ローカル環境で利用できる
digとnslookup(ほとんどの OS に標準で含まれています)。
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 対応