環境
Cargo.toml
tokio = { version = "1.17.0", features = ["full"] }
tokio-postgres = "0.7.5"
openssl = "0.10.38"
postgres-openssl = "0.5.0"
問題
tokio-postgresのDocumentを参考にプログラムを書くと、とりあえず以下のようになる。
use dotenv::dotenv;
use std::env;
async fn connect_to_database() -> Result<tokio_postgres::Client, Box<dyn std::error::Error>> {
dotenv().ok();
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let (client, connection) = tokio_postgres::connect(&database_url, tokio_postgres::NoTls).await?;
tokio::spawn(async move {
if let Err(e) = connection.await {
eprintln!("connection error: {}", e);
}
});
Ok(client)
}
(ここではdotenvについては触れない)
ローカル環境のデータベースにならこれでも接続できるが、Herokuにデプロイして実行してみると以下のようなエラーが発生する。
Error: Error { kind: Tls, cause: Some(NoTlsError(())) }
どうやら、SSL/TLSの設定をしなければならないようだ。
おそらくtokio_postgres::connect
の第2引数に指定すればいいのだが、一体何を指定すればいいのだろうか。
解決
いろいろ調べた結果、最終的に接続に成功することができた。
手順
-
openssl
とpostgres-openssl
を追加する - Heroku上で実行する際にSSL証明書を作成するようにする
- 以下のコードで接続ができる
use dotenv::dotenv;
use std::env;
use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
use postgres_openssl::MakeTlsConnector;
async fn connect_to_database() -> Result<tokio_postgres::Client, Box<dyn std::error::Error>> {
dotenv().ok();
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let mut builder =
SslConnector::builder(SslMethod::tls()).expect("unable to create sslconnector builder");
builder
.set_ca_file("tmp/ca.crt")
.expect("unable to load ca.cert");
builder.set_verify(SslVerifyMode::NONE);
let connector = MakeTlsConnector::new(builder.build());
let (client, connection) = tokio_postgres::connect(&database_url, connector).await?;
tokio::spawn(async move {
if let Err(e) = connection.await {
eprintln!("connection error: {}", e);
}
});
Ok(client)
}
SSL証明書の作成は以下のコマンドで行なった。
openssl genrsa -out ./tmp/ca.key 2048 && openssl req -new -key ./tmp/ca.key -out ./tmp/ca.csr -subj '/C=JP/ST=Tokyo/L=Shibuya-ku/O=Oreore CA inc./OU=Oreore Gr./CN=Oreore CA' && openssl x509 -days 3650 -in ./tmp/ca.csr -req -signkey ./tmp/ca.key -out ./tmp/ca.crt
(このコマンドはHeroku上で行う)
参考
おわりに
Rust、SSLの知識が何もない状態で見様見真似でやったのでもっと良い方法がきっとある。