LinuxSkill - Сводки с прода и Шпаргалки
10.7K subscribers
68 photos
102 videos
12 files
531 links
Следим за новостями Linux, DevOps и ИБ, чтобы быть готовым к любым факапам.
Бонусом — плотные шпаргалки и чеклисты для ежедневной работы в терминале.

📩 По всем вопросам: @chorapov

Зеркало в MAX: https://max.ru/LinuxSkill

РКН https://vk.cc/cMUwm4
Download Telegram
Посмотреть, какие интерфейсы подняты, и не принять погасший порт за живой

Краткий статус интерфейсов


ip -4 -br address show up


Нюанс: up фильтрует по состоянию линка, а не по наличию адреса. Погасил eth0 — с ключом он пропал из вывода совсем, без ключа виден как DOWN со всеми адресами на месте. Пустая строка тут не значит «адреса нет».

Второй адрес без алиасов вида eth0:1


ip address add 10.0.0.50/24 dev eth0
ip address del 10.0.0.50/24 dev eth0


Второй адрес встаёт рядом с первым, при удалении линк не дёргается.

Узнать, куда реально пойдёт пакет


ip route get 8.8.8.8
# 8.8.8.8 via 192.0.2.1 dev eth0 src 192.0.2.2


Не читает таблицу, а спрашивает у ядра готовое решение вместе с исходящим адресом. Для локального ответит local 192.0.2.2 dev lo.

Увидеть все таблицы маршрутизации


ip route show table all


Обычный show дал одну строку, table all — шесть, включая local с broadcast и host-маршрутами. С VPN и контейнерами разница уходит в десятки строк.

Посмотреть, кто есть в сети рядом


ip -4 neigh show
ip -6 neigh show


Нюанс: ip neigh — не ARP-таблица, как пишут в шпаргалках, а таблица соседей: ARP плюс IPv6 NDP. Без ключа -4 или -6 получишь обе вперемешку. arp -n показывал только первую, отсюда и путаница.

Сбросить кэш соседей


ip -s -s neigh flush dev eth0


Нюанс: без -s -s команда молчит и отдаёт код 0 — не отличишь «очистил десять записей» от «там было пусто». С ключом печатает удалённые записи и итог *** Round 1, deleting 1 entries ***.

Дать интерфейсу второе имя без даунтайма


ip link property add dev eth0 altname eno2


altname eno2 появляется в ip link show eth0, и по новому имени интерфейс находится: ip address show dev eno2 отдаёт eth0. Есть с ядра 5.8 и iproute2 5.8, на RHEL 7 синтаксис не разберётся.

Всё, что пишет, требует CAP_NET_ADMIN — в контейнере без --cap-add=NET_ADMIN упадёт.

А вы ip route get в отладке применяете или сразу лезете в show?

#Linux #iproute2 #Networking #DevOps #Debug
👍8🔥1
Закрыть системные файлы от правки и не получить молча сломанный useradd

Запретить правку файла даже руту


chattr +i /etc/passwd


Нюанс: useradd после этого выдаёт cannot open /etc/passwd и завершается с кодом 0. Пользователь не создаётся, скрипт не падает, мониторинг молчит. Снял атрибут — создался.

Разрешить логу только дозапись


chattr +a /var/log/secure


Нюанс: ротация делается переименованием, а его атрибут не пускает. Запустил logrotate на таком файле:


error: failed to rename: Operation not permitted
rc=0


Снова ноль на выходе. Файл не ротировался, cron считает, что всё прошло, логи растут до конца места.

Найти файлы с SUID и SGID


find / -xdev -perm /6000 -type f -ls 2>/dev/null


Нюанс: без -xdev поиск по корню вернул ноль файлов и код 1 — захлебнулся на /proc. С ним нашлось 16 штук. Пустой вывод легко принять за чистую систему. Старый синтаксис +6000 GNU find уже не понимает, отвечает invalid mode.

Выдать права одному пользователю


setfacl -m u:lisa:rw file
setfacl -b file


Единственное место без подвоха. После первой команды в ls -l появляется плюс: -rw-rw-r--+, после сброса исчезает — по нему и замечают ACL.

Поставить наблюдение за файлом


auditctl -w /etc/passwd -p wa -k pwd_change


Нюанс: правило живёт до перезапуска auditd. Постоянные пишутся в /etc/audit/rules.d/audit.rules.

Закрыть входящий трафик, оставшись в сессии


iptables -A INPUT -m conntrack \
--ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -P INPUT DROP


Порядок именно такой: политика последней. iptables -P INPUT DROP первой командой на удалённом сервере обрывает соединение сразу. И два уточнения: -m state до сих пор принимается, но актуален -m conntrack --ctstate, а iptables -V на 24.04 отвечает v1.8.10 (nf_tables) — правила уезжают в nftables.

У двух худших находок общее одно: команда не сработала, а код возврата ноль. Мониторингом такое не ловится.

А вы chattr +i на боевых конфигах ставите или считаете это ловушкой для самого себя?

#Linux #Security #Hardening #iptables #DevOps
👍5🔥1
Пробросить TCP через WebSocket мимо DPI и не собрать по дороге утечку сокетов

websocat — консольный клиент вебсокетов на Rust, авторства Виталия Шукелы. Соединение начинается с обычного HTTP-рукопожатия Upgrade, поэтому фильтр видит легитимный веб-трафик. Проверял на версии 1.14.0, скачанной статическим бинарником с релизов.

Пробросить локальный TCP-порт в вебсокет


websocat --binary -E \
tcp-l:127.0.0.1:8080 ws://example.com/socket


Нюанс: без -E websocat печатает предупреждение про утечку сокетов при обслуживании нескольких клиентов. У меня оно вылезало на каждом запуске туннеля, с флагом лог чистый.

Держать сессию живой на нестабильной сети


websocat -t --ping-interval 10 \
- autoreconnect:ws://example.com/socket


Нюанс: autoreconnect: требует двух аргументов. Вариант с одним, который ходит по подборкам, падает: Specify ws:// or wss:// URI to connect to a websocket. Первым аргументом идёт источник данных — - для stdin или tcp-l: для туннеля.

Проверил разрыв: поднял клиент раньше сервера, в логе Reconnecting failed, процесс жив. Сервер появился — соединение поднялось само.

Отправить одно сообщение и выйти


echo "get_metrics" | websocat -1 ws://example.com/socket


Отправляет ровно один фрейм из stdin и закрывает сессию. Удобно дёргать из скрипта. Локальный эхо-сервер вернул get_metrics и завершился с кодом 0.

Пробить туннель на тестовый сервер с самоподписанным TLS


websocat -k wss://staging.example.com/socket


Флаг -k отключает проверку сертификата. Для стенда годится, дальше стенда — нет: MITM на таком туннеле не отличить от обычной работы.

Из полезного при отладке: websocat -t ws-l:127.0.0.1:1234 mirror: поднимает локальный эхо-сервер, на котором можно проверить свою команду, не выходя наружу.

Честный минус — синтаксис. Аргументы это цепочки специферов вида overlay:addrtype:address, и с непривычки половина попыток заканчивается Invalid command-line parameters. Плюс инкапсуляция в кадры съедает скорость, а на больших объёмах приходится крутить -B вручную.

А чем вы пробиваете туннель, когда наружу открыт только 443?

#Linux #websocat #Networking #Tunneling #DevOps
👍2👀2🔥1
Если гоняешь ansible по сотне серверов, SSH каждый раз делает хендшейк заново

Переиспользовать одно TCP-соединение


# ~/.ssh/config
Host *
ControlMaster auto
ControlPath ~/.ssh/sockets/%C
ControlPersist 10m


Замерил на локальном sshd: первое подключение 0.22 секунды, второе и третье — по 0.01. Разница в двадцать раз, и это на loopback, где сети как таковой нет. На реальном канале с задержкой выигрыш будет больше.

Каталог ~/.ssh/sockets надо создать заранее, сам он не появится.

Не упереться в лимит длины пути

Нюанс: %C тут не для красоты. Классический %r@%h:%p на длинных именах хостов выходит за предел, и ssh отказывается работать:


ControlPath too long ('/root/.ssh/sockets/xxx...
-root@127.0.0.1:2222' >= 108 bytes)


Проверил на пути в 109 байт — ровно на границе. %C даёт хеш фиксированной длины и снимает вопрос совсем.

Проверить, жив ли мастер


ssh -O check user@host


Отвечает Master running (pid=924). Пригодится, когда непонятно, идёт ли новая сессия через кеш или поднимает соединение с нуля.

Сбросить залипшую сессию


ssh -O exit user@host


Печатает Exit request sent. и удаляет файл сокета. Нужно, когда на сервере поменялись ключи или конфиг, а мастер держит старую сессию.

Нюанс: если мастер-процесс умер не сам, а был убит, файл сокета остаётся сиротой. Прибил мастера через kill -9-O check стал отвечать Connection refused, но новое подключение прошло нормально: ssh увидел мёртвый сокет и поднял соединение заново.

Честный минус: ноутбук ушёл в сон с активным сокетом — при пробуждении получишь висящую сессию и таймаут вместо мгновенного входа. Лечится тем же -O exit, но сначала надо догадаться, что дело в нём.

А вы ControlPersist держите глобально на Host * или включаете точечно?

#Linux #SSH #Ansible #DevOps #Terminal
👍4🔥1
Как достать пароль из kdbx, когда графика легла и буфер обмена недоступен
Всё проверено на keepassxc-cli 2.7.6 из репозитория Ubuntu 24.04.

Посмотреть, что вообще есть в базе


keepassxc-cli ls -R database.kdbx


Нюанс: без -R увидишь только верхний уровень. Вложенные записи в группах не покажет — легко решить, что база пустая.

Вытащить конкретный пароль в терминал


keepassxc-cli show -a Password database.kdbx "Production/DB"


Нюанс: обычный show без ключей выводит Password: PROTECTED вместо значения. Флаг -s раскрывает все поля, -a Password отдаёт только пароль одной строкой — удобно подставлять в скрипт.

Открыть базу с файлом ключей


keepassxc-cli ls -k keyfile.key database.kdbx


Тот же -k работает во всех подкомандах. Если пароля на базе нет вообще, добавь --no-password, иначе утилита будет ждать ввода.

Найти запись, когда не помнишь путь


keepassxc-cli search database.kdbx "DB"


Вернёт полный путь вида /Production/DB, который дальше подставляется в show.

Забрать всю базу разом


keepassxc-cli export -f csv database.kdbx


Отдаёт в stdout все записи вместе с паролями открытым текстом. Полезно при переезде, но перенаправлять это в файл на общей машине — плохая идея.

Про clip, который советуют для копирования пароля в буфер. Именно в сценарии «GUI лёг» он и не работает: без графической сессии команда отвечает All clipping programs failed. Tried xclip. Смысл в нём есть только в живой графике, где он же и чистит буфер через 10 секунд.

И про совет закрыть GUI перед работой в консоли. Проверил: при открытой базе KeePassXC создаёт рядом файл .kdbx.lock. Утилита о нём знает, так что «гарантированного повреждения» не будет — но менять базу из двух мест одновременно всё равно не стоит, последняя запись затрёт чужие правки.

А вы держите пароли в локальных kdbx или переехали на self-hosted Vaultwarden?

#Linux #KeePass #Security #CLI #DevOps
👍2
Диски гостей раздулись, а внутри места полно. Вернуть его хосту — и не просадить запись

Проверить, поддерживает ли диск discard


lsblk --discard


Нюанс: в подборках советуют hdparm -I /dev/sda | grep -i trim. На virtio-диске это не сработает вовсе — у меня вернуло Operation not permitted, потому что hdparm говорит по протоколу ATA, которого у виртуального диска нет. lsblk --discard показывает нужное для любого типа:


NAME DISC-GRAN DISC-MAX
vda 4K 1G
vdb 0B 0B


Ненулевые DISC-GRAN и DISC-MAX означают, что discard проходит. Нули — гипервизор его не отдаёт, дальше можно не настраивать.

Отдать блоки хосту прямо сейчас


fstrim -av --dry-run
fstrim -av


Сначала --dry-run: он делает всё то же самое, но без самого discard. У меня показал 0 B (dry run) trimmed on /dev/vda, а боевой запуск вернул 243.1 GiB trimmed.

Настроить регулярный TRIM


systemctl enable --now fstrim.timer
systemctl list-timers fstrim.timer


Нюанс: свой скрипт в /etc/cron.weekly писать не нужно — в пакете util-linux уже лежит готовый fstrim.timer с OnCalendar=weekly и разбросом запуска до 100 минут, чтобы виртуалки не пошли в discard одновременно.

Если всё-таки делаешь через cron, помни про две вещи. Скрипт без строки #!/bin/sh не выполнится: run-parts: failed to exec: Exec format error. И файл с точкой в имени, вроде fstrim.sh, run-parts молча пропустит.

Не включать онлайн-TRIM в fstab


UUID=xxxx / ext4 defaults,discard 0 1


Опция discard при монтировании шлёт запрос на очистку при удалении каждого файла. Пакетный TRIM раз в неделю делает то же самое, но одним заходом и в спокойное время.

Всё это работает, только если discard включён в настройках диска на самом гипервизоре. Иначе гость честно шлёт команды, а хост их игнорирует и продолжает копить мусор.

А вы fstrim по таймеру гоняете или руками, когда место кончилось?

#Linux #Virtualization #Proxmox #fstrim #DevOps
🔥2
Сервис упал ночью, до утра гигабайт логов. Порядок, в котором в них лезть

Начать с ошибок текущей загрузки


journalctl -p err -b


-b отсекает всё, что было до последней перезагрузки, -p err оставляет уровень Error и выше. Цифровой вариант -p 3 делает то же самое, но словом читается лучше.

Сузить окно до времени инцидента


journalctl --since "2026-08-13 23:00:00" \
--until "2026-08-14 01:00:00"


Нюанс: форматы вроде yesterday 23:00:00, которые кочуют по подборкам, systemd не разбирает — получишь Failed to parse timestamp. Проверил на systemd 255: отдельно yesterday работает, -2h работает, 23:00 работает, а вот их комбинация — нет. Надёжнее всегда писать полную дату.

Посмотреть, не прибило ли сервис ядро


dmesg -T --level=err,warn
dmesg -T | grep -i oom-killer


-T переводит секунды аптайма в нормальную дату. Фильтр по уровню полезнее грепа: покажет и OOM, и ошибки диска, и отвалившийся сетевой интерфейс.

Проверить блокировки SELinux


ausearch -m avc -ts recent


Нюанс: на Debian и Ubuntu команда чаще всего вернёт пустоту — там AppArmor, а не SELinux, и /sys/fs/selinux просто нет. Шаг актуален для RHEL-семейства; на Debian смотри journalctl -t audit и dmesg | grep -i apparmor.

Найти, кто сканирует сайт


awk -F'"' '{split($3,a," ");
if (a[1]==404) print $1}' access.log |
awk '{print $1}' | sort | uniq -c | sort -rn


Нюанс: ходовой вариант awk '$9 == 404' разваливается, если в URL попал пробел — поле уезжает, и строка молча не считается. У меня из трёх запросов с 404 такой вариант нашёл два. Разбор по кавычкам берёт код ответа там, где он реально лежит.

Для пары серверов этого хватает. Когда машин десятки, CLI перестаёт работать и нужен Loki или ELK — но и там первый вопрос будет тот же: какое окно и какой приоритет.

А с чего начинаете вы, когда прод упал и надо быстро локализовать причину?

#Linux #Logs #journalctl #Troubleshooting #DevOps
👍5🔥1
Прокинуть скрипт и каталог на сервер и не собрать по дороге чужие абсолютные пути
Всё проверено на OpenSSH 9.6p1, подключением к живому sshd.

Увидеть, какие параметры реально применились


ssh -G user@host


Отдаёт итоговый конфиг после разбора всех Host и Match: порт, пользователя, список шифров, таймауты. Быстрее, чем перечитывать ~/.ssh/config глазами и гадать, какая секция сработала. Если сессия висит — ssh -vvv покажет, на каком этапе.

Выполнить локальный скрипт на сервере


ssh user@host bash -s arg1 arg2 < ./script.sh


Нюанс: -s обязателен, если передаёшь аргументы. Без него bash примет arg1 за имя файла и ответит No such file or directory. И второе: интерактивный read внутри такого скрипта работать не будет — stdin уже занят самим скриптом.

Убрать устаревший ключ хоста


ssh-keygen -f ~/.ssh/known_hosts -R '[10.0.0.1]:2222'


Нюанс: для нестандартного порта нужен формат [host]:port в кавычках. Просто -R 10.0.0.1 строку не найдёт и молча ничего не сделает. Старый файл сохраняется рядом как known_hosts.old.

Забрать каталог без промежуточных файлов


ssh user@host "tar -cf - -C /data ." | tar -xC ~/bak/


Нюанс: -C на удалённой стороне обязателен. Вариант tar -cf - /data утащит в архив весь абсолютный путь, и локально ты получишь ~/bak/data/... вместо содержимого. Проверил — распаковалось именно так.

Уйти в фон сразу после авторизации


ssh -f user@host "sleep 300"


Управление вернулось через 181 мс, при этом клиентский процесс продолжает висеть, пока команда не отработает. Удобно для проброса портов: ssh -f -N -L 9998:localhost:15672 user@host.

Держать ключ в агенте ограниченное время


ssh-add -t 30 ~/.ssh/id_ed25519


Через 30 секунд ключ уйдёт из памяти агента сам. Нюанс: без запущенного ssh-agent команда просто скажет Could not open a connection to your authentication agent.

Про sshpass из подборок: он кладёт пароль в аргументы процесса, где его видно в ps любому пользователю системы. Для закрытого стенда — ладно, дальше стенда лучше ProxyJump и ключи.

А чем пробрасываете доступ к внутренним панелям — -L руками или прописываете в конфиг?

#Linux #SSH #Networking #DevOps #Terminal
👍5
🎥 Вебинар: «LVM без простоя: расширение тома, перенос данных и аварийный откат через snapshot»

На открытом уроке разберем, как использовать возможности LVM при работе с хранилищем в production-среде. Рассмотрим расширение логического тома, перенос данных на другое блочное устройство и применение snapshot для возврата к предыдущему состоянию системы.

О чем поговорим:
— Как устроен LVM и какие задачи он помогает решать
— Как расширять логические тома при увеличении объема данных
— Как перенести данные на другое блочное устройство
— Что такое snapshot и как он работает
— Как использовать snapshot для отката при возникновении проблем

🧠 Вебинар приурочен к старту курса «Администратор Linux. Продвинутый уровень». Программа постоянно обновляется с учётом современных требований рынка. Занятия проводят практикующие эксперты, которые ежедневно работают с производственной инфраструктурой. Вы изучите востребованные инструменты: Zabbix, Prometheus, Docker, Nginx, PostgreSQL, ELK, Ansible, SELinux, Bash и многие другие.

👉 Для участия зарегистрируйтесь https://otus.pw/T9OrR/

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
👍5👎1
Обойти массив путей с пробелами и не получить вместо одной папки три несуществующих.

Перебрать элементы, не разорвав их по пробелам


folders=("/var/log/nginx" "/var/log/app with space")
for d in "${folders[@]}"; do
ls -ld "$d"
done


Кавычки вокруг ${folders[@]} обязательны. Без них тот же цикл на моём тесте выдал четыре итерации вместо двух: путь распался на /var/log/app, with и space. И не путай @ с *: под кавычками "${folders[*]}" склеивает весь массив в одну строку.

Посчитать элементы


echo "${#folders[@]}"


Нюанс: ${#folders} без [@] — это не размер массива, а длина первого элемента. У меня вернуло 8 вместо 3, и никакой ошибки.

Обойти разреженный массив


for i in "${!sparse[@]}"; do
echo "$i = ${sparse[$i]}"
done


Нюанс: если удалить элемент через unset, индексы останутся с дырками. Массив с индексами 0, 5, 9 имеет размер 3 — обход по seq 0 2 найдёт один элемент из трёх. Перебирать надо индексы через ${!arr[@]}, а не числа от нуля.

Прочитать файл в массив


readarray -t lines < /var/log/app.log
readarray -t lines < <(grep -v '^$' /var/log/app.log)


Нюанс: cat file | readarray -t lines не работает. Пайп запускает readarray в подоболочке, массив заполняется там и умирает вместе с ней. У меня получилось 0 элементов вместо 4, снова без ошибки. Нужен либо редирект, либо подстановка процесса < <(...).

Сделать словарь


declare -A ports=([nginx]=80 [php-fpm]=9000)


Нюанс: declare -A не формальность. Без него bash создаёт обычный индексный массив, все строковые ключи считаются нулём, и каждое присваивание перетирает предыдущее. Проверил: ${ports[nginx]} вернуло 9000 — значение от php-fpm.

Общее у всех пяти: bash не ругается, а тихо делает не то. Поэтому shellcheck на скриптах с массивами экономит больше времени, чем кажется.

А вы конфиги в bash разбираете ассоциативными массивами или сразу отдаёте jq?

#Linux #Bash #Shell #Scripting #DevOps
👍2
Выкинуть из скрипта форки awk и cut и не нарваться на подстановку, которая молчит

Разобрать путь без basename и dirname


path="/var/log/nginx/access.log.tar.gz"
name="${path##*/}" # access.log.tar.gz
dir="${path%/*}" # /var/log/nginx


Замерил тысячу итераций в цикле: basename — 1107 мс, подстановка — 5 мс. Разница в двести раз, и это не про скорость самой утилиты, а про форк процесса на каждый вызов.

Собрать файлы в массив вместо ls


shopt -s nullglob
files=(/var/log/nginx/*.log)
cp -- "${files[@]}" /backup/logs/


Нюанс: без nullglob массив по несуществующей маске не пустой. Проверил — в нём оказался один элемент, сама строка /var/log/nginx/*.nosuch, и cp уедет с несуществующим файлом. shopt -s nullglob заставляет пустой glob разворачиваться в ноль элементов.

Сравнить вывод двух команд без временных файлов


diff <(ls -1 dir1) <(ls -1 dir2)


<(...) подставляет путь вида /dev/fd/63, за которым стоит обычный pipe — проверил через ls -l. Нюанс: код возврата команды внутри скобок теряется, diff его не увидит. И это только bash: в dash тот же синтаксис даёт Syntax error, так что для #!/bin/sh не годится.

Задать дефолт и проверить обязательные переменные


: "${TIMEOUT:=30}"
: "${DB_USER:?не задана}"


Нюанс: двоеточие в :? обязательно. Вариант ${DB_USER?...} из подборок срабатывает только когда переменная не объявлена вовсе — пустую строку он пропускает, и скрипт идёт дальше с пустым логином. С :? тот же случай падает с кодом 127. То же и с :-: он подставляет дефолт, но не присваивает, переменная остаётся пустой.

Собрать тайминги шагов скрипта


PS4='+ ${EPOCHREALTIME} '
set -x


Нюанс: в подборках сюда пишут PS4='+ $(date "+%s.%N") => ' — и это форк date на каждую строку трассировки, в посте про избавление от форков. Встроенная EPOCHREALTIME даёт то же время с микросекундами и без единого процесса.

А что вы чаще выносите из скриптов — cut и awk или всё-таки оставляете, потому что читается понятнее?

#Linux #Bash #Shell #Scripting #DevOps
👍3🔥1
Найти на сервере скрытых рутов и не поверить проверке, которая их не видит.

Найти лишние учётки с нулевым UID


getent passwd | awk -F: '($3 == 0) {print $1}'


Нюанс: в подборках пишут awk -F: '($3 == "0")' — со строковым сравнением. Оно пропускает UID, записанный как 00 или 0000. Проверил: завёл пользователя с -u 00, id показал uid=0(root), то есть для ядра это полноценный рут, а строковая проверка его не увидела. Без кавычек awk сравнивает числа и ловит все варианты.

getent вместо cat /etc/passwd нужен, чтобы захватить пользователей из LDAP и SSSD.

Убедиться, что root не пускают по SSH


sshd -T | grep -i permitrootlogin


Нюанс, и он главный. grep по /etc/ssh/sshd_config показывает то, что написано, а не то, что действует. Собрал стенд: в основном конфиге PermitRootLogin no, а в /etc/ssh/sshd_config.d/99-cloud.confyes. Строка Include стоит выше, drop-in побеждает:


grep -> PermitRootLogin no
sshd -T -> permitrootlogin yes


Именно так выглядит типовой облачный образ. sshd -T печатает итоговую конфигурацию после всех включений.

Проверить sudoers перед сохранением


visudo -c -f /etc/sudoers.d/devops


visudo без аргументов знают все, а вот -c -f работает с любым файлом и годится для CI или проверки после Ansible. На кривом правиле показывает строку и место ошибки, на нормальном — parsed OK. Заодно sudo -l покажет, что реально разрешено текущему пользователю.

Найти SUID-бинарники


find / -xdev -perm /6000 -type f -ls 2>/dev/null


Нюанс: -perm -4000 -user root из чек-листов пропускает SGID. На моей машине разница 9 файлов против 12 — мимо проверки прошли chage, expiry, ssh-agent. Фильтр -user root тоже лишний: чужой SUID опаснее рутового, а он под этот фильтр не попадёт. И -xdev обязателен, иначе find захлебнётся на /proc.

Про sudo -i вместо su спорить не буду, но помнить стоит другое: жёсткие правила в sudoers обходятся через less, find, awk и десяток других утилит — у всех есть побег в шелл. Разрешать по одной команде безопаснее, чем кажется, только если это не интерпретатор.

А вы root на серверах отключаете совсем или держите для аварийной консоли?

#Linux #Security #SSH #sudo #DevOps
👍3
🎥 Вебинар: Где Linux хранит настройки и логи: разбираем файловую структуру на практике.

На открытом уроке разберем структуру каталогов Linux и узнаем, где искать конфигурационные файлы, системные журналы и другие важные данные. Рассмотрим назначение основных директорий и вспомним, как права доступа влияют на работу с файлами.
Данный открытый урок проходит в рамках курса «Администратор Linux. Базовый уровень».

О чем поговорим:
— Как устроена файловая структура Linux
— Для чего предназначены основные системные каталоги
— Что такое конфигурационный файл и где обычно хранятся настройки сервисов
— Где Linux хранит системные логи и как найти нужный журнал
— Как права доступа влияют на чтение и изменение файлов

🧠 Вебинар приурочен к старту курса «Администратор Linux. Базовый уровень». Вы освоите Bash, TCP/IP, Nginx, Apache, MySQL, Docker, Git, Prometheus, Grafana и ELK. На живых занятиях с практикующими экспертами научитесь настраивать веб-серверы, работать с сетью, контейнерами, мониторингом и фильтрацией трафика.

👉 Для участия зарегистрируйтесь https://otus.pw/e3sf/

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
👎1
Смонтировать сетевую шару и не подвесить процессы, когда сервер отвалится.

Убрать пароль из fstab


mount -t cifs -o credentials=/etc/cifs-creds \
//10.0.0.10/share /mnt/samba


Файл /etc/cifs-creds из трёх строк: username=, password=, domain=. Нюанс: chmod 600 на нём — целиком на вашей совести, mount права не проверяет и с файлом 644 отработает молча. Заодно проверьте, что каталог с ним не уезжает в бэкап открытым текстом.

Отцепить зависшую шару


umount -l /mnt/nfs


Проверил на tmpfs: после -l каталог пуст и монтирования в mount больше нет, но процесс, державший файл открытым, спокойно дочитал его по старому дескриптору. Нюанс: -l убирает точку из дерева, а не освобождает ресурсы — пока живы процессы, ФС остаётся. Ищите их через lsof +D до того, как отцепите, иначе искать будет негде.

-f имеет смысл только для NFS и только вместе с недоступным сервером, для cifs он почти ничего не даёт.

Посмотреть, что отдаёт сервер


showmount -e 10.0.0.10


Нюанс: showmount говорит по протоколу MOUNT, которого в NFSv4 нет вообще. На сервере с отключёнными v2 и v3 получите clnt_create: RPC: Program not registered — и это не значит, что сервер мёртв. Для v4 просто монтируйте корень экспорта: mount -t nfs4 10.0.0.10:/ /mnt.

Монтировать по требованию, а не при загрузке


//10.0.0.10/share /mnt/samba cifs
noauto,x-systemd.automount,_netdev,
credentials=/etc/creds 0 0


Нюанс: _netdev нужен наравне с x-systemd.automount. Без него systemd не знает, что монтирование сетевое, и может дёрнуть его до поднятия интерфейсов. Плюс x-systemd.idle-timeout= отцепит шару после простоя — на нестабильном канале это лучше, чем висящая точка.

Не залипнуть на медленном NFS


mount -t nfs -o soft,timeo=50,retrans=2 \
10.0.0.10:/data /mnt/nfs


timeo в децисекундах, так что 50 — это 5 секунд. По умолчанию для TCP стоит 600, то есть минута, да ещё с линейным ростом после каждой переотправки.

Нюанс: man про soft пишет прямо — silent data corruption. Приложение получит I/O error, и если оно его не обработает, запись потеряется тихо. Для баз и любой записи оставляйте hard. И не тащите из старых шпаргалок intr — опция игнорируется с ядра 2.6.25.

А вы сетевые шары монтируете через fstab или отдаёте systemd с automount?

#Linux #NFS #Samba #systemd #DevOps
👍4
Не оставить пароль в bash_history и не удивиться, что он всё равно там оказался.

Скрыть команду от истории


mysql -u root -p'super_secret'


Ведущий пробел, и строка не попадёт в ~/.bash_history. Работает, если в HISTCONTROL есть ignorespace. Нюанс: в Ubuntu это уже настроено, но по-разному. В /etc/skel/.bashrc стоит ignoreboth, а в root-сессии у меня было ignoredups:ignorespace. Проверьте своё:


echo "$HISTCONTROL"


Если пусто — трюк не сработает вообще, а вы будете уверены в обратном.

Исправить опечатку в предыдущей команде


systemctl status nginx-confg
^confg^config


Заменяет и сразу выполняет. Нюанс: только первое вхождение. Проверил на echo aaa bbb aaa — после ^aaa^XXX получилось XXX bbb aaa. Для всех вхождений другая конструкция:


!!:gs/aaa/XXX/


Открыть длинную команду в редакторе


fc


Вытаскивает последнюю команду в $EDITOR, после сохранения bash её выполняет. Нюанс: порядок поиска редактора — FCEDIT, потом EDITOR, и только потом vi по умолчанию. На голом сервере без vi получите bash: vi: command not found и никакого редактирования. Заранее пропишите export FCEDIT=nano или что вам ближе.

Оживить терминал после вывода бинарника


reset


clear только прокручивает экран, а reset переинициализирует терминал целиком. Если и это не помогает — stty sane возвращает настройки ввода, когда не видно набираемых символов.

Отвязать процесс от закрывающейся сессии


bg
disown -h %1


Нюанс: -h и без него — разные вещи. С -h задача остаётся в jobs, но не получит SIGHUP при закрытии терминала. Без флага задача исчезает из таблицы совсем. Проверил оба варианта, разница именно в этом.

И про главное ограничение трюка с пробелом: он прячет команду от файла истории, но не от системы. Пока процесс жив, его аргументы видны в ps -eo args любому пользователю. Пароль в командной строке остаётся паролем в командной строке — читайте его из файла или переменной окружения.

А чем вы правите длинные пайплайны — fc или сразу пишете в файл?

#Linux #Bash #Terminal #Security #DevOps
👍2