Posted at

RustでAlpineからHTTPS

More than 1 year has passed since last update.


目的

x86_64-unknown-linux-muslでビルドしたバイナリを使って、DockerコンテナのAlpineからHTTPS通信をしたい!

HTTPS通信と書いていますが、想定しているユースケースはhyperを使った通信処理です。

gothamなど多くのWebFrameworkがhyperを使用しているため、WebServerを作る場合のTipsでもあります。

Ubuntuでビルドして、Ubuntuで起動するなら簡単ですが、muslを使ってBuildし

Alpineで起動するとハマりどころが多いのでメモっておきます。


前提

軽量なDockerイメージにするため、Compile OSとRuntime OSを分けます。


環境


  • Compile OS: ubuntu16.04

  • Runtime OS: alpine3.7

  • Rust: v1.23

  • Target: rust-opensslx86_64-unknown-linux-musl

  • SSL Lib: OpenSSL(openssl-rust)




  • サンプルソース



    • makeで実行




設定


Compile時の設定

OpenSSLを静的リンクするために以下の設定を行います。


  • OpenSSLをmusl-libcを使ってコンパイルし、Staticなlibraryを用意

  • 静的リンクするためのビルド設定を環境変数に設定


    • OPENSSL_STATIC=1

    • 必要に応じてOPENSSL_プリフィックスで始まる環境変数の設定



具体的にはこちらのDockerfileが参考となります。


Runtime時の設定

Linuxディストリビューションによって証明書のパスが違うため、証明書のパスを設定する必要があります。

Alpineで実行する際には以下の設定をします。

$ apk add --no-cache ca-certificates && update-ca-certificates

$ export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
$ export SSL_CERT_DIR=/etc/ssl/certs

他の方法として、Alpine以外のLinuxディストリビューションでも動作させたい場合、openssl-probeを使うことで証明書のパスをRuntime時に解決できます

[dependencies]

openssl-probe = "0.1"

init_ssl_cert_env_vars()を実行する。

extern crate openssl_probe;

fn main() {
openssl_probe::init_ssl_cert_env_vars();
//... your code
}


Docker

上記で紹介したイメージを利用しMultiStageでbuildすると、軽量なDockerイメージを作成できます。

FROM ekidd/rust-musl-builder:stable AS rust-builder

ADD . .
RUN cargo build --release --target x86_64-unknown-linux-musl

FROM alpine:3.7
COPY --from=rust-builder /home/rust/src/target/x86_64-unknown-linux-musl/release/{bin} /usr/local/bin
RUN apk add --no-cache ca-certificates && update-ca-certificates
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
ENV SSL_CERT_DIR=/etc/ssl/certs
CMD ["{bin}"]

サンプルソースでは13Mと軽量なDockerイメージを作ることができました。


備考

証明書が発見できない場合は以下の様なエラーが発生します。

The OpenSSL library reported an error: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed:s3_clnt.c:1269