前回の記事では、external-dnsを使ってKubernetesリソースからAWS Route53のDNSレコードを自動生成する基本的な方法を紹介しました。その中で、external-dnsが管理に使用するTXTレコードが公開されてしまう点について触れましたが、本記事ではその解決策として、TXTレコードの暗号化機能の実装方法を詳しく解説します。
TXTレコードとRegistryについて
external-dnsは、DNSレコードの管理情報をRegistryと呼ばれる場所に保存します。このRegistryには、TXTレコード以外にもDynamoDBやAWS Service Discoveryなどを使用することができます。
TXT Registryを選択する利点は、これ自身がDNSのプロトコルにしか依存していないおかげで、クラウドベンダー固有のサービスを避けられることです。これによりベンダーロックインを回避しつつ、管理情報を保持することができます。ただし、TXTレコードはパブリックに公開されるため、そのままでは管理情報が外部から見えてしまいます。そこで、TXTレコードの暗号化機能を使用することで、この問題を解決できます。
前提条件
- Kubernetesクラスターがセットアップされていること
- 必要なコマンドツールがインストールされていること
- kubectl
- helm
- aws
- dig
- AWSアカウントのアクセスキーとシークレットキー
セットアップ手順
1. AWS Route53 Hosted Zoneの作成
まず、AWSの認証情報を環境変数に設定します:
export AWS_ACCESS_KEY_ID=AKIAXXXXXXXXXXXXXXXX
export AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
認証情報が正しく設定されているか確認します:
aws sts get-caller-identity
AWS Route53でHosted Zoneを作成します:
aws route53 create-hosted-zone --name example-tutorial.com --caller-reference external-dns-tutorial-$(date +%s)
Note: caller-referenceは各作成試行で一意である必要があります。ここではタイムスタンプを使用して一意性を確保しています。
2. external-dnsのインストール(TXTレコード暗号化有効)
Bitnamiが提供するHelmチャートを使用します。このチャートは、kubernetes-sigsが提供するものよりもオプションが豊富で、AWS Route53の設定が容易です:
helm install external-dns \
--set provider=aws \
--set aws.zoneType=public \
--set aws.credentials.accessKey="$AWS_ACCESS_KEY_ID" \
--set aws.credentials.secretKey="$AWS_SECRET_ACCESS_KEY" \
--set txtOwnerId=example-owner-id-123 \
--set "domainFilters[0]=example-tutorial.com" \
--set policy=sync \
--set "sources[0]=crd" \
--set crd.create=true \
--set crd.apiversion=externaldns.k8s.io/v1alpha1 \
--set crd.kind=DNSEndpoint \
--set txtEncrypt.enabled=true \
--set txtEncrypt.aesKey="" \
oci://registry-1.docker.io/bitnamicharts/external-dns
インストールオプションの説明
オプション | 説明 |
---|---|
provider=aws |
AWS Route53を使用することを指定 |
aws.zoneType=public |
パブリックゾーンを使用することを指定 |
aws.credentials.accessKey |
AWSのアクセスキー |
aws.credentials.secretKey |
AWSのシークレットキー |
txtOwnerId |
TXTレコードのオーナーID(任意の値を指定可能) |
domainFilters[0] |
監視対象のドメイン |
policy=sync |
DNSレコード同期ポリシー |
sources[0]=crd |
CRDを使用することを指定 |
crd.create=true |
CRDの作成を有効化 |
crd.apiversion |
CRDのAPIバージョン |
crd.kind |
CRDの種類 |
txtEncrypt.enabled=true |
TXTレコードの暗号化を有効化 |
txtEncrypt.aesKey |
暗号化用のAESキー(空文字列の場合は自動生成) |
インストール後、external-dnsのログを確認して正常に起動していることを確認します:
kubectl logs -l app.kubernetes.io/name=external-dns -f
次のようなログが表示されれば、暗号化機能が有効な状態で正常に起動しています:
time="2024-11-06T07:03:47Z" level=info msg="config: {...TXTEncryptEnabled:true...}"
time="2024-11-06T07:03:47Z" level=info msg="Instantiating new Kubernetes client"
time="2024-11-06T07:03:47Z" level=info msg="Using inCluster-config based on serviceaccount-token"
time="2024-11-06T07:03:47Z" level=info msg="Created Kubernetes client https://10.43.0.1:443"
time="2024-11-06T07:03:49Z" level=info msg="Applying provider record filter for domains: [example-tutorial.com. .example-tutorial.com.]"
AES暗号化キーが生成され、Secretに保存されていることを確認します:
kubectl get secret external-dns -o yaml
Secretの中に txt_aes_encryption_key
フィールドが存在していることを確認できます:
apiVersion: v1
kind: Secret
data:
txt_aes_encryption_key: Q2NCSUF6c2I1N215SGY4RWZtWmZvWm1keUl2SHBsTDY= # Base64エンコードされたAESキー
# ... 他のフィールドは省略
3. DNSレコードの作成
external-dnsがDNSレコードを作成することを確認します。今回は実体リソースが不要なCRDのDNSEndpointを使用します:
# test.example-tutorial.com.yaml
apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
name: test.example-tutorial.com
spec:
endpoints:
- dnsName: test.example-tutorial.com
recordTTL: 180
recordType: A
targets:
- 127.0.0.1
このマニフェストを適用します:
kubectl apply -f test.example-tutorial.com.yaml
しばらくすると、external-dnsがDNSレコードを作成します。ログを確認します:
time="2024-11-06T07:12:52Z" level=info msg="Desired change: CREATE a-test.example-tutorial.com TXT" profile=default zoneID=/hostedzone/Z00418233KGBJI8AZJFPR zoneName=example-tutorial.com.
time="2024-11-06T07:12:52Z" level=info msg="Desired change: CREATE test.example-tutorial.com A" profile=default zoneID=/hostedzone/Z00418233KGBJI8AZJFPR zoneName=example-tutorial.com.
time="2024-11-06T07:12:52Z" level=info msg="2 record(s) were successfully updated" profile=default zoneID=/hostedzone/Z00418233KGBJI8AZJFPR zoneName=example-tutorial.com.
AWS CLIを使用してDNSレコードが作成されたことを確認します:
aws route53 list-resource-record-sets --hosted-zone-id Z00418233KGBJI8AZJFPR
AレコードとTXTレコード(暗号化済み)の両方が確認できます:
{
"ResourceRecordSets": [
{
"Name": "test.example-tutorial.com.",
"Type": "A",
"TTL": 180,
"ResourceRecords": [
{
"Value": "127.0.0.1"
}
]
},
{
"Name": "a-test.example-tutorial.com.",
"Type": "TXT",
"TTL": 300,
"ResourceRecords": [
{
"Value": "\"YwPTDxmRgtKjryuSqYrqA35DoRkFw94ZxoojvZ9goHiyXbd8zYS8wBqS7t3ZtZoqREqDDaLtLcB0wbzTpw9n1+HxgGrJc795b4ISnJXRI03+sJ+DgN71dU7hCCyoPx25w/jYbOX3/zP DP59BmZaAly/OLmCEcDTW7dl697qdj4lsNHBrr+6Z1lAFKHAKfX3pM9w6RFGmpGl4WULtAA==\""
}
]
}
]
}
TXT暗号化を有効にしたことで、TXTレコードの内容はAES暗号化されています。このTXTレコードには従来と同じ管理情報(heritage、owner、resourceなど)が含まれていますが、暗号化されているため外部からの参照はできません。
クリーンアップ
1. DNSレコードの削除
CRDリソースを削除します:
kubectl delete -f test.example-tutorial.com.yaml
external-dnsのログで削除が完了したことを確認できます:
time="2024-11-06T05:48:24Z" level=info msg="Desired change: DELETE a-test.example-tutorial.com TXT" profile=default zoneID=/hostedzone/Z08033563HFN15GSXJ766 zoneName=example-tutorial.com.
time="2024-11-06T05:48:24Z" level=info msg="Desired change: DELETE test.example-tutorial.com A" profile=default zoneID=/hostedzone/Z08033563HFN15GSXJ766 zoneName=example-tutorial.com.
time="2024-11-06T05:48:24Z" level=info msg="Desired change: DELETE test.example-tutorial.com TXT" profile=default zoneID=/hostedzone/Z08033563HFN15GSXJ766 zoneName=example-tutorial.com.
time="2024-11-06T05:48:24Z" level=info msg="3 record(s) were successfully updated" profile=default zoneID=/hostedzone/Z08033563HFN15GSXJ766 zoneName=example-tutorial.com.
2. external-dnsの削除
Helmリリースを削除します:
helm uninstall external-dns
3. Hosted Zoneの削除
Hosted Zoneの一覧を確認し:
aws route53 list-hosted-zones
確認したIDを使用してHosted Zoneを削除します:
aws route53 delete-hosted-zone --id Z00418233KGBJI8AZJFPR
おわりに
本記事では、external-dnsのTXTレコード暗号化機能を使用して、DNS管理情報をセキュアに保つ方法を解説しました。TXTレコードは、クラウドベンダー固有のサービスを避けつつ管理情報を保持できる便利なRegistryですが、そのままでは情報が公開されてしまいます。暗号化機能を使用することで、この問題を解決しつつTXT Registryのメリットを活かすことができます。
前回の記事と合わせて参照いただくことで、より理解が深まるかと思います。ぜひ実際に試してみてください!