diff --git a/code/backupfortigate.py b/code/backupfortigate.py new file mode 100644 index 0000000..f625dcd --- /dev/null +++ b/code/backupfortigate.py @@ -0,0 +1,51 @@ +# /// script +# requires-python = ">=3.12" +# dependencies = [ "pexpect", "typer"] +# /// + +# uv run backupfortigate.py 192.168.1.241 USERNAME PASSWORD +import pexpect +import sys +import tempfile +import typer +from enum import Enum + +CONFIG_SUFFIX="conf" + +class ConfigType(Enum): + FULL = 1 + SHORT = 2 + +def download_fortigate_config(ip:str,username:str,password:str,whichtype:ConfigType): + + p=pexpect.spawn(f'ssh {username}@{ip}',encoding='utf-8') + #p.logfile = sys.stdout + p.expect("assword:") + p.sendline(password) + p.expect("#") + prompt=p.before.lstrip() + if whichtype==ConfigType.FULL: + show_command="show full-configuration" + else: + show_command="show" + p.sendline(show_command) + p.expect(prompt) + return(p.before[len(show_command)+1:]) + +def backup(ip:str,username:str,password:str): + + with tempfile.TemporaryDirectory(delete=False) as dirname: + config_text = download_fortigate_config(ip=ip,username=username,password=password,whichtype=ConfigType.FULL) + fg_fn=f"{dirname}/fg-full.{CONFIG_SUFFIX}" + with open(fg_fn,"w") as outfile: + outfile.write(config_text) + config_text = download_fortigate_config(ip=ip,username=username,password=password,whichtype=ConfigType.SHORT) + fg_fn=f"{dirname}/fg-short.{CONFIG_SUFFIX}" + with open(fg_fn,"w") as outfile: + outfile.write(config_text) + print(dirname) + +if __name__ == "__main__": + typer.run(backup) + +sys.exit() diff --git a/code/hourly.sh b/code/hourly.sh index 64fa101..0da1a24 100755 --- a/code/hourly.sh +++ b/code/hourly.sh @@ -4,5 +4,6 @@ docker run --rm -e DFLT_PASSWORD=$DFLT_PASSWORD -e DFLT_USERNAME=$DFLT_USERNAME docker run --rm -e DFLT_PASSWORD=$DFLT_PASSWORD -e DFLT_USERNAME=$DFLT_USERNAME -e PASSWORD=$PASSWORD -e USERNAME=$USERNAME -v /home/johnp/scsd-configs/git:/repo -v /home/johnp/scsd-configs/git/code:/work -v /home/johnp/scsd-configs/git/configs/:/configs --privileged -t scsdansible ./run_backup_configs-cisco.sh 2>/tmp/run_cisco_backups.2.txt >/tmp/run_cisco_backups.1.txt docker run --rm -e WLC_PASSWORD=$WLC_PASSWORD -e DFLT_PASSWORD=$DFLT_PASSWORD -e DFLT_USERNAME=$DFLT_USERNAME -e PASSWORD=$PASSWORD -e USERNAME=$USERNAME -v /home/johnp/scsd-configs/git:/repo -v /home/johnp/scsd-configs/git/code:/work -v /home/johnp/scsd-configs/git/configs/:/configs --privileged -t scsdansible:pyexpect ./run_backup_wlcs.sh 2>/tmp/run_wlc_backups.2.txt >/tmp/run_wlc_backups.1.txt sed -i -E 's/(key|ipsec|wpa-passphrase|password) ([a-f0-9]+) $/ \1 *redacted*/' /home/johnp/scsd-configs/git/configs/wlc/wlc*cfg +docker run --rm -e FG_USERNAME=$FG_USERNAME -e FG_PASSWORD=$FG_PASSWORD -e DFLT_PASSWORD=$DFLT_PASSWORD -e DFLT_USERNAME=$DFLT_USERNAME -e PASSWORD=$PASSWORD -e USERNAME=$USERNAME -v /home/johnp/scsd-configs/git:/repo -v /home/johnp/scsd-configs/git/code:/work -v /home/johnp/scsd-configs/git/configs/:/configs --privileged -t scsdansible:oct2025 ./run_backup_fortigate.sh 2>/tmp/run_fortigate.2.txt >/tmp/run_fortigate.1.txt /home/johnp/scsd-configs/git/code/run_git.sh 2>/tmp/run_git.2.txt >/tmp/run_git.1.txt diff --git a/code/run_backup_fortigate.sh b/code/run_backup_fortigate.sh new file mode 100755 index 0000000..7fbbb27 --- /dev/null +++ b/code/run_backup_fortigate.sh @@ -0,0 +1,28 @@ +#!/usr/bin/bash + +openfortivpn vpn.scsd.us:10443 --username=$USERNAME --trusted-cert fda7d7ed64a9bd84562c6643e858c4a61cfdc6e90b0d4ee60e07fd0bb7fb7a9f --password=$PASSWORD & +while [ ! `ip a | grep -q "inet .*ppp" && echo "1"` ]; +do + #echo checking + sleep 1 +done +sleep 3 +dirname=$(uv run backupfortigate.py 192.168.1.241 $FG_USERNAME $FG_PASSWORD) + +uv run splitfgconfig.py $dirname/fg-short.conf + +subdirs=$(find $dirname -type d -name "v*" -or -name "gl*") + +changes=no +for subdir in $subdirs; do + diff -q $subdir /configs/fortigate/$(basename $subdir) || changes=yes + diff -q $subdir /configs/fortigate/$(basename $subdir) || cp -f -r $subdir /configs/fortigate/ +done + +echo changes=$changes + +if [ $changes = "yes" ];then + cp $dirname/fg-full.conf /configs/fortigate/fortigate.conf +fi + +chown -R 1000:1000 /configs/ diff --git a/code/run_git.sh b/code/run_git.sh index 05798eb..bd3b953 100755 --- a/code/run_git.sh +++ b/code/run_git.sh @@ -2,6 +2,13 @@ datestamp=`date` +cd /home/johnp/scsd-configs/git/configs/fortigate +git add global vdom* +git commit -m "fortigate $datestamp" +git add fortigate.conf +git commit -m "fortigate-backup $datestamp" + + cd /home/johnp/scsd-configs/git/configs for f in `find . -type f -name "*.cfg" -or -name "*.set" | sed 's:./::' ` do diff --git a/code/splitfgconfig.py b/code/splitfgconfig.py new file mode 100644 index 0000000..b512e45 --- /dev/null +++ b/code/splitfgconfig.py @@ -0,0 +1,66 @@ +# /// script +# requires-python = ">=3.12" +# dependencies = [ "typer"] +# /// + +# uv run splitfgconfig.py fg-short.conf +import sys +import os +import typer +from contextlib import suppress + + +def split_configfile(config_fn:str): + + dirname=os.path.dirname(config_fn) + redacted_fn = f"{dirname}/redacted.cfg" + cmd="sed -r 's/(password ENC|key ENC|token ENC|random-number ENC) .*/\\1 *HIDDEN*/' "+config_fn+" | sed -r '/BEGIN ENCRYPTED PRIVATE KEY/,/END ENCRYPTED PRIVATE KEY/{/^#/!{/^$/!d;};}' >"+redacted_fn + os.system(cmd) + + outfile=None + vdom_def=False + in_vdom_def=False + vdom_list=[] + with open(redacted_fn) as infile: + for line in infile: + if line.find("uuid")>0: + continue + if not vdom_def and line.startswith("config vdom"): + in_vdom_def=True + vdom_list_ptr=0 + continue + if in_vdom_def: + if line.startswith("edit"): + vdom_name=line.strip().split()[1] + vdom_list.append(vdom_name) + elif line.startswith("end"): + in_vdom_def=False + vdom_def=True + continue + if line.startswith("config global"): + subdir="global" + continue + elif line.startswith("config vdom"): + subdir=f"vdom_{vdom_list[vdom_list_ptr]}" + vdom_list_ptr+=1 + continue + if line.startswith("edit "): + continue + if line.startswith("config "): + section_name="_".join(line.split()[1:2]) + #print(section_name) + with suppress(FileExistsError): + os.mkdir(f"{dirname}/{subdir}") + section_fn=f"{dirname}/{subdir}/{section_name}.cfg" + if outfile: + outfile.close() + outfile=open(section_fn,"a") + if outfile: + outfile.write(line) + + #print(dirname) + +if __name__ == "__main__": + typer.run(split_configfile) + +sys.exit()