※現在、ブログ記事を移行中のため一部表示が崩れる場合がございます。
順次修正対応にあたっておりますので何卒ご了承いただけますよう、お願い致します。

Azure Key Vaultで秘密鍵の管理する


2018年 10月 30日

AZUREソリューション部の土田です。 ブロックチェーン上にサービスを構築する場合、秘密鍵の管理は重要な要素です。 現状、ユーザーに秘密鍵を生成してもらい、各自で安全に管理してもらうといった方式は、現実的ではない場合が多いです。 何らかの手段で、秘密鍵を管理する必要があります。 今回は、Azure Key Vaultを使用した管理方法を紹介します。 Azure Key VaultをWebアプリケーションから使用するためには、 以下のものが必要です。 * Azure Key Vault のシークレットURI * クライアント ID * クライアントのシークレット URI 取得方法、アプリでの設定方法は公式ドキュメント、[Azure Key Vaultの概要](https://docs.microsoft.com/ja-jp/azure/key-vault/key-vault-get-started)および[WebアプリからAzure Key Vaultの使用する](https://docs.microsoft.com/ja-jp/azure/key-vault/key-vault-use-from-web-application)を参照してください。 Key Vaultのクライアントクラスは以下の通りです。 public class KeyVault : ISecretsStore { public string Url { get; } #region private members private readonly KeyVaultClient m_kvClient; private readonly string m_applicationId; private readonly string m_applicationSecret; #endregion /// /// Ctor for Key vault class /// /// The Azure keyvault url /// The azure service principal application id /// The azure service principal application secret public KeyVault(string kvUrl, string applicationId, string applicationSecret) { Url = kvUrl; m_applicationId = applicationId; m_applicationSecret = applicationSecret; m_kvClient = new KeyVaultClient(GetAccessTokenAsync, new HttpClient()); } /// /// Gets the specified secret /// /// The secret /// Secret identifier public async Task GetSecretAsync(string secretName) { try { return (await m_kvClient.GetSecretAsync(Url, secretName)).Value; } catch (KeyVaultErrorException ex) { Console.WriteLine($”Exception while trying to get secret {secretName}, {ex}”); throw; } } /// /// Sets a secret in Azure keyvault /// /// The secret. /// Secret identifier. /// The value to be stored. public async Task SetSecretAsync(string secretName, string value) { try { await m_kvClient.SetSecretAsync(Url, secretName, value); } catch (KeyVaultErrorException ex) { Console.WriteLine($”Exception while trying to set secret {secretName}, {ex}”); throw; } } #region Private Methods private async Task GetAccessTokenAsync( string authority, string resource, string scope) { var clientCredential = new ClientCredential(m_applicationId, m_applicationSecret); var context = new AuthenticationContext(authority, TokenCache.DefaultShared); var result = await context.AcquireTokenAsync(resource, clientCredential); return result.AccessToken; } #endregion } このKey Vaultクライアントを使用して、秘密鍵を管理するAccountクラスを作成します。 Accountクラスには以下のような機能が実装されています。 * 新規に秘密鍵・公開鍵のペアを生成する * 秘密鍵をKey Vaultに保存する * 秘密鍵をKey Vaultから取り出す * 取得した秘密鍵で署名する * トランザクションを作成する(送信する) * 公開鍵を取得する * 現在の残高を取得する サンプルはEthereum版ですが、以下のようになります。 public class EthereumAccount : IBlockchainAccount { private readonly Web3 m_web3; private readonly ISecretsStore m_db; #region Public Methods /// /// Ctor for EthereumAccount class /// /// The database which holds the clients’ private keys. /// The Ethereum node Url. If it’s empty, it will work with the local Ethereum testnet. public EthereumAccount(ISecretsStore database, string nodeUrl = “”) { m_db = database; m_web3 = string.IsNullOrEmpty(nodeUrl) ? new Web3() : new Web3(nodeUrl); } /// /// Creates blockchain account if needed and store the private key in Azure KeyVault /// /// key pair identifier. /// The given private key to store, if not supplied a new private key will be generated public async Task CreateAccountAsync(string identifier, string privateKey = “”) { if (string.IsNullOrEmpty(privateKey)) { var account = EthECKey.GenerateKey(); privateKey = account.GetPrivateKey(); } await StoreAccountAsync(identifier, privateKey); return new EthECKey(privateKey).GetPublicAddress(); } /// /// Returns the public key by the key vault identifier /// /// The user id /// The user’s public address public async Task GetPublicAddressAsync(string identifier) { var privatekey = await GetPrivateKeyAsync(identifier); return new EthECKey(privatekey).GetPublicAddress(); } /// /// Sign a blockchain transaction /// /// The sender identifier, as it saved in the Azure KeyVault (Id, name etc.) /// The receiver public address /// The amount to send in Wei (ethereum units) /// The transaction hash public async Task SignTransactionAsync(string senderIdentifier, string recieverAddress, BigInteger amountInWei) { var senderPrivateKey = await GetPrivateKeyAsync(senderIdentifier); var senderEthKey = new EthECKey(senderPrivateKey); var txCount = await m_web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(senderEthKey.GetPublicAddress()); return Web3.OfflineTransactionSigner.SignTransaction(senderPrivateKey, recieverAddress, amountInWei, txCount.Value); } /// /// Send the transaction to the public node. /// /// The transaction hash /// The transaction result public async Task SendRawTransactionAsync(string hash) { return await m_web3.Eth.Transactions.SendRawTransaction.SendRequestAsync(hash); } /// /// Gets the balance of the provided account – if public address provided get balance by address /// Otherwise get balance by identifier /// /// The public address of the account /// Returns the balance in ether. public async Task GetCurrentBalance(string publicAddress = “”, string identifier = “”) { if (string.IsNullOrEmpty(publicAddress) && string.IsNullOrEmpty(identifier)) { throw new ArgumentNullException(“public address or identifier should be provided”); } if (string.IsNullOrEmpty(publicAddress)) { publicAddress = await GetPublicAddressAsync(identifier); } var unitConverion = new UnitConversion(); return unitConverion.FromWei(await m_web3.Eth.GetBalance.SendRequestAsync(publicAddress)); } #endregion #region Private Methods /// /// Stores the account async. /// /// If the account was created successfully /// Identifier. /// The private key. private async Task StoreAccountAsync(string identifier, string privateKey) { await m_db.SetSecretAsync(identifier, privateKey); } /// /// Returns the private key by the key vault identifier /// /// The user id /// The user’s public key private async Task GetPrivateKeyAsync(string identifier) { return await m_db.GetSecretAsync(identifier); } #endregion } 参考資料 サンプルリポジトリ [https://github.com/Azure/Secured-SaaS-Wallet](https://github.com/Azure/Secured-SaaS-Wallet) 公式ドキュメント [https://docs.microsoft.com/ja-jp/azure/key-vault/key-vault-get-started](https://docs.microsoft.com/ja-jp/azure/key-vault/key-vault-get-started) [https://docs.microsoft.com/ja-jp/azure/key-vault/key-vault-use-from-web-application](https://docs.microsoft.com/ja-jp/azure/key-vault/key-vault-use-from-web-application ) 公式ブログ [https://blogs.msdn.microsoft.com/uk_faculty_connection/2018/03/22/blockchain-azure-samples-and-resources-for-building-interesting-blockchain-projects-and-solutions/](https://blogs.msdn.microsoft.com/uk_faculty_connection/2018/03/22/blockchain-azure-samples-and-resources-for-building-interesting-blockchain-projects-and-solutions/)