Zenoh 中継サーバー
遠隔 PC と車両 ECU の Zenoh bridge は、EC2 上の中継 router(zenohd)に mTLS で接続します。このページは、その中継サーバーを立てる手順です。遠隔 PC 側の手順は遠隔操作、ECU 側はECU の初期構築を参照してください。
遠隔 PC: joy_node → zenoh-bridge-ros2dds (-n /Ax) ─┐
├─ mTLS → EC2: zenohd(号機ごとに別プロセス・別ポート)
ECU: Autoware ↔ zenoh-bridge-ros2dds (-n /Ax) ─┘
router は号機ごとに別のポートで動かし、router 同士はつなぎません。遠隔 PC と ECU が同じ号機のポートにつながったときだけ、その2台の間でトピックが流れます。
1. EC2 インスタンスを立てる
- OS は Ubuntu 22.04(x86_64)にします。ROS 2 は要りません。router は軽いので、t3.micro 程度で足ります。
- security group で、号機ごとのポートを TCP で開けます。号機ごとのポートは、本体リポジトリの
vehicle/vehicle_ports.shで決まっています。 - EC2 に Elastic IP を割り当て、その IP を DNS 名
zenoh.dev.aichallenge-board.jsae.or.jpの A レコードに登録します。遠隔 PC と ECU はこの名前でつなぎ、server 証明書もこの名前で発行します。自動で付く公開 IP は EC2 を停止・起動すると変わるので、Elastic IP を使います。
2. 証明書を置く
mTLS の証明書は、server 用と client 用で別の CA(minica)から発行します。client CA は号機の組ごとに分けられます。組ごとに別の client CA で client 証明書を発行し、その組の号機の遠隔 PC と ECU に配ります。
証明書は手元の端末で発行します。minica は Go で書かれているので、先に Go を入れておきます(Ubuntu では golang-go パッケージ)。go install で入れた minica は $(go env GOPATH)/bin に入ります。
go install github.com/jsha/minica@v1.1.0
export PATH="${PATH}:$(go env GOPATH)/bin"
mkdir -p ~/zenoh_tls/server
cd ~/zenoh_tls/server && minica --domains zenoh.dev.aichallenge-board.jsae.or.jp
server 証明書は最初に1回だけ発行します。発行し直すと server CA が変わり、配った tls.zip が使えなくなります。client CA と client 証明書は、組ごとに ca_dir を変えて発行します。
ca_dir=client-xxxx # client CA の組の名前。client- で始める
mkdir -p ~/zenoh_tls/"${ca_dir}"
cd ~/zenoh_tls/"${ca_dir}" && minica --domains aichallenge-zenoh-client
openssl x509 -in aichallenge-zenoh-client/cert.pem -noout -ext extendedKeyUsage # TLS Web Client Authentication を含むこと
EC2 に置くのは、server 証明書と鍵、組ごとの client CA(minica.pem)だけです。CA の鍵(minica-key.pem)と client 証明書は置きません。手元の端末から、この3種類だけを同じ構成で EC2 の ~/zenoh_tls_upload に送ります。
cd ~/zenoh_tls
server_name=zenoh.dev.aichallenge-board.jsae.or.jp
ec2=xxxx # EC2 に ssh で入るときの宛先
rsync -a --relative "server/${server_name}/cert.pem" "server/${server_name}/key.pem" client-*/minica.pem "${ec2}:zenoh_tls_upload/"
EC2 内で /etc/zenoh/tls/ の下に置きます。zenohd パッケージを更新・削除すると /etc/zenohd は消えるので、そこには置きません。router は root で動くので、鍵は root だけが読める 0600 にします。
server_name=zenoh.dev.aichallenge-board.jsae.or.jp
src=~/zenoh_tls_upload
for ca in "${src}"/client-*/minica.pem; do
ca_dir=$(basename "$(dirname "${ca}")")
sudo install -d -m 0755 "/etc/zenoh/tls/${ca_dir}"
sudo install -m 0644 "${ca}" "/etc/zenoh/tls/${ca_dir}/minica.pem"
done
sudo install -d -m 0755 "/etc/zenoh/tls/server/${server_name}"
sudo install -m 0644 "${src}/server/${server_name}/cert.pem" "/etc/zenoh/tls/server/${server_name}/cert.pem"
sudo install -m 0600 "${src}/server/${server_name}/key.pem" "/etc/zenoh/tls/server/${server_name}/key.pem"
rm -r "${src}"
遠隔 PC と ECU には、組ごとに tls.zip を配ります。zip の中は、tls/server/minica.pem(~/zenoh_tls/server/minica.pem)と、tls/client/cert.pem・tls/client/key.pem(~/zenoh_tls/<組>/aichallenge-zenoh-client/ の2つ)にします。置き方は遠隔操作の 1-6 とECU の初期構築の 4-4 にあります。
3. 依存を入れる
EC2 内で、Eclipse Zenoh の apt リポジトリから zenohd を、版を指定して入れます。apt upgrade で版が変わらないよう hold します。パッケージに付いてくる zenohd.service は使わないので、無効にします。
sudo install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://download.eclipse.org/zenoh/debian-repo/zenoh-public-key |
sudo gpg --dearmor --yes -o /etc/apt/keyrings/zenoh-public-key.gpg
echo 'deb [signed-by=/etc/apt/keyrings/zenoh-public-key.gpg] https://download.eclipse.org/zenoh/debian-repo/ /' |
sudo tee /etc/apt/sources.list.d/zenoh.list >/dev/null
sudo apt-get update
apt-cache madison zenohd # 入れられる版の一覧
zenohd_version=x.y.z # 上の一覧から選んだ版
sudo apt-get install -y "zenohd=${zenohd_version}"
sudo apt-mark hold zenohd
sudo systemctl disable --now zenohd
4. systemd service を用意する
号機ごとに、router の設定と systemd service を作ります。EC2 内で、号機ごとに vehicle_id、port、ca_dir を変えて、次の2つを実行します。
vehicle_id=A2
port=7448 # この号機のポート(vehicle/vehicle_ports.sh)
ca_dir=client-xxxx # この号機の組の client CA(/etc/zenoh/tls/ の下のディレクトリ名)
server_name=zenoh.dev.aichallenge-board.jsae.or.jp
sudo install -d -m 0755 /etc/zenoh/routers
sudo tee "/etc/zenoh/routers/router-${vehicle_id,,}.json5" >/dev/null <<EOF
{
"mode": "router",
"scouting": {
"multicast": { "enabled": false },
"gossip": { "enabled": false }
},
"listen": {
"endpoints": ["tls/0.0.0.0:${port}"]
},
"connect": {
"endpoints": []
},
"transport": {
"unicast": {
"compression": { "enabled": true }
},
"multicast": {
"compression": { "enabled": true }
},
"link": {
"tls": {
"root_ca_certificate": "/etc/zenoh/tls/${ca_dir}/minica.pem",
"enable_mtls": true,
"listen_private_key": "/etc/zenoh/tls/server/${server_name}/key.pem",
"listen_certificate": "/etc/zenoh/tls/server/${server_name}/cert.pem"
}
}
}
}
EOF
scoutingを無効にし、connectを空にして、router 同士をつながないようにします。root_ca_certificateには、その号機の組の client CA を指定します。bridge の client 証明書はこれで検証されます。enable_mtlsで、client 証明書のない接続を断ります。
sudo tee "/etc/systemd/system/zenoh-router-${vehicle_id,,}.service" >/dev/null <<EOF
[Unit]
Description=zenoh router ${vehicle_id}
After=network-online.target
Wants=network-online.target
[Service]
User=root
ExecStart=/usr/bin/zenohd -c /etc/zenoh/routers/router-${vehicle_id,,}.json5
Restart=always
RestartSec=2s
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now "zenoh-router-${vehicle_id,,}"
systemctl status "zenoh-router-${vehicle_id,,}" --no-pager # active (running)
journalctl -u zenoh-router-a2 に TLS や設定の読み込みのエラーが出ていないことを確かめます。遠隔 PC と ECU からつながるかは、遠隔操作の第2部で確かめます。