From 711773e5807e9b5b40eaf1f9e4639745dae63165 Mon Sep 17 00:00:00 2001 From: Joey Hafner Date: Thu, 29 Aug 2024 00:00:24 -0700 Subject: [PATCH] Add DIY DDNS script for Cloudflare to VyOS Clean out old, unused scripts --- homelab/wizard/scripts/cfddns.sh | 50 +++++++++++++++++ homelab/wizard/scripts/cloudflare.token | 58 ++++++++++++++++++++ homelab/wizard/scripts/dns_cloudflare.sh | 16 ------ homelab/wizard/scripts/dns_pihole.sh | 16 ------ homelab/wizard/scripts/edit_config.sh | 8 --- homelab/wizard/scripts/ipupdate.sh | 30 ++++++++++ homelab/wizard/scripts/update_hairpin_nat.sh | 23 -------- homelab/wizard/scripts/webhook.token | 58 ++++++++++++++++++++ 8 files changed, 196 insertions(+), 63 deletions(-) create mode 100644 homelab/wizard/scripts/cfddns.sh create mode 100644 homelab/wizard/scripts/cloudflare.token delete mode 100644 homelab/wizard/scripts/dns_cloudflare.sh delete mode 100644 homelab/wizard/scripts/dns_pihole.sh delete mode 100644 homelab/wizard/scripts/edit_config.sh create mode 100644 homelab/wizard/scripts/ipupdate.sh delete mode 100644 homelab/wizard/scripts/update_hairpin_nat.sh create mode 100644 homelab/wizard/scripts/webhook.token diff --git a/homelab/wizard/scripts/cfddns.sh b/homelab/wizard/scripts/cfddns.sh new file mode 100644 index 00000000..f5b0474c --- /dev/null +++ b/homelab/wizard/scripts/cfddns.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# Takes two positional arguments: +# $1 is the name of the zone to update +# E.g. jafner.net +# $2 is an auth token for Cloudflare; +# Must have the following permissions +# for the given zone: +# - Zone: Read +# - DNS: Read +# - DNS: Edit +function cfddns () { + ZONE=$1 + TOKEN=$2 + + # 1. Get the zone ID from the zone name + ZONE_ID=$( + curl -s \ + -X GET "https://api.cloudflare.com/client/v4/zones" \ + --header "Authorization: Bearer $TOKEN" \ + --header "Content-Type:application/json" |\ + jq -r --arg NAME "$ZONE" '.[] | .[]? | select(.name?==$NAME) | .id' 2>/dev/null |\ + xargs + ); echo $ZONE_ID + + # 2. Get the record ID of the root A record + RECORD_ID=$( + curl -s \ + -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \ + --header "Authorization: Bearer $TOKEN" \ + --header 'Content-Type:application/json' |\ + jq -r --arg NAME "$ZONE" '.[] | .[]? | select(.type=="A") | select(.name?==$NAME) | .id' 2>/dev/null |\ + xargs + ); echo $RECORD_ID + + # 3. Compose the json payload for the record to push + DATA=$(jq --null-input \ + --arg CONTENT "$(curl -s ipinfo.io/ip)" \ + --arg NAME "$ZONE" \ + '{"content": $CONTENT, "name": $NAME, "type": "A"}' + ); echo $DATA + + # 4. Finally submit the updated record to Cloudflare + curl --request PUT \ + --url https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID \ + --header "Authorization: Bearer $TOKEN" \ + --header 'Content-Type:application/json' \ + --data "$DATA" > /dev/null 2>&1 +} + +cfddns $1 $2 \ No newline at end of file diff --git a/homelab/wizard/scripts/cloudflare.token b/homelab/wizard/scripts/cloudflare.token new file mode 100644 index 00000000..d5792947 --- /dev/null +++ b/homelab/wizard/scripts/cloudflare.token @@ -0,0 +1,58 @@ +{ + "data": "ENC[AES256_GCM,data:i5Lxi5BD/whq/11xY/AeSU22Lvx2oee6ooR7Xrycm1bjWIJCGGZ9Wg==,iv:9d8M7WEKUSfYIKuWQ6KkzM08tr5PAxXH/SEDQHwDko4=,tag:6/KSwxdZD7HVVk/lRI29PQ==,type:str]", + "sops": { + "shamir_threshold": 2, + "key_groups": [ + { + "hc_vault": null, + "age": [ + { + "recipient": "age1zswcq6t5wl8spr3g2wpxhxukjklngcav0vw8py0jnfkqd2jm2ypq53ga00", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuR3ZGekxTR1JZNGphaGRj\ncVZCM1NGd2w3SFlkR0VKMlZxM0lxdGlQMVFvCkRRK2VjVUlEVndjZ25RUWl3NDUz\nUkNXdXNubTZ5REVOUDI5MGZXdVh6bTAKLS0tIHhCTlorSVdmZTY3ekQ1aVJkQ0Ix\nV001NGVyKzdtaXFhcmJURFhJRDFhNncKTDLvXoXS6OW/LwUs9av4ATIq4nqpWqtX\n7Z0TTB/Ms1l0l6lBmJMT/ep/aWj9RHkdIQGlpPlxJ5HVBhMcIiDH6JE=\n-----END AGE ENCRYPTED FILE-----\n" + } + ] + }, + { + "hc_vault": null, + "age": [ + { + "recipient": "age1zswcq6t5wl8spr3g2wpxhxukjklngcav0vw8py0jnfkqd2jm2ypq53ga00", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBFTWNpbUduY0RYeWd6ekVy\nN2dlS3VWYkZZZVJWMTJFNzZkbVNNOFY2QlZZCmd4VWw4VUQ2blR2VTdma00yVy9F\nUlN0UEV0Wk9ZaXZGUTkvL0hpV29zOWcKLS0tIDlwdjBkOXBJNXdjc0FMQm5QbUda\nbjVQbU1EcFl2RStCcnRIeFhUaTRkV2cKFtV2Tq+v5uQMgOCUTuT/PCrhhykEc3g8\n5SWMZmiKxSNZsGMSXJqHzVSK615nKmm4Tgbm09UHBMgS3gEo/GStpuk=\n-----END AGE ENCRYPTED FILE-----\n" + } + ] + }, + { + "hc_vault": null, + "age": [ + { + "recipient": "age12xgfd2w8acy5c2mrg3xv7ndzx3zw2j4kxv2a6ull385vxe8lcq2qpkhnv5", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGWEtWSEhsRmtEbzdYZzRN\nanEwYStlZHZOWlVobWVpd0JUb0xHUlY2N2xjCkllaGl2NGhsZmFzMGVqalNtaHgw\nSm5ublc3cjRMVmJ1TEhmd0VWZElyQTAKLS0tIHgzdlMybnFuQTRqNGNoUTZmM0hI\ndmcxSHA4NzBzcTBnWmFLcFVIdUwyZk0KmAxGREoNa42UYoHV8aFBVMpbF5jtAmAu\nMDwj8f9IVSMNBKZ695uFfS+opJJgEUT5k6dCpms55SOmVVI2ueVtumY=\n-----END AGE ENCRYPTED FILE-----\n" + } + ] + }, + { + "hc_vault": null, + "age": [ + { + "recipient": "age13prhyye2jy3ysa6ltnjgkrqtxrxgs0035d86jyn4ltgk3wxtqgrqgav855", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6UmlnOVlML3FYaDFDZThP\nVVNiZU1rN08raWNUSHMxVkppTmFpL0hqUndVCmgvRTdLMHQwajZabWZjTXpodm8x\nUnZKZVN0MHBMaGVoMlBmY29DZEV2R00KLS0tIHpPWVYrUWxkVmIzV0NmaGNUNmti\neHRIVlVuM1p5Y3FxVHpHMnVDVGp4UEkKD8Yp2JdE4LPVtWGibIv9IQGxCvrJXi8D\nUwnRPwYOxqKDc82YkiB+xmPLybGNyDTySkfEmgYJVVC3nrRTBu6n0Sw=\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age1n20krynrj75jqfy2muvhrygvzd4ee8ngamljqavsrk033zwx0ses2tdtfe", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBRakVSbHFsQjJwU09HMEpK\nVnY5UE9zNzgzOEtUVEV1RTlHN2oySU1CYnhjCkZKMTBnK0Fia0FGdFowVXR1S01z\nVldWc096QW01c0w3OGt4MytrTWNjdGcKLS0tIHBsbUxDMHhTT0JMTGZWR09aRUhh\nQWNKbngzRmhUL1VmdHc2MU13Y3VZejAKbByk3tp2ya7d6Lqe/I8Q5VWfkBBre5EH\nfXUd2ARacgPhaAT03z5TSc+ufVM6J7OUtGcY+ux4aTliQi+Uf3Lgsy0=\n-----END AGE ENCRYPTED FILE-----\n" + } + ] + } + ], + "kms": null, + "gcp_kms": null, + "azure_kv": null, + "hc_vault": null, + "age": null, + "lastmodified": "2024-08-29T06:59:11Z", + "mac": "ENC[AES256_GCM,data:PNmmT1P861SjNMyIti1LeReS59FGHTx4w+DlbcuI7ImTdcCCOYerGYzoQ4ocqLWzRODrPFs9GMrPS6CIxW0eIZ6NFUrRjk+0gOKDITVWwGWHfBG1GkEi5x4PSjqDL0lxQOxZlLtBLIhvaNMrRvbydcuYN4O3uCV+A2AtuVKCJVA=,iv:bL77QIfKp3yXmQbI5Alak/GzeQAfJGbs6beKFsEiY0A=,tag:qsbFZgh6cm6FyoIxkNV+tQ==,type:str]", + "pgp": null, + "unencrypted_suffix": "_unencrypted", + "version": "3.9.0" + } +} \ No newline at end of file diff --git a/homelab/wizard/scripts/dns_cloudflare.sh b/homelab/wizard/scripts/dns_cloudflare.sh deleted file mode 100644 index 4cf9feac..00000000 --- a/homelab/wizard/scripts/dns_cloudflare.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/vbash -# https://docs.vyos.io/en/equuleus/automation/command-scripting.html -source /opt/vyatta/etc/functions/script-template -configure - -delete service dns forwarding name-server 192.168.1.21 -delete service dns forwarding name-server 192.168.1.22 -set service dns forwarding name-server 1.1.1.1 - -delete service dhcp-server shared-network-name LAN name-server 192.168.1.21 -delete service dhcp-server shared-network-name LAN name-server 192.168.1.22 -set service dhcp-server shared-network-name LAN name-server 192.168.1.1 - -commit -save -exit \ No newline at end of file diff --git a/homelab/wizard/scripts/dns_pihole.sh b/homelab/wizard/scripts/dns_pihole.sh deleted file mode 100644 index f0d1d173..00000000 --- a/homelab/wizard/scripts/dns_pihole.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/vbash -# https://docs.vyos.io/en/equuleus/automation/command-scripting.html -source /opt/vyatta/etc/functions/script-template -configure - -delete service dns forwarding name-server 1.1.1.1 -set service dns forwarding name-server 192.168.1.21 -set service dns forwarding name-server 192.168.1.22 - -delete service dhcp-server shared-network-name LAN name-server 192.168.1.1 -set service dhcp-server shared-network-name LAN name-server 192.168.1.21 -set service dhcp-server shared-network-name LAN name-server 192.168.1.22 - -commit -save -exit \ No newline at end of file diff --git a/homelab/wizard/scripts/edit_config.sh b/homelab/wizard/scripts/edit_config.sh deleted file mode 100644 index 518a9219..00000000 --- a/homelab/wizard/scripts/edit_config.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/vbash -# https://docs.vyos.io/en/equuleus/automation/command-scripting.html -source /opt/vyatta/etc/functions/script-template - -cp /config/config.boot /config/config.new -nano /config/config.new -configure -load /config/config.new diff --git a/homelab/wizard/scripts/ipupdate.sh b/homelab/wizard/scripts/ipupdate.sh new file mode 100644 index 00000000..02f981cd --- /dev/null +++ b/homelab/wizard/scripts/ipupdate.sh @@ -0,0 +1,30 @@ +#!/bin/vbash +source /opt/vyatta/etc/functions/script-template + +SCRIPT_PATH="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +WEBHOOK_URL="$(cat $SCRIPT_PATH/webhook.token)" +NAT_COMMANDS="$(run show configuration commands | grep 'set nat destination' | grep 'destination address')" + +# Assert all destination nat rules use the same IP +if [[ "$(echo "$NAT_COMMANDS" | cut -d' ' -f8 | sort -u | wc -l)" != "1" ]]; then + curl -i -H "Accept: application/json" -H "Content-Type:application/json" -X POST --data "{\"content\": \"$SCRIPT_PATH/ipupdate.sh: Error: Existing NAT rules are not consistent\"}" $WEBHOOK_URL +fi + +# Get new and old public IPs +PUBLIC_IP="$(curl -s ipinfo.io/ip)" + +echo "$NAT_COMMANDS" | cut -d' ' -f-7 | while read line; do echo $line "$PUBLIC_IP"; done > /tmp/commands + +configure; source /tmp/commands > /dev/null; rm /tmp/commands +compare |\ +if [[ "$(cat -)" != *"No changes between working and active configurations."* ]]; then + curl -s -o /dev/null -i -H "Accept: application/json" -H "Content-Type:application/json" -X POST --data "{\"content\": \"$SCRIPT_PATH/ipupdate.sh: Info: Attempting to update hairpin NAT rules. New public IP: $PUBLIC_IP\"}" $WEBHOOK_URL + { # try commit, save, exit + commit && save && exit + } || { # catch, exit discard and create a very basic error file + exit discard + curl -s -o /dev/null -i -H "Accept: application/json" -H "Content-Type:application/json" -X POST --data "{\"content\": \"$SCRIPT_PATH/ipupdate.sh: Error: Failed during commit, save, exit.\"}" $WEBHOOK_URL + } +else + exit +fi \ No newline at end of file diff --git a/homelab/wizard/scripts/update_hairpin_nat.sh b/homelab/wizard/scripts/update_hairpin_nat.sh deleted file mode 100644 index 5acf9a09..00000000 --- a/homelab/wizard/scripts/update_hairpin_nat.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/vbash -source /opt/vyatta/etc/functions/script-template - -# get current public IP -NEW_IP=$(show interfaces pppoe pppoe1 | grep "inet\s" | cut -d ' ' -f 6) -# get old public IP -OLD_IP=$(show nat destination rules | grep 1100 | head -1 | tr -s ' ' | cut -d' ' -f 3) - - -show configuration commands | grep $OLD_IP | sed --expression="s/$OLD_IP/$NEW_IP/" > ipupdate.tmp - -configure - -source ipupdate.tmp - -{ # try commit, save, exit - commit && save && exit -} || { # catch, exit discard and create a very basic error file - exit discard - echo "Script failed. Write some real error handling." -} - -rm ipupdate.tmp diff --git a/homelab/wizard/scripts/webhook.token b/homelab/wizard/scripts/webhook.token new file mode 100644 index 00000000..1226c691 --- /dev/null +++ b/homelab/wizard/scripts/webhook.token @@ -0,0 +1,58 @@ +{ + "data": "ENC[AES256_GCM,data:J0L1cIwxF9x+zi8VnDglNPEXaTjPKAyn6KuUeRAFSwseAa3CxW2AgB+p2O97VJGisW/4Ft87jDuLecZAKBbytOlWRQmvPwcHzNl4bVMfzIfqXTb/mplQY736r4Ibzko/QWN3rlIRVg2BMpTeKem3cEgyxHCtAvMHrA==,iv:9o5DcCX9U224+GeUOZ0MVyrX41OjWkin2Zii914In2A=,tag:IG1x4JX7MCML1F7KZYRy+g==,type:str]", + "sops": { + "shamir_threshold": 2, + "key_groups": [ + { + "hc_vault": null, + "age": [ + { + "recipient": "age1zswcq6t5wl8spr3g2wpxhxukjklngcav0vw8py0jnfkqd2jm2ypq53ga00", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4Ykp5a1hJMGNDZ3VUSEl1\nTTNVdG82QW9MbmJqSFVWVzl2bVhaMWFiR1cwCjdrN2d4UlVHeHVOUEMzWXdCNzRC\nTk8wUTRRODRYMGJDVUltUVVrQ0d5RDQKLS0tIE5ORi9NUzdWM2lWUmtWemtrdTBR\nVGJGNnVERVIvYTNQU01YNFlGOE9kRDgKqA5t9bmCIpdEx8uIRZRuJqyHqVkV1v+l\ngZvorclJF36oSI+NWtj3pWZRFbxXh/CbMpTq9FMNaY5pmgVK7TUGq2E=\n-----END AGE ENCRYPTED FILE-----\n" + } + ] + }, + { + "hc_vault": null, + "age": [ + { + "recipient": "age1zswcq6t5wl8spr3g2wpxhxukjklngcav0vw8py0jnfkqd2jm2ypq53ga00", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuTys0TDZqb1pwejFyWU5Q\ncG1rM3pRMEJod1p1MWNneHk2OE5zdWRoQ1RVCkJjeEVvMVNUM0ZhOHhiWWN2VDYz\nKysrNmZWYTljaVBuVDNqQkRqQktpZWsKLS0tIEI4OGxLRzIzai9RRlFmVlpuVEZC\nT1UrSTYvNndwQ2toOTdoQ0hhV2V1NWcKiNXIZqUGwsgOKp63oaFoUMifcJPsgWXv\nRUTjlQCPnaWf5dWWqgtFQ5BpVIEp7t1o10Bz1l+njwb26ArsOUFI+MI=\n-----END AGE ENCRYPTED FILE-----\n" + } + ] + }, + { + "hc_vault": null, + "age": [ + { + "recipient": "age12xgfd2w8acy5c2mrg3xv7ndzx3zw2j4kxv2a6ull385vxe8lcq2qpkhnv5", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBSeFdUS2dyL29LMnpWdzA0\nWWhVN1NKWHp2VjF0bStONlVCZzQrME1DMUVRClNRWXJxQWVCNUlycXQ2YkVyOUlL\nWGZCZk1zZW1KVkhncGhDSjIrNVdOWWMKLS0tIFd4VjFLVnBlNjRNczhnU2lvYzh4\nRVJmU2k2Q2oySmdyc3dQVEpvR2lMZUkKLxIX14E7+ETRCQCgkE944+UiP+k6sp2F\n1mPDBVW4wK6UBcl5YVDVQfh3cY2dHSLmwzsDVkrqJgFvnlJtILPSDG4=\n-----END AGE ENCRYPTED FILE-----\n" + } + ] + }, + { + "hc_vault": null, + "age": [ + { + "recipient": "age13prhyye2jy3ysa6ltnjgkrqtxrxgs0035d86jyn4ltgk3wxtqgrqgav855", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQTFp1VFZ4QUtzQTc2RG1K\nQmk1aGdOZWNwUUlkZndyWk85WW1nZExMMWo4CjR4d2pSUitGZVhJK3h6WUFsaFNy\nS1dYWk9lM25Va2VKMnJnbVNWZ2lWTnMKLS0tIDd4NUMwRFplNktabm81aGdoeUVV\nOWU1RnM1YTI4WDlVOEFCaEtuM2ZvOWMKai54kxKRvRxCchAGxcfn1dW1o1UBOWsx\n8TneFFmpPOT67IaCc1APOeIyWYYNUIz1POoA+SpEiSaQAMVeAif5ek8=\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age1n20krynrj75jqfy2muvhrygvzd4ee8ngamljqavsrk033zwx0ses2tdtfe", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBrWFh5aFczYmRsblM3dkxZ\nTGg2WWg3SmhSUUJJL2NUcHcydlhDaUs5MjJjCnRyY1ltWjJrM0ZGUjZQTm5zMXV4\naVFPcm5BcXY1OFZQOU1SejRlYjBBNjQKLS0tIDlqNUllUXY1MUdoN2VMM2ozS2ti\nSXBQeDNrTEt1a2VhYkdrT0xLaTQxbDgKQ8ef/QkEzgqNF8dQ5o9WUmfsP3f+fwHJ\nm/IaR+tFiBjCqJsbr6sExc7wxQpyY2Ir/S6fsJ9dwtbjCTT032T+cTU=\n-----END AGE ENCRYPTED FILE-----\n" + } + ] + } + ], + "kms": null, + "gcp_kms": null, + "azure_kv": null, + "hc_vault": null, + "age": null, + "lastmodified": "2024-08-29T06:59:11Z", + "mac": "ENC[AES256_GCM,data:YuQ0M5fLfnTLY3oSpBkf35pH7AUwCq5ROIpNw13+Jk3GvKplX3acp54hxbKVBKK78sP6duh6mr+l7tROxsNer60PIMBCyAlFap3Bwhjm7wxuQuEv+0JTNC2MgzJBsZZxl/GbUhvX8DznK8mxMiNUSLvWvHUp6OF8dlhs39jaPEA=,iv:1WrF+cuLsGs6HSGSml/BJ4Ocprdkmt6IW/azHWF08Cs=,tag:hNzozSh9G0pblU6XeyEGwA==,type:str]", + "pgp": null, + "unencrypted_suffix": "_unencrypted", + "version": "3.9.0" + } +} \ No newline at end of file