Хабрахабр

IPFS без боли (но это не точно)

Не смотря на то, что на хабре была уже не одна статья про IPFS

Сегодня я опять взялся за эксперименты и получил кое-какие результаты, которыми хотел бы поделиться. Сразу уточню, что я не являюсь экспертом в этой области, но не раз проявлял интерес к этой технологии, но попытки поиграться с ней часто вызывало некоторую боль. Если коротко, то будет описан процесс установки IPFS и некоторые фишки (все выполнялось на ubuntu, на других платформах не пробовал).

Если вы пропустили что же такое IPFS, довольно подробно написано здесь: habr.com/ru/post/314768

Установка

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

Устанавливаем go

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

Дело в том, что ниже мы рассмотрим вариант с монтированием через FUSE и там есть тонкости. Замечание: лучше устанавливать IPFS от имени пользователя, которым и предполагается наиболее частое использование.

12. 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. 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

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

Устанавливаем 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!

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

Check out some of the other files in this directory:

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

Ребята еще на этапе установки уже начинают использовать свои же технологии. Вот тут, на мой взгляд, уже начинается интересное. То есть до релиза они подготовили приветственный текст, вылили его в IPFS и адрес добавили в инсталятор. Предложенный хеш QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv — не сгенерированный специально для вас, а вшитый в релиз. И этот файл (точнее, всю папку) теперь можно просмотреть не только локально, но и на официальном шлюзе 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-интерфейсам обращаться по локальным адресам и вам будет все доступно (К примеру, localhost:5001/webui/). Админка webui (github) на порту 5001.
2. Шлюзов два:
1. Внешнее API на порту 8080 (readonly).

Еще есть 4001 порт, он нужен, чтобы другие пиры могли вас найти. Пока для экспериментов можно открыть оба порта (5001 и 8080), но на боевом сервере конечно же порт 5001 надо бы закрыть фаерволом. Его следует оставить открытым для запросов извне.

Открываем для редактирования ~/.ipfs/config и находим в нем эти строки:
"Addresses":

0. Меняем 127. 1 на ip вашего сервера и сохраняем файл, после чего перезапускаем ipfs (запущенную команду останавливаем Ctrl+C и опять запускаем).
Должны получить
...
WebUI: http://ip_вашего_сервера:5001/webui
Gateway (readonly) server listening on /ip4/ip_вашего_сервера/tcp/8080
0.

Вот теперь внешние интерфейсы должны быть доступны.
Проверьте
http://домен_или_ip_сервера:8080/ipfs/QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv/readme
Должен открыться приведенный выше ридми-файл.

http://домен_или_ip_сервера:5001/webui/
Должен открыться веб-интерфейс.

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

Настраиваем веб-интерфейс для работы со своим сервером

Вот тут первый подводный камень, на который было потрачено часа три.
Если вы IPFS установили на внешнем сервере, но не устанавливали или не запускали IPFS локально, то при заходе на /webui в веб-интерфейсе вы должны видеть ошибку подключения:

Сначала он пытается подключиться к API того сервера, где открыт интерфейс (конечно же основываясь на адресе в браузере). Дело в том, что webui, по моему мнению, работает весьма неоднозначно. И если у вас локально запущен IPFS, то у вас webui будет работать нормально, только вот работать вы будете с локальной IPFS, а не внешней, хоть и открыли webui на внешнем сервере. и если не получается там, то пытается подключиться на локальный шлюз. В нашем случае ошибка скорее всего из-за CORS, о чем и говорит в том числе webui, предлагая добавить конфиг.
ipfs config --json API. Потом заливаете файлы, но почему-то не видите их просто так на внешнем сервере…
А если и локально не запущен, то получаем ошибку соединения. Access-Control-Allow-Origin '["http://ip_вашего сервера:5001", "http://127. HTTPHeaders. 0. 0. HTTPHeaders. 1:5001", "https://webui.ipfs.io"]'
ipfs config --json API. HTTPHeaders. Access-Control-Allow-Methods '["PUT", "GET", "POST"]'

Я же у себя просто wildcard прописал
ipfs config --json API. В моем случае это "API": {
"HTTPHeaders": {
"Access-Control-Allow-Origin": [
"*"
]
}
},

Перезапускаем ipfs и видим, что webui успешно соединился (во всяком случае должен, если вы открыли шлюзы для запросов извне, как и описано выше). Access-Control-Allow-Origin '["*"]'

Добавленные заголовки можно найти все в том же ~/.ipfs/config.

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

Монтирование файловой системы 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

При этом внутри папки даже автодополнение работает при указании пути.

Если вы хотите сделать эти папки доступными другим пользователям, то в конфиге надо изменить «FuseAllowOther»: false на «FuseAllowOther»: true. Как я и говорил выше, при таком монтировании есть тонкости: по-умолчанию смонтированые FUSE-папки доступны только текущему пользователю (даже root не сможет читать из такой папки, не говоря уже про других пользователей в системе). Если вы 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. Если повезет, то файл будет найден за несколько секунд. А если нет, то не будет найден и за несколько минут, что очень сильно бьет по комфорту работы. Но мы-то знаем где этот файл в первую очередь появится. Так почему нам сразу не сказать нашему локальному серверу «Ищи в первую очередь там»? Судя по всему, это можно сделать.

Заходим на удаленный сервер и в конфиге ~/.ipfs/config ищем
"Identity": {
"PeerID": "QmeCWX1DD7HnPSuMHZSh6tFuxxxxxxxxxxxxxxxx",

2. 1. Складываем из этого общий адрес вида "/ip4/ip_вашего_сервера/tcp/4001/ipfs/$PeerID".
4. Выполняем sudo service ipfs status и ищем в нем записи Swarm, например:
Swarm announcing /ip4/ip_вашего_сервера/tcp/4001
3. Если все ОК, открываем локальный конфиг ~/.ipfs/config, находим в нем «Bootstrap»: […
и дописываем первым в массив полученный адрес.
Рестартим IPFS. Для надежности через наш локальный webui попробуем добавить этот адрес в пиры.

5.

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

Насколько я понимаю, даже если мы указываем адрес пира в Bootstrap, в процессе работы ipfs меняет список активных соединений с пирами. Но этот функционал пока нестабилен. 0+ Во всяком случае обсуждение этого и пожелания на счет возможности указывать постоянные пиры ведется здесь и вроде как предполагается добавить какой-то функционал в ipfs@5.

Список текущих пиров можно посмотреть как в webui, так и в терминале.
ipfs swarm peers

И там и там можно добавить вручную свой пир.
ipfs swarm connect "/ip4/ip_вашего_сервера/tcp/4001/ipfs/$PeerID"

Пока не улучшили этот функционал, можно написать тулзу, чтобы проверяла наличие соединения с нужным пиром и если нет, чтобы добавляла соединение.

Рассуждения

Среди тех, кто уже знаком с 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-нодами эти ключи используются. В таком случае останется только каждому позаботиться о сохранении своих приватных ключей и каждый сам будет ответственнен за свою безопасность, а не быть заложником очередного человеческого фактора на каком-нибудь супер-популярном интернет-гиганте. То есть теоритически каждое устройство (мобильное и не только) может быть легко оснащено своими шифровально-дешифровальными машинами.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть