Amazon Web Services ブログ
Ethereumアカウントを AWS Key Management Service を活用して安全に管理する – Part 1
このブログは、Use Key Management Service (AWS KMS) to securely manage Ethereum accounts: Part 1を翻訳したものです。
Ethereumは、止まらないアプリケーションを作ることが可能な人気のパーミッションレス型のパブリックブロックチェーンです。Ethereumアカウントを持っているすべてのユーザーが利用できます。これらのEthereumアカウントは、秘密鍵と関連する公開鍵で構成されています。
Ethereumなどのパブリックブロックチェーンに参加するユーザーの主な課題は、ブロックチェーンの認証情報を安全に管理することです。
外部所有の Ethereum アカウントは、資金移動やその他の機密操作を含むトランザクションを承認する必要があるため、そのキー マテリアルは慎重に保護する必要があります。
一部の完全に分散化されたアプリケーションでは、ユーザーが独自のキー マテリアルを管理する必要があります。ただし、キー マテリアルの管理を外部のプロセスまたはサービスに委ねるのが望ましいアプリケーションは他にもあります。例えば、ユーザーが利用できないときでもキー マテリアルが頻繁に必要になる場合などです。これは、トークンのステーキングやその他の最新のブロックチェーン アプリケーションの一般的な要件です。
この一連の投稿では、AWS Key Management Service (AWS KMS) を使用してソリューションを作成する方法について説明します。この最初の投稿では、以下の項目について説明します。
-
AWS Cloud Development Kit (AWS CDK) と Python を使用してクラウドインフラストラクチャテンプレートを開発および構築する
-
Docker を使用した AWS CDK ベースの AWS Lambda 関数をバンドルしてデプロイする
-
カスタマーマスターキー (CMK) を使用して、新しい AWS KMS ベースのEthereumアカウントを設定およびプロビジョニングする
2つ目の投稿では、Ethereumの内部の仕組みと、作成した CMK インスタンスを安全なEthereumキー管理サービスとして使用する方法に焦点を当てています。
この一連の3つ目の投稿では、Ethereum改善提案 1559 (EIP-1559) の詳細と、AWS KMS を使用して EIP-1559 トランザクションを署名する方法について説明しています。
ソリューション概要
次の図は、ソリューションアーキテクチャを示しています。
AWS CDK リポジトリで提供されるソリューションの範囲は、赤い点線内の領域に限定されます。
前提条件
このチュートリアルでは、次の前提条件を満たしている必要があります。
- AWS account
- 管理者アクセス権を持つAWS Identity and Access Management (IAM) user
- 設定されたAWS認証情報
- ソリューションをデプロイする予定のワークステーションにDocker, Node.js, Python 3, および pip がインストールされている
AWS CDKを使用してソリューションをデプロイする
AWS CDK は、クラウドアプリケーションリソースを定義およびプロビジョニングするためのオープンソースフレームワークです。JavaScript、C#、Python などの一般的なプログラミング言語を使用します。
AWS CDK command line interface (CLI)を使用すると、AWS CDK アプリケーションを操作できます。AWS CloudFormation テンプレートの合成、セキュリティ変更の確認、アプリケーションのデプロイなどの機能を提供します。
このセクションでは、AWS CDK とサンプルコードを実行するための環境を準備する方法を示します。
Python を使用するときは、venv を使ってプロジェクト固有の仮想環境を作成するのが良いでしょう。AWS CDKもvenvを使用することに対応しています。詳細については、ワークショップ Activating the virtualenv をご覧下さい。
サンプルアプリケーションをインストールするには、以下の手順を実行します。
- AWS CDK をインストールして AWS CDK CLI をテストします。
- GitHub リポジトリからコードをダウンロードし、新しいディレクトリに移動します。
- lambci/lambda: build-python3.8 Docker コンテナをダウンロードする。
- Python パッケージマネージャーを使用して依存関係をインストールします。
- AWS CDK CLI を使用してサンプルコードをデプロイします。
AWS CDK は、次のスクリーンショットに示すように、ソリューションをデプロイするための追加の確認を求めます。
y
を入力して確定します。
これにより、派生した CloudFormation テンプレートが指定した AWS アカウントにデプロイされます。AWS CloudFormation コンソールに移動して aws-kms-lambda-ethereum
スタックを選択すると、デプロイプロセスとスタック (設定とリソース) に関する追加の詳細を確認できます。
デプロイが完了すると、ターミナルには CloudFormation スタック ARN とCMK KeyID
が表示されます。
CMK でEthereumトランザクションに署名する
Ethereumネットワークに公開できるEthereumトランザクションを作成して署名するには、十分な資金があるアカウントが必要です。RinkebyのようなEthereumテストネットのアカウントに資金を供給するには、Rinkeby faucet を 使用できます。
CMK ベースのEthereumアドレスを特定するには、まず CMK ベースのアカウントのパブリック Ethereum アドレスを返す Lambda 関数を実行する必要があります。
- Lambda コンソールで、新しく作成した
aws-kms-lambda-ethereum-ethkmsclientFunction
Lambda 関数を選択します。
Lambda 関数に付けられるランダムなサフィックスは、AWS CDK がどのようにリソースに名前を付けて識別するかに関係しています。
- 関数を選択したら、[Test] タブを選択します。
- 次の JSON スニペットを新しいテストイベントのリクエストとして使用します。
- [Test] を選択します。
テストイベントを正常に実行すると、CMK パブリックキーの一致する Ethereum アドレスが計算され、次のスクリーンショットに示すように、チェックサムが有効なアドレス(eth_checksum_address
)として返されます。
- 指定した CMK ベースのアドレスでEthereumトランザクションを作成して署名するには、次の JSON スニペットを使用して Lambda 関数を実行します。
上記の JSON スニペットでは、Amount
は送信するイーサの量を指定し、dst_address
はEthereumの宛先アドレスを指定し、nonce
は送信アドレスの現在のトランザクション数を指定します。
AWS KMS ベースのアドレスは一度も使用されていないため、最初のトランザクションではnonce
値は 0 でなければなりません。
- [Test] を選択します。
正しいパラメータが指定されている場合、sign
オペレーションは署名されたトランザクションを JSON オブジェクトにラップされた 16 進文字列として返します。
おめでとうございます!AWS KMS CMK が支援するEthereumトランザクションを初めて作成しました。
Amazon Managed Blockchain Ethereum ノードを介してトランザクションを送信するには、「Amazon Managed Blockchain でのEthereumノードのデプロイ」の手順に従います。参照されているブログから新しく作成された Lambda 関数は、署名バージョン 4 認証を使用して、専用の Amazon Managed Blockchain Ethereum ノードで認証されます。次の Node.JS の例に示すように、Ethereum クライアント Lambda 関数への入力パラメータとして 16 進エンコードされた Ethereum トランザクションを指定する必要があります。
内部では何が起きているのか?
ローカルワークステーションにクローンされた CDKソースコードリポジトリには、CloudFormation テンプレートを定義する 2 つのファイルが含まれています。このテンプレートは、ソリューションアーキテクチャに示されている AWS クラウドインフラストラクチャを定義します。
aws-kms-ethereum-accounts
フォルダの中にあるapp.py
はスタック名をaws-kms-lambda-ethereum
と定義し、aws_kms_lambda_ethereum.aws_kms_lambda_ethereum_stack
をスタック定義としてインポートします。
cdk deploy
または cdk synthesize
ステップ中に、このハイレベル ConstructはCloudFormation ステートメントに変換されます。
Python で利用できるハイレベル API では、期待されるタイプ、デフォルト値、または一致する必要がある正規表現を指定できます。
モジュールを追加するには、リポジトリのルートフォルダの setup.py ファイルにリストします。
これらのモジュールは、前述の pip インストール手順でインストールされます。
スタック定義ファイルでは、これらのモジュールを標準的な Python の方法でインポートできます。
aws_kms
モジュールが利用可能になったので、それを使用してEthereum CMK インスタンスを定義できます。
表示されている CMK インスタンス定義について詳しく説明しなければならないことが 2 つあります。
まず、デフォルトの CMK インスタンスは RETAIN
ポリシーで作成されます。つまり、CloudFormation スタックが削除されても、これらのインスタンスは削除されません。特にこのアドレスに資金が送られた後は、キー(またはこの場合はEthereumアカウント)を失いたくないので、これは重要です。
この例では、removal_policy
が明示的に DESTROY
に設定されているため、CMK リソースはこのソリューションの CloudFormation スタックによって自動的に削除され、今後の請求を防ぐことができます。作成された CMK リソースと関連付けられている Ethereum アカウントを CloudFormation スタックと一緒に削除しない場合は、removal_policy を RETAIN に戻す必要があります。
CMK リソースを削除すると、デフォルトで 30 日間の待機期間 が設定され、その後 CMK は消去されます。待機時間の間、CMK はどの暗号化操作にも使用できませんが、回復は可能です。
さらに、CDK キーの定義では、この例ではいわゆるエスケープハッチを使用しています。これらは、低レベルの CloudFormation リソース構造にアクセスするために必要です。
この記事の執筆時点では、標準の AWS CDK では対称キーしか定義できないため、この低レベルの AWS CDK API を使用して、非対称キーの定義とキーの使用法を指定する必要があります。
低レベル API を使用して、key_spec
と key_usage
を指定できます。key_usage
パラメータを ECC_SECG_P256K1
に設定する必要があります。これは、Ethereumで使用されているのと同じ楕円曲線 secp256k1
を表します。
非対称 CMK の場合は、key_usage
を SIGN_VERIFY に設定する必要があります。
aws_kms
モジュールと同様に、Lambda リソースを指定するには aws_lambda
モジュールをインポートする必要があります。
このコード例は aws-kms-ethereum-accounts/aws_kms_lambda_ethereum/aws_kms_lambda_ethereum_stack.py
ファイルにあります。
CloudFormation リソースの作成と設定の他に、AWS CDK では高レベルの Python オブジェクトを使用してアクセス権限を管理することもできます。
この投稿では、Lambda 関数のみが AWS CMK リソースを使用する必要があります。これを確実にするために、CMK オブジェクトで使用できる付与メソッドを使用できます。Lambda リソースの参照と、許可するアクション (‘kms:GetPublicKey’
と ‘kms:Sign’
) を渡す必要があります。
AWS KMS のアクションとアクセス権限の詳細については、「AWS KMS アクセス許可」を参照してください。
Dockerベースのビルド
Lambda 関数で利用可能にする必要がある外部依存関係によっては、Lambda コンストラクターをローカルファイルシステムフォルダーに指定するだけで十分な場合があります。詳細については、「AWS CDK を使用してサーバーレスアプリケーションを作成する」を参照してください。
このフォルダはsynthesizeステップで圧縮され、デプロイステップ中に Amazon S3 にアップロードされます。このメカニズムは、Lambda 関数が Python Lambda ランタイム環境 で利用可能な Boto3 ライブラリのみを必要とする場合にうまく機能します。
追加の依存関係を提供する必要がある場合は、これらの依存関係が Lambda ソースコードファイルとともにルートディレクトリにある必要があります。詳細については、「チュートリアル:Python 3.8 での Lambda 関数の作成」を参照してください。
無効な ELF ヘッダーなど、Lambda 環境でのインポートの問題を防ぐために、特定の Python 依存関係をコンパイルして Linux 環境にインストールする必要があります。
同じ要件がカスタム node.js パッケージとモジュールにも当てはまります。詳細については、「AWS Lambda でのパッケージとネイティブ nodejs モジュールの使用」を参照してください。
Amazon Linux on EC2 ベースのアプローチに加えて、Docker ベースのバンドルを使用して依存関係をインストールし、適切なファイル形式を維持することができます。
これを行うには、Linux Docker コンテナー内でpip install
ステップ (requirements.txt
ファイルにリストされている Lambda 要件を利用可能にするために必要です) を実行します。
AWS CDK で Docker ベースのバンドルを使用するには、Lambda 関数のソースコードへのパスを指定して bundling_config
をaws_lambda.Code.from_asset()
メソッドに渡す必要があります。次のコード例は aws -kms-ethereum-accounts/aws_kms_lambda_ethereum/aws_kms_lambda_ethereum_stack.py
ファイルにあります。
このbundling_config
は、Dockerイメージ、lambci/lambda:build-python3.8
, および依存関係をバンドルするためにDockerコンテナで実行されるコマンドを指定します。
Golang などの他のプログラミング言語で Docker ベースのバンドルを使用する方法の詳細については、「AWS CDK によるアプリケーションのビルド、バンドル、デプロイ」を参照してください。
カスタムバンドル関数の代わりに、Amazon Lambda Python ライブラリ を使用できます。このライブラリは、必要なすべてのモジュールの Lambda 互換 Docker コンテナへのインストールを、ランタイムに従ってすぐに処理します。
Ethereum キー計算
CMK パブリックキーに基づいてEthereumパブリックアドレスを計算する方法の詳細な説明は、このシリーズの第 2 つ目の投稿「AWS KMS を使用して Ethereum ID を安全に管理する:パート 2」にあります。
クリーンアップ
今後料金が発生しないようにするには、リソースを削除してください。次のコマンドを使用して、AWS CDK でこれを行うことができます。
AWS CDK によってデプロイされたスタックは、AWS CloudFormation コンソールを使用して削除することもできます。
結論
この投稿では、AWS CDK を使用して Lambda および CMK リソースを作成する方法を示しました。さらに、Python で AWS CDK オブジェクトにカスタム設定を適用して、Ethereum互換の CMK インスタンスを作成する方法を説明しました。また、AWS CDK によってポリシーとアクセス権限の設定と管理が可能になる方法についても詳しく説明しました。
この連載の 2 つ目の投稿には、Ethereum署名の仕組みと、この記事で作成したリソース (CMK インスタンスと関連する Lambda 関数) を使用して安全に計算する方法についての詳細な説明が含まれています。
著者について
David Dornseiferは、Amazon ProServe ブロックチェーンチームのブロックチェーンアーキテクトです。彼は、顧客がエンドツーエンドのブロックチェーンソリューションを設計、展開、拡張するのを支援することに重点を置いています。
このブログは、ソリューションアーキテクトの渡邊英士が翻訳しました。