チュートリアル: Memorystore for Redis でのアプリケーション レベルの暗号化

このチュートリアルでは、Google Cloud 上の Memorystore for Redis ストアに格納されたコンテンツを暗号化するために、Cloud Key Management Service(Cloud KMS)API と通信するアプリケーションを作成する方法について説明します。このチュートリアルで使用するコンセプトの詳細については、このチュートリアルに関連するドキュメントのアプリケーション レベルの暗号化: Memorystore for Redisをご覧ください。

このチュートリアルは、Google Cloud、Linux、鍵管理サービス、Redis、Git、Maven、Java に精通しているアプリケーション デベロッパーやセキュリティの専門家を対象としています。

このチュートリアルは、テスト駆動型開発の手法と同様に段階的に構成されています。まず、テストを実行します。次に、テストに変更を加えて、テストを失敗させます。最後に、テストの失敗部分を取り除くための措置を講じます。

目標

  • 1 組の Memorystore for Redis インスタンスを作成してテストする。
  • データを変換し、Redis に読み込む。
  • 独自の鍵管理システム(KMS)を作成する。
  • 暗号鍵の管理プロセスについて学習する。

料金

このチュートリアルでは、課金対象である次の Google Cloud コンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。新しい Google Cloud ユーザーは無料トライアルをご利用いただけます。

このチュートリアルを終了した後、作成したリソースを削除すると、それ以上の請求は発生しません。詳しくは、クリーンアップをご覧ください。

始める前に

  1. Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。

    [プロジェクトの選択] ページに移動

  2. Cloud プロジェクトに対して課金が有効になっていることを確認します。プロジェクトに対して課金が有効になっていることを確認する方法を学習する

  3. Compute Engine, Cloud KMS, and Memorystore for Redis API を有効にします。

    API を有効にする

  4. Cloud Console で、Cloud Shell をアクティブにします。

    Cloud Shell をアクティブにする

プロジェクト VM インスタンスの作成

  1. Cloud Shell で、gcloud コマンドライン ツール構成を設定します。

    gcloud config set project PROJECT_NAME
    gcloud config set compute/zone us-central1-f
    gcloud config set compute/region us-central1
    

    PROJECT_NAME を、このチュートリアルで使用する Google Cloud プロジェクトの名前に置き換えます。

  2. 仮想マシン(VM)インスタンスを作成します。

    gcloud compute instances create ale-instance \
        --machine-type=n1-standard-1 \
        --image-family=debian-10 \
        --image-project=debian-cloud \
        --boot-disk-size=200GB
    
  3. [VM インスタンス] ページのユーザー コンソールで、[SSH] をクリックして VM インスタンスにログインします。

    Cloud Shell の SSH ボタン

    新しいウィンドウが開きます。このチュートリアルでは、Cloud Shell ウィンドウに対して、プロジェクト ウィンドウが呼び出されます。チュートリアルの一部の手順を完了するには、プロジェクト ウィンドウと Cloud Shell ウィンドウを切り替える必要があります。

Git と Maven のインストール

  • プロジェクト ウィンドウで、GitMaven をインストールします。

    sudo apt-get install git wget maven
    

    次の警告が表示される場合があります。

    E: Could not get lock /var/lib/dpkg/lock
    

    このエラーは、VM 起動スクリプトがまだ実行中の場合に発生することがあります。このエラーが表示された場合は、1~2 分待ってから上記のコマンドを再実行してください。

Java Development Kit(JDK)のインストール

  1. プロジェクト ウィンドウで、ディレクトリを変更します。

    cd /tmp
    
  2. Java のインストール パッケージをダウンロードします。

    wget https://download.java.net/java/GA/jdk14.0.1/664493ef4a6946b186ff29eb326336a2/7/GPL/openjdk-14.0.1_linux-x64_bin.tar.gz
    

    出力は次のようになります。

    --2020-05-17 19:21:39--  https://download.java.net/java/GA/jdk14.0.1/664493ef4a6946b186ff29eb326336a2/7/GPL/openjdk-14.0.1_linux-x64_bin.tar.gz
    Resolving download.java.net (download.java.net)... 23.213.168.108
    Connecting to download.java.net (download.java.net)|23.213.168.108|:443... connected.
    HTTP request sent, awaiting response... 200 OK
    Length: 198665889 (189M) [application/x-gzip]
    Saving to: 'openjdk-14.0.1_linux-x64_bin.tar.gz'
    oenjdk-14.0.1_linux-x64_  80%[======================>      ] 151.72M  4.86MB/s    eta 8s
    
  3. Java Virtual Machine(JVM)ディレクトリの内容を表示します。

    ls /usr/lib/jvm/
    

    次のような出力が表示される場合があります。

    ls: /usr/lib/jvm/: No such file or directory
    

    この出力は、フォルダが存在しないことを示しています。その場合は、フォルダを作成します。

    sudo mkdir /usr/lib/jvm
    
  4. JDK をインストールします。

    cd /usr/lib/jvm
    sudo tar xzf /tmp/openjdk-14.0.1_linux-x64_bin.tar.gz
    export JAVA_HOME=/usr/lib/jvm/jdk-14.0.1/
    

tinkCryptoHelper リポジトリのクローンの作成

次の手順では、このチュートリアルで使用する Java アプリケーションである tinkCryptoHelper のコード リポジトリのクローンを作成します。

  1. プロジェクト ウィンドウで、ホーム ディレクトリに移動します。

    cd ~
    
  2. tinkCryptoHelper コードベースのクローンを作成します。

    git clone https://github.com/google/tinkCryptoHelper.git
    cd tinkCryptoHelper
    

tinkCryptoHelper アプリケーションのビルドの作成

次の手順では、mvn ツールを使用して、Java ソースコードから実行可能な Java パッケージに tinkCryptoHelper の最初のビルドを行います。

  1. プロジェクト ウィンドウで、パッケージをビルドします。

    mvn package
    

    出力は次の内容で終了します。

    [INFO] --------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] --------------------------------------------------------------------
    [INFO] Total time: 13.880 s
    [INFO] Finished at: 2020-05-17T19:29:13+00:00
    [INFO] Final Memory: 19M/116M
    [INFO] --------------------------------------------------------------------
    

システムをテストする

以降のセクションでは、構成変更後にシステムがどのように動作するかを評価するテストを行います。リポジトリ内のコードには、14 個の統合テストがあります。各テストでは、システムが適切に機能すること確認するために、さまざまな動作をテストします。重要なことは、テストは構成に依存するということです。たとえば、システムに接続された Redis システムがない場合、テストは Redis 接続のテストを試みません。

基本的な機能テスト

tinkCryptoHelper のビルドを作成すると、基本的な機能をテストする準備が整います。ここでは、オンラインの Redis データベースがないため、接続テストは失敗しません。

  1. プロジェクト ウィンドウでテストを実行します。

    mvn test
    

    出力は次のようになります。

    [INFO] -------------------------------------------------------
    [INFO]  T E S T S
    [INFO] -------------------------------------------------------
    [INFO] Running com.google.samples.kms.ale.AppTest
    AES256_GCM encryption cipherlength: 64
    Envelope encryption cipherlength: 224
    [INFO] Tests run: 14, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.057 s - in com.google.samples.kms.ale.AppTest
    [INFO]
    [INFO] Results:
    [INFO]
    [INFO] Tests run: 14, Failures: 0, Errors: 0, Skipped: 0
    [INFO]
    [INFO] --------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] --------------------------------------------------------------------
    [INFO] Total time: 7.087 s
    [INFO] Finished at: 2020-05-17T19:34:21+00:00
    [INFO] Final Memory: 12M/56M
    

    主な結果は Tests run: 14, Failures: 0, Errors: 0, Skipped: 0 です。この出力は、すべてのテストが正常に実行されたことを示します。

インスタンスなしで Redis 接続をテストする

完全統合テストでは、アプリケーション(tinkCryptoHelper)が Redis と通信する必要があります。アプリケーションは、prefs.xml ファイルから Redis 接続文字列情報を取得します。前のセクションで実行した最初のテストの一環として、tinkCryptoHelper アプリケーションでは Java ソースコードのクラス構造に従って、さまざまな場所にいくつかの prefs.xml ファイルが作成されました。

演習として、prefs.xml ファイルで redisIsOnlinetrue に設定します。Redis インスタンスは、まだ作成する必要があるため、オンラインではありません。このテストでは、接続テストは失敗になります。

  1. プロジェクト ウィンドウで、ソースコード構造内の XML ファイルを一覧表示し、正しい prefs.xml ファイルを見つけて編集します。

    find ~/.java -name '*.xml'
    

    出力は次のようになります。

    /home/USERNAME/.java/.userPrefs/com/google/samples/kms/ale/prefs.xml
    /home/USERNAME/.java/.userPrefs/com/google/samples/kms/prefs.xml
    /home/USERNAME/.java/.userPrefs/com/google/samples/prefs.xml
    /home/USERNAME/.java/.userPrefs/com/google/prefs.xml
    /home/USERNAME/.java/.userPrefs/com/prefs.xml
    

    この出力で、USERNAME はログインに使用したユーザー名です。

  2. Maven を使用して Redis をテストする準備をするには、nano(または vi などの別の UNIX エディタ)で次のファイルを開きます。

    nano ~/.java/.userPrefs/com/google/samples/kms/ale/prefs.xml
    

    この構成ファイルの内容は次のようになります。

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <!DOCTYPE map SYSTEM "http://java.sun.com/dtd/preferences.dtd">
    <map MAP_XML_VERSION="1.0">
      <entry key="com.google.samples.kms.ale.AppTest" value="true"/>
    </map>
    
  3. 構成ファイルの map セクションに 2 番目のエントリを追加します。

    <entry key="redisIsOnline" value="true"/>
    

    map セクションは次のようになります。

    <map MAP_XML_VERSION="1.0">
      <entry key="com.google.samples.kms.ale.AppTest" value="true"/>
      <entry key="redisIsOnline" value="true"/>
    </map>
    
  4. ファイルを保存して終了します。

  5. テストを実行します。

    mvn test
    

    Redis がオンラインではないため、出力には次のようなエラーが表示されます。

    [ERROR]   AppTest.testRedis3_2:86 » JedisConnection Failed connecting to host 127.0.0.2:...
    [ERROR]   AppTest.testRedis4_0:79 » JedisConnection Failed connecting to host 127.0.0.1:...
    [ERROR]   AppTest.testRedisRoundtripRedis3_2:93->testRedisRoundtripRedisSeries:105->testRedisRoundtripClear:149 » JedisConnection
    [ERROR]   AppTest.testRedisRoundtripRedis4_0:99->testRedisRoundtripRedisSeries:105->testRedisRoundtripClear:149 » JedisConnection
    [INFO]
    

    エラーを発生させました。次のセクションでは、このエラーを修正します。

Redis インスタンスの作成

前の手順では、接続先の Redis インスタンスがないため、テストが失敗しました。これを修正するには、Redis インスタンスを作成する必要があります。tinkCryptoHelper アプリケーションでテストを実行するには、異なるリリース バージョンの 2 つの Redis インスタンスが必要です。テストは両方のインスタンスで実行されます。

Redis インスタンスを作成する

  1. Cloud Shell で、異なるバージョンの 2 つの Redis インスタンスを作成します。

    gcloud redis instances create redis32 --redis-version redis_3_2 --region us-central1
    gcloud redis instances create redis40 --redis-version redis_4_0 --region us-central1
    

    Redis 3.2 と Redis 4.0 インスタンスの作成には数分かかります。

  2. インスタンスに関する情報を表示します。

    gcloud redis instances list --region us-central1
    

    出力は次のようになります。

    INSTANCE_NAME  VERSION    REGION       TIER   SIZE_GB  HOST            PORT  NETWORK  RESERVED_IP        STATUS  CREATE_TIME
    redis32        REDIS_3_2  us-central1  BASIC  1        10.126.141.179  6379  default  10.126.141.176/29  READY   2020-05-17T19:47:15
    redis40        REDIS_4_0  us-central1  BASIC  1        10.55.16.163    6379  default  10.55.16.160/29    READY   2020-05-17T19:50:44
    
  3. 出力から IP アドレスをコピーします。次の手順ではホスト IP アドレスが必要になります。

Redis インスタンスの IP アドレスを構成する

次の手順では、Redis インスタンスがある場所を tinkCryptoHelper アプリケーションに指示します。

  1. プロジェクト ウィンドウで、先ほど開いた prefs.xml ファイルを開きます。

    nano ~/.java/.userPrefs/com/google/samples/kms/ale/prefs.xml
    
  2. 構成ファイルの map セクションで、前に追加したエントリの後に次の 2 行を追加します。

    <entry key="redisHost3_2" value="IP_ADDRESS3.2" />
    <entry key="redisHost4_0" value="IP_ADDRESS4.0" />
    

    以下を置き換えます。

    • IP_ADDRESS3.2: 先ほどコピーした redis32 インスタンスの値
    • IP_ADDRESS4.0: 先ほどコピーした redis40 インスタンスの値
  3. ファイルを保存して終了します。

  4. テストを実行します。

    mvn test
    

    出力は次のようになります。

    Set of 5000 cleartext values took on average 2µs on host 10.126.141.179
    Get of 5000 cleartext values took on average 1µs on host 10.126.141.179
    Set of 5000 encrypted values took on average 40µs on host 10.126.141.179
    ...
    Envelope encryption cipherlength: 224
    [INFO] Tests run: 14, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 8.312 s - in com.google.samples.kms.ale.AppTest
    [INFO]
    [INFO] Results:
    [INFO]
    [INFO] Tests run: 14, Failures: 0, Errors: 0, Skipped: 0
    [INFO]
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 12.470 s
    [INFO] Finished at: 2020-05-17T20:55:46+00:00
    [INFO] Final Memory: 12M/56M
    [INFO] ------------------------------------------------------------------------
    

Redis との統合テストが正常に完了しました。

データを変換して Redis に読み込む

前のセクションで、テストには複数の副作用がありました。そのうちの 1 つは、Redis インスタンスにデータを挿入することでした。統合テストを完了するには、このプロセスが必要です。独自のデータでシステムをテストする場合は、次の手順で説明する tinkCryptoHelper を使用したデータを暗号化する方法を行ってから、独自のデータで Redis データベースを更新します。Git リポジトリにはサンプルの data.csv ファイルが用意されていますが、独自のファイルを作成することもできます。

  1. プロジェクト ウィンドウで、JAR ファイルを作成します。

    mvn assembly:single
    
  2. data.csv ファイルを Redis import コマンドと互換性のあるファイルに変換します。

    $JAVA_HOME/bin/java -jar target/cryptoHelper-1.0-jar-with-dependencies.jar data.csv redis_import.txt
    

    redis_import.txt ファイルには、Redis にデータを挿入するための一連のコマンドが含まれています。

  3. コマンドライン インターフェース(CLI)を含む Redis ツールをインストールします。

    sudo apt-get install redis-tools
    
  4. 既存のデータを Redis データベースに保持しない場合は、次のことを行います。

    1. Redis CLI を使用して Redis に接続します。

      redis-cli -h IP_ADDRESS
      

      IP_ADDRESS は、先ほどコピーした IP アドレスの 1 つに置き換えます。

    2. データベースのデータを削除します。

      FLUSHALL
      exit
      
  5. データを読み込みます。

    cat redis_import.txt | redis-cli -h IPADDRESS --pipe
    
  6. データが存在するかどうかをテストするには、Redis に再度接続してキーを取得します。

    1. Redis に接続します。

      redis-cli -h IP_ADDRESS
      
    2. キーを取得します。

      get 1
      

      次のような出力が表示されます。

      Hello World
      

      独自のデータを使用した場合、キーと値が異なることがあります。

独自の KMS を作成する

このチュートリアルの KMS 暗号鍵は、作成したプロジェクトにではなく、tink-test-infrastructure という名前の Google 所有の Cloud プロジェクトに属しています。このサンプル プロジェクトには、暗号鍵を公開して使用できるようにするために使用される KMS があります。

独自の KMS インスタンスと鍵を作成するには、サービス アカウントを作成し、そのアカウントをCloud KMS CryptoKey の暗号化 / 復号の IAM ロールroles/cloudkms.cryptoKeyEncrypterDecrypter)と関連付けます。このロールがあると、サービス アカウントは KMS キーリングを作成し、鍵を追加できます。

サービス アカウントの設定

  1. Cloud Shell で、新しいサービス アカウントを作成します。

    gcloud iam service-accounts create tink-509 \
        --description="Account for KMS" \
        --display-name="tinkAccount"
    
  2. Cloud Console で、[IAM と管理] ページに移動します。

    [IAM と管理] ページに移動

  3. [追加] をクリックし、サービス アカウント tink-509Cloud KMS CryptoKey の暗号化 / 復号のロールに追加します。

    Cloud Console で IAM ロールを追加する

  4. 変更を保存して Cloud Console を終了します。

  5. プロジェクト ウィンドウで、新しいサービス アカウントの JSON 認証情報キーファイルを保存します。

    1. 古い認証情報のファイルをバックアップします。

      mv kmsServiceAccountCredentials.json kmsServiceAccountCredentials.json.old
      
    2. ログインしていることを確認します。次のコマンドを実行して、OAuth の手順を行います。

      gcloud config set project PROJECT_ID
      gcloud auth login
      

      PROJECT_ID を Cloud プロジェクト ID に置き換えます。

    3. 新しい認証情報キーファイルを作成します。

      gcloud iam service-accounts keys create kmsServiceAccountCredentials.json \
          --iam-account tink-509@app-lev-enc.iam.gserviceaccount.com
      

      出力は次のようになります。

      created key [c09dfea3892d6c309333f1998caf35845dc50608] of type [json] as [kmsServiceAccountCredentials.json] for [tink-509@app-lev-enc.iam.gserviceaccount.com]
      

Cloud KMS キーリングと鍵を作成する

  1. Cloud Shell で、Cloud KMS キーリングを作成します。

    gcloud kms keyrings create "unit-and-integration-testing" --location "global"
    gcloud kms keys create aead-key --purpose=encryption --location "global" \
        --keyring unit-and-integration-testing
    
  2. IAM ポリシーに roles/cloudkms.cryptoKeyEncrypterDecrypter IAM ロールを追加します。

    gcloud kms keys add-iam-policy-binding \
        aead-key --location global --keyring unit-and-integration-testing \
        --member serviceAccount:tink-509@app-lev-enc.iam.gserviceaccount.com \
        --role roles/cloudkms.cryptoKeyEncrypterDecrypter
    

    このロールにより、サービス アカウントは、その鍵にアクセスできるようになります。

以前の Redis データを削除する

上記のテストでは、Redis データベースにサンプルデータが入力されますが、暗号化は古い鍵に基づいていました。データをクリアして古いキーを削除する必要があります。

  1. Cloud Shell で、すべての Redis インスタンスを一覧表示します。

    gcloud redis instances list --region us-central1
    

    作成したインスタンスの IP アドレスをメモします。

  2. 2 つの Redis インスタンスに接続します。

    redis-cli -h IP_ADDRESS
    

    前述のコマンドを 2 回実行します。IP_ADDRESS を、各インスタンスの IP アドレスに置き換えます。

  3. データベースのデータを削除します。

    FLUSHALL
    exit
    

    このチュートリアルで、この後に最終テストを実行する際は、Redis テーブルのデータは新しい鍵で暗号化されます。

tinkCryptoHelper が新しい KMS を見つける場所を指定する

  1. プロジェクト ウィンドウで、UNIX エディタを使用して KMS pref.xml ファイルを開きます。

    nano ~/.java/.userPrefs/com/google/samples/kms/prefs.xml
    
  2. 2 つ目のエントリとして、次の行を追加します。

    <entry key="keyResourceIdUri" value="gcp-kms://projects/PROJECT_ID/locations/global/keyRings/unit-and-integration-testing/cryptoKeys/aead-key"/>
    

    PROJECT_ID をクラウド プロジェクト ID に置き換えます。

最終テストを実行する

  • プロジェクト ウィンドウでテストを実行します。

    mvn test
    

    出力は次のようになります。

    ...
    Envelope encryption cipherlength: 224
    [INFO] Tests run: 14, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 8.312 s - in com.google.samples.kms.ale.AppTest
    ...
    

    KMS と鍵を正常に作成し、それを使用して tinkCryptoHelper をテストしました。

クリーンアップ

このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにするには、プロジェクトを削除します。

プロジェクトの削除

  1. Cloud Console で [リソースの管理] ページに移動します。

    [リソースの管理] に移動

  2. プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
  3. ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。

次のステップ