.. include:: global.rst .. _Overview: *************************** Overview *************************** Theory Areas ================ .. _user-management: User Management --------------- **The idea.** A new Contabo VM comes with just one account, :term:`root`, which is allowed to do anything. Every attacker on the internet knows it exists, so it's the first name they try. To close that obvious attack path I: * made an everyday account of my own, * let it borrow root's powers only when asked, with :term:`sudo`, * made it log in with an :term:`SSH Key` instead of a password, and * blocked root from logging in over :term:`SSH` at all. That leaves exactly one account that can get in, and only with its key. **Where it fits.** This account is the front door. Everything after it (the firewall, web server, wiki, git and backups) is done while logged in as it. The programs we add later each run as a user of their own too, so the ideas here come up again and again. If the front door ever fails, the :term:`Contabo Control Panel` is the back way in, which is why that account should have :term:`MFA` turned on. **Where it lives in the OS.** The kernel doesn't know names; to it a user is just a number, the :term:`UID` (root is 0, my account is 1000). Every running :term:`Process` carries the UID of whoever started it, and the kernel checks that number before letting the process touch a file. The names are only kept in plain text files: :term:`/etc/passwd` (accounts), :term:`/etc/shadow` (password hashes) and ``/etc/group`` (each :term:`Group`, including the ``sudo`` group). SSH's own settings live in ``/etc/ssh/sshd_config.d/``, and my allowed keys in :term:`authorized_keys`. **What I did.** #. Logged in as root and made my account: ``adduser ``, then added it to the sudo group with ``usermod -aG sudo ``. The password I set here is the one ``sudo`` asks for. #. Went back to my own machine (WSL) and copied my *existing* key to the new account with :term:`ssh-copy-id`. One key works for every account, so there's no need to make a new one. #. In a new window, logged in as myself and ran ``sudo whoami``. It printed ``root``, so sudo works. #. Created ``/etc/ssh/sshd_config.d/10-hardening.conf`` containing :term:`PermitRootLogin` ``no`` and :term:`PasswordAuthentication` ``no``. #. Checked the file for mistakes with ``sudo sshd -t``, restarted SSH with ``sudo systemctl restart ssh``, then tested from a third window: ``ssh @`` gets in, ``ssh root@`` is refused. **If you are locked out.** Remember your VM password, protect your Contabo password, and turn VNC off after use. To get back in: #. Sign in to the Contabo control panel. #. Turn on the :term:`VNC Console` and copy its address, port and password. #. Connect with a VNC program (TigerVNC, RealVNC or UltraVNC). #. Log in as your own user with your *VM password* (VNC isn't SSH, so the key doesn't apply) and fix whatever locked you out. #. Turn VNC off again. **Lessons learned.** * **Keep the old window logged in** while changing SSH settings. If the new settings are wrong, that open session is your way back in. * **Test the way back in now, while nothing is broken.** A rescue route you've never tried isn't one you can count on. * Put your own settings in a :term:`Drop-in File` under ``sshd_config.d/`` instead of editing the main config. * If this goes from a practice system to a live one, add more :term:`Emergency Admin` accounts so one lost login can't lock everyone out. **Good sources.** * `Initial Server Setup with Debian 11 — DigitalOcean `_ * `Users and groups — ArchWiki `_ * How to connect to your server using VNC — `Contabo Help Center `_ Firewall & Security ------------------- **The idea.** A server on the internet gets knocked on all day by strangers. A :term:`Firewall` is the fence that decides which of those knocks are even allowed to reach the server. Everything is shut by default, and only the doors we actually need are opened on purpose. The one door we can never shut is :term:`SSH`, because that's how we get in ourselves, so the SSH door gets its own guard: :term:`Fail2ban`. **Layers of protection on our server.** * **The fence**: :term:`UFW` blocks every incoming :term:`Port` except 22 (SSH). When the web server is added later, ports 80 (HTTP) and 443 (HTTPS) get opened here too. * **The guard at the door**: :term:`Fail2ban` reads the login logs and bans any address that keeps failing to log in. * **The lock**: key-only login (from :ref:`user-management`) means that even a guest who is let through can't guess their way in with a password. **Where it lives in the OS.** The filtering itself happens inside the kernel, done by :term:`netfilter`. UFW does no filtering of its own; it's a friendly tool that writes netfilter's rules for us. Fail2ban is a :term:`Service` that runs in the background. When it spots an attacker, it asks UFW to add a block rule. Their settings live in ``/etc/ufw/`` and ``/etc/fail2ban/``. **What I did.** #. Installed UFW (``sudo apt install ufw``). #. Set a :term:`Default Deny` policy: block all incoming, allow all outgoing, then allow SSH with ``sudo ufw allow 22/tcp``. #. Turned it on (``sudo ufw enable``) and checked the rules with ``sudo ufw status verbose``. #. Opened a *new* terminal window to prove I could still log in. #. Installed Fail2ban (``sudo apt install fail2ban``). #. Wrote my settings in ``/etc/fail2ban/jail.local``, turning on the ``sshd`` :term:`Jail` with ``banaction = ufw``, ``maxretry = 5`` and ``bantime = 1h``. #. Started it with ``sudo systemctl enable --now fail2ban`` and confirmed the jail was running with ``sudo fail2ban-client status sshd``. **Lessons learned.** * **Order matters.** If you turn the firewall on *before* allowing SSH, you lock yourself out of your own server. After that, the only way back in is the :term:`VNC Console` in the Contabo panel. Keep a second window logged in until you've proven a fresh login still works. * **Never edit** ``jail.conf``. A package update overwrites it. Your own settings go in ``jail.local``, which is read on top of it and left alone by updates. * **A firewall can't protect a door it has to leave open.** That's why SSH needs extra defenses (Fail2ban and key-only login) behind the firewall. **Good sources.** * `Uncomplicated Firewall (ufw) — Debian Wiki `_ * `nftables — Debian Wiki `_ * `How To Set Up a Firewall with UFW on Debian 10 — DigitalOcean `_ * `How To Protect SSH with Fail2Ban on Debian 11 — DigitalOcean `_ * `fail2ban on GitHub `_