Lessons Learned: Building statically-linked Rust binaries (OpenSSL)

In a couple of modules which used in CyberSift, Rust is slowly making an appearance, depending on the use-case at hand. Generally we develop in GoLang, and one of the advantages was the resulting binary, which pretty much ran anywhere as long as the right architecture and OS are used. We could develop on Ubuntu, and run in CentOS without any issues.

By default however, Rust isn’t quite the same. Rust compiles to dynamically-linked binaries… meaning the resulting executable expects to find certain shared libraries accessible. If your project includes some crates like OpenSSL, moving the default resulting executable from Ubuntu to CentOS will cause “missing library” errors at runtime. The solution is to configure the Rust compiler to output static binaries. The procedure is very well documented here:

https://doc.rust-lang.org/edition-guide/rust-2018/platform-and-target-support/musl-support-for-fully-static-binaries.html

In a nutshell:

### Compile static binary using rust

# 1. Update rustup
rustup update

# 2. Add some MUSL dependencies
sudo apt-get install pkg-config musl-tools

# 3. Add the Linux MUSL toolchain
rustup target add x86_64-unknown-linux-musl`-

Running the above gets you most of the way there, but still gives compilation errors if your project contains OpenSSL crates. The solution is two fold: at the OS level and at Rust level.

@ OS Level : Install OpenSSL development packages

In a (Ubuntu) command prompt:

sudo apt-get install libssl-dev

@ Rust Level : Ensure to use the OpenSSL “vendored” feature

In your Cargo.toml file:

[dependencies]
# ...
openssl = { version = "*", features = ["vendored"] } #https://docs.rs/openssl/0.10.34/openssl/#vendored

And you should be good to go to produce a Rust compiled static binary including OpenSSL with:

cargo build --target x86_64-unknown-linux-musl --release