[Shuttle] shuttle-secretsで機密情報を取得する

2022.10.27

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Introduction

ShuttleはRustアプリをデプロイ可能な
クラウドプラットフォームです。
* 詳しくはここを参照

例えば、Shuttleで外部のサービスを使用したいケースがあると、
APIキーなどの機密性が高い情報をどこかで管理する必要があります。

そういったケースでは、shuttle-secretsプラグインを使うことで
Shuttleで使用するSecret情報を簡単に扱うことができます。

Environment

  • OS :  MacOS 12.4
  • Rust : 1.64.0
  • curgo-shuttle : 0.7.1

ここを参考に
cargo-shuttleのセットアップをしておいてください。

Try

shuttle-secretsプラグインの使い方は簡単です。
Cargo.tomlに依存ライブラリを追加して、
プロジェクトのルートにSecrets.tomlファイルを作成します。
このファイルに保存したい機密情報を追加します。
※git管理からSecrets.tomlを外すなら.gitignoreに追加しておきましょう

ではやってみます。
まずはプロジェクトの作成。

% cargo shuttle init --axum secret-example-axum && cd secret-example-axum

プロジェクトのルートにSecrets.tomlを作成して、key-valueペアを記述します。

MY_API_KEY = 'It is Secret API key'

そして、src/lib.rsを修正します。
main部分では(アノテーション付きの)shuttle_secrets::SecretStoreを
引数に受け取り、状態を保持するために
axum::extract::Extension機能を使います。

#[shuttle_service::main]
async fn axum(
    #[shuttle_secrets::Secrets] secret_store: SecretStore,
) -> shuttle_service::ShuttleAxum {

    let secret = if let Some(secret) = secret_store.get("MY_API_KEY") {
        secret
    } else {
        return Err(anyhow!("secret was not found").into());
    };

    let state = State { secret };

    let router = Router::new()
        .route("/secret", get(hello_world))
        .layer(Extension(state));

    let sync_wrapper = SyncWrapper::new(router);

    Ok(sync_wrapper)
}

Secret.tomlの値はSecretStore::getでキーを指定すれば取得できます。

ハンドラでは↓のようにExtentionをうけとって使うことができます。

async fn hello_world(Extension(state): Extension<State>) -> &'static str {
    println!("{}",state.secret.to_string());
    "Hello, world!"
}

コード全文はこちら。

use axum::{extract::Extension, routing::get, Router};
use sync_wrapper::SyncWrapper;
use anyhow::anyhow;
use shuttle_secrets::SecretStore;

async fn hello_world(Extension(state): Extension<State>) -> &'static str {
    println!("{}", state.secret); //show secret
    "Hello, world!"
}

#[derive(Clone)]
struct State {
    secret: String,
}

#[shuttle_service::main]
async fn axum(
    #[shuttle_secrets::Secrets] secret_store: SecretStore,
) -> shuttle_service::ShuttleAxum {

    let secret = if let Some(secret) = secret_store.get("MY_API_KEY") {
        secret
    } else {
        return Err(anyhow!("secret was not found").into());
    };

    let state = State { secret };

    let router = Router::new()
        .route("/secret", get(hello_world))
        .layer(Extension(state));

    let sync_wrapper = SyncWrapper::new(router);

    Ok(sync_wrapper)
}

runコマンドを使い、ローカルで起動します。

% cargo shuttle run
Building //rust/secret-example-axum
    Finished dev [unoptimized + debuginfo] target(s) in 1.15s

Starting secret-example-axum on http://127.0.0.1:8000

localhost:8080/secretにアクセスすると、
コンソールにMY_API_KEYの値が表示されます。

Summary

今回はshuttle-secretsを使って、
Secrets.tomlから値を取得する方法について紹介しました。
本稿ではAxumを使いましたが、
Rocket版のサンプルはここにありますので、
こちらもご確認ください。

References