diff --git a/.gitignore b/.gitignore index 169841b..04fa59d 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ terraria/password.txt # nas nas/*.json +nas/smb.conf nas/users.sh # backup diff --git a/README.md b/README.md index 8d0d609..0718a85 100644 --- a/README.md +++ b/README.md @@ -45,3 +45,7 @@ Services deployed on [matthewtran.com](https://matthewtran.com). ## backup Run `scripts/backup.py` and save the resultant `data.zip` somewhere. I should probably automate this. + +## security + +To protect against vulnerabilities, all services run as non-root users inside containers that are on separate networks by function and have all capabilities dropped. These non-root users have a UID that doesn't exist on the host and a GID that maps to their function. Hopefully, even in the event of a full container compromise and root escalation, there is little damage an attacker can do. The main security hole left is containers accessing the LAN and host, AppArmor might help with this. diff --git a/nas/smb.conf b/nas/base.conf similarity index 76% rename from nas/smb.conf rename to nas/base.conf index 45d5eb7..bbe17c1 100644 --- a/nas/smb.conf +++ b/nas/base.conf @@ -36,5 +36,14 @@ directory mask = 0770 force user = me force group = me -[share] -path = /home/me/share +vfs objects = fruit streams_xattr +fruit:metadata = stream +fruit:model = Backup +fruit:veto_appledouble = no +fruit:nfs_aces = no +fruit:wipe_intentionally_left_blank_rfork = yes +fruit:delete_empty_adfiles = yes +fruit:posix_rename = yes +fruit:time machine = yes +spotlight backend = elasticsearch + diff --git a/scripts/setup_repo.py b/scripts/setup_repo.py index 55685df..ab99e24 100755 --- a/scripts/setup_repo.py +++ b/scripts/setup_repo.py @@ -37,7 +37,7 @@ if __name__ == "__main__": f.write(f"su - me -c 'echo \"{users[user]}\\n{users[user]}\\n\" | pdbedit -s smb.conf -a {user}'\n") # add volumes to nas - mounts = json.load(open("nas/mounts.json")) + mounts = json.load(open("nas/mounts.json", "r")) with open("compose.override.yml", "w") as f: if mounts: f.writelines(s + "\n" for s in [ @@ -47,3 +47,12 @@ if __name__ == "__main__": ] + [ f" - {mounts[m]}:/home/me/share/{m}" for m in mounts ]) + + # generate nas config + shutil.copyfile("nas/base.conf", "nas/smb.conf") + with open("nas/smb.conf", "a") as f: + if mounts: + for dest in mounts: + f.write(f"[{dest}]\n") + f.write(f"path = /home/me/share/{dest}\n") + f.write("\n") diff --git a/scripts/setup_router.py b/scripts/setup_router.py index 1a3e069..0a3b9be 100755 --- a/scripts/setup_router.py +++ b/scripts/setup_router.py @@ -81,6 +81,7 @@ if __name__ == "__main__": # IPv6 traffic rules "uci add firewall rule", f"uci set firewall.@rule[-1].name='allow-{name}'", + "uci set firewall.@rule[-1].family='ipv6'", "uci set firewall.@rule[-1].src='wan'", "uci set firewall.@rule[-1].dest='lan'", f"uci set firewall.@rule[-1].dest_ip='::{IPV6}/{DP_LEN-128}'", diff --git a/scripts/setup_server.py b/scripts/setup_server.py index 701ed2c..45fc11d 100755 --- a/scripts/setup_server.py +++ b/scripts/setup_server.py @@ -24,17 +24,6 @@ if __name__ == "__main__": if not file.exists(): with file.open("w") as f: f.write("PasswordAuthentication no\n") - try: - run("addgroup --gid 2000 web") - run("addgroup --gid 2001 monero") - run("addgroup --gid 2002 game") - run("addgroup --gid 2003 nas") - run(f"adduser {os.getlogin()} web") - run(f"adduser {os.getlogin()} monero") - run(f"adduser {os.getlogin()} game") - run(f"adduser {os.getlogin()} nas") - except: - pass # install docker and configure run("snap install docker") @@ -48,6 +37,18 @@ if __name__ == "__main__": json.dump(cfg, f, indent=4) run("systemctl restart snap.docker.dockerd.service") + try: + run("addgroup --gid 2000 web") + run("addgroup --gid 2001 monero") + run("addgroup --gid 2002 game") + run("addgroup --gid 2003 nas") + run(f"adduser {os.getlogin()} web") + run(f"adduser {os.getlogin()} monero") + run(f"adduser {os.getlogin()} game") + run(f"adduser {os.getlogin()} nas") + except: + pass + # restrict network access from containers file = Path("/etc/systemd/system/docker-restrict.service") if not file.exists():