を使用してコンテナ製品を AWS Marketplace Metering Service に統合するAWS SDK for Java - AWS Marketplace

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

を使用してコンテナ製品を AWS Marketplace Metering Service に統合するAWS SDK for Java

以下の手順では、AWS SDK for Java を使用して AWS Marketplace Metering ServiceRegisterUsage アクションと統合する実装例を説明します。完全なソースコードについては、「RegisterUsage Java の例」を参照してください。これらの手順の多くは、言語にかかわらず適用されます。

AWS Marketplace Metering Service 統合のステップ例

  1. AWS Marketplace 管理ポータル にサインインします。

  2. [Assets (アセット)] から [コンテナ] を選択して、新しいコンテナ製品の作成を開始します。製品を作成すると、製品とコンテナイメージを統合するための製品コードが生成されます。公開の詳細については、「コンテナ製品の公開」を参照してください。IAM のアクセス権限の設定については、「」を参照してください。AWS Marketplace での Metering API および Entitlement API のアクセス許可

  3. 公開 AWS Java SDK をダウンロードします。

    重要

    Amazon EKS からメータリング API を呼び出すには、サポートされるAWSSDKを使用し、これを Kubernetes 1.13 以降を搭載する Amazon EKS クラスターで実行します。

  4. (オプション) と統合する場合RegisterUsageアクションを実行し、デジタル署名検証を実行する場合は、BouncyCastleアプリケーションクラスパス内の署名検証ライブラリ。

    JSON ウェブトークン (JWT) を使用する場合は、アプリケーションのクラスパスに JWT Java ライブラリも含める必要があります。JWT を使用することで署名検証により簡単にアプローチできますが、必須ではありません。スタンドアロン BouncyCastle 代わりに。JWTを使用するか BouncyCastleなどの他の圧縮アルゴリズムを含めるには、Maven などのビルドシステムを使用する必要があります。 BouncyCastle または、アプリケーションクラスパスの JWT。

    // Required for signature verification using code sample <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk15on</artifactId> <version>1.60</version> </dependency> // This one is only required for JWT <dependency> <groupId>com.nimbusds</groupId> <artifactId>nimbus-jose-jwt</artifactId> <version>6.0</version> </dependency>
  5. 製品提供の各有料コンテナイメージから RegisterUsage を呼び出します。ProductCodePublicKeyVersion は必須パラメータとなり、その他の入力はすべてオプションです。RegisterUsage のペイロード例を次に示します。

    { "ProductCode" : "string", // (required) "PublicKeyVersion": 1, // (required) "Nonce": "string", // (optional) to scope down the registration // to a specific running software // instance and guard against // replay attacks }
    注記

    AWS Marketplace Metering Service への接続で、一時的な問題が発生する可能性があります。AWS Marketplace短期間の停止やネットワークの問題を避けるために、指数関数的にバックオフした状態で最大 30 分間の再試行を実装することを強く推奨します。

  6. RegisterUsage は、リクエストの信頼性の検証に使用できる SHA-256 を使用して、RSA-PSS デジタル署名を生成します。署名には、ProductCodePublicKeyVersionNonce のフィールドが含まれています。デジタル署名を検証するには、リクエストからこれらのフィールドを保持する必要があります。次のコードは、RegisterUsage 呼び出しに対するレスポンスの例です。

    { "Signature": "<<JWT Token>>" } // Where the JWT Token is composed of 3 dot-separated, // base-64 URL Encoded sections. // e.g. eyJhbGcVCJ9.eyJzdWIMzkwMjJ9.rrO9Qw0SXRWTe // Section 1: Header/Algorithm { "alg": "PS256", "typ": "JWT" } // Section 2: Payload { "ProductCode" : "string", "PublicKeyVersion": 1, "Nonce": "string", "iat": date // JWT issued at claim } // Section 3: RSA-PSS SHA256 signature "rrO9Q4FEi3gweH3X4lrt2okf5zwIatUUwERlw016wTy_21Nv8S..."
  7. を含むコンテナイメージの新しいバージョンを再構築します。RegisterUsageを呼び出し、コンテナにタグを付け、Amazon ECR や Amazon ECR パブリックなどの Amazon ECS または Amazon EKS と互換性のあるコンテナレジストリにプッシュします。Amazon ECR を使用している場合は、Amazon ECS タスクまたは Amazon EKS ポッドを起動するアカウントに Amazon ECR リポジトリへのアクセス許可があることを確認します。それ以外の場合、起動は失敗します。

  8. を作成するIAMルールを使用してを呼び出すためのアクセス許可をコンテナに付与するロールRegisterUsageなどの他の圧縮アルゴリズムを使用したり、この IAM ロールはタスクロールAmazon ECS タスクまたは Amazon EKS ポッド定義のパラメータ。

    { "Version": "2012-10-17", "Statement": [ { "Action": [ "aws-marketplace:RegisterUsage" ], "Effect": "Allow", "Resource": "*" } ] }
  9. と統合されているコンテナを参照する Amazon ECS タスクまたは Amazon EKS ポッド定義を作成します。AWS Marketplaceとは、ステップ 7 で作成した IAM ロールを参照します。ログ記録を表示する場合は、タスク定義で AWS CloudTrail ログを有効にする必要があります。

  10. Amazon ECS クラスターまたは Amazon EKS クラスターを作成して、タスクまたはポッドを実行します。Amazon ECS クラスター作成の詳細については、「」を参照してください。クラスターの作成Amazon Elastic Container Service。Amazon EKS クラスターの作成 (Kubernetes バージョン 1.3.x 以降を使用) の詳細については、「」を参照してください。Amazon EKS クラスターの作成

  11. Amazon ECS または Amazon EKS クラスターを設定し、作成した Amazon ECS タスク定義または Amazon EKS ポッドを us-east-1 で起動します。AWS リージョン。製品が本番稼働になる前のこのテストプロセス中にのみ、このリージョンを使用する必要があります。

  12. RegisterUsage から有効なレスポンスを取得すると、コンテナ製品の作成を開始することができます。ご質問がある場合は、AWS Marketplace Seller Operations チームまでお問い合わせください。

RegisterUsage Java の例

次の例では、AWS SDK for Java と AWS Marketplace Metering Service を使用して RegisterUsage オペレーションを呼び出します。署名の検証はオプションですが、署名の検証を実行する場合は、必要なデジタル署名検証ライブラリを含める必要があります。この例は、例示のみを目的としています。

import com.amazonaws.auth.PEM; import com.amazonaws.services.marketplacemetering.AWSMarketplaceMetering; import com.amazonaws.services.marketplacemetering.AWSMarketplaceMeteringClientBuilder; import com.amazonaws.services.marketplacemetering.model.RegisterUsageRequest; import com.amazonaws.services.marketplacemetering.model.RegisterUsageResult; import com.amazonaws.util.json.Jackson; import com.fasterxml.jackson.databind.JsonNode; import com.nimbusds.jose.JWSObject; import com.nimbusds.jose.JWSVerifier; import com.nimbusds.jose.crypto.RSASSAVerifier; import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; import java.security.PublicKey; import java.security.Security; import java.security.Signature; import java.security.interfaces.RSAPublicKey; import java.util.Base64; import java.util.Optional; import java.util.UUID; import org.bouncycastle.jce.provider.BouncyCastleProvider; /** * Class for making calls out to AWS Marketplace Metering Service. */ class RegisterUsage { private static final String PRODUCT_CODE = "......."; private final AWSMarketplaceMetering registerUsageClient; private final SignatureVerifier signatureVerifier; private final int publicKeyVersion; public RegisterUsage(final SignatureVerifier signatureVerifier) { this.signatureVerifier = signatureVerifier; this.publicKeyVersion = PublicKeyProvider.PUBLIC_KEY_VERSION; this.registerUsageClient = AWSMarketplaceMeteringClientBuilder.standard().build(); } /** * Shows how to call RegisterUsage client and verify digital signature. */ public void callRegisterUsage() { RegisterUsageRequest request = new RegisterUsageRequest() .withProductCode(PRODUCT_CODE) .withPublicKeyVersion(publicKeyVersion) .withNonce(UUID.randomUUID().toString()); // Execute call to RegisterUsage (only need to call once at container startup) RegisterUsageResult result = this.registerUsageClient.registerUsage(request); // Verify Digital Signature w/o JWT boolean isSignatureValid = this.signatureVerifier.verify(request, result); if (!isSignatureValid) { throw new RuntimeException("Revoke entitlement, digital signature invalid."); } } } /** * Signature verification class with both a JWT-library based verification * and a non-library based implementation. */ class SignatureVerifier { private static BouncyCastleProvider BC = new BouncyCastleProvider(); private static final String SIGNATURE_ALGORITHM = "SHA256withRSA/PSS"; private final PublicKey publicKey; public SignatureVerifier(PublicKeyProvider publicKeyProvider) { this.publicKey = publicKeyProvider.getPublicKey().orElse(null); Security.addProvider(BC); } /** * Example signature verification using the NimbusJOSEJWT library to verify the JWT Token. * * @param request RegisterUsage Request. * @param result RegisterUsage Result. * @return true if the token matches. */ public boolean verifyUsingNimbusJOSEJWT(final RegisterUsageRequest request, final RegisterUsageResult result) { if (!getPublicKey().isPresent()) { return false; } try { JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey) getPublicKey().get()); JWSObject jwsObject = JWSObject.parse(result.getSignature()); return jwsObject.verify(verifier) && validatePayload(jwsObject.getPayload().toString(), request, result); } catch (Exception e) { // log error return false; } } /** * Example signature verification without any JWT library support. * * @param request RegisterUsage Request. * @param result RegisterUsage Result. * @return true if the token matches. */ public boolean verify(final RegisterUsageRequest request, final RegisterUsageResult result) { if (!getPublicKey().isPresent()) { return false; } try { String[] jwtParts = result.getSignature().split("\\."); String header = jwtParts[0]; String payload = jwtParts[1]; String payloadSignature = jwtParts[2]; Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM, BC); signature.initVerify(getPublicKey().get()); signature.update(String.format("%s.%s", header, payload).getBytes(StandardCharsets.UTF_8)); boolean verified = signature.verify(Base64.getUrlDecoder() .decode(payloadSignature.getBytes(StandardCharsets.UTF_8))); String decodedPayload = new String(Base64.getUrlDecoder().decode(payload)); return verified && validatePayload(decodedPayload, request, result); } catch (Exception e) { // log error return false; } } /** * Validate each value in the returned payload matches values originally * supplied in the request to RegisterUsage. TimeToLiveInMillis and * PublicKeyExpirationTimestamp will have the values in the payload compared * to values in the signature */ private boolean validatePayload(final String payload, final RegisterUsageRequest request, final RegisterUsageResult result) { try { JsonNode payloadJson = Jackson.getObjectMapper().readTree(payload); boolean matches = payloadJson.get("productCode") .asText() .equals(request.getProductCode()); matches = matches && payloadJson.get("nonce") .asText() .equals(request.getNonce()); return matches = matches && payloadJson.get("publicKeyVersion") .asText() .equals(String.valueOf(request.getPublicKeyVersion())); } catch (Exception ex) { // log error return false; } } private Optional<PublicKey> getPublicKey() { return Optional.ofNullable(this.publicKey); } } /** * Public key provider taking advantage of the AWS PEM Utility. */ class PublicKeyProvider { // Replace with your public key. Ensure there are new-lines ("\n") in the // string after "-----BEGIN PUBLIC KEY-----\n" and before "\n-----END PUBLIC KEY-----". private static final String PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\n" + "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugd\n" + "UWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQs\n" + "HUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5D\n" + "o2kQ+X5xK9cipRgEKwIDAQAB\n" + "-----END PUBLIC KEY-----"; public static final int PUBLIC_KEY_VERSION = 1; public Optional<PublicKey> getPublicKey() { try { return Optional.of(PEM.readPublicKey(new ByteArrayInputStream( PUBLIC_KEY.getBytes(StandardCharsets.UTF_8)))); } catch (Exception e) { // log error return Optional.empty(); } } }