Туториали

Fortify Your Old Laptop: A Hands-On Hardened Linux Server Build

Зајакнете го вашиот стар лаптоп: практична изработка на зацврстен Linux сервер

Стар лаптоп веќе содржи неколку функции што малите сервери често ги немаат: напојување поддржано од батерија, екран и тастатура за итен пристап и хардвер дизајниран да работи тивко. Со дисциплинирана конфигурација на Linux, може да стане способен приватен сервер наместо импровизирана машина поставена под биро.

Оваа поставеност користи Debian stable, WireGuard, OpenSSH, nftables, LUKS-шифриран контејнер за податоци, systemd надзор и шифрирани резервни копии надвор од локацијата. По прекин на струјата, домаќинот автоматски се подига и ја обновува далечинската администрација. Заштитените податоци остануваат заклучени сè додека администратор изрично не ги отклучи.

Намерниот компромис е нешифриран оперативен систем со шифрирани податоци на апликациите. Тој овозможува ненадгледувано закрепнување без лозинката за волуменот со податоци да се чува на лаптопот. Напаѓач со физички пристап може да го прегледа или измени оперативниот систем, затоа користете шифрирање на целиот диск и мерено подигање кога таа закана е поважна од автоматското закрепнување.

Предуслови и архитектура

Почнете со поддржан 64-битен лаптоп, доверливо складиште, Ethernet ако е достапен и чиста инсталација на Debian stable. При инсталацијата создадете административен корисник со име admin. Не ја изложувајте машината директно на јавниот интернет.

Потребен ви е и втор уред за администрација на WireGuard и посебен резервен домаќин со можност за SSH. Примерите ги користат следниве адреси за документација:

  • 10.44.0.1: WireGuard адресата на лаптопот
  • 10.44.0.2: WireGuard адресата на администраторот
  • 51820/udp: WireGuard на рутерот и лаптопот
  • 2222/tcp: SSH, достапен само преку WireGuard

Ако лаптопот се наоѓа зад рутер, пренасочете ја UDP портата 51820 кон неговата LAN адреса. Јавна адреса што се менува бара динамички DNS. Примерната клиентска крајна точка server.example.net значи DNS име што го контролирате; тоа не е услуга што ја обезбедува ова упатство.

Добиената конфигурација намерно е мала:

/etc/wireguard/wg0.conf
/etc/ssh/sshd_config.d/60-hardened.conf
/etc/nftables.conf
/etc/fstab
/etc/systemd/logind.conf.d/server.conf
/etc/systemd/system/vault-health.service
/etc/systemd/system/vault-health.timer
/etc/systemd/system/restic-vault.service
/etc/systemd/system/restic-vault.timer
/usr/local/sbin/vault-open
/usr/local/sbin/vault-health
/var/lib/vault.luks
/srv/vault

Прво воспоставете ја административната патека

Поврзете се преку доверливата LAN мрежа и инсталирајте ги основните пакети. Сите команди за домаќинот во оваа статија се извршуваат на лаптопот, освен ако изрично не се означени како клиентски команди.

sudo apt update
sudo apt install wireguard nftables cryptsetup openssh-server \
  unattended-upgrades smartmontools restic
sudo systemctl enable --now ssh nftables
sudo systemctl enable --now unattended-upgrades

Командите за резервни копии се наменети за Restic 0.16.x до 0.18.x. Проверете ја пакетираната верзија со restic version пред да продолжите. Ако вашата дистрибуција испорачува верзија надвор од тој опсег, наместо да претпоставувате идентично однесување, консултирајте ја документацијата за тоа издание.

Создадете Ed25519 клуч на уредот на администраторот со ssh-keygen -t ed25519, а потоа инсталирајте го неговиот јавен клуч во /home/admin/.ssh/authorized_keys. Потврдете дека работи втора SSH сесија заснована на клуч пред да ги оневозможите лозинките.

Изградете го WireGuard тунелот

Генерирајте го серверскиот клуч како root за неговите дозволи да бидат точни:

sudo install -d -m 0700 /etc/wireguard
sudo sh -c 'umask 077; wg genkey > /etc/wireguard/server.key'
sudo sh -c 'wg pubkey < /etc/wireguard/server.key'
sudo wg genkey | tee client.key | wg pubkey > client.pub

Последните две датотеки се привремен клиентски материјал создаден во вашата тековна папка. Безбедно префрлете го client.key на уредот на администраторот, забележете го client.pub и отстранете ја локалната копија од приватниот клуч по тестирањето.

Користете sudoedit /etc/wireguard/wg0.conf и внесете ги серверскиот приватен клуч и содржината на client.pub:

[Interface]
Address = 10.44.0.1/24
ListenPort = 51820
PrivateKey = SERVER_PRIVATE_KEY

[Peer]
PublicKey = ADMIN_CLIENT_PUBLIC_KEY
AllowedIPs = 10.44.0.2/32

Тука, вредностите со големи букви се замени за клучевите што штотуку ги генериравте, а не буквална конфигурација. На уредот на администраторот, конфигурирајте:

[Interface]
Address = 10.44.0.2/32
PrivateKey = ADMIN_CLIENT_PRIVATE_KEY

[Peer]
PublicKey = SERVER_PUBLIC_KEY
Endpoint = server.example.net:51820
AllowedIPs = 10.44.0.1/32
PersistentKeepalive = 25

Овозможете го серверскиот тунел со sudo systemctl enable --now wg-quick@wg0. Подигнете го клиентот и проверете ping 10.44.0.1 пред да ги менувате правилата за SSH или заштитниот ѕид.

Ограничете ги SSH и заштитниот ѕид

Создадете /etc/ssh/sshd_config.d/60-hardened.conf со sudoedit:

Port 2222
ListenAddress 10.44.0.1
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
AllowUsers admin
X11Forwarding no
AllowAgentForwarding no
PermitTunnel no
MaxAuthTries 3
LoginGraceTime 30

Потврдете пред повторното вчитување: sudo sshd -t. Оставете ја постојната сесија отворена, извршете sudo systemctl reload ssh и воспоставете нова сесија со ssh -p 2222 [email protected].

На посветен нов домаќин, зачувајте го пакетираниот заштитен ѕид пред да го уредувате:

sudo cp --no-clobber /etc/nftables.conf /etc/nftables.conf.factory
sudoedit /etc/nftables.conf

Користете го овој сет правила. Заменете го enp3s0 со физичкиот интерфејс пријавен од ip -brief link.

flush ruleset

table inet filter {
  chain input {
    type filter hook input priority 0; policy drop;

    iifname "lo" accept
    ct state established,related accept
    ct state invalid drop

    ip protocol icmp accept
    ip6 nexthdr ipv6-icmp accept

    iifname "enp3s0" udp dport 51820 accept
    iifname "wg0" ip saddr 10.44.0.0/24 tcp dport 2222 accept
  }

  chain forward {
    type filter hook forward priority 0; policy drop;
  }

  chain output {
    type filter hook output priority 0; policy accept;
  }
}

Извршете sudo nft -c -f /etc/nftables.conf за да ја проверите синтаксата, а потоа sudo systemctl reload nftables. Повторно тестирајте WireGuard и нова SSH врска. Политиката за влез сега одбива LAN SSH и секоја непобарана услуга освен WireGuard.

Создадете шифрирано складиште за апликации

LUKS контејнер поддржан од датотека го избегнува нагаѓањето на имињата на уредите за диск и случајното форматирање на погрешниот диск. Донекаде е побавен од посветена партиција и не може да го надмине својот основен датотечен систем, но лесно се одредува неговата големина, се прави резервна копија и се отстранува.

Следново создава нов контејнер од 100 GiB. Прво потврдете дека /var/lib/vault.luks не постои и дека df -h /var/lib покажува доволно простор. Запрете ако некој од условите не е исполнет.

sudo test ! -e /var/lib/vault.luks
sudo fallocate --length 100G /var/lib/vault.luks
sudo chmod 0600 /var/lib/vault.luks
sudo cryptsetup luksFormat --type luks2 /var/lib/vault.luks
sudo cryptsetup open /var/lib/vault.luks vault
sudo mkfs.ext4 -L vault /dev/mapper/vault
sudo install -d -m 0750 -o admin -g admin /srv/vault

luksFormat ја уништува содржината на својата цел, поради што смее да се користи само на новосоздадениот контејнер. Изберете долга, единствена лозинка и чувајте копија за опоравување надвор од лаптопот.

Додајте го овој точен запис во /etc/fstab:

/dev/mapper/vault /srv/vault ext4 noauto,nosuid,nodev,noexec 0 2

Создадете /usr/local/sbin/vault-open со sudoedit:

#!/bin/sh
set -eu

if ! cryptsetup status vault >/dev/null 2>&1; then
    cryptsetup open /var/lib/vault.luks vault
fi

if ! mountpoint -q /srv/vault; then
    mount /srv/vault
fi

chown admin:admin /srv/vault
printf '%s\n' "Vault is open and mounted at /srv/vault"

Поставете sudo chmod 0750 /usr/local/sbin/vault-open. По рестартирање, поврзете се преку WireGuard, извршете sudo /usr/local/sbin/vault-open и внесете ја лозинката. Услугите што го користат овој волумен треба да декларираат RequiresMountsFor=/srv/vault и не смеат тивко да запишуваат во празната папка на точката за монтирање.

Конфигурирајте шифрирани резервни копии надвор од локацијата

Создадете ограничена сметка со име backup на посебен SSH сервер и празна папка во нејзина сопственост, како /srv/restic/laptop. Конфигурирајте root на лаптопот со посветен SSH клуч и прицврстете го клучот на домаќинот на резервниот сервер во /root/.ssh/known_hosts. Интерактивно проверете ја таа врска пред да ја автоматизирате.

Создадете /etc/restic/vault.env со режим 0600:

RESTIC_REPOSITORY=sftp:[email protected]:/srv/restic/laptop
RESTIC_PASSWORD_FILE=/etc/restic/password

Создадете /etc/restic/password користејќи sudoedit, внесете посебна лозинка за складиштето со висока ентропија и поставете ги двете датотеки на root:root со режим 0600. Иницијализирајте го само новото празно складиште:

sudo env $(sudo cat /etc/restic/vault.env) restic init
sudo env $(sudo cat /etc/restic/vault.env) restic backup /srv/vault
sudo env $(sudo cat /etc/restic/vault.env) restic snapshots

Бидејќи проследувањето анализирани датотеки со околински променливи преку школка е кревко, автоматизацијата треба да му дозволи на systemd директно да ја прочита датотеката. Создадете /etc/systemd/system/restic-vault.service:

[Unit]
Description=Encrypted backup of the vault
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
EnvironmentFile=/etc/restic/vault.env
ExecCondition=/usr/bin/mountpoint -q /srv/vault
ExecStart=/usr/bin/restic backup --one-file-system /srv/vault
ExecStart=/usr/bin/restic forget --keep-daily 7 --keep-weekly 5 --keep-monthly 12
Nice=10
IOSchedulingClass=best-effort
IOSchedulingPriority=7

Создадете restic-vault.timer покрај неа:

[Unit]
Description=Nightly vault backup

[Timer]
OnCalendar=*-*-* 03:15:00
RandomizedDelaySec=20m
Persistent=true

[Install]
WantedBy=timers.target

Извршете sudo systemctl daemon-reload и sudo systemctl enable --now restic-vault.timer. Нискиот I/O приоритет спречува резервните копии да доминираат над застарен диск. Извршете restic prune одделно во период за одржување, бидејќи компактирањето на складиштето може да биде скапо.

Резервната копија не е докажана сè додека не се обнови. Периодично користете restic restore latest --target со нова привремена папка на машина што има доволно простор, споредете ги важните датотеки и потоа отстранете ја тест-копијата.

Додајте видливи проверки на здравјето

Надзорот треба да разликува заклучен vault од мртов сервер. Создадете /usr/local/sbin/vault-health:

#!/bin/sh
set -u
failed=0

for unit in wg-quick@wg0 ssh nftables; do
    systemctl is-active --quiet "$unit" || {
        logger -p daemon.err -t vault-health "$unit is not active"
        failed=1
    }
done

if mountpoint -q /srv/vault; then
    usage=$(df -P /srv/vault | awk 'NR == 2 {gsub("%","",$5); print $5}')
    if [ "$usage" -ge 85 ]; then
        logger -p daemon.warning -t vault-health \
          "vault filesystem is ${usage}% full"
        failed=1
    fi
else
    logger -p daemon.warning -t vault-health "vault is locked or unmounted"
    failed=1
fi

exit "$failed"

Направете ја извршна и дефинирајте oneshot услуга што ја извршува на секои пет минути:

[Unit]
Description=Check hardened server health

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/vault-health

Соодветниот тајмер користи OnBootSec=5m, OnUnitActiveSec=5m и WantedBy=timers.target. Откако ќе го овозможите, проверете ги резултатите со journalctl -t vault-health и systemctl list-timers. Исто така, закажете smartctl -H за вистинскиот физички диск откриен со lsblk; никогаш не претпоставувајте дека е /dev/sda.

Подгответе се за прекини на струја и термички дефекти

Во фирмверот, овозможете „restore after AC loss“ ако е достапно. Батеријата на лаптопот служи како мал UPS, но надуена, прегреана или ненадежна батерија е опасност, а не отпорност. Проверувајте го ладењето, одржувајте ги отворите чисти и следете ја температурата на складиштето и SMART историјата.

Создадете /etc/systemd/logind.conf.d/server.conf:

[Login]
HandleLidSwitch=ignore
HandleLidSwitchExternalPower=ignore
HandleLidSwitchDocked=ignore

Применете го со sudo systemctl restart systemd-logind. На овој посветен сервер, спречете случајно суспендирање со sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target. Ова може да се врати со systemctl unmask.

Вообичаени патеки на неуспех

  • WireGuard воспоставува ракувања, но SSH не успева: потврдете дека клиентот ја рутира 10.44.0.1/32, SSH слуша на таа адреса и nftables ги гледа пакетите на wg0.
  • WireGuard никогаш не воспоставува ракување: проверете го пренасочувањето на рутерот, јавниот DNS, името на физичкиот интерфејс, системското време и разменетите јавни клучеви.
  • Vault се отвора, но не се монтира: проверете ги cryptsetup status vault, journalctl -k и fsck.ext4 -n /dev/mapper/vault. Опцијата -n врши проверка само за читање.
  • Restic работи интерактивно, но не и од systemd: проверете го SSH клучот на root, прицврстениот клуч на домаќинот, дозволите на датотеката со околински променливи, DNS и journalctl -u restic-vault.service.
  • Датотеки се појавуваат додека vault е заклучен: услуга запишувала во основната папка на точката за монтирање. Запрете ја, безбедно преместете ги тие датотеки и додајте RequiresMountsFor=/srv/vault.

Конечна проверка

  1. Потврдете дека WireGuard и SSH само со клуч работат надвор од домашната LAN мрежа.
  2. Проверете дека LAN врските до TCP 2222 и други непобарани порти се одбиени.
  3. Рестартирајте во планиран период за одржување и потврдете дека далечинската администрација се враќа додека vault останува заклучен.
  4. Отклучете го vault, стартувајте ги зависните услуги и потврдете ги сопственоста и опциите за монтирање.
  5. Направете резервна копија, прикажете ја нејзината снимка и завршете тестно обновување.
  6. Прегледајте ги дневниците за здравје, резервни копии, SSH, WireGuard, јадрото и nftables.
  7. Запишете ги постапките за опоравување на LUKS и Restic некаде што не зависи од овој лаптоп.

Најсилниот дел од оваа поставеност не е ниту еден поединечен пакет. Тоа е раздвојувањето на одговорностите: WireGuard изложува една тесна врата, SSH ги автентицира администраторите, LUKS ги штити податоците во мирување, Restic ги штити независните копии, systemd ги прави неуспесите видливи, а нешифрираниот основен систем го обновува пристапот по прекин. Така стариот лаптоп престанува да биде паметен експеримент и почнува да се однесува како инфраструктура.

Портрет на автор на блогот

Mihajlo

Јас сум Михајло - развивач поттикнат од љубопитност, дисциплина и постојаната желба да создадам нешто значајно. Споделувам увиди, упатства и бесплатни услуги за да им помогнам на другите да ја поедностават својата работа и да растат во постојано развивачкиот свет на софтверот и вештачката интелигенција.