安全に `cargo` で `ssh` する
GitHub のプライベートレポジトリに依存する Rust アプリケーションを ビルドする Dockerfile の書き方について説明します。 結論としては、以下の Dockerfile をベースにアプリケーションごとにアレンジするとよさそうです。
# Use the official Rust image as the base image
FROM rust
WORKDIR /app
# Build the application with cargo, using SSH
COPY Cargo.lock Cargo.toml ./
COPY src ./src
RUN --mount=type=ssh \ cargo build --release
CMD ["./target/release/your-executable"]
ビルドするときは以下です。
$ DOCKER_BUILDKIT=1 docker build . --ssh default
背景
私たちのチームは Rust アプリケーションの開発に従事しています。チームメンバは全員、唯一の GitHub Enterprise Organization に所属しています。私たちの Rust アプリケーションやライブラリのソースコードはチームメンバだけがアクセスできるプライベートレポジトリにホスティングしています。 アプリケーションが git レポジトリにあるライブラリに依存する場合は、アプリケーションの Cargo.toml を以下のように記述します。
[dependencies]
yourrustlib = { git = "ssh://git@github.com/.../yourrustlib.git", branch = "main" }
このときビルド環境は、このレポジトリにアクセスする権限を有する必要があります。したがって、このアプリケーションを Docker コンテナイメージとしてビルドする場合は何らかの工夫が必要です。うっかり、認証情報が漏洩してしまうことのない安全な方法を調べました。
Prerequisites
- Docker BuildKit が使えること
- ホストPCからSSHでプライベートレポジトリにアクセスできること
- トラブルシューティングするときは最低限
ssh -T git@github.comが疎通することを確認します。 - https://docs.github.com/ja/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent
安全にビルド時にSSHする
--mount=type=ssh と書いてある RUN コマンドだけは、ホストPC上のように SSH が使えます。 Dockerfile RUN --mount=type=ssh \ cargo build --release この手順の優れている点は以下です。 - 秘密鍵が曝される必要はありません。 - 他のビルド手順では認証情報をうっかりイメージに残してしまう可能性があります。仮に安全だとしても、ただの一度も秘密鍵は曝されるべきではないと思います。 - SSH フォワーディングは明示的です。 - 意図しないタイミングで SSH アクセスすることがないので安心できます。 - Dockerfile はチームメンバーに共通です。 - ホストPC上で依存ライブラリに SSH アクセスができていれば、だれでもそのままビルドできるはずです。
— https://medium.com/@tonistiigi/build-secrets-and-ssh-forwarding-in-docker-18-09-ae8161d066
トラブルシューティング
Cargo で git cargo の built-in git は ~/.ssh/config を読まない
ので、ホストPCでは CARGO_NET_GIT_FETCH_WITH_CLI を true にしていました。はじめとくに何も考えず Dockerfile に以下を書いていました。
# Configure cargo to use SSH
ENV CARGO_NET_GIT_FETCH_WITH_CLI=true
— https://doc.rust-lang.org/cargo/appendix/git-authentication.html#ssh-authentication — https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli
この場合、以下のように接続先の公開鍵を known_hosts に追加する必要があります。
# Add GitHub's SSH key to known hosts
RUN mkdir -p -m 0600 ~/.ssh && \ ssh-keyscan github.com >> ~/.ssh/known_hosts
追加していない場合は Host key verification failed. エラーになります。
$ docker build .
// ...
#16 1.038 Host key verification failed.
#16 1.039 fatal: Could not read from remote repository.
#16 1.039 #16 1.039 Please make sure you have the correct access rights
#16 1.039 and the repository exists.
// ...
今回の手順では SSHフォワーディングしているので CARGO_NET_GIT_FETCH_WITH_CLI は false のまま、cargo の built-in git を使えば良いです。