Comment faire rouler votre propre DNS dynamique avec AWS Route 53
Si vous avez des serveurs qui fonctionnent à la maison, vous ne pourrez pas leur acheminer un domaine sans adresse IP statique. Au lieu de payer pour un service DNS dynamique, vous pouvez créer le vôtre à l'aide d'AWS Route 53.
Sommaire
Le DNS dynamique n'est pas compliqué
Le DNS dynamique est assez simple dans son concept. Un démon s'exécute sur la machine cliente et vérifie régulièrement l'adresse IP publique pour toute modification. Si l'adresse IP change, le démon envoie une mise à jour au fournisseur DNS, qui modifie l'enregistrement. Ceci est souvent offert en tant que service payant chez de nombreux registraires de domaine et fournisseurs DNS.
AWS n'a pas de service spécifique pour fournir un DNS dynamique, mais il est assez simple à configurer vous-même. La «façon AWS» de procéder consiste à configurer un événement CloudWatch qui déclenche une fonction Lambda en réponse aux changements d'infrastructure. (Bien que vous deviez probablement simplement utiliser un équilibreur de charge et un groupe de mise à l'échelle automatique dans la plupart des scénarios.)
Cependant, si vous souhaitez configurer un DNS dynamique pour un serveur domestique ou un autre appareil non AWS qui aura de fréquents changements d'adresse IP, l'écriture de scripts est assez facile. Route 53 propose des commandes CLI simples que vous pouvez utiliser pour mettre à jour les enregistrements DNS à partir de la ligne de commande; le raccordement à un travail cron qui recherche une modification de l'adresse IP publique et exécute l'AWS CLI fera le travail.
En ce qui concerne les prix, Route 53 ne coûte pas vraiment cher: des frais fixes de 0,50 $ par mois pour chaque nom de domaine, plus quelques frais mineurs pour les recherches DNS en fonction de l'utilisation. Les enregistrements sont gratuits (la recherche la plus courante), vous ne verrez donc probablement pas plus de quelques centimes par mois sur votre facture, sauf si vous générez un trafic important. À titre de comparaison, le prix de DynDNS commence à 55 $ par an.
Configuration du côté AWS des choses
Pour commencer, rendez-vous sur la console de gestion AWS Route 53. Si vous ne possédez pas de domaine, vous pouvez en enregistrer un sous «Domaines enregistrés» pour un prix relativement bon marché, généralement juste le prix des frais d'enregistrement de l'ICANN. Si votre domaine n'est pas actuellement sur Route 53, vous devrez le transférer, ce qui est un processus simple mais long.
Recherchez ou créez la zone hébergée pour votre domaine, qui contiendra tous les enregistrements. Vous devez noter l'ID de la zone hébergée, car vous en aurez besoin pour le script.
Vous souhaiterez créer un espace réservé A pour que le script ait quelque chose à référencer. Vous pouvez définir cela sur quelque chose qui n'est évidemment pas correct …255.255.255.255
fonctionnerait – pour tester la fonctionnalité du script.
Vous devrez également configurer l'AWS CLI, ce que vous pouvez faire avec:
curl "https://d1vvhvl2y92vvt.cloudfront.net/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" unzip awscliv2.zip sudo ./aws/install
Et configurez-le avec les informations d'identification d'un utilisateur IAM avec:
aws2 configure
Écrire le script
Si vous voulez juste le script, vous pouvez vous référer à cet essentiel, mais nous expliquerons comment il est configuré, car il est cool. Si vous copiez et collez simplement, vous devrez modifier HOSTED_ZONE_ID
et NAME
variables pour correspondre à l'enregistrement que vous essayez de mettre à jour. Notez que ce script utilise également le aws2
CLI, que vous devrez modifier si vous utilisez la version 1.
Tout d'abord, nous aurons besoin d'un moyen d'obtenir notre adresse IP publique par programmation. Pour cela, nous pouvons utiliser l'API checkip.amazonaws.com d'AWS. C'est entièrement gratuit et il n'y a pas de limite de taux. Vous pouvez également utiliser api.ipify.org à cet effet, qui est également gratuit et illimité. Nous allons le charger dans une variable et l'enregistrer pour plus tard.
IP=$(curl https://api.ipify.org/)
Ensuite, nous devrons valider cela pour nous assurer d'avoir récupéré une adresse IP valide et non un code d'erreur ou quelque chose de mal formé. Il suffit de vérifier que l'entrée est des nombres séparés par des périodes est suffisant à cet effet, donc un peu de regex à côté du =~
L'opérateur (renvoie vrai si l'expression régulière correspond à l'entrée de gauche, très utile) fera l'affaire:
if (( ! $IP =~ ^(0-9){1,3}.(0-9){1,3}.(0-9){1,3}.(0-9){1,3}$ )); then exit 1 fi
Nous devrons comparer cela à notre ancienne adresse IP pour voir si quelque chose a changé. Nous pourrions stocker cela sur le disque sous forme de fichier dans /tmp/
, mais c'est désordonné et sujet à des erreurs. Au lieu de cela, nous interrogerons Route 53 directement avec list-resource-record-sets
et filtrer l'adresse IP de l'enregistrement que nous essayons de mettre à jour avec jq
:
aws2 route53 list-resource-record-sets --hosted-zone-id Z1VCYR76DBUXPL | jq -r '.ResourceRecordSets() | select (.Name == "'"$NAME"'") | select (.Type == "'"$TYPE"'") | .ResourceRecords(0).Value' > /tmp/current_route53_value
Cela le sauve /tmp/current_route53_value
, que nous pouvons ensuite utiliser pour vérifier avec grep
, ce qui est assez résistant:
if grep -Fxq "$IP" /tmp/current_route53_value; then echo "IP Has Not Changed, Exiting" exit 1 fi
Enfin, nous préparons la charge utile pour change-resource-record-sets
. Cela doit être en JSON, nous allons donc sortir dans un fichier sur le disque et l'envoyer comme argument à la commande.
cat > /tmp/route53_changes.json << EOF { "Comment":"Updated From DDNS Shell Script", "Changes":( { "Action":"UPSERT", "ResourceRecordSet":{ "ResourceRecords":( { "Value":"$IP" } ), "Name":"$NAME", "Type":"$TYPE", "TTL":$TTL } } ) } EOF #update records aws2 route53 change-resource-record-sets --hosted-zone-id $HOSTED_ZONE_ID --change-batch file:///tmp/route53_changes.json
Tout est réuni pour former le script suivant. Vous voudrez changer le HOSTED_ZONE_ID
et NAME
variables pour correspondre à l'enregistrement que vous essayez de mettre à jour. Notez que NAME
a une période à la toute fin.
#!/bin/bash #Variable Declaration - Change These HOSTED_ZONE_ID="XXXXXXXXXXXX" NAME="example.com." TYPE="A" TTL=60 #get current IP address IP=$(curl http://checkip.amazonaws.com/) #validate IP address (makes sure Route 53 doesn't get updated with a malformed payload) if (( ! $IP =~ ^(0-9){1,3}.(0-9){1,3}.(0-9){1,3}.(0-9){1,3}$ )); then exit 1 fi #get current aws2 route53 list-resource-record-sets --hosted-zone-id $HOSTED_ZONE_ID | jq -r '.ResourceRecordSets() | select (.Name == "'"$NAME"'") | select (.Type == "'"$TYPE"'") | .ResourceRecords(0).Value' > /tmp/current_route53_value cat /tmp/current_route53_value #check if IP is different from Route 53 if grep -Fxq "$IP" /tmp/current_route53_value; then echo "IP Has Not Changed, Exiting" exit 1 fi echo "IP Changed, Updating Records" #prepare route 53 payload cat > /tmp/route53_changes.json << EOF { "Comment":"Updated From DDNS Shell Script", "Changes":( { "Action":"UPSERT", "ResourceRecordSet":{ "ResourceRecords":( { "Value":"$IP" } ), "Name":"$NAME", "Type":"$TYPE", "TTL":$TTL } } ) } EOF #update records aws2 route53 change-resource-record-sets --hosted-zone-id $HOSTED_ZONE_ID --change-batch file:///tmp/route53_changes.json >> /dev/null
Configurez votre Crontab
Vous pouvez éditer votre crontab avec:
crontab -e
Vous pouvez configurer ce script pour qu'il s'exécute toutes les minutes, car il est assez léger. Donnez à cron un chemin vers votre script sur le disque. Vous pouvez envoyer la sortie vers un fichier journal ou /dev/null
si vous ne voulez pas y faire face.
* * * * * /home/user/update_dns.sh >/dev/null 2>&1