KotlinでgRPC。grpc-javaのTLS with JDKとTLS with OpenSSLの使い方をまとめた。
grpc-java/SECURITY.md
を読み進めるとTLSを有効にしたgRPCサーバの起動には2つのプロトコルプロバイダーを選択できる。
JDK
とOpenSSL
がその2つである。それぞれを有効にする方法は異なりドキュメントも豊富ではない。この機会にまとめていきたいというのが今回のモチベーション。
TLS with JDK
まずはJDKからみていきたい。grpc-java/SECURITY.md
にも記載があるとおり、この方式は推奨されていない。
JavaのTLS実装にALPNがサポートされるのはJava9からでありJava8(Java < 8)を利用している場合は、JVMオプションにjavaagent
を加える。加えたjavaagent
にjetty-alpn-agent
を指定する。
起動までの流れとしては次ようになる。
mkdir -p /var/lib wget -q -O /var/lib/jetty-alpn-agent.jar https://repo.maven.apache.org/maven2/org/mortbay/jetty/alpn/jetty-alpn-agent/2.0.6/jetty-alpn-agent-2.0.6.jar java $JAVA_OPTS -javaagent:/var/lib/jetty-alpn-agent.jar -jar /usr/local/your-project/lib/app-name.jar
これでTLS with JDK
で起動できる。
TLS with OpenSSL
次にOpenSSLである。grpc-java/SECURITY.md
にも記載があるとおりstaticなnetty-tcnativeを使わない場合はOpenSSL version >= 1.0.2
、Apache APR library (libapr-1) version >= 1.5.2.
が必要になる。
DockerコンテナでJVMを起動する場合は事前にインストールをしておく。
apt-get install -y ca-certificates openssl libc6 libapr1
libc6
はprotoBufferを生成する際に必要となる。コンテナ起動時にビルドのタスクに.proto
からprotoBuffer
を生成している。
OpenSSLのハマりポイントがありalpineをコンテナイメージのベースにしていたが上手く起動できなかった。ubuntuベースにするとサクッと起動した。 alpineで起動すると次のようなエラーに遭遇する。netty-tcnativeを使うためにalpineで何かが足りていないのだろう。今後深追いしていきたい。
Caused by: java.lang.UnsatisfiedLinkError: /tmp/libnetty-tcnative3270913869898400045.so: Error relocating /tmp/libnetty-tcnative3270913869898400045.so: SSL_add0_chain_cert: symbol not found at java.lang.ClassLoader$NativeLibrary.load(Native Method) at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1941) at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1824) at java.lang.Runtime.load0(Runtime.java:809) at java.lang.System.load(System.java:1086) at io.netty.util.internal.NativeLibraryUtil.loadLibrary(NativeLibraryUtil.java:36) ... 21 more
ubutuを許容できるのであればubuntuベースでOpenSSLを利用するのがよさそう。
最後に必要なnetty-tcnativeはドキュメントのGetting netty-tcnative from Gradleが参考になる。
これでTLS with OpenSSL
が起動できる。
JDKとOpenSSLを有効にしたDockerfileをまとめた
ここまでJDK
とOpenSSL
についてまとめてきたがコードの断片しかなく参考にならないため、それぞれのDockerfileと動作確認環境をシュッと起動できるdocker-composeをまとめたので詳細はgithubを参照してほしい。
READMEに動作確認手順をまとめているが、docker-composeでJDKとOpenSSLが有効になったgRPCサーバを起ち上げ、gRPCクライアントを含むアプリの起動時にサーバの環境変数を切り替えている。
ここまでgrpc-javaについて触れていたけどgithubに置いているコードはkotlinで書いている。適宜javaに置き換えて参照いただきたい。
grpc-javaはそこまでドキュメントが豊富とは言いづらい。積極的にアウトプットしていきたい。
PagerDutyとAsanaをzapierをつかって連携させてみた
zapierをつかってPagerDutyとAsanaを連携させる方法をまとめます。
モチベーション
PagerDutyのIncidentをSlackに通知をして、その対応をAsanaでタスク化して運用をするうえで Asanaのタスク化
を自動化させたい。そんなときzaiperは zap
という単位でAサービスで発生したイベントをトリガーにBサービスにアクションを行うという一連の運用フローを自動化することができる。
PagerDuty
でIncidentが新しく作られたら Asana
でタスクを作成する、このような運用フローがzaiperのダッシュボードからポチポチと設定するだけで自動化できる。
連携させてみた
zaiperのダッシュボードは直感的で設定フローの理解もすぐにできた。
PagerDutyをトリガーにAsanaでタスクを作るというフローだけど、他にもステップを追加することができる。例えばGoogleCalendarにイベントを追加したりgithubでissue化したり認証できるサービスであれば多様なステップを作ることができる。
ここからはzaiperの設定フローで補足したいところをまとめていく。
設定フローの補足
PagerDutyの設定
- Incidentの発生条件はオプションで設定できる。
- Incidentが誰にアサインされたかを指定したり、どのイベントタイプをトリガーにするか指定できる。
- 今回は誰にアサインされたかは指定せず、イベントタイプは
Trigger
とした。つまり認知していない新規のIncidentの発生がトリガーとなる。
- zaiperはPagerDutyのイベントを検知するためにEndpoinURLを生成するのでPagerDuty側でそのURLをWebhookに追加する必要がある。
Asanaの設定
- 今回はAsanaのタスクを作成するアクションにしたが、
Story
やProject
など他のアクションも設定できる。 - タスクを生成するうえでタスクのタイトルやメモなどをテンプレートとして設定できる。
- PagerDutyのIncidentから要素を取得することができるので、タイトルにIncidentの
ServiceName
やメモにIncidentのURL
やStatus
などを変数としてテンプレート化できる。 - 今回は次のように設定してみた。
- PagerDutyのIncidentから要素を取得することができるので、タイトルにIncidentの
- その他にもタスクを誰にアサインするかなどタスクの要素を細かく設定できる。
動かしてみる
あらかじめPagerDutyとAsanaはSlackと連携させているのでIncidentとタスクのイベントに応じてSlackに通知されることが確認できた。
実際にPagerDutyでIncidentを発生させてみて、Incidentが発生した通知の後にAsanaのタスクが作成されていることが分かる。
AsanaのタスクにはIncidentの情報が参照されていてzaiperで設定したAsanaのテンプレートが適応されていることが確認できる。
まとめ
zaiperをつかって運用フローの自動化を試してみた。zaiperのダッシュボードは使いやすい印象でつくってる方たちも好印象だった。
zaiperのプランはzapとタスクの数でグレードが分かれている。あとはzapierが稼働するのがBasicだと15分毎
でBusiness以降は5分毎
なので運用要件に合わせたプラン選択が必要だと感じた。
他のzapの組み合わせとしてはGoogleカレンダーにイベントが登録されたのをトリガーにSlackにイベントを通知する連携方法なども試しみたりした。
GoogleカレンダーのイベントをトリガーにしてSlackで告知するような運用はよくあるケースなので、まずはこういったところから導入を始めて、運用に合わせてzapを増やしていくとよさそうである。
KotlinでgRPC。SSL/TLSを有効にする方法をまとめた。
前回のエントリではgrpc/grpc-javaをベースにkotlinでgRPCを試しました。今回はSSL/TLSを有効にする方法をまとめていきます。grpc/grpc-java/SECURITY.mdを参照しながら進めました。
証明書を準備する
手元に適当な証明書がなかったのでgrpc-go/testdataにある証明書を利用しました。
Subject Alternative Name
を確認するとマルチドメインに*.test.google.fr
, waterzooi.test.google.be
, *.test.youtube.com
が定義されていますので、hostsにwaterzooi.test.google.be
を追加しました。
openssl x509 -text -in ./server1.pem
127.0.0.1 waterzooi.test.google.be
OpenSSLを有効にする
netty-tcnativeをプロジェクトに追加します。
buildscript { repositories { mavenCentral() } } dependencies { compile 'io.netty:netty-tcnative-boringssl-static:1.1.33.Fork26' }
netty-tcnativeはDynamic
とStatic
があります。このエントリではStatic
を利用しました。grpc/grpc-java/SECURITY.mdを参照するとStatic
の利用を推奨していますがOpenSSLのセキュリティパッチが提供された場合、Static
ではパッチ反映が即座には行われないためプロジェクト方針によってはDynamic
の利用を検討する必要があります。
GrpcSslContextsでSslContextを生成する
サーバ側とクライアント側ではGrpcSslContexts
に定義されているforServer
とforClient
のメソッドをつかってSslContext
を生成します。
サーバ側
(serverBuilder as NettyServerBuilder).sslContext( GrpcSslContexts.forServer( File(classLoader.getResource("server1.pem").file), File(classLoader.getResource("server1.key").file)) .clientAuth(ClientAuth.OPTIONAL) .build())
クライアント側
NettyChannelBuilder.forAddress("waterzooi.test.google.be", 50051) .sslContext( GrpcSslContexts.forClient() .trustManager(File(classLoader.getResource("ca.pem").file)) .build()) .build()
コードを公開しています
このエントリのコードはgithubに公開しています。
SSL/TLSを有効にするにあたり情報が少ない印象をもちました。java or kotlinで実装をする方に少しでも参考になると嬉しいです。