IPFS без болю (але це не точно)

IPFS без болю (але це не точно)

Незважаючи на те, що на Хабрі була вже не одна стаття про IPFS.

Відразу уточню, що я не є експертом у цій галузі, але не раз виявляв інтерес до цієї технології, але спроби погратися з нею часто викликали певний біль. Сьогодні я знову взявся за експерименти і отримав деякі результати, якими хотів би поділитися. Якщо коротко, то буде описано процес встановлення IPFS і деякі фішки (все виконувалося на Ubuntu, на інших платформах не пробував).

Якщо ви пропустили що таке IPFS, досить докладно написано тут: habr.com/ua/post/314768

Встановлення

Для чистоти експерименту пропоную відразу встановлювати на якомусь зовнішньому сервері, тому що ми розглядатимемо деякі підводні камені з роботою в локальному режимі і віддаленому. Потім за бажання не довго буде знести, там небагато.

Встановлюємо go

Офіційна документація
Актуальну версію дивіться на golang.org/dl

Примітка: краще встановлювати IPFS від імені користувача, яким і передбачається найчастіше використання. Справа в тому, що нижче ми розглянемо варіант з монтуванням через FUSE і там є тонкощі.

cd ~
curl -O https://dl.google.com/go/go1.12.9.linux-amd64.tar.gz
tar xvf go1.12.9.linux-amd64.tar.gz
sudo chown -R root:root ./go
sudo mv go /usr/local
rm go1.12.9.linux-amd64.tar.gz

Потім треба оновити оточення (докладніше тут: golang.org/doc/code.html#GOPATH).

echo 'export GOPATH=$HOME/work' >> ~/.bashrc
echo 'export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin' >> ~/.bashrc
source ~/.bashrc

Перевіряємо, що go встановився

go version

Встановлюємо IPFS

Мені найбільше сподобався спосіб встановлення через ipfs-update.

Встановлюємо його командою

go get -v -u github.com/ipfs/ipfs-update

Після цього можна виконувати такі команди:

ipfs-update versions щоб побачити всі доступні версії для завантаження.
ipfs-update version — щоб побачити поточну версію (поки у нас не встановлено IPFS, буде none).
ipfs-update install latest — Встановити останню версію IPFS. Замість latest відповідно можна вказати будь-яку бажану версію зі списку доступних.

Встановлюємо ipfs

ipfs-update install latest

перевіряємо

ipfs --version

Безпосередньо з установкою загалом усе.

Запуск IPFS

ініціалізація

Для початку треба виконати ініціалізацію.

ipfs init

У відповідь ви отримаєте щось такого:

 ipfs init
initializing IPFS node at /home/USERNAME/.ipfs
generating 2048-bit RSA keypair...done
peer identity: QmeCWX1DD7HnXXXXXXXXXXXXXXXXXXXXXXXXxxx
to get started, enter:
	ipfs cat /ipfs/QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv/readme

Можна виконати запропоновану команду

ipfs cat /ipfs/QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv/readme

Результат

Hello and Welcome to IPFS!

██╗██████╗ ███████╗███████╗
██║██╔══██╗██╔════╝██╔════╝
██║██████╔╝█████╗  ███████╗
██║██╔═══╝ ██╔══╝  ╚════██║
██║██║     ██║     ███████║
╚═╝╚═╝     ╚═╝     ╚══════╝

If you're seeing this, you have successfully installed
IPFS and are now interfacing with the ipfs merkledag!

 -------------------------------------------------------
| Warning:                                              |
|   This is alpha software. Use at your own discretion! |
|   Much is missing or lacking polish. There are bugs.  |
|   Not yet secure. Read the security notes for more.   |
 -------------------------------------------------------

Check out some of the other files in this directory:

  ./about
  ./help
  ./quick-start     <-- usage examples
  ./readme          <-- this file
  ./security-notes

Ось тут, як на мене, вже починається цікаве. Діти ще на етапі установки вже починають використовувати свої ж технології. Запропонований хеш QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv — не згенерований спеціально для вас, а вшитий у реліз. Тобто до релізу вони підготували вітальний текст, вилили його в IPFS і додали адресу в інсталятор. На мою думку, це дуже круто. І цей файл (точніше всю папку) тепер можна переглянути не тільки локально, але і на офіційному шлюзі ipfs.io/ipfs/QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv. При цьому можна бути впевненим, що вміст папки ніяк не змінювався, бо якби змінилося, то хеш теж змінився б.

До речі, у цьому випадку IPFS має деяку подібність із сервером контролю версій. Якщо у вихідні файли папки внести зміни і знову вилити папку в IPFS, вона отримає нову адресу. При цьому стара папка нікуди не дінеться просто так і буде доступна на свою колишню адресу.

Безпосередньо запуск

ipfs daemon

Повинні у відповідь отримати такий тип:

ipfs daemon
Initializing daemon...
go-ipfs version: 0.4.22-
Repo version: 7
System version: amd64/linux
Golang version: go1.12.7
Swarm listening on /ip4/x.x.x.x/tcp/4001
Swarm listening on /ip4/127.0.0.1/tcp/4001
Swarm listening on /ip6/::1/tcp/4001
Swarm listening on /p2p-circuit
Swarm announcing /ip4/127.0.0.1/tcp/4001
Swarm announcing /ip6/::1/tcp/4001
API server listening on /ip4/127.0.0.1/tcp/5001
WebUI: http://127.0.0.1:5001/webui
Gateway (readonly) server listening on /ip4/127.0.0.1/tcp/8080
Daemon is ready

Відкриваємо двері для Інтернету

Зверніть увагу на ці два рядки:

WebUI: http://127.0.0.1:5001/webui
Gateway (readonly) server listening on /ip4/127.0.0.1/tcp/8080

Ось якщо ви встановили IPFS у себе локально, то ви будете звертатися до IPFS-інтерфейсів за локальними адресами і вам буде все доступно (Наприклад, локальний:5001/webui/). Але при встановленні на зовнішньому сервері шлюзи за замовчуванням закриті для інтернету. Шлюзів два:

  1. Адмінка webui (GitHub) на порту 5001.
  2. Зовнішнє API на порту 8080 (readonly).

Поки що для експериментів можна відкрити обидва порти (5001 і 8080), але на бойовому сервері звичайно ж порт 5001 треба було б закрити фаєрволом. Ще є 4001 порт, він потрібен, щоб інші бенкети могли вас знайти. Його слід залишити відкритим для запитів ззовні.

Відкриваємо для редагування ~/.ipfs/config та знаходимо в ньому ці рядки:

"Addresses": {
  "Swarm": [
    "/ip4/0.0.0.0/tcp/4001",
    "/ip6/::/tcp/4001"
  ],
  "Announce": [],
  "NoAnnounce": [],
  "API": "/ip4/127.0.0.1/tcp/5001",
  "Gateway": "/ip4/127.0.0.1/tcp/8080"
}

Змінюємо 127.0.0.1 на ip вашого сервера та зберігаємо файл, після чого перезапускаємо ipfs (запущену команду зупиняємо Ctrl+C і знову запускаємо).

Повинні отримати

...
WebUI: http://ip_вашего_сервера:5001/webui
Gateway (readonly) server listening on /ip4/ip_вашего_сервера/tcp/8080

Ось тепер зовнішні інтерфейси мають бути доступні.

Перевірте

http://домен_или_ip_сервера:8080/ipfs/QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv/readme

Повинен відкритися наведений вище рідмі-файл.

http://домен_или_ip_сервера:5001/webui/

Повинен відкрити веб-інтерфейс.

Якщо у вас працює webui, то налаштування IPFS можна змінювати прямо в ньому, в тому числі і переглядати статистику, але нижче я розглядатиму варіанти конфігурації саме безпосередньо через файл-конфіг, що в цілому не критично. Просто краще запам'ятати де саме конфіг лежить і що з ним робити, а якщо веб-морда працювати не буде, то буде вже складніше.

Налаштовуємо веб-інтерфейс для роботи зі своїм сервером

Ось тут перший підводний камінь, на який було витрачено години зо три.

Якщо ви встановили IPFS на зовнішньому сервері, але не встановлювали або не запускали IPFS локально, то при заході на /webui у веб-інтерфейсі ви повинні бачити помилку підключення:

IPFS без болю (але це не точно)

Справа в тому, що webi, на мою думку, працює дуже неоднозначно. Спочатку він намагається підключитися до API того сервера, де відкритий інтерфейс (звісно ж ґрунтуючись на адресі в браузері). і якщо не виходить там, намагається підключитися на локальний шлюз. І якщо у вас локально запущений IPFS, то у вас webu буде працювати нормально, тільки ось працювати ви будете з локальною IPFS, а не зовнішньою, хоч і відкрили web на зовнішньому сервері. Потім заливаєте файли, але чомусь не бачите їх просто так на зовнішньому сервері.

А якщо і локально не запущено, то отримуємо помилку з'єднання. У нашому випадку помилка швидше за все через CORS, про що й каже навіть webi, пропонуючи додати конфіг.

ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin '["http://ip_вашего сервера:5001", "http://127.0.0.1:5001", "https://webui.ipfs.io"]'
ipfs config --json API.HTTPHeaders.Access-Control-Allow-Methods '["PUT", "GET", "POST"]'

Я ж у себе просто wildcard прописав

ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin '["*"]'

Додані заголовки можна знайти все в тому ж ~/.ipfs/config. У моєму випадку це

  "API": {
    "HTTPHeaders": {
      "Access-Control-Allow-Origin": [
        "*"
      ]
    }
  },

Перезапускаємо ipfs і бачимо, що webi успішно з'єднався (у всякому разі повинен, якщо ви відкрили шлюзи для запитів ззовні, як і описано вище).

Тепер можна прямо через веб-інтерфейс заливати папки та файли, а також створювати свої папки.

Монтування файлової системи FUSE

Ось це досить цікава фішка.

Файли (як і папки), ми можемо додавати не лише через веб-інтерфейс, а й безпосередньо в терміналі, наприклад

ipfs add test -r
added QmfYuz2gegRZNkDUDVLNa5DXzKmxxxxxxxxxx test/test.txt
added QmbnzgRVAP4fL814h5mQttyqk1aURxxxxxxxxxxxx test

Останній хеш – це хеш кореневої папки.

За цим хешем ми можемо відкрити папку на будь-якій ipfs-ноді (яка зможе знайти нашу ноду та отримати вміст), можемо у веб-інтерфейсі на порту 5001 або 8080, а можемо локально через ipfs.

ipfs ls QmbnzgRVAP4fL814h5mQttyqk1aUxxxxxxxxxxxxx
QmfYuz2gegRZNkDUDVLNa5DXzKmKVxxxxxxxxxxxxxx 10 test.txt

Але ще можна і як звичайну папку відчиняти.

Створимо докорінно дві папки і права на них надамо нашому користувачеві.

sudo mkdir /ipfs /ipns
sudo chown USERNAME /ipfs /ipns

і перезапустимо ipfs з прапором -mount

ipfs daemon --mount

Можна створити папки та в інших місцях і вказати шлях до них через параметри ipfs daemon -mount -mount-ipfs /ipfs_path -mount-ipns /ipns_path

Тепер читання з цієї папки дещо незвичайне.

ls -la /ipfs
ls: reading directory '/ipfs': Operation not permitted
total 0

Тобто прямого доступу до кореня цієї папки немає. Але можна отримати вміст, знаючи хеш.

ls -la /ipfs/QmbnzgRVAP4fL814h5mQttyqxxxxxxxxxxxxxxxxx
total 0
-r--r--r-- 1 root root 10 Aug 31 07:03 test.txt

cat /ipfs/QmbnzgRVAP4fL814h5mQttyqxxxxxxxxxxxxxxxxx/test.txt 
test
test

При цьому всередині папки навіть доповнення авто працює при вказівці шляху.

Як я й говорив вище, при такому монтуванні є тонкощі: за замовчуванням змонтовані FUSE-папки доступні тільки поточному користувачеві (навіть root не зможе читати з такої папки, не кажучи вже про інших користувачів у системі). Якщо ви хочете зробити ці папки доступними іншим користувачам, то в конфізі треба змінити FuseAllowOther: false на FuseAllowOther: true. Але це ще не все. Якщо ви запускаєте IPFS від імені root, то все ОК. А якщо від імені звичайного користувача (нехай і sudo), то отримайте помилку

mount helper error: fusermount: option allow_other only allowed if 'user_allow_other' is set in /etc/fuse.conf

У такому разі треба підправити /etc/fuse.conf, розкоментувавши рядок #user_allow_other.

Після цього перезапускаємо ipfs.

Відомі проблеми з FUSE

Не раз була помічена проблема, що після рестарту ipfs з монтуванням (а може і в інших випадках) точки монтування /ipfs і /ipns стають недоступними. Доступу до них немає ніякого, а ls-la/ipfs показує???? у списку прав.

Знайшов таке рішення:

fusermount -z -u /ipfs
fusermount -z -u /ipns

Після чого рестартим ipfs.

Додаємо службу

Звичайно ж, запуск у терміналі годиться тільки для первинних тестів. У бойовому режимі демон повинен запускатися автоматично під час запуску системи.

Від імені судно створюємо файл /etc/systemd/system/ipfs.service та записуємо до нього:

[Unit]
Description=IPFS Daemon
After=syslog.target network.target remote-fs.target nss-lookup.target

[Service]
Type=simple
ExecStart=/home/USERNAME/work/bin/ipfs daemon --mount
User=USERNAME
Restart=always

[Install]
WantedBy=multi-user.target

USERNAME звичайно треба замінити на свого користувача (і можливо повний шлях до програми ipfs буде у вас інший (вказувати треба саме повний шлях)).

Активуємо службу.

sudo systemctl enable ipfs.service

Запускаємо службу.

sudo service ipfs start

Перевіряємо статус служби.

sudo service ipfs status

Для чистоти експерименту можна буде надалі ребутнути сервер, щоб перевірити, що ipfs успішно стартує автоматично.

Додаємо відомі нам бенкети

Розглянемо ситуацію, коли IPFS ноди встановлені і на зовнішньому сервері і локально. На зовнішньому сервері ми додаємо якийсь файл і намагаємося його отримати через IPFS локально CID. Що відбуватиметься? Звичайно ж локальний сервер швидше за все нічого не знає про зовнішній наш сервер і буде просто намагатися знайти файл CID «питаючи» у всіх доступних йому IPFS-бенкетів (з якими йому вже вдалося «познайомитися»). Ті у свою чергу в інших запитуватимуть. І так, поки файл не буде знайдено. Власне, те саме відбувається і коли ми намагаємося файл отримати через офіційний шлюз ipfs.io. Якщо пощастить, файл буде знайдено за кілька секунд. А якщо ні, то не буде знайдено і за кілька хвилин, що дуже сильно б'є по комфорту роботи. Але ми знаємо де цей файл в першу чергу з'явиться. То чому нам одразу не сказати нашому локальному серверу «Шукай насамперед там»? Зважаючи на все, це можна зробити.

1. Заходимо на віддалений сервер і в конфізі ~/.ipfs/config шукаємо

"Identity": {
    "PeerID": "QmeCWX1DD7HnPSuMHZSh6tFuxxxxxxxxxxxxxxxx",

2. Виконуємо sudo service ipfs status та шукаємо в ньому записи Swarm, наприклад:

Swarm announcing /ip4/ip_вашего_сервера/tcp/4001

3. Складаємо з цього загальну адресу виду "/ip4/ip_вашого_сервера/tcp/4001/ipfs/$PeerID".

4. Для надійності через наш локальний webi спробуємо додати цю адресу в бенкети.

IPFS без болю (але це не точно)

5. Якщо всі ОК, відкриваємо локальний конфіг ~/.ipfs/config, знаходимо в ньому "Bootstrap": […
і дописуємо першим в масив отриману адресу.

Рестартім IPFS.

Тепер додамо файл на зовнішній сервер і спробуємо його попросити на локальному. Мушу залетіти швидко.

Але цей функціонал поки що нестабільний. Наскільки я розумію, навіть якщо ми вказуємо адресу бенкету в Bootstrap, в процесі роботи ipfs змінює список активних з'єднань з бенкетами. Принаймні обговорення цього та побажання щодо можливості вказувати постійні бенкети ведеться тут і начебто як передбачається додати якийсь функціонал у [захищено електронною поштою]+

Список поточних бенкетів можна подивитися як у webi, так і в терміналі.

ipfs swarm peers

І там і там можна додати вручну свій бенкет.

ipfs swarm connect "/ip4/ip_вашего_сервера/tcp/4001/ipfs/$PeerID"

Поки не покращили цей функціонал, можна написати тулзу, щоб перевіряла наявність з'єднання з потрібним бенкетом і якщо ні, щоб додавала з'єднання.

міркування

Серед тих, хто вже знайомий з IPFS, є аргументи як за IPFS, так і проти. В принципі, позавчорашнє обговорення і спонукало мене ще раз покопати IPFS. І ось щодо згаданої дискусії: я не можу сказати, що сильно проти якогось наведеного аргументу висловилися (не згоден тільки з тим, що півтора програміста використовують IPFS). Загалом по-своєму мають рацію і ті, й інші (особливо коментар про чеки доставляє задуматися). Але якщо відкинути моральну та юридичну оцінку, хто дасть технічну оцінку даної технології? Особисто в мене якесь внутрішнє відчуття є, що «це треба однозначно, це має певні перспективи». Але чому саме немає чіткого формулювання. Типу якщо подивитися вже наявні централізовані засоби, то за багатьма параметрами вони сильно попереду (стабільність роботи, швидкість роботи, керованості тощо). Проте в мене є одна думка, яка начебто має сенс і яка навряд чи може бути реалізована без таких децентралізованих систем. Звичайно, сильно я замахуюсь, але я б сформулював її так: принцип поширення інформації в Інтернеті треба поміняти.

Поясню. Якщо так подумати, то зараз у нас інформація поширюється за принципом: «Я сподіваюся, що той, кому я її передав, її захистить і вона не буде втрачена або отримана тим, кому вона не призначалася». Для прикладу легко розглянути різноманітні поштові послуги, хмарні сховища тощо. І що ми маємо у результаті? На Хабре хаб Інформаційна безпека стоїть на першому рядку і практично щодня ми отримуємо новини про черговий глобальний витік. В принципі, все найцікавіше перераховано в <іронія>чудовою статті Літо майже скінчилося. Не втеклих даних майже не залишилося. Тобто основні інтернет-гіганти стають дедалі більшими, акумулюють вони у себе все більше інформації, і подібні витоки — це своєрідні інформаційні атомні вибухи. Ніколи такого не було, і знову. При цьому, хоча багато хто розуміє, що ризики є, продовжать довіряти свої дані стороннім компаніям. По-перше, альтернативи особливо немає, а по-друге, ті обіцяють, що залатали всі дірки і більше ніколи не повториться.

Який мені бачиться варіант? На мою думку, дані спочатку повинні поширюватися відкрито. Але відкритість у цьому випадку — це не означає, що все має легко читатись. Я говорю про відкритість зберігання та поширення, але не тотальну відкритість у читанні. Я припускаю, що інформація має розповсюджуватися з відкритими ключами. Адже принцип відкритих/закритих ключів вже старий, як Інтернет. Якщо інформація не конфіденційна і розрахована на широке коло, то вона викладається відразу з відкритим ключем (але все одно в зашифрованому вигляді, просто її будь-хто може розшифрувати наявним ключем). А якщо ні, то викладається без відкритого ключа, а сам ключ передається тому, що повинен мати доступ до цієї інформації. При цьому той, хто має її прочитати, повинен мати тільки ключ, а де взяти цю інформацію, його не має особливо ширяти — він просто її тягне з мережі (це і є новий принцип розповсюдження за вмістом, а не за адресою).

Таким чином, зловмисникам для масової атаки треба буде отримати величезну кількість закритих ключів, і навряд чи це вдасться зробити в одному місці. Це завдання, як мені здається, складніше, ніж зламати якийсь певний сервіс.

І тут-таки закривається ще одна проблема: підтвердження авторства. Зараз в інтернеті можна знайти багато цитат, написаних нашими знайомими. Але де гарантія, що вони їх писали? Ось якби кожен такий запис супроводжувався цифровим підписом, то було б набагато простіше. І не важливо, де ця інформація лежить, головне — підпис, який, свідомо, складно підробити.

І ось що тут цікаво: IPFS вже несе у собі засоби шифрування (адже він побудований на технології блокчейну). У конфізі відразу вказано приватний ключ.

  "Identity": {
    "PeerID": "QmeCWX1DD7HnPSuMHZSh6tFuMxxxxxxxxxxxxxx",
    "PrivKey": "CAASqAkwggSkAgEAAoIBAQClZedVmj8JkPvT92sGrNIQmofVF3ne8xSWZIGqkm+t9IHNN+/NDI51jA0MRzpBviM3o/c/Nuz30wo95vWToNyWzJlyAISXnUHxnVhvpeJAbaeggQRcFxO9ujO9DH61aqgN1m+JoEplHjtc4KS5
pUEDqamve+xAJO8BWt/LgeRKA70JN4hlsRSghRqNFFwjeuBkT1kB6tZsG3YmvAXJ0o2uye+y+7LMS7jKpwJNJBiFAa/Kuyu3W6PrdOe7SqrXfjOLHQ0uX1oYfcqFIKQsBNj/Fb+GJMiciJUZaAjgHoaZrrf2b/Eii3z0i+QIVG7OypXT3Z9JUS60
KKLfjtJ0nVLjAgMBAAECggEAZqSR5sbdffNSxN2TtsXDa3hq+WwjPp/908M10QQleH/3mcKv98FmGz65zjfZyHjV5C7GPp24e6elgHr3RhGbM55vT5dQscJu7SGng0of2bnzQCEw8nGD18dZWmYJsE4rUsMT3wXxhUU4s8/Zijgq27oLyxKNr9T7
2gxqPCI06VTfMiCL1wBBUP1wHdFmD/YLJwOjV/sVzbsl9HxqzgzlDtfMn/bJodcURFI1sf1e6WO+MyTc3.................

Я не фахівець з безпеки і не можу точно знати, як це правильно використовувати, але мені здається, що на рівні обміну між IPFS-нодами ці ключі використовуються. А ще js-ipfs і такі проекти-приклади як orbit-db, на якій працює orbit.chat. Тобто теоретично кожен пристрій (мобільний і не тільки) може бути легко оснащений своїми дешифрувальними машинами. У такому разі залишиться лише кожному подбати про збереження своїх приватних ключів і кожен сам буде відповідальний за свою безпеку, а не бути заручником чергового людського чинника на якомусь супер-популярному інтернет-гіганті.

Тільки зареєстровані користувачі можуть брати участь в опитуванні. Увійдіть, будь ласка.

Чи чули ви раніше про IPFS?

  • Ніколи не чув про IPFS, але начебто цікаво

  • Не чув і не хочу чути

  • Чув, але так і не зацікавило

  • Чув, але не зрозумів, а зараз начебто цікаво

  • Давно вже активно використовую IPFS

Проголосували 69 користувачів. Утрималися 13 користувачів.

Джерело: habr.com

Додати коментар або відгук