クライアント側の暗号化が有効になっている場合、オブジェクトはOSS (Object Storage Service) にアップロードされる前にローカルで暗号化されます。 オブジェクトを復号化できるのは、顧客マスターキー (CMK) の所有者だけです。 これにより、データ送信および保存中のデータセキュリティが向上します。
免責事項
クライアント側の暗号化を使用する場合は、CMKの整合性と有効性を確保する必要があります。 不適切なメンテナンスのためにCMKが誤って使用されたり失われたりした場合、復号化の失敗によって引き起こされるすべての損失と結果に対して責任があります。
暗号化されたデータをコピーまたは移行する場合、オブジェクトメタデータの整合性と有効性に責任があります。 暗号化されたメタデータが正しくないか、不適切なメンテナンスのために失われた場合、データの復号化の失敗によって引き起こされるすべての損失と結果に対して責任があります。
シナリオ
機密性の高いデータ: 個人識別情報 (PII) 、金融取引記録、医療および健康データなどの機密性の高い情報を含むデータの場合、ユーザーは、データがローカル環境を離れる前にデータを暗号化して、送信中に傍受されても元のデータが効果的に保護されるようにすることができます。
コンプライアンス要件: 医療保険の相互運用性および説明責任法 (HIPAA) や一般データ保護規則 (GDPR) などの特定の業界および規制では、サードパーティのプラットフォームに保存されているデータの厳密な暗号化管理が必要です。 CMKはユーザーによって管理され、ネットワークを経由したり、クラウドサービスプロバイダーに公開されたりしないため、クライアント側の暗号化はこれらのコンプライアンス要件を満たすのに役立ちます。
強力な権限管理: 企業または開発者は、暗号化アルゴリズムの選択、CMKの管理とローテーションなど、暗号化プロセスを完全に制御したい場合があります。 クライアント側の暗号化により、合法的に許可されたユーザーのみがデータを復号およびアクセスできます。
クロスリージョンデータ移行のセキュリティ: クライアント側の暗号化は、クロスリージョンデータ移行の前後でデータを暗号化された状態に維持するのに役立ちます。 これは、インターネット上のデータ伝送のセキュリティを増幅する。
使用上の注意
このトピックでは、中国 (杭州) リージョンのパブリックエンドポイントを使用します。 OSSと同じリージョンにある他のAlibaba CloudサービスからOSSにアクセスする場合は、内部エンドポイントを使用します。 OSSリージョンとエンドポイントの詳細については、「リージョンとエンドポイント」をご参照ください。
このトピックでは、アクセス資格情報は環境変数から取得します。 アクセス資格情報の設定方法の詳細については、「アクセス資格情報の設定」をご参照ください。
このトピックでは、OSSエンドポイントを使用してOSSClientインスタンスを作成します。 カスタムドメイン名またはSTS (Security Token Service) を使用してOSSClientインスタンスを作成する場合は、「初期化」をご参照ください。
背景情報
クライアント側の暗号化では、オブジェクトに対して対称暗号化を実行するために、オブジェクトごとにランダムなデータキーが生成されます。 クライアントはCMKを使用してランダムデータキーを暗号化します。 暗号化されたデータキーは、オブジェクトメタデータの一部としてアップロードされ、OSSサーバーに保存されます。 暗号化されたオブジェクトがダウンロードされると、クライアントはCMKを使用してランダムデータキーを復号し、次にデータキーを使用してオブジェクトを復号します。 データのセキュリティを確保するために、CMKはクライアントでのみ使用され、ネットワーク経由で送信されたり、サーバーに保存されたりすることはありません。
暗号化方法
クライアント側の暗号化には、次の2種類のCMKを使用できます。
KMSマネージドCMK
Key Management Service (KMS) が管理するCMKをクライアント側の暗号化に使用する場合、CMK IDをOSS SDK for Pythonに送信する必要があります。
自分で管理するRSAベースのCMK
自分で管理するCMKをクライアント側の暗号化に使用する場合は、CMKの公開鍵と秘密鍵をOSS SDK for Pythonにパラメーターとして送信する必要があります。
上記の暗号化方法を使用して、データ漏洩を防ぎ、クライアント上のデータを保護できます。 データが漏洩しても、他のユーザーはデータを復号することはできません。
詳細については、「OSS開発者ガイド」の「クライアント側暗号化」をご参照ください。
クライアント側暗号化V2 (推奨)
クライアント側の暗号化は、サイズが5 GBを超えるオブジェクトのマルチパートアップロードをサポートします。 マルチパートアップロードを使用してオブジェクトをアップロードする場合、オブジェクトの合計サイズと各パーツのサイズを指定する必要があります。 最後の部分を除く各部分のサイズは同じで、16バイトの倍数でなければなりません。
ローカルクライアントで暗号化されたオブジェクトをアップロードすると、オブジェクトのメタデータは暗号化されて保護され、CopyObjectなどの操作を呼び出して変更することはできません。
暗号化されたオブジェクトのメタデータのパラメータ
パラメーター
説明
必須
x-oss-meta-client-side-encryption-key
暗号化されたデータキー。 暗号化されたデータキーは、RSAベースのCMKまたはKMS管理CMKを使用して暗号化され、Base64でエンコードされた文字列です。
可
x-oss-meta-client-side-encryption-start
データ暗号化のためにランダムに生成された初期化ベクトル。 初期化ベクトルは、RSAベースのCMKまたはKMS管理CMKを使用して暗号化され、Base64でエンコードされた文字列です。
可
x-oss-meta-client-side-encryption-cek-alg
データの暗号化に使用されるアルゴリズム。
可
x-oss-meta-client-side-encryption-wrap-alg
データキーの暗号化に使用されるアルゴリズム。
可
x-oss-meta-client-side-encryption-matdesc
JSON形式のコンテンツ暗号化キー (CEK) の説明。
任意
x-oss-meta-client-side-encryption-unencrypted-content-length
暗号化前のデータの長さ。 content-lengthを指定しない場合、このパラメーターは生成されません。
任意
x-oss-meta-client-side-encryption-unencrypted-content-md5
暗号化前のデータのMD5ハッシュ。 content-md5を指定しない場合、このパラメーターは生成されません。
任意
x-oss-meta-client-side-encryption-data-size
マルチパートアップロードを使用してアップロードするオブジェクトの合計サイズ。
いいえ (マルチパートアップロードに必要)
x-oss-meta-client-side-encryption-part-size
マルチパートアップロードタスクの各パーツのサイズ。
いいえ (マルチパートアップロードに必要)
クライアント側暗号化用のバケットを作成する
オブジェクトを暗号化してアップロードする前、またはクライアントでオブジェクトをダウンロードして復号する前に、バケットを初期化する必要があります。 バケットの操作を呼び出して、オブジェクトをアップロードまたはダウンロードできます。 クライアント側の暗号化では、CryptoBucketクラスはBucketクラスから操作を継承します。 バケットの初期化と同じ方法で、パラメータを設定してCryptoBucketインスタンスを初期化できます。
自分で管理するRSAベースのCMKを使用してオブジェクト暗号化用のバケットを初期化する
重要RSAベースのCMKを使用する場合は、CMKを管理する必要があります。 CMKの損失またはCMKデータの損傷は、復号化の失敗を引き起こす可能性があります。 KMSによって管理されるCMKを使用することを推奨します。 RSAベースのCMKを使用して暗号化を実行する必要がある場合は、CMKデータをバックアップすることをお勧めします。
次のサンプルコードは、自分が管理するRSAベースのCMKを使用してオブジェクト暗号化用にバケットを初期化する方法の例を示しています。
# -*-コーディング: utf-8 -*- osのインポート oss2のインポート oss2.credentialsからEnvironmentVariableCredentialsProviderをインポート oss2.cryptoからRsaProviderをインポート # 環境変数からアクセス資格情報を取得します。 サンプルコードを実行する前に、OSS_ACCESS_KEY_IDおよびOSS_ACCESS_KEY_SECRET環境変数が設定されていることを確認してください。 auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider()) # オブジェクトを復号化するだけの場合は、秘密鍵のみを指定します。 # key_pair = {'private_key': 'yourPrivateKey'} # オブジェクトを暗号化するだけの場合は、公開鍵のみを指定します。 # key_pair = {'public_key': 'yourPublicKey'} # オブジェクトを暗号化および復号化する場合は、公開鍵と秘密鍵の両方を指定する必要があります。 key_pair = {'private_key': 'yourPrivateKey', 'public_key': 'yourPublicKey'} bucket = oss2.CryptoBucket(auth、endpoint、bucket_name、 crypto_provider=RsaProvider(key_pair)
KMSによって管理されるCMKを使用してオブジェクト暗号化のためにバケットを初期化する
次のサンプルコードは、KMSによって管理されるCMKを使用してオブジェクト暗号化のためにバケットを初期化する方法の例を示しています。
# -*-コーディング: utf-8 -*- osのインポート oss2のインポート oss2.cryptoからAliKMSProviderをインポート oss2.credentialsからEnvironmentVariableCredentialsProviderをインポート # 環境変数からアクセス資格情報を取得します。 サンプルコードを実行する前に、OSS_ACCESS_KEY_IDおよびOSS_ACCESS_KEY_SECRET環境変数が設定されていることを確認してください。 auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider()) kms_provider=AliKMSProvider(auth, 'yourRegion', 'yourCMKID') bucket = oss2.CryptoBucket(auth, 'yourEndpoint', 'yourBucketName', crypto_provider = kms_provider)
複数のCMKの使用と管理
異なるCMKを使用して、バケットにアップロードされたオブジェクトを暗号化したり、同じバケットからダウンロードされたオブジェクトを復号したりできます。 CMKに異なる説明を指定し、CMKとその説明をバケットに関する暗号化関連情報に追加できます。 データが復号化されると、OSS SDK for Pythonは説明に基づいてCMKを自動的に照合します。 サンプルコード:
# -*-コーディング: utf-8 -*- osのインポート oss2のインポート oss2.cryptoからRsaProviderをインポート oss2.credentialsからEnvironmentVariableCredentialsProviderをインポート # 環境変数からアクセス資格情報を取得します。 サンプルコードを実行する前に、OSS_ACCESS_KEY_IDおよびOSS_ACCESS_KEY_SECRET環境変数が設定されていることを確認してください。 auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider()) # RSAベースのキーペアを作成します。 key_pair_1 = {'private_key': 'yourPrivateKey_1 ', 'public_key': 'yourPublicKey_1'} mat_desc_1 = {'key1': 'value1'} # RSAベースのキーペアを作成します。 key_pair_2 = {'private_key': 'yourPrivateKey_2 ', 'public_key': 'yourPublicKey_2'} mat_desc_2 = {'key2': 'value2'} # key_pair_1の説明をプロバイダーに追加します。 provider = RsaProvider(key_pair={'private_key': private_key_str_2, 'public_key': public_key_str_2}, mat_desc=mat_desc_2) encryption_materials = oss2.EncryptionMaterials(mat_desc_1, key_pair=key_pair_1) provider.add_encryption_materials(encryption_materials) # プロバイダを使用してcrypto_bucketを初期化します。 次に、crypto_bucketの操作を呼び出して、記述がmat_desc_1であるCMKによって暗号化されたオブジェクトデータをダウンロードできます。 crypto_bucket = oss2.CryptoBucket(auth, 'yourEndpoint', 'yourBucketName', crypto_provider=provider)
簡単なアップロードとダウンロードでクライアント側の暗号化を実行する
次のサンプルコードは、KMSが管理するCMKを使用して、単純なアップロードでオブジェクトをアップロードするときにオブジェクトを暗号化する方法、またはオブジェクトをダウンロードするときにオブジェクトを復号する方法の例を示しています。
# -*-コーディング: utf-8 -*- osのインポート oss2のインポート oss2.credentialsからEnvironmentVariableCredentialsProviderをインポート oss2.cryptoからRsaProviderをインポート oss2.cryptoimportAliKMSProviderから # 環境変数からアクセス資格情報を取得します。 サンプルコードを実行する前に、OSS_ACCESS_KEY_IDおよびOSS_ACCESS_KEY_SECRET環境変数が設定されていることを確認してください。 auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider()) kms_provider=AliKMSProvider(auth, 'yourRegion', 'yourCMKID') bucket = oss2.CryptoBucket(auth, 'yourEndpoint', 'yourBucketName', crypto_provider = kms_provider) キー='motto.txt' content = b'a' * 1024*1024 filename = 'download.txt' # オブジェクトをアップロードします。 bucket.put_object (キー、コンテンツ、ヘッダー={'content-length ': str(1024*1024)}) # OSSからローカルメモリにオブジェクトをダウンロードします。 result = bucket.get_object (キー) # ダウンロードしたオブジェクトのコンテンツとアップロード前のオブジェクトのコンテンツのデータの整合性を確認します。 content_got = b'' 結果のチャンクの場合: content_got +=チャンク assert content_got == content # OSSからローカルメモリにオブジェクトをダウンロードします。 result = bucket.get_object_to_file (キー、ファイル名) # ダウンロードしたオブジェクトのコンテンツとアップロード前のオブジェクトのコンテンツのデータの整合性を確認します。 with open(filename, 'rb') as fileobj: assert fileobj.read() == content
マルチパートアップロードでクライアント側の暗号化を実行する
説明マルチパートアップロードタスクが中断され、プロセスが終了すると、マルチパートアップロードタスクのコンテキストが失われる可能性があります。 マルチパートアップロードタスクが中断され、オブジェクトを再アップロードする場合は、オブジェクト全体を再アップロードする必要があります。
OSSで再開可能アップロードの操作を呼び出して、大きなオブジェクトをアップロードすることを推奨します。 これにより、マルチパートアップロードタスクのコンテキストをローカルクライアントに保存できるため、アップロードタスクが中断されてもコンテキストを保持できます。
次のサンプルコードは、KMS管理CMKを使用して、マルチパートアップロードを使用してアップロードするオブジェクトを暗号化する方法の例を示しています。
# -*-コーディング: utf-8 -*- osのインポート oss2のインポート oss2.credentialsからEnvironmentVariableCredentialsProviderをインポート oss2.cryptoからRsaProviderをインポート oss2.cryptoimportAliKMSProviderから # 環境変数からアクセス資格情報を取得します。 サンプルコードを実行する前に、OSS_ACCESS_KEY_IDおよびOSS_ACCESS_KEY_SECRET環境変数が設定されていることを確認してください。 auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider()) kms_provider=AliKMSProvider(auth, 'yourRegion', 'yourCMKID') bucket = oss2.CryptoBucket(auth, 'yourEndpoint', 'yourBucketName', crypto_provider = kms_provider) """ マルチパートアップロード """ # マルチパートアップロードタスクを開始します。 part_a = b'a' * 1024*100 part_b = b'b' * 1024*100 part_c = b'c' * 1024*100 multi_content = [part_a, part_b, part_c] parts = [] data_size = 100*1024*3 part_size = 100*1024 multi_key = "test_crypto_multipart" # クライアント側の暗号化を使用する場合、マルチパートアップロードタスクのコンテキストを初期化します。 context = models.MultipartUploadCryptoContext(data_size, part_size) res = bucket.init_multipart_upload(multi_key, upload_context=コンテキスト) upload_id = res.upload_id # この例では、部品は順番にアップロードされます。 マルチパートアップロードは、アップロードを高速化するために複数の並列スレッドをサポートします。 範囲のiのため (3): # コンテキストの値は変更できません。 コンテキストの値を変更すると、データのアップロードに失敗します。 result = bucket.upload_part(multi_key, upload_id, i + 1, multi_content[i], upload_context=コンテキスト) parts.append(oss2.models.PartInfo(i + 1, result.etag, size=part_size, part_crc=result.crc)) # マルチパートアップロードタスクを完了します。 result = bucket.com plete_multipart_upload(multi_key, upload_id, parts) # ダウンロードしたオブジェクトのコンテンツとアップロード前のオブジェクトのコンテンツのデータの整合性を確認します。 result = bucket.get_object(multi_key) content_got = b'' 結果のチャンクの場合: content_got +=チャンク assert content_got[0:102400] == part_a assert content_got[102400:204800] == part_b assert content_got[204800:307200] == part_c
再開可能アップロードでクライアント側の暗号化を実行する
次のサンプルコードは、自分で管理するRSAベースのCMKを使用して、再開可能なアップロードを使用してアップロードするオブジェクトを暗号化する方法の例を示しています。
# -*-コーディング: utf-8 -*- osのインポート oss2のインポート oss2.credentialsからEnvironmentVariableCredentialsProviderをインポート oss2.cryptoからRsaProviderをインポート キー='motto.txt' content = b'a' * 1024*1024*100 file_name_put = 'upload.txt' # コンテンツに含まれるデータをファイルに書き込みます。 open(file_name_put、'wb') をfileobjとして持つ: fileobj.write (コンテンツ) # 環境変数からアクセス資格情報を取得します。 サンプルコードを実行する前に、OSS_ACCESS_KEY_IDおよびOSS_ACCESS_KEY_SECRET環境変数が設定されていることを確認してください。 auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider()) # バケットを作成し、RSAベースのCMKを使用してクライアント側の暗号化を実行します。 この暗号化方法は、オブジェクト全体のアップロードとダウンロードのみをサポートします。 # OSS SDK for Python 2.9.0以降を使用する場合は、バケットの初期化にLocalRsaProviderを使用しないことを推奨します。 # bucket = oss2.CryptoBucket(auth,'yourEndpoint', 'yourBucketName', crypto_provider=LocalRsaProvider()) # オブジェクトを復号化するだけの場合は、秘密鍵のみを指定します。 # key_pair = {'private_key': 'yourPrivateKey'} # オブジェクトを暗号化するだけの場合は、公開鍵のみを指定します。 # key_pair = {'public_key': 'yourPublicKey'} # オブジェクトを暗号化および復号化する場合は、公開鍵と秘密鍵の両方を指定する必要があります。 key_pair = {'private_key': 'yourPrivateKey', 'public_key': 'yourPublicKey'} # バケットを初期化します。 upload_contexts_flagをTrueに設定します。 upload_part操作を呼び出すときに、マルチパートアップロードコンテキストのパラメーターを設定する必要はありません。 bucket = oss2.CryptoBucket(auth、endpoint、bucket_name、 crypto_provider=RsaProvider(key_pair) # この例では、multipart_thresholdの値は10*1024*1024に設定されています。 デフォルトのマルチパートアップロードしきい値は10 MBです。 シナリオに基づいて値を指定します。 # multipart_thresholdは、オブジェクトサイズのしきい値を示します。 オブジェクトサイズがしきい値を超える場合、マルチパートアップロードが使用されます。 オブジェクトサイズがしきい値より小さい場合は、put_objectを呼び出してオブジェクトをアップロードすることを推奨します。 # part_sizeは、マルチパートアップロードの各パートのサイズを示します。 デフォルトの部品サイズは10 MBです。 # num_threadsは、並列アップロードスレッドの数を示します。 デフォルト値は 1 です。 oss2.resumable_upload(bucket、key、file_name_put、multipart_threshold=10*1024*1024、part_size=1024*1024、num_threads=3)
再開可能なダウンロードでクライアント側の暗号化を実行する
次のサンプルコードは、KMSが管理するCMKを使用して、再開可能ダウンロードでダウンロードするオブジェクトを復号化する方法の例を示しています。
# -*-コーディング: utf-8 -*- osのインポート oss2のインポート oss2.cryptoからRsaProviderをインポート oss2.cryptoimportAliKMSProviderから oss2.credentialsからEnvironmentVariableCredentialsProviderをインポート # 環境変数からアクセス資格情報を取得します。 サンプルコードを実行する前に、OSS_ACCESS_KEY_IDおよびOSS_ACCESS_KEY_SECRET環境変数が設定されていることを確認してください。 auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider()) キー='motto.txt' content = b'a' * 1024*1024*100 file_name_get = 'download.txt' kms_provider=AliKMSProvider(auth, 'yourRegion', 'yourCMKID') bucket = oss2.CryptoBucket(auth, 'yourEndpoint', 'yourBucketName', crypto_provider = kms_provider) # 再開可能ダウンロードを使用してオブジェクトをダウンロードします。 oss2.resumable_download(bucket、key、file_name_get、multiget_threshold=10*1024*1024、part_size=1024*1024、num_threads=3) # ダウンロードしたオブジェクトのコンテンツとアップロード前のオブジェクトのコンテンツのデータの整合性を確認します。 open(file_name_get、'rb') をfileobjとして持つ: assert fileobj.read() == content
クライアント側暗号化V1 (推奨しない)
クライアント側の暗号化V1は、PutObjectを呼び出して5 GB未満のオブジェクトのアップロードのみをサポートします。 マルチパートアップロード、再開可能アップロード、および再開可能ダウンロード操作はサポートされていません。
CryptoBucketクラスの操作を呼び出してオブジェクトをアップロードした後、CopyObjectなどの操作を呼び出してオブジェクトメタデータを変更することはできません。 メタデータが修正された場合、データは復号化されない可能性がある。
OSS SDK for Pythonのみがクライアント側暗号化V1をサポートしています。 他のプログラミング言語のOSS SDKは、クライアント側暗号化V1を使用してアップロードされたデータを復号できません。
Python 2.11.0以降のOSS SDKは、クライアント側暗号化V2をサポートしています。 クライアント側暗号化V2は、クライアント側暗号化V1よりも多くの機能を提供する。 最新バージョンへのアップグレードを推奨します。
暗号化されたオブジェクトのメタデータのパラメータ
パラメーター
説明
必須
x-oss-meta-oss-crypto-key
暗号化されたデータキー。 暗号化されたデータキーは、RSAベースのCMKを使用して暗号化され、Base64でエンコードされた文字列です。
可
x-oss-meta-oss-crypto-start
データ暗号化のためにランダムに生成された初期値。 値は、RSAベースのCMKを使用して暗号化され、Base64でエンコードされた文字列です。
可
x-oss-meta-oss-cek-alg
データの暗号化に使用されるアルゴリズム。
可
x-oss-meta-oss-wrap-alg
データキーの暗号化に使用されるアルゴリズム。
可
x-oss-meta-oss-matdesc
JSON形式のCEKの説明。 このパラメータは有効になりません。
任意
x-oss-meta-unencrypted-content-length
暗号化前のデータの長さ。 content-lengthを指定しない場合、このパラメーターは生成されません。
任意
x-oss-meta-unencrypted-content-md5
暗号化前のデータのMD5ハッシュ。 content-md5を指定しない場合、このパラメーターは生成されません。
任意
自分で管理するRSAベースのCMKを使用して、オブジェクトのアップロードとダウンロードのクライアント側暗号化を実行します
次のサンプルコードは、RSAベースのCMKを使用して、ダウンロードするオブジェクトをアップロードまたは復号化するオブジェクトを暗号化する方法の例を示しています。
# -*-コーディング: utf-8 -*- osのインポート oss2のインポート oss2.credentialsからEnvironmentVariableCredentialsProviderをインポート oss2.cryptoインポートからLocalRsaProvider # 環境変数からアクセス資格情報を取得します。 サンプルコードを実行する前に、OSS_ACCESS_KEY_IDおよびOSS_ACCESS_KEY_SECRET環境変数が設定されていることを確認してください。 auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider()) # バケットを作成し、RSAベースのCMKを使用してクライアント側の暗号化を実行します。 この暗号化方法は、オブジェクト全体のアップロードとダウンロードのみをサポートします。 bucket = oss2.CryptoBucket(auth,'yourEndpoint', 'yourBucketName', crypto_provider=LocalRsaProvider()) キー='motto.txt' content = b'a' * 1024*1024 filename = 'download.txt' # オブジェクトをアップロードします。 bucket.put_object (キー、コンテンツ、ヘッダー={'content-length ': str(1024*1024)}) # OSSからローカルメモリにオブジェクトをダウンロードします。 result = bucket.get_object (キー) # ダウンロードしたオブジェクトのコンテンツとアップロード前のオブジェクトのコンテンツのデータの整合性を確認します。 content_got = b'' 結果のチャンクの場合: content_got +=チャンク assert content_got == content # OSSからローカルメモリにオブジェクトをダウンロードします。 result = bucket.get_object_to_file (キー、ファイル名) # ダウンロードしたオブジェクトのコンテンツとアップロード前のオブジェクトのコンテンツのデータの整合性を確認します。 with open(filename, 'rb') as fileobj: assert fileobj.read() == content
参考資料
クライアント側の暗号化の実行に使用される完全なサンプルコードについては、『GitHub』をご参照ください。