From d755bad314385bcf042c880f2245ac3c4f5dd265 Mon Sep 17 00:00:00 2001 From: Benjamin Hays Date: Fri, 11 Oct 2024 19:06:13 -0400 Subject: [PATCH] Add Dynamic DNS and Heartbeat Playbook --- .gitmodules | 3 ++ Ansible/cloudflare-dns.yml | 36 ++++++++++++++++++++ Ansible/debian.yml | 2 ++ Ansible/heartbeat.yml | 15 ++++++++ Ansible/homelab-vault | 1 + Ansible/inventory.ini | 11 +++--- Bash/cloudflare-dns.sh | 70 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 133 insertions(+), 5 deletions(-) create mode 100644 Ansible/cloudflare-dns.yml create mode 100644 Ansible/heartbeat.yml create mode 160000 Ansible/homelab-vault create mode 100755 Bash/cloudflare-dns.sh diff --git a/.gitmodules b/.gitmodules index f501478..e63c81a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "Configs/elk-stack/docker-elk"] path = Configs/elk-stack/docker-elk url = https://github.com/deviantony/docker-elk.git +[submodule "Ansible/homelab-vault"] + path = Ansible/homelab-vault + url = gitea@10.0.0.8:BenHays42/homelab-vault.git diff --git a/Ansible/cloudflare-dns.yml b/Ansible/cloudflare-dns.yml new file mode 100644 index 0000000..d39bdfc --- /dev/null +++ b/Ansible/cloudflare-dns.yml @@ -0,0 +1,36 @@ +--- +- name: Cloudflare Dynamic DNS Script + hosts: linux + remote_user: bhays + become: true + become_user: root + vars_files: + - homelab-vault/secrets.yml + tasks: + - name: Copy Cloudflare IPAM Script + ansible.builtin.copy: + owner: bhays + mode: "0600" + src: ../Bash/cloudflare-dns.sh + dest: /opt/cloudflare-dns.sh + - name: Insert API Token + ansible.builtin.replace: + path: "/opt/cloudflare-dns.sh" + regexp: "^cloudflare_zone_api_token=''" + replace: "cloudflare_zone_api_token='{{ CF_API_TOKEN }}'" + - name: Insert Zone ID + ansible.builtin.replace: + path: "/opt/cloudflare-dns.sh" + regexp: "^zoneid=''" + replace: "zoneid='{{ CF_ZONE_ID }}'" + - name: Insert Zone ID + ansible.builtin.replace: + path: "/opt/cloudflare-dns.sh" + regexp: "^dns_record=''" + replace: "dns_record='{{ inventory_hostname }}'" + - name: Add Cronjob for IPAM Script + ansible.builtin.cron: + name: "Cloudflare IPAM Script" + job: "/opt/cloudflare-dns.sh" + special_time: hourly + user: bhays diff --git a/Ansible/debian.yml b/Ansible/debian.yml index 0da7091..a6e9dc0 100644 --- a/Ansible/debian.yml +++ b/Ansible/debian.yml @@ -4,6 +4,8 @@ remote_user: bhays become: true become_user: root + vars_files: + - homelab-vault/secrets.yml tasks: - name: Update/install Debian Utilities ansible.builtin.apt: diff --git a/Ansible/heartbeat.yml b/Ansible/heartbeat.yml new file mode 100644 index 0000000..48c9405 --- /dev/null +++ b/Ansible/heartbeat.yml @@ -0,0 +1,15 @@ +--- +- name: Betterstack Heartbeat Cronjob + hosts: linux + remote_user: bhays + become: true + become_user: root + vars_files: + - homelab-vault/secrets.yml + tasks: + - name: Add Cronjob + ansible.builtin.cron: + name: "Betterstack Heartbeat" + job: "curl {{ heartbeat_url }}" + special_time: hourly + user: bhays diff --git a/Ansible/homelab-vault b/Ansible/homelab-vault new file mode 160000 index 0000000..d7f23e2 --- /dev/null +++ b/Ansible/homelab-vault @@ -0,0 +1 @@ +Subproject commit d7f23e227008f394956850c71655389cd67a304c diff --git a/Ansible/inventory.ini b/Ansible/inventory.ini index bc32ae3..46a9b0b 100644 --- a/Ansible/inventory.ini +++ b/Ansible/inventory.ini @@ -2,8 +2,9 @@ proxmox.benhays.cloud [linux] -devops.benhays.cloud -web.benhays.cloud -tailscale.benhays.cloud -bitwarden.benhays.cloud -nextcloud.benhays.cloud +devops.benhays.cloud heartbeat_url="https://uptime.betterstack.com/api/v1/heartbeat/xVM4MLbQARNndNDcSA5bsnpR" +web.benhays.cloud heartbeat_url='https://uptime.betterstack.com/api/v1/heartbeat/cyWGjSGDk1VFJNtabDB8tchU' +tailscale.benhays.cloud heartbeat_url='https://uptime.betterstack.com/api/v1/heartbeat/Sp7CXapJDwtjQmCMVdjeQsMy' +bitwarden.benhays.cloud heartbeat_url='https://uptime.betterstack.com/api/v1/heartbeat/YUBUtgJjBDJKEqM1qUXroj1v' +nextcloud.benhays.cloud heartbeat_url='https://uptime.betterstack.com/api/v1/heartbeat/oijvrZGFtc9Dev2AefP8iTfB' + diff --git a/Bash/cloudflare-dns.sh b/Bash/cloudflare-dns.sh new file mode 100755 index 0000000..2152c6a --- /dev/null +++ b/Bash/cloudflare-dns.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash + +ttl="600" +proxied="false" +zoneid='' +cloudflare_zone_api_token='' +dns_record='' + +REIP='^((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])\.){3}(25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])$' + +if which ip >/dev/null; then + interface=$(ip route get 1.1.1.1 | awk '/dev/ { print $5 }') + ip=$(ip -o -4 addr show ${interface} scope global | awk '{print $4;}' | cut -d/ -f 1) +else + echo "Error! 'ip' command not found. Please install iproute2." + exit 1 +fi + +if [ -z "$ip" ]; then + echo "Error! Can't read ip from ${interface}" + exit 1 +fi + +echo "==> Internal ${interface} IP is: $ip" + +IFS=',' read -d '' -ra dns_records <<<"$dns_record," +unset 'dns_records[${#dns_records[@]}-1]' +declare -a dns_records + +for record in "${dns_records[@]}"; do + if [ "${proxied}" == "false" ]; then + if which nslookup >/dev/null; then + dns_record_ip=$(nslookup ${record} 1.1.1.1 | awk '/Address/ { print $2 }' | sed -n '2p') + else + dns_record_ip=$(host -t A ${record} 1.1.1.1 | awk '/has address/ { print $4 }' | sed -n '1p') + fi + + if [ -z "$dns_record_ip" ]; then + echo "Error! Can't resolve the ${record} via DNS" + exit 1 + fi + is_proxed="${proxied}" + fi + + cloudflare_record_info=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records?type=A&name=$record" \ + -H "Authorization: Bearer $cloudflare_zone_api_token" \ + -H "Content-Type: application/json") + + if [[ ${cloudflare_record_info} == *"\"success\":false"* ]]; then + echo ${cloudflare_record_info} + echo "Error! Can't get ${record} record information from Cloudflare API" + exit 1 + fi + + cloudflare_dns_record_id=$(echo ${cloudflare_record_info} | grep -o '"id":"[^"]*' | cut -d'"' -f4) + + update_dns_record=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records/$cloudflare_dns_record_id" \ + -H "Authorization: Bearer $cloudflare_zone_api_token" \ + -H "Content-Type: application/json" \ + --data "{\"type\":\"A\",\"name\":\"$record\",\"content\":\"$ip\",\"ttl\":$ttl,\"proxied\":$proxied}") + + if [[ ${update_dns_record} == *"\"success\":false"* ]]; then + echo ${update_dns_record} + echo "Error! Update failed" + exit 1 + fi + + echo "==> Success!" + echo "==> $record DNS Record updated to: $ip, ttl: $ttl, proxied: $proxied" +done \ No newline at end of file