MastodonインスタンスがTor内インスタンスと連合ネットワークを組むのに必要なサポートが2.4.0から組み入れられました。その機能を導入するための手順を解説したいと思います。
- 改訂にあたり、2.4.0には脆弱性が存在するため2.4.5を対象とするように書き換えました。
Clearnet側
Clearnet側がTor連合に必要なのはTorに繋がるHTTPプロクシだけです。それをTorとPrivoxyを組み合わせて作成します。Mastodonインスタンスは既に動いているものとします。また、パッケージ導入のコマンドはDebian系を仮定します。
まずはPrivoxyとTorをインストールします。
apt install privoxy tor
次に「Tor内(.onion
のURL)へはTorのSOCKSプロクシへフォワードし、それ以外は直接アクセスする」という設定のため、以下を/etc/privoxy/config
へ追記します
forward-socks5t .onion 127.0.0.1:9050 .
Privoxyを再起動したら、このプロクシが機能しているかチェックします。まず、clearnet側へのアクセスがTorを経由していないことを確認します。
curl -Ss --proxy http://127.0.0.1:8118 https://check.torproject.org/ |sed -n '/<h1/,/<\/h1>/p'
<h1 class="off">
Sorry. You are not using Tor.
</h1>
次にTorサイトへのアクセスを確認。
curl -Ss --proxy http://127.0.0.1:8118 http://nq5jmc5rsyo4fiph.onion/
<html><body>You are being <a href="http://nq5jmc5rsyo4fiph.onion/about">redirected</a>.</body></html>
こうして出来たHTTPプロクシをMastodonに使わせるため.env.production
に以下を追記します。
http_proxy=http://127.0.0.1:8118
ALLOW_ACCESS_TO_HIDDEN_SERVICE=true
これでsidekiqとpumaの再起動をするとTorインスタンスと連合を組むことが出来ます。試しにユーザー検索欄から実際に@root@nq5jmc5rsyo4fiph.onion
を検索してみましょう。木之本桜とGentooロゴのアバターのユーザー情報が取得されるはずです。
Cloudflareを利用している場合の注意点
Cloudflareをキャッシュや攻撃防御、etc...に利用中の場合、Torからの接続を介したサーバ間通信で403が出る可能性があります。これはCloudflare側で自動的に危険な接続と判断されてBOT回避ページをCloudflareが差し込んでいる為です。1
CloudflareにはWhitelistに追加することによって接続を信頼する方法があるので、手順を以下にざっくりと記します。なお、Cloudflareの操作方法はそれなりに理解しているものと仮定しています。
ドメインのOverviewからFirewallを選択。
下の方にあるIP Firewallに
t1
と入力、するとドロップダウンにTor
が出てくるのでそれを選択。
標準ではBlock
になっているが、今回はWhitelist化するのでBlock
の部分をクリック。
出てきたドロップダウンからWhitelist
を選択。
最後にAdd
をクリック。
するとルールリストのValue(接続元)にTor (T1)
、Action(動作)にWhitelist
が選択されたものが追加される。
以上でTorネットワークからの接続が拒否されることがなくなるでしょう。
Tor側
MastodonインスタンスをTorネットワーク内に立てる為に必要なこと。
押さえておきたいこと
MastodonにはHTTPプロクシ機能が実装されましたが、Tor内で動かすにあたってその機能を使ってはいけません。HTTPプロクシが使われるのはMastodon自身のソース部分のみであり、Mastodonが依存しているGemがそれを使うとは限りません。もしそれらGemがプロクシを経由しない通信を発生させた場合、そこから情報が漏洩することになります。
Mastodonに限らず、能動的に外部にアクセスするプログラムをTor内で動かす場合は透過プロクシ環境を構築することが必須です。それを怠ったためにサーバー特定に繋がり、権力の餌食となっていった事例が存在します2。
他に、Tor内のサイトは基本的にHTTPSを使わないというのがあります。
手順
流れは以下のとおりです。
- Torをインストールする
- インスタンスのホスト名を生成する
- Torとiptablesの組み合わせによる透過プロクシ環境を構築する。
- Tor向けに特化したMastodonのインストール・設定を行う。
透過プロクシ環境構築・ホスト名生成
透過プロクシの通信の流れは次の下手なポンチ絵のような感じになります。
これはTorインスタンスから別のTorサイトへアクセスする様子。
これはTorインスタンスからClearnetサイトへアクセスする様子。
まずTorとiptables-persistentをインストールします。
apt install tor iptables-persistent
次にTorでアクセスを受ける為とホスト名生成の為のディレクティブを追記します。
TransPort 127.0.0.1:9040
DNSPort 127.0.0.1:5353
VirtualAddrNetwork 127.192.0.0/10
TransPort [::1]:9040
DNSPort [::1]:5353
VirtualAddrNetworkIPv6 [fc00:70a::]/32
AutomapHostsOnResolve 1
HiddenServiceDir /var/lib/tor/mastodon
HiddenServiceVersion 3
HiddenServicePort 80 [::1]:80
こうしてTorを再起動すると、/var/lib/tor/mastodon/hostname
に***.onion
のような新しいホスト名が生成されるのでメモっておきます。
次に、iptablesを使って特定ユーザー(mastodon)から発信された通信をTorに投げるルールを設定します。
まずnatテーブルとfilterテーブルにTORIFYチェーンを作成。
iptables -N TORIFY
iptables -t nat -N TORIFY
取り敢えずlocalhost宛はTorに投げないし拒否もしないようにします。
iptables -t nat -A TORIFY -d 127.0.0.0/8 -j ACCEPT
iptables -A TORIFY -d 127.0.0.0/8 -j ACCEPT
『UDP:53宛の通信を、ローカルのTorがDNSPortとして受け付けている5353へ、TCP全てをTransPortの9040へ投げる。以上のnatテーブルをすり抜けてきたものは拒否』というルールをTORIFYチェーンの末尾に追加します。
iptables -t nat -A TORIFY -p udp --dport 53 -j REDIRECT --to-ports 5353
iptables -t nat -A TORIFY -p tcp -j REDIRECT --to-ports 9040
iptables -A TORIFY -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A TORIFY -j REJECT --reject-with icmp-net-prohibited
DB等、Mastodonの動作に必要なローカルネットワークに載っているサービスをTorに投げないようにするルールをTORIFYの「先頭に」追加(-Aではなく-I)します。また、filterテーブルのTORIFYチェーンにも同じ宛先を追加します。以下はポスグレが192.168.16.2:5432にある場合の例です。redisやMTAに対しても同じ要領で繰り返します。
iptables -t nat -I TORIFY -p tcp -d 192.168.16.2 --dport 5432 -j ACCEPT
iptables -I TORIFY -p tcp -d 192.168.16.2 --dport 5432 -j ACCEPT
- このように、DB等がローカルホストではなく他のホストに散らばっている場合、透過プロクシの例外を設定していくのが面倒くさいので、Mastodonと同一のホストで動かすこと、出来れば通信にUNIXドメインソケットを使う事がおすすめです。
以上のTORIFYチェーンに、ユーザーがmastodonだった時に放り込むようにします。
iptables -A OUTPUT -m owner --uid-owner mastodon -j TORIFY
iptables -t nat -A OUTPUT -m owner --uid-owner mastodon -j TORIFY
ここまででIPv4接続に対する透過プロクシ環境が完成しました。これと同じ要領でIPv6用のiptablesの設定を進めていきます。
# チェーン作成
ip6tables -N TORIFY
ip6tables -t nat -N TORIFY
# localhostは許可。転送無し
ip6tables -t nat -A TORIFY -d ::1 -j ACCEPT
ip6tables -A TORIFY -d ::1 -j ACCEPT
# DNSリクエストとTCPはTorへ
ip6tables -t nat -A TORIFY -p udp --dport 53 -j REDIRECT --to-ports 5353
ip6tables -t nat -A TORIFY -p tcp -j REDIRECT --to-ports 9040
# 確立済みを除いてそれ以外の送出は拒否
ip6tables -A TORIFY -m state --state RELATED,ESTABLISHED -j ACCEPT
ip6tables -A TORIFY -j REJECT --reject-with icmp6-adm-prohibited
# Torへ転送しないもの。ポスグレが[fd00::5432:1]:5432にある場合
ip6tables -t nat -I TORIFY -p tcp -d fd00::5432:1 --dport 5432 -j ACCEPT
ip6tables -I TORIFY -p tcp -d fd00::5432:1 --dport 5432 -j ACCEPT
# mastodonユーザーの時はTORIFYへ
ip6tables -A OUTPUT -m owner --uid-owner mastodon -j TORIFY
ip6tables -t nat -A OUTPUT -m owner --uid-owner mastodon -j TORIFY
以上で透過プロクシ環境が構築されました3。mastodonユーザーに切り替えて、プロクシ使用に関するオプションを指定していないプログラムがTor経由のアクセスを出来ているか、ポスグレ等各種デーモンに接続できるかを確認しましょう
su mastodon
curl -Ss https://check.torproject.org |sed -n "/<h1/,/<\\/h1/p"
psql -h fd00::5432:1 -U hoge
<h1 class="not">
Congratulations. This browser is configured to use Tor.
</h1>
問題が無さそうだったら、iptablesの設定を永続化します。
iptables-save >/etc/iptables/rules.v4
ip6tables-save >/etc/iptables/rules.v6
Tor用インスタンス設定・改変
ここから大体Production Guideに則ってインストールを進めていくことになります。まっさらな状態からインストールするという場合、既に透過プロクシの影響によりgit clone
やbundle
が遅くなっているはずですが驚かないように。以下、clearnetにインスタンスを立てる時と手順が変わる所だけを述べていきます。
Mastodon本体
Tor内のサイトはHTTPSが基本的には使われないのですが、素のMastodonはHTTPSを無効化する設定がどこかのバージョンから削除され、HTTPアクセスをどうやっても強制的にリダイレクトしてしまうので、それを無効化するパッチを当てます。
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 29ba6cad6..df22cf32e 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -33,7 +33,7 @@ class ApplicationController < ActionController::Base
private
def https_enabled?
- Rails.env.production?
+ false
end
def store_current_location
diff --git a/config/initializers/ostatus.rb b/config/initializers/ostatus.rb
index 5773b7290..93961fd19 100644
--- a/config/initializers/ostatus.rb
+++ b/config/initializers/ostatus.rb
@@ -7,7 +7,7 @@ web_host = ENV.fetch('WEB_DOMAIN') { host }
alternate_domains = ENV.fetch('ALTERNATE_DOMAINS') { '' }
Rails.application.configure do
- https = Rails.env.production? || ENV['LOCAL_HTTPS'] == 'true'
+ https = false
config.x.local_domain = host
config.x.web_domain = web_host
diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb
index 3dc0edd6f..85983d259 100644
--- a/config/initializers/session_store.rb
+++ b/config/initializers/session_store.rb
@@ -1,3 +1,3 @@
# Be sure to restart your server when you modify this file.
-Rails.application.config.session_store :cookie_store, key: '_mastodon_session', secure: (Rails.env.production? || ENV['LOCAL_HTTPS'] == 'true')
+Rails.application.config.session_store :cookie_store, key: '_mastodon_session'
.env.production
編集時、Torアクセスを許可するための環境変数をさらに追加します。もちろんLOCAL_DOMAIN
に先程生成された.onionアドレスを指定すること。
ALLOW_ACCESS_TO_HIDDEN_SERVICE=true
- 2.4.0では
HIDDEN_SERVICE_VIA_TRANSPARENT_PROXY=true
が必要でしたが、2.4系列の最新では必要が無くなりました。以前にこのガイドに沿ってインストールした方は削除しても構いません。
nginx
HTTPSを使わなくなったので、それに関する設定を削除し、443番から80番で(というかHiddenServicePortで指定したポートで)listenするようにします。また、server_name
ディレクティブを.onionアドレスにします。
以上の手続きを経てnginx・Mastodon各種サービスを再起動させたら、Torインスタンスの完成です。ユーザー検索で@root@nq5jmc5rsyo4fiph.onion
の情報取得は出来たでしょうか。
代替手段: socksifyによるプロクシ使用方法
透過プロクシを構築する代わりに、socksify(1)を使う方法もあります。あるソフトウェアをsocksify(1)経由で起動させると、通信に関するライブラリコールをフックすることにより元来プロクシに対応していないソフトウェアでもプロクシを通過させるようにすることが出来ます。
メリットは、対象プログラムだけTorプロクシを使わせるように出来るため、作業時に他のサーバーとのやり取りがやりやすいこと、透過プロクシ設定と確認にrootと一般ユーザーを行き来する必要がなく管理が楽であることが挙げられます。デメリットは、環境によってはセグフォを起こす可能性があり、試してみるまでわからないこと、IPv6に対応していないことが挙げられます。
socksifyインストール・設定
socksifyをインストールします。このプログラムはDanteというソフトウェアの一部です。
apt install dante-client
socksifyでどのプロクシにアクセスするかなどの設定を行います。
## 名前解決をSOCKSの先でさせるようにする
resolveprotocol: fake
## bindは素通しさせる
route {
from: 0.0.0.0/0 to: 0.0.0.0/0 via: direct
command: bind
}
## データベースなど、サービスに必要なローカルネットへのアクセスを
## SOCKS接続から除外させるためのルールを列挙していく。
## ポスグレが192.168.16.2:5432にある時
route {
from: 0.0.0.0/0 to: 192.168.16.2/32 port = 5432 via: direct
}
## redisが127.0.0.1:6379にある時
route {
from: 0.0.0.0/0 to: 127.0.0.1/32 port = 6379 via: direct
}
## その他MTAなどがあればそれも同じように
## 列挙が面倒臭ければネットワークの範囲を指定して除外させるという設定も可
#route {
# from: 0.0.0.0/0 to: 127.0.0.0/8 via: direct
#}
#route {
# from: 0.0.0.0/0 to: 192.168.16.0/24 via: direct
#}
## 残りの外向きの通信はTorに投げる
route {
from: 0.0.0.0/0 to: 0.0.0.0/0 via: 127.0.0.1 port = 9050
proxyprotocol: socks_v5
method: none
}
Mastodon本体
透過プロクシの時と同じようにHTTPSの無効化をします。まずは同じパッチを本体に当てて下さい。
次に、プライベートアドレスかのチェックをする機能を完全に抑えるパッチを当てます。socksifyを通した通信を行うと名前解決先のIPアドレスがいつも0.0.0.xになるのですが、これがMastodon内部で行っているプライベートアドレスかのチェックに引っ掛かって例外を投げてしまうためです。
diff --git a/app/lib/request.rb b/app/lib/request.rb
index 397614fac..8227cb03d 100644
--- a/app/lib/request.rb
+++ b/app/lib/request.rb
@@ -101,7 +101,7 @@ class Request
end
def use_proxy?
- Rails.configuration.x.http_client_proxy.present?
+ true
end
def block_hidden_service?
.env.production
に以下を追加します。http_proxy
は指定しません。
ALLOW_ACCESS_TO_HIDDEN_SERVICE=true
サービス起動スクリプト
pumaとsidekiqの起動に、socksifyのラッパースクリプトを経由させるようにします。以下はサービス起動をsystemdユニットで行っている場合の例です。
ExecStart=/usr/bin/socksify /home/mastodon/live/bin/bundle exec puma -C config/puma.rb -b tcp://127.0.0.1:3000
あとは同じようにnginxの設定を行い、各種サービスを再起動させて完成です。……セグフォしなければ。
外部リンク
- Darknet連合対応インスタンスの一覧 — Tor対応が出来たら追加してみましょう。
-
Example of building Tor instance — この記事の前に書いたTorインスタンス構築法です。
英語がダメなので最小限のコメントと必要なコマンドだけが列挙されているので最速でTorインスタンス立てたい人はこちら。但し、UNIXドメインソケットを積極的に使おうとしているのと、yarnのために野良リポジトリを導入したくないとの思いとでその周りで少々Production Guideとの差があります。
-
https://ezoeryou.github.io/blog/article/2017-10-08-australian-police-run-cp.html ↩
-
ところでTor自体は外への接続にIPv6を使うことが出来るのですが、TorのDNS機能を使うと何故かAAAAを返してこないのでIPv6が使われないかのような動作をします。そのため、他のキャッシュDNSを組み合わせて
.onion
だけはTorに、それ以外を1.1.1.1
にフォワードするという運用方法もあります。 ↩