Debian 13: Хаос із правами після rsync — чистий спосіб зберегти власника

Було корисно?

Ви запустили rsync. Він завершився. Ви на мить відчули себе всемогутнім. Потім почали падати сервіси, тому що половина файлів тепер належить не тому користувачу,
мають неправильні права або втратили свої ACL. Нова машина з Debian 13 виглядає нормально, поки ви не спробуєте запустити PostgreSQL, перезавантажити nginx або дозволити додатку
записати власний кеш.

Хаос з правами після rsync рідко буває «rsync поводиться дивно». Майже завжди ми дали йому неправильні інструкції, копіювали через межу, де змінюється
ідентичність (UID/GID mapping), або копіювали на файлову систему, яка не може відобразити те, що ви намагаєтесь зберегти. Ця стаття — чистий підхід до збереження
власності на Debian 13 — що робити, чого уникати і як довести, що ви зробили все правильно.

Ментальна модель: що насправді означає «власник»

У Debian (і в Linux загалом) файл не «належить» імені користувача. Він належить числовому ідентифікатору користувача та групи. Імена — це лише мітки в
/etc/passwd та /etc/group (або LDAP/SSSD), які перекладаються під час відображення. Якщо ви копіюєте файл, що належить UID 1001 з хоста A на хост B,
і UID 1001 — це «alice» на хості A, але «postgres» на хості B, ви саме присвоїли цей файл «postgres» на хості B. rsync зробив те, про що ви просили; ви задали неправильне
питання.

Збереження власності має три рівні:

  • Біти режиму (rwx для користувача/групи/інших плюс setuid/setgid/sticky): зберігаються в inode; більшість файлових систем їх підтримують.
  • Числові ID власника/групи (UID/GID): зберігаються в inode; чи можна їх встановити — залежить від привілеїв та опцій монтування.
  • Розширені права (POSIX ACL) та метадані (xattrs, наприклад мітки SELinux, capabilities, user.* теги): опціональні й залежать від файлової системи.

rsync може зберегти усе це, але тільки якщо ви скажете йому і якщо місце призначення може це відобразити. Якщо ви вкажете rsync призначення, яке «бреше» (привіт, деякі конфігурації CIFS),
або запустите його без потрібних привілеїв для встановлення власності, ви отримаєте «успіх» і зламані права. Це не парадокс; це вівторок.

Швидкий план діагностики

Коли права «виглядають неправильно» після rsync, найшвидший шлях — визначити, який рівень зламався: ID, біти чи додаткові атрибути. Не гадати. Вимірюйте.

1) Спочатку: підтвердіть, що саме не так (IDs vs modes vs ACL/xattr)

  • Якщо власник неправий по всьому дереву: підозрюйте невідповідність UID/GID, привілеї або root-squash.
  • Якщо режими неправильні (наприклад, все 755): підозрюйте umask, відсутність -p/-a або те, що місце призначення нормалізує права.
  • Якщо лише окремі додатки падають (наприклад, systemd unit-и, ssh ключі, бінарники): підозрюйте втрату xattrs/capabilities, відсутні setuid біти або втрачені ACL.

2) По-друге: перевірте транспортну межу

  • Локальний диск → локальний диск: найпростіше; rsync має зберегти майже все як root.
  • По SSH: залежить від віддаленого rsync та привілеїв; root→root працює, якщо налаштовано; інакше ви побачите мовчазні зниження.
  • NFS: root-squash може тихо зруйнувати «збереження власника», не повідомивши так, щоб ваш втомлений мозок це помітив.
  • CIFS/SMB: семантика дозволів може емулюватись; збереження може бути неможливим або відображуватись.

3) По-третє: відтворіть на одному файлі з максимальною вербозністю

Візьміть один файл з відомим власником/режимом/ACL/xattr, скопіюйте його через rsync з -vv і перевірте на обох кінцях. Ви шукаєте саме той клас метаданих,
який не перейшов.

Перефразована ідея від Gene Kim (автор з DevOps операцій): «Надійність приходить від того, що робота видима й повторювана, а не від героїчних дій о 2-й ночі».

Факти та історичний контекст (чому це повторюється)

  1. UID/GID — джерело істини. Імена користувачів — цукор для читання; rsync може зберегти ID навіть якщо ім’я не існує — якщо ви цього попросите.
  2. «Режим архівації» rsync — це набір опцій. -a — це скорочення для кількох прапорів, але не всіх, які люди собі уявляють.
  3. POSIX ACL з’явилися задовго до багатьох «сучасних» Linux зручностей. Вони були в enterprise Unix десятиліттями й перейшли в Linux як першокласні, але їх часто забувають під час міграцій.
  4. Linux capabilities зберігаються в xattrs. Якщо ви губите xattrs, бінарник з cap_net_bind_service може припинити прив’язувати порт 80 без setuid root.
  5. NFS root-squash ворожий до «збереження власника». Це фічa безпеки, яка відображає root в nobody, й часто ламає наївні схеми бекапу/відновлення.
  6. Жорсткі посилання не «копіюються», якщо ви не збережете їх. Без -H rsync може дублювати пов’язані файли, збільшуючи використання диска і змінюючи семантику для деяких системних дерев.
  7. Sticky bit і setgid каталоги важливі для спільних шляхів запису. Неправильна копія режимів у таких місцях як /tmp або спільні групові каталоги може стати проблемою безпеки, а не лише відмовою.
  8. SELinux мітки та AppArmor метадані живуть поза класичними бітом режиму. Навіть у Debian (де часто першим є AppArmor), xattrs можуть бути важливими для runtime контейнерів, snap-подібних середовищ або кастомних LSM конфігурацій.
  9. Деякі файлові системи не можуть відобразити потрібні метадані. FAT і exFAT — очевидні приклади, але CIFS монти можуть бути «Unix-подібними» або «не Unix-подібними» залежно від опцій.

Що rsync зберігає (а що ні)

Перша брехня, яку ми собі говоримо: «Я використав -a, отже все таке саме». Режим архівації чудовий, але це не «всі метадані у всесвіті». Він включає:

  • -r рекурсія
  • -l збереження симлінків
  • -p збереження прав (біти режиму)
  • -t збереження часу
  • -g збереження групи
  • -o збереження власника (вимагає root)
  • -D збереження девайсів і спеціальних файлів (вимагає root)

Що -a не включає автоматично:

  • ACL, якщо не додати -A
  • xattrs, якщо не додати -X
  • жорсткі посилання, якщо не додати -H (і так, це може бути витратно)
  • збереження числових ID при різних сервісах імен, якщо не додати --numeric-ids

Ось суть: якщо вам важлива власність — вам важлива числова ідентичність. Якщо вам важливо, щоб «додаток працював», вам важливі ACL, xattrs і іноді capabilities.

Жарт №1: rsync не «втрачає» права. Він виконує інструкції з впевненістю стажера, який ніколи не ставить уточнюючих питань.

Чисті командні рядки для міграцій Debian 13

Ось опініоновані значення за замовчуванням, що добре себе поводять у реальних міграціях. Налаштовуйте свідомо. Якщо ви не можете пояснити, чому прибрали прапорець — залиште його.

Копіювання локально (той же хост, різні диски)

Якщо копіюєте в межах одного хоста (або в змонтовану файлову систему, де у вас реальні root-привілеї), це чиста базова команда:

cr0x@server:~$ sudo rsync -aHAX --numeric-ids --info=stats2,progress2 /src/ /dst/
...output...

Чому цей набір:

  • -a: зберігає базові метадані
  • -H: зберігає жорсткі посилання (корисно для деяких системних дерев, шарів контейнерів, кешів пакетів)
  • -A: зберігає ACL
  • -X: зберігає xattrs (capabilities, мітки, кастомні метадані)
  • --numeric-ids: зберігає UID/GID числа, а не імена (критично при переході між хостами)

По SSH, root → root (бажано для повної точності міграцій)

cr0x@server:~$ sudo rsync -aHAX --numeric-ids --info=stats2,progress2 -e "ssh -o BatchMode=yes" /src/ root@newhost:/dst/
...output...

Якщо root SSH заборонений (поширено і не завжди погано), використайте обліковий запис автоматизації плюс sudo на пункті призначення і запустіть rsync у серверному режимі. Це
ускладнює налаштування. Для більшості команд краще: копіюйте як root по SSH з дозволеної мережі керування, а потім закрийте доступ.

Коли ви не root (але хочете розумні результати)

Якщо ви неповноважений, ви не можете встановлювати довільних власників. rsync збереже те, що може. Не прикидайтеся, що це вірна міграція; розглядайте це як копію даних,
де власність треба буде переназначити після.

cr0x@server:~$ rsync -aAX --info=stats2,progress2 /src/ user@newhost:/dst/
...output...

Примітка: -o і -g всередині -a не вдасться у бажаному вигляді без привілеїв. rsync все одно виконається. Просто дива не відбудеться.

Коли місце призначення — NFS (відповідально ставтесь до root-squash)

Якщо NFS експортується з root-squash (часто за замовчуванням), root на клієнті не може встановити власника. У вас є три чисті опції:

  • Тимчасово експортуйте з no_root_squash з обмеженого хоста на час міграції (переглянуто з міркувань безпеки, обмежено в часі).
  • Міграція на локальний диск на сервері призначення, а потім перемістіть дані вже на сервері (зберігаючи власність локально).
  • Прийміть, що ви не можете зберегти власність і заплануйте контрольоване chown/chgrp/повторне застосування ACL.

Практичні завдання: команди, виводи, рішення

Ви не виправите права, пильно глянувши на ls -l і надіючись. Ви виправляєте права, ставлячи системі питання й дозволяючи відповідям визначити ваш наступний крок. Ось практичні завдання, які я реально виконую під час міграцій і реакцій на інциденти.

Завдання 1: Підтвердіть версію rsync і скомпільовані можливості (підтримка ACL/xattr)

cr0x@server:~$ rsync --version
rsync  version 3.2.7  protocol version 32
Capabilities:
    64-bit files, 64-bit inums, 64-bit timestamps, ACLs, xattrs, iconv, symtimes
...output...

Що це означає: Шукайте ACLs і xattrs у переліку можливостей. Якщо їх немає, прапори як -A і -X не зроблять того, що ви очікуєте.

Рішення: Якщо ACL/xattrs не підтримуються, оновіть rsync або змініть метод (tar з xattrs, реплікація знімків файлової системи тощо).

Завдання 2: Перевірте повні метадані відомого проблемного файлу (режим, UID/GID, ACL)

cr0x@server:~$ sudo stat -c '%n mode=%a uid=%u(%U) gid=%g(%G)' /dst/app/config.yml
/dst/app/config.yml mode=640 uid=1001(alice) gid=1001(alice)

Що це означає: Числові ID — це істина; імена в дужках — локальна інтерпретація. Якщо UID «правильний», але ім’я «неправильне», у вас проблема з відображенням, а не з копіюванням.

Рішення: Якщо UID/GID відрізняються від очікувань джерела, зупиніться і виправте відображення ідентичностей перед подальшим копіюванням.

Завдання 3: Перевірте наявність ACL і порівняйте очікуваний доступ

cr0x@server:~$ sudo getfacl -p /dst/app
# file: /dst/app
# owner: 1001
# group: 1001
user::rwx
group::r-x
group:33:r-x
mask::r-x
other::---

Що це означає: Каталог надає читання/виконання групі 33 (часто www-data). Якщо цей ACL зник, ваш веб-сервіс не зможе читати дерево додатку, хоча біти режиму «виглядають нормально».

Рішення: Якщо ACL відсутні там, де ви очікуєте, треба перезапустити rsync з -A і впевнитися, що файлова система призначення підтримує ACL і вони увімкнені.

Завдання 4: Перевірте xattrs на файлі, який може містити capabilities або мітки

cr0x@server:~$ sudo getfattr -d -m- /dst/usr/local/bin/myhelper
# file: /dst/usr/local/bin/myhelper
security.capability=0sAQAAAgAgAAAAAAAAAAAAAAAAAAA=

Що це означає: Бінарник має Linux capabilities, збережені в xattr. Втрата цього означає загадкове «permission denied» при привілейованих операціях без змін власника.

Рішення: Якщо xattrs відсутні, перекопіюйте з -X. Якщо файлова система призначення не може зберігати xattrs, потрібна інша ціль.

Завдання 5: Перевірте, що rsync дійсно запущений як root на обох кінцях

cr0x@server:~$ sudo rsync -a --rsync-path="id && rsync" /src/ root@newhost:/dst/ 2>/dev/null | head
uid=0(root) gid=0(root) groups=0(root)

Що це означає: Віддалена сторона вивела свою ідентичність перед запуском rsync. Якщо ви бачите не-root UID, збереження власника буде обмеженим.

Рішення: Якщо віддалений не root — виправте підхід SSH/sudo або прийміть стратегію post-copy chown.

Завдання 6: Виявити невідповідність UID/GID між хостами для конкретного сервісного облікового запису

cr0x@server:~$ getent passwd www-data
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
cr0x@server:~$ ssh root@newhost getent passwd www-data
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin

Що це означає: Добре: узгоджені UID/GID для www-data. Але не зупиняйтеся на цьому; користувачі вашого додатку зазвичай кастомні, а не Debian-за замовчуванням.

Рішення: Якщо ID не співпадають — вирівняйте їх (бажано перед копіюванням) або використайте --numeric-ids і виправте службу імен пізніше.

Завдання 7: Інвентаризація «незнайомих» числових власників на місці призначення

cr0x@server:~$ sudo find /dst -xdev -printf '%u %g %p\n' | awk '$1 ~ /^[0-9]+$/ || $2 ~ /^[0-9]+$/' | head
1001 1001 /dst/app
1001 1001 /dst/app/config.yml

Що це означає: Числові власники без розв’язання імен. Це не обов’язково помилка: може бути правильне числове збереження за відсутності визначень облікових записів.

Рішення: Якщо багато числових ID — вирівняйте /etc/passwd//etc/group (або LDAP/SSSD) перед тим, як запускати сервіси.

Завдання 8: Підтвердіть, що опції монтування дозволяють POSIX-права та ACL

cr0x@server:~$ mount | grep " on /dst "
/dev/sdb1 on /dst type ext4 (rw,relatime,acl)

Що це означає: ext4 змонтовано з підтримкою acl. В деяких налаштуваннях ACL увімкнені за замовчуванням; в інших — опція монтування має значення.

Рішення: Якщо не бачите acl і ACL працюють некоректно — перемонтуйте з увімкненим ACL або налаштуйте дефолти файлової системи.

Завдання 9: Виявити root-squash на NFS-монті «жорстким» методом (спробою)

cr0x@server:~$ sudo touch /dst/.rootsquash-test && sudo chown 0:0 /dst/.rootsquash-test; ls -ln /dst/.rootsquash-test
-rw-r--r-- 1 65534 65534 0 Dec 29 12:00 /dst/.rootsquash-test

Що це означає: UID/GID стали 65534 (nobody/nogroup). Класична поведінка root-squash.

Рішення: Перестаньте намагатися зберегти власника на цьому монті. Змініть політику експорту тимчасово або копіюйте сервер-сайду.

Завдання 10: Dry-run rsync з поелементними змінами, щоб побачити, які метадані будуть змінені

cr0x@server:~$ sudo rsync -aHAX --numeric-ids -n -i /src/ /dst/ | head
.d..t...... ./
>f..tpogax  app/config.yml
>f..t...... app/static/logo.png

Що це означає: Поелементний вивід кодує зміни. У >f..tpogax літери показують, що буде оновлено: час (t),
права (p), власник (o), група (g), ACL (a), xattr (x).

Рішення: Якщо ви бачите багато o/g змін, яких не очікували, ваша власність не вирівняна; виправте перед виконанням.

Завдання 11: Підтвердіть, що дерево каталогів має setgid/sticky біт там, де треба

cr0x@server:~$ sudo find /dst/shared -maxdepth 1 -type d -printf '%m %p\n'
2775 /dst/shared
2775 /dst/shared/team-a
2770 /dst/shared/private

Що це означає: 2 у ведучому розряді вказує на setgid на каталогах (успадкування групи). Якщо вони змінилися на 0775,
нові файли можуть потрапляти в невірну групу, викликаючи довготривалі проблеми з доступом.

Рішення: Якщо setgid/sticky біти відсутні — перекопіюйте збереженням прав або явно виправте їх і проведіть повторний аудит.

Завдання 12: Перевірте, що «спеціальні файли» (пристрої, сокети) не були зіпсовані

cr0x@server:~$ sudo find /dst/dev -maxdepth 1 -type c -o -type b | head
/dst/dev/null
/dst/dev/zero
/dst/dev/random

Що це означає: Ноди девайсів існують. Якщо ви копіювали системний образ або chroot і вони стали звичайними файлами — щось сильно пішло не так (ймовірно,
відсутні root-привілеї або опущено -D).

Рішення: Для системних дерев завжди копіюйте як root з -a. Якщо пристрої неправильні — відтворіть їх або перекопіюйте правильно перед завантаженням
чи chroot.

Завдання 13: Перевірка симптому «все належить користувачу, що запускав rsync»

cr0x@server:~$ sudo find /dst -xdev -printf '%u\n' | sort | uniq -c | sort -nr | head
152340 backup
  2193 root
   812 www-data

Що це означає: Більшість файлів належить backup. Зазвичай це означає, що копія виконувалась без привілеїв або місце призначення відмовлялося від chown.

Рішення: Якщо вам потрібна точність — повторіть копію з правильними привілеями і на файловій системі, що дозволяє зміну власників. Не намагайтеся «виправити пізніше»,
якщо у вас немає детермінованого відображення.

Завдання 14: Швидко порівняйте власників джерела і призначення на вибірці

cr0x@server:~$ sudo (cd /src && find . -maxdepth 2 -type f -printf '%u:%g %m %p\n' | head) > /tmp/src.sample
cr0x@server:~$ sudo (cd /dst && find . -maxdepth 2 -type f -printf '%u:%g %m %p\n' | head) > /tmp/dst.sample
cr0x@server:~$ diff -u /tmp/src.sample /tmp/dst.sample
--- /tmp/src.sample
+++ /tmp/dst.sample
@@
-alice:alice 640 ./app/config.yml
+postgres:postgres 640 ./app/config.yml

Що це означає: Той самий режим, різна власність. Файл читається, але належить невірній ідентичності. Це або невідповідність UID, або відображення по імені.

Рішення: Використайте --numeric-ids (або вирівняйте облікові записи) і повторіть, або погодьтесь на заплановане перепризначення власності.

Невідповідність UID/GID: мовчазний убивця прав

Debian 13 не вигадував невідповідності UID/GID, але це типовий момент для її прояву, бо оновлення/міграції часто збігаються зі змінами служби імен, впровадженням контейнерів
або «ми потім почистимо користувачів». «Потім» — це як отримати відмови.

Типова помилка: на старому хості ваш app-користувач має UID 1005. На новому хості UID 1005 належить іншому сервісному обліковому запису, створеному раніше. Ви робите rsync
з «збереженням власника». Тепер секрети додатка належать якомусь сторонньому демону. Додаток не запускається, і ви ще створили випадкову витік привілеїв.

Що робити замість (опініоновано і нудно)

  • Перед копіюванням, переконайтесь, що на місці призначення сервісні облікові записи та групи мають ті самі UID/GID, що й на джерелі.
  • Використайте --numeric-ids, щоб rsync не намагався «допомогти» відображенням імен.
  • Якщо ви покладаєтесь на LDAP/SSSD, перевірте, що воно працює на місці призначення перед початком копії. Тимчасовий відступ на локальні користувачі може створити невідповідності.

Коли не можна вирівняти ID

Іноді ви успадковуєте безлад: нове середовище використовує централізовану ідентичність, а старе — ручні облікові записи. У такому випадку не робіть «збереження власності» догмою.
Розглядайте це як контрольовану трансформацію:

  • Копіюйте дані з цілісністю (контент і часові мітки) спочатку.
  • Потім застосуйте політику власності/ACL детерміновано (скрипти, маніфести або інструменти на рівні додатку).
  • Нарешті зробіть аудит прав і запустіть сервіси під наглядом.

ACL та xattrs: збереження «невидимих» прав

Біти режиму — перші 80% прав. ACL та xattrs — останні 20%, які викликають 80% відмов.

ACL: пастка «чому www-data не може прочитати?»

ACL часто використовують, щоб надати групі сервісу доступ на читання до каталогів, що належать іншому власнику, або щоб дозволити розробникам деплой без зроблення всього дерева групо-записувальним.
Якщо ви їх втрачаєте, ls -l не видасть правди. Ви можете побачити + в деяких виводах, але люди ігнорують це, як і лампочку «check engine».

Зберігайте ACL з -A. Потім перевірте з getfacl кілька відомих шляхів. При міграції серверів додатків зверніть увагу на:

  • спільні каталоги для завантажень
  • директорії деплою з мішаною власністю
  • шляхи, де сервісному користувачу потрібен доступ, але він не повинен бути власником

xattrs: capabilities, мітки і ефект «але вчора все працювало»

Розширені атрибути використовують для всього — від контекстів SELinux до користувацьких метаданих та capabilities. На Debian capabilities — найважливіші в продакшні: це чистий спосіб дозволити бінарнику прив’язувати низькі порти або робити сирі операції з мережею без запуску від root.

Зберігайте xattrs з -X. Потім перевірте відомий бінарник або файл, який повинен мати xattrs. Якщо xattrs не збереглись, симптоми можуть бути дивними:
сервіси відмовляються прив’язуватися, контейнери не запускаються або інструменти безпеки поводяться по-іншому.

Межі файлових систем: ext4 vs XFS vs ZFS vs NFS vs CIFS

rsync може зберегти лише те, що файлова система призначення може зберігати, і те, що опції монтування дозволяють встановлювати. Найпростіший шлях отримати «хаос прав» — скопіювати з Unix-файлової системи на щось, що лише прикидається нею.

Локальні Linux-файлові системи (ext4, XFS)

Загалом безпечно для біту режиму, власності, ACL, xattrs. Слідкуйте за опціями монтування. Також зверніть увагу, якщо ви копіюєте в файлову систему з іншим дефолтним поводженням з ACL.

ZFS on Linux

ZFS підтримує права, ACL, xattrs, але режим ACL може відрізнятися (POSIX vs NFSv4 ACL). Якщо бачите дивний переклад ACL — підтвердіть властивості dataset-у і як ваше ПЗ очікує бачити ACL. rsync може зберігати ACL, але якщо модель ACL відрізняється, «збережено» не означає «еквівалентно».

NFS

NFS фантастичний, поки ви не намагаєтесь виконувати Unix-операції власності з клієнта як root, а сервер каже «ні». Це root-squash. Це нормально. Плануйте його замість того, щоб боротися.

CIFS/SMB

CIFS монт може відображати власність і права залежно від опцій монтування та можливостей сервера. Деякі налаштування можуть зберігати Unix-біти; інші відображають усе в одиний UID/GID. Якщо місце призначення — CIFS і вам потрібні справжні Unix-семантики, протестуйте на невеликій вибірці перед серйозною міграцією.

Жарт №2: Права CIFS схожі на офісні кавомашини — хтось клянеться, що налаштовано правильно, а потім вони роблять якусь бурду.

Три корпоративні міні-історії з практики

Міні-історія 1: Інцидент, спричинений неправильною гіпотезою

Команда мігрувала пул Debian додатків на нове залізо. План був чистий: збирати Debian 13, rsync деревo додатків, перемкнути балансувальник. Вони використали rsync -a і не-root обліковий запис «deploy», бо root SSH був заборонений (розумна політика). Міграція завершилась раніше. Всі пішли на обід з тим тихим відчуттям, яке виникає, коли графік зелений.

Перші помилки були про «випадкові 403» та «завантаження не працює». Вони відкатили один сервер, все добре. Повернули нові — зламано. Люди сперечалися про мережеві шляхи й фаєрволи, бо так роблять, коли не хочуть думати про файлові права.

Справжня проблема: на старих серверах використовували ACL, щоб надати групі веб-воркерів доступ до дерева, що належало іншому сервісному облікові. Deploy користувач міг читати файли, тому rsync скопіював вміст нормально, але не зберіг ACL, бо -A не використовувався. Біти режиму виглядали схожими.
Відсутні ACL почали впливати, коли веб-сервіс спробував записати нові об’єкти.

Виправлення не було героїчним. Вони перезапустили rsync з -aA (а потім -X для повноти) використавши контрольований sudo-воркфлоу на місці призначення. Додали перевірку ACL у runbook міграції: вибрати три відомі ACL-важкі каталоги, порівняти getfacl, відхилити міграцію при невідповідності.

Неправильна гіпотеза була проста: «архівний режим означає все». Архівний режим означає «багато», але не «все».

Міні-історія 2: Оптимізація, що обернулась проблемою

Інша організація мала велику медіапайплайн-міграцію щодня між серверами. Вони хотіли прискорити повільне вікно rsync і прибрали «витратні» прапори і ввімкнули агресивні опції. Хтось запропонував: прибрати -H і -X, додати --inplace і --no-owner, бо «власність не важлива для медіафайлів». У лабораторії на спокійному датасеті швидкість підросла. Зміни пішли в прод.

Два тижні потому використання диска на місці призначення зросло несподівано. Це не було просто «потрібно більше місця»; джоби почали падати через заповнені томи, що спричинило хвилю відставання в черзі. Операції провели ніч, видаляючи тимчасові каталоги і перемігруючи джоби. Постмортем спочатку списав це на «неочікуваний ріст вхідних даних». Це було заспокійливо і неправильно.

Корінь проблеми — жорсткі посилання. Деякі джерельні дерева використовували hard link-и для дедуплікації однакових payload-ів. Видалення -H означало, що rsync скопіював кожний пов’язаний файл як окремий файл, множачи займаний простір. Зміна прапорів власності також прибрала тонку перевірку безпеки: кілька каталогів були захищені правилами групової власності і setgid; уніфікація власності дозволила подальшим джобам записувати туди, де не слід, породжуючи плутані «успіхи» з неправильним розташуванням виходу.

Вони відкотили «оптимізацію», потім переробили pipeline правильно: зберегли -H там, де dataset його використовує, зберегли -X для інструментів з capabilities, і спрямували роботу над продуктивністю на I/O патерни (батчинг, уникнення непотрібних пересканувань), замість виривати прапори коректності. Швидко неправильно — все ще неправильно; просто впевнено провалюється.

Міні-історія 3: Нудна, але правильна практика, що врятувала день

Третя команда робила міграцію Debian 13 для старого моноліту. Додаток був достатньо старий, щоб мати власні вимоги до режимів файлів, і дерево містило мікс setgid директорій, кілька дивних ACL і один бінарник з capabilities, щоб прив’язувати низький порт без root. Лід команди був впертим щодо процесу: передпольотні перевірки, dry-run-и і невелика канаркова копія перед основним набором.

Вони почали з ідентичності: забезпечили, що сервісні акаунти мають збігаючі UID/GID на старих і нових серверах. Не «те саме ім’я», а саме номера. Перевірили доступність LDAP/SSSD. Потім виконали rsync dry-run з поелементним виводом і зберегли результат у тикеті. Це було нудно. І в цьому суть.

Під час канарки помітили кілька файлів, які втратять xattrs. Місце призначення було NFS з root-squash. Ніхто про це не згадав, бо це «просто сховище». Ця деталь зламала б весь cutover: бінарники втратили б capabilities, а деякі каталоги стали б власністю nobody. Оскільки їх виявили рано, вони змінили план: спочатку stage на локальний диск, потім server-side move у сховищі, де можна зберегти власність локально.

День cutover був нудним. Сервіси піднялись. Моніторинг мовчав. Перемога не була геніальною; вона полягала в тому, що не пропустили нудні перевірки, які ловлять проблеми з правами до того, як їх помітять користувачі.

Поширені помилки: симптом → причина → виправлення

  • Симптом: На місці призначення все належить користувачу, що запускав rsync.
    Причина: rsync запущений без привілеїв або місце призначення відмовлялося від chown (root-squash, CIFS mapping).
    Виправлення: Запустіть rsync як root по всій лінії на файловій системі, що підтримує власність; або погодьтесь на політично-обгрунтоване перепризначення власності/ACL після копіювання.
  • Симптом: Імена власників виглядають правильно, але сервіси все одно падають з «permission denied».
    Причина: Втрачено ACL або xattrs; самі біти режиму недостатні.
    Виправлення: Перезапустіть з -A і -X; перевірте з getfacl і getfattr.
  • Симптом: Файли мають правильні режими, але власність призначена невірному локальному акаунту.
    Причина: Невідповідність UID/GID між хостами; rsync відображав по імені без збереження чисел, або місце призначення по-іншому вирішує імена.
    Виправлення: Вирівняйте UID/GID перед міграцією; використайте --numeric-ids; валідуйте з stat і getent.
  • Симптом: Веб-додаток може читати файли, але не може записувати uploads або кеші після міграції.
    Причина: Відсутні setgid/sticky біти або відсутні дефолтні ACL, що надавали право запису групі сервісу.
    Виправлення: Збережіть права і ACL; повторно застосуйте дефолтні ACL; перевірте з getfacl на каталогах.
  • Симптом: Бінарник, що раніше прив’язував порт 80, тепер падає без root.
    Причина: Втрачене capability xattr (security.capability).
    Виправлення: Перекопіюйте з -X, або повторно застосуйте capabilities за допомогою setcap і переконайтесь, що майбутні міграції зберігають xattrs.
  • Симптом: Використання диска вибухнуло після міграції; «однакові» дерева набрали набагато більше місця.
    Причина: Жорсткі посилання не збережено тому, що відсутній -H.
    Виправлення: Повторіть з -H для датасетів, що використовують hard links; вирішіть, чи прийнятна вартість і протестуйте на підмножині.
  • Симптом: rsync повідомляє успіх, але спеціальні файли/пристрої неправильні або відсутні.
    Причина: Копіювання не запускали як root або не зберегли specials (-D через -a), або місце призначення не може їх зберігати.
    Виправлення: Використовуйте root + archive mode на сумісній файловій системі; для системних образів розгляньте міграцію на рівні знімків.
  • Симптом: Деякі каталоги після міграції мають дозвіл запису для «other».
    Причина: Хтось застосував --chmod широко або копіював через монтування, що нормалізує права; або «полагодили» проблему, послабивши все.
    Виправлення: Відмініть широке chmod. Відновіть з джерела з належними прапорами збереження. Проведіть аудит з find на світ-писабельних шляхах.

Чеклісти / покроковий план

План A: Міграція з повною точністю (бажано)

  1. Підтвердіть вирівнювання ідентичностей: сервісні акаунти й групи мають однакові UID/GID на джерелі і призначенні. Якщо ви використовуєте LDAP/SSSD, перевірте його роботу на місці призначення.
  2. Підтвердіть семантику файлової системи призначення: локальна Linux-файлова система — пріоритет. Уникайте CIFS для дерев, критичних до Unix-прав. Ставтесь до NFS root-squash як до жорсткого обмеження.
  3. Виберіть канарковий каталог: включіть файл з ACL і бінарник з xattrs/capabilities, якщо потрібно.
  4. Dry-run rsync з -n -i і збережіть поелементний вивід. Шукайте зміни власника/групи/ACL/xattr.
  5. Реальний rsync: sudo rsync -aHAX --numeric-ids --info=stats2,progress2.
  6. Верифікація: вибірковий stat, getfacl, getfattr. Виконайте smoke test додатку, що зачіпає шляхи запису.
  7. Фінальний синк: повторіть rsync, щоб підхопити дельти перед cutover (ті ж прапори).
  8. Cutover: запускайте сервіси; моніторьте логи на помилки, пов’язані з правами; тримайте старі дані доступними лише для читання до впевненості.

План B: Контрольована трансформація (коли ID не можна вирівняти)

  1. Копіюйте контент з часовими мітками: використайте rsync, але не прикидайтесь, що власність збігатиметься.
  2. Застосуйте політику власності: явні chown/chgrp і скрипти ACL для кожного каталогу.
  3. Проведіть аудит: перевірте числових власників, несподівані світ-писабельні файли і відсутні очікувані ACL.
  4. Документуйте відображення, щоб наступна міграція не стала археологічною роботою.

План C: NFS призначення з root-squash (практичні варіанти)

  1. Віддавайте перевагу стаджингу на локальний диск на хості призначення, збереженню власності там.
  2. Потім перемістіть дані сервер-сайду (на NFS-сервері) у експортований шлях, де власність може бути збережена локально.
  3. Якщо потрібно копіювати безпосередньо на NFS: прийміть, що збереження власності може бути неможливим і розглядайте це як задачу переприсвоєння власників.

FAQ

1) Чи зберігає rsync -a власника?

Він включає -o і -g, але справді збереже власника тільки якщо rsync має достатні привілеї, щоб встановити uid/gid на місці призначення. По SSH це зазвичай означає root на віддаленому боці також.

2) Навіщо потрібен --numeric-ids?

Тому що імена можуть мапитися на різні числові ID на різних хостах. --numeric-ids наказує rsync зберігати числа точно, уникаючи «допоміжного» мапінгу імен, що тихо може перевизначити власність.

3) Я запускав як root, але власність все одно неправильна. Чому?

Типові причини: місце призначення — NFS з root-squash; місце призначення — CIFS з примусовим відображенням uid/gid; або ви копіювали в файлову систему/монтування, яке відмовляє chown.
Перевірте вручну chown на шляху призначення.

4) Які прапори зберігають ACL і xattrs?

-A зберігає ACL. -X зберігає розширені атрибути. Якщо вам важливо, щоб додатки працювали, зазвичай потрібно обидва.

5) Чи завжди потрібно використовувати -H?

Не завжди. -H може збільшити використання пам’яті і час виконання, оскільки rsync має відстежувати відносини жорстких посилань. Використовуйте його, коли ваш датасет використовує hard links
(деякі системні дерева, дедуплікований контент, кеші пакетів) і вам важливо їх зберегти.

6) Чи можна зберегти власника, копіюючи як неповноважений користувач?

В загальному випадку — ні. Неповноважений користувач може встановити власність тільки на себе (і іноді групи, до яких він належить). Якщо вам потрібна вірна власність — використовуйте root або контрольований привілейований воркфлоу.

7) Чому права виглядають нормально, але systemd сервіси падають?

Сервіси можуть падати через відсутні capabilities на бінарниках (xattrs), відсутній доступ до runtime-директорій через втрату ACL або неправильну власність у state-директоріях під /var.
Перевірте getfattr для capabilities і getfacl для директорій.

8) Чи безпечно «виправити все» через chmod -R 777 або масовий chown -R?

Це швидко, «працює», і це спосіб перетворити міграцію на інцидент безпеки. Якщо потрібно переписати власників, робіть це з відображенням і проведіть аудит результату.

9) Який найшвидший спосіб довести, що джерело і призначення співпадають?

Використайте rsync dry-run з поелементним виводом (-n -i) і зосередьтесь на маркерах p, o, g, a та x.
Потім валідуйте вибірку з stat, getfacl і getfattr.

10) Я копіюю на файлову систему, що не підтримує Unix-власність. Що робити?

Тоді ви не зможете «зберегти власність» в жодному суттєвому вигляді. Або змініть місце призначення (бажано), або прийміть, що права будуть представлені по-іншому і керуйте доступом через модель цієї системи замість вдавання POSIX.

Висновок: наступні кроки, які можна виконати

Якщо ви хочете, щоб міграції Debian 13 були нудними, перестаньте ставитись до прав як до побічного ефекту. Розглядайте їх як первинні дані. Власність — це числові ID, а не імена. ACL і xattrs не опціональні, коли ви переносите реальні продакшн-системи. Межі файлових систем — це місце, де хороші наміри гинуть.

Практичні наступні кроки:

  1. Виберіть одну проблемну директорію і виконайте канаркові перевірки: stat, getfacl, getfattr.
  2. Виконайте rsync dry-run з -aHAX --numeric-ids -n -i і читайте літери, наче це контракт.
  3. Підтвердіть вирівнювання UID/GID для сервісних акаунтів з getent на обох хостах.
  4. Якщо ціль — NFS/CIFS, протестуйте встановлення власника на одному файлі перед початком міграції. Якщо не можна chown — неможливо зберегти власність; дискусії не допоможуть.
  5. Потім виконайте реальну копію з повним набором прапорів і валідуйте перед cutover.
← Попередня
Панель здоров’я ZFS: метрики, які потрібно відстежувати (інакше ви сліпі)
Наступна →
RAIDZ2 в ZFS: баланс ємності та виживання (зазвичай)

Залишити коментар