GolangでTLS証明書を作ってgRPCでmTLSする(簡易版)
---
gRPCをするときにmTLSをしたく、オレオレ証明書をGoで作りたかったのでメモです。今回はサインする必要はなく、証明書と秘密鍵のペアだけできれば良いという前提で作っています。
作ったものは https://github.com/atpons/genkey で公開しています。自作のGoで作ったgRPCアプリ等に組み込んで使うことも可能です。
## 秘密鍵を生成
`crypto/rsa`を使って生成します。([実装部分](https://github.com/atpons/genkey/blob/807c9a1fbfa6da61df3bd9bfdb60fb2b740ae65b/pkg/generator/generator.go#L19))
ここで作った鍵はPEM形式でエンコードします。PEM形式とは、OpenSSLのデフォルトであり、ASN.1をBase64でエンコードしたものになります。([実装部分](https://github.com/atpons/genkey/blob/807c9a1fbfa6da61df3bd9bfdb60fb2b740ae65b/pkg/pem/encoder.go#L13-L30))
## オレオレ認証局を作る
認証局は、前で作った秘密鍵から作成します。`crypto/x509`を使うことで証明書を作成することができます。([実装部分](https://github.com/atpons/genkey/blob/807c9a1fbfa6da61df3bd9bfdb60fb2b740ae65b/pkg/pem/encoder.go#L55-L74))
これも同様にPEM形式でエンコードしましょう。([実装部分](https://github.com/atpons/genkey/blob/master/pkg/pem/encoder.go#L55-L74))
## 生成する
一連の生成の流れは[こちら](https://github.com/atpons/genkey/blob/807c9a1fbfa6da61df3bd9bfdb60fb2b740ae65b/main.go)で見るとこができます。これにより、`server.key`と`server.crt`が作成されます。これは、OpenSSLでは以下と同じようなコマンドになります。
```
openssl genrsa -out server.key 2048
openssl req -new -x509 -days 3650 \
-subj "/C=JP/L=Gunma/O=IGGG/CN=dev.iggg.org" \
-key server.key -out server.crt
```
あとはこれをgRPCで使うのみです。使い方は[公式サイト](https://www.grpc.io/docs/guides/auth/)より、以下のようにします。
```
// Client
creds, _ := credentials.NewClientTLSFromFile("server.crt", "dev.iggg.org")
conn, _ := grpc.Dial("localhost:50051", grpc.WithTransportCredentials(creds))
// error handling omitted
client := pb.NewGreeterClient(conn)
// ...
// Server
creds, _ := credentials.NewServerTLSFromFile("server.crt", "server.key")
s := grpc.NewServer(grpc.Creds(creds))
lis, _ := net.Listen("tcp", "localhost:50051")
// error handling omitted
s.Serve(lis)
```
以上でクライアント認証をgRPCに組み込むことができます。また、秘密鍵/証明書の作成もGo上で簡単に作ることができました。さらにこれに少しコードを足して、実際に認証局を使って発行することもできます。
## 参考リンク
- https://shaneutt.com/blog/golang-ca-and-signed-cert-go/
- https://chai2010.cn/advanced-go-programming-book/ch4-rpc/ch4-05-grpc-hack.html