diff --git a/Containerfile b/Containerfile new file mode 100644 index 0000000..550a199 --- /dev/null +++ b/Containerfile @@ -0,0 +1,4 @@ +FROM debian + +COPY machine_admin / +COPY machine_setup.py / diff --git a/README.md b/README.md index ef18837..05ebea2 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,14 @@ -This repo is a collection of ad-hoc scripts and snippets for setting up and administering a small cloud server. +This repo is a collection of ad-hoc scripts and snippets for setting up and administering a small cloud server. They are just a stepping stone toward for formal automation. + +# Machine setup + +```sh +./setup_machine.sh +``` + +# Set up basic nginx server + +```sh +./setup_basic_nginx.sh +``` diff --git a/machine_admin/__init__.py b/machine_admin/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/machine_admin/firewall.py b/machine_admin/firewall.py new file mode 100644 index 0000000..7ed1619 --- /dev/null +++ b/machine_admin/firewall.py @@ -0,0 +1,28 @@ +import logging +from util import run_op + +class UfwInterface: + + def __init__(self): + pass + + def enable(self): + op = "ufw enable" + logging.info(f"Enabling ufw: {op}") + run_op(op) + + def allow_app(self, app_name: str): + op = f"ufw allow {app_name}" + logging.info(f"Allowing ufw app: {op}") + run_op(op) + +class Firewall: + + def __init__(self): + self.ufw = UfwInterface() + + def allow_app(self, app_name: str): + self.ufw.allow_app(app_name) + + def enable(self): + self.ufw.enable() \ No newline at end of file diff --git a/machine_admin/machine.py b/machine_admin/machine.py new file mode 100644 index 0000000..63aa482 --- /dev/null +++ b/machine_admin/machine.py @@ -0,0 +1,29 @@ +from firewall import Firewall +from user import User, UserManager +from ssh_config import SshConfig +from package_manager import PackageManager + +class Machine: + + def __init__(self, default_user: User): + self.user = default_user + self.user_manager = UserManager() + self.firewall = Firewall() + self.ssh_config = SshConfig() + self.package_manager = PackageManager() + + def enable_firewall(self): + self.firewall.allow_app("OpenSSH") + self.firewall.enable() + + def secure_ssh_config(self): + self.ssh_config.sync_target_values() + self.ssh_config.restart_service() + + def setup(self): + self.package_manager.update() + self.user_manager.setup_user(self.user) + self.enable_firewall() + self.secure_ssh_config() + self.package_manager.install_packages(["rsync", "fail2ban"]) + self.ssh_config.copy_ssh_dir_to_user(self.user.name) \ No newline at end of file diff --git a/machine_admin/package_manager.py b/machine_admin/package_manager.py new file mode 100644 index 0000000..56b8b20 --- /dev/null +++ b/machine_admin/package_manager.py @@ -0,0 +1,39 @@ +import logging +from util import run_op + +class AptInterface: + + def __init__(self): + pass + + def update(self): + op = "apt-get update" + logging.info(f"Updating apt: {op}") + run_op(op) + + def upgrade(self): + op = "apt-get -y upgrade" + logging.info(f"Upgrading via apt: {op}") + run_op(op) + + def install_packages(self, packages: list): + packages_str = "".join(packages) + op = f"apt-get install -y {packages_str}" + logging.info(f"Installing packages: {op}") + run_op(op) + + +class PackageManager: + + def __init__(self): + self.apt = AptInterface() + + def update(self): + self.apt.update() + + def upgrade(self): + self.update() + self.apt.upgrade() + + def install_packages(self, packages: list): + self.apt.install_packages(packages) diff --git a/machine_admin/ssh_config.py b/machine_admin/ssh_config.py new file mode 100644 index 0000000..74259c8 --- /dev/null +++ b/machine_admin/ssh_config.py @@ -0,0 +1,25 @@ +from pathlib import Path +import logging +from util import run_op + +class SshConfig: + + def __init__(self): + self.config_path = Path("/etc/ssh/ssh_config") + self.target_values = {"PermitRootLogin": "No", + "PasswordAuthentication": "No", + "ChallengeResponseAuthentication": "No", + "UsePAM": "No"} + + def sync_target_values(self): + logging.info(f"Updating ssh config in: {self.config_path}") + pass + + def restart_service(self): + op = "systemctl restart ssh" + logging.info(f"Restarting ssh service: {op}") + run_op(op) + + def copy_ssh_dir_to_user(self, username:str): + op = f"rsync --archive --chown={username}:{username} ~/.ssh /home/{username}" + \ No newline at end of file diff --git a/machine_admin/user.py b/machine_admin/user.py new file mode 100644 index 0000000..071b1ad --- /dev/null +++ b/machine_admin/user.py @@ -0,0 +1,27 @@ +import logging +from util import run_op + +class User: + def __init__(self, name, has_sudo=False): + self.name = name + self.has_sudo = has_sudo + +class UserManager: + + def __init__(): + pass + + def setup_user(self, user: User): + add_user(user) + if user.has_sudo: + add_user_to_sudo(user) + + def add_user(self, user: User): + op = f"adduser {user.name}" + logging.info(f"Adding user: {op}") + run_op(op) + + def add_user_to_sudo(self, user: User): + op = f"usermod -aG sudo {user.name}" + logging.info(f"Adding user to sudo: {op}") + run_op(op) \ No newline at end of file diff --git a/machine_admin/util.py b/machine_admin/util.py new file mode 100644 index 0000000..2fef7c7 --- /dev/null +++ b/machine_admin/util.py @@ -0,0 +1,4 @@ +import subprocess + +def run_op(op: str): + return subprocess.run(op, shell=True) \ No newline at end of file diff --git a/machine_setup.py b/machine_setup.py new file mode 100644 index 0000000..57e2071 --- /dev/null +++ b/machine_setup.py @@ -0,0 +1,21 @@ +import argparse +import logging + +from machine_admin.user import User +from machine_admin.machine import Machine + +if __name__ == "__main__": + + parser = argparse.ArgumentParser( + prog='MachineSetup', + description='Scripts for machine provisioning') + + parser.add_argument('--username', + help="Name of the default non-root user") + + args = parser.parse_args() + + user = User(args.username, has_sudo=True) + machine = Machine(user) + machine.setup() + diff --git a/setup_basic_nginx.sh b/setup_basic_nginx.sh index 33846bf..f4fed51 100644 --- a/setup_basic_nginx.sh +++ b/setup_basic_nginx.sh @@ -1,16 +1,18 @@ +export MY_DOMAIN="my_domain" + apt install nginx ufw allow 'Nginx HTTP' -mkdir -p /var/www/your_domain/html -chown -R $USER:$USER /var/www/your_domain/html -chmod -R 755 /var/www/your_domain +mkdir -p /var/www/$MY_DOMAIN/html +chown -R $USER:$USER /var/www/$MY_DOMAIN/html +chmod -R 755 /var/www/$MY_DOMAIN -echo "Hello world" | /var/www/your_domain/html/index.html +echo "Hello world" | /var/www/$MY_DOMAIN/html/index.html -cp basic_serverblock.txt /etc/nginx/sites-available/your_domain +cp basic_serverblock.txt /etc/nginx/sites-available/$MY_DOMAIN -ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/ +ln -s /etc/nginx/sites-available/$MY_DOMAIN /etc/nginx/sites-enabled/ # sudo nano /etc/nginx/nginx.conf server_names_hash_bucket_size 64; \ No newline at end of file