Intégrer votre produit en conteneur au AWS Marketplace Metering Service à l'aide du AWS SDK for Java - AWS Marketplace

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Intégrer votre produit en conteneur au AWS Marketplace Metering Service à l'aide du AWS SDK for Java

Vous pouvez utiliser le AWS SDK for Java pour intégrer le AWS Marketplace Metering Service. La mesure continue pour l'utilisation du logiciel est automatiquement gérée par le AWS Marketplace Metering Control Plane. Votre logiciel n'est pas obligé d'effectuer des actions spécifiques de mesure, sauf d'en appeler RegisterUsage une seule fois pour que le mesurage de l'utilisation du logiciel commence. Cette rubrique fournit un exemple d'implémentation utilisant le AWS SDK for Java pour intégrer l'RegisterUsageaction AWS Marketplace du service de mesure.

RegisterUsagedoit être appelé immédiatement au moment du lancement d'un conteneur. Si vous n'enregistrez pas le conteneur dans les 6 premières heures suivant son lancement, AWS Marketplace Metering Service ne fournit aucune garantie de comptage pour les mois précédents. Cependant, le comptage se poursuivra pour le mois en cours jusqu'à la fin du conteneur.

Pour la source complète, consultez RegisterUsage Exemple Java. La plupart de ces étapes s'appliquent quelle que soit la AWS SDK langue.

Exemples d'étapes pour l'intégration AWS du Marketplace Metering Service
  1. Connectez-vous au Portail de gestion AWS Marketplace.

  2. À partir de Assets (Ressources), choisissez Containers (Conteneurs) pour commencer à créer un produit de conteneur. La création du produit génère le code produit pour l'intégration du produit à votre image de conteneur. Pour plus d'informations sur la définition IAM des autorisations, consultezAWS Marketplace autorisations de l'API de mesure et d'autorisation.

  3. Téléchargez le AWSJava publicSDK.

    Important

    Pour appeler le compteur APIs depuis AmazonEKS, vous devez utiliser un cluster compatible AWS SDK et exécuter sur un EKS cluster Amazon exécutant Kubernetes 1.13 ou version ultérieure.

  4. (Facultatif) Si vous intégrez l'RegisterUsageaction et que vous souhaitez effectuer une vérification de signature numérique, vous devez configurer la bibliothèque de vérification de BouncyCastlesignature dans le chemin de classe de votre application.

    Si vous souhaitez utiliser JSON Web Token (JWT), vous devez également inclure les bibliothèques JWTJava dans le chemin de classe de votre application. L'utilisation JWT fournit une approche plus simple de la vérification des signatures, mais elle n'est pas obligatoire, et vous pouvez utiliser le mode autonome à la BouncyCastle place. Que vous utilisiez JWT ou BouncyCastle que vous deviez utiliser un système de compilation tel que Maven pour inclure les dépendances transitives de BouncyCastle ou JWT dans le chemin de classe de votre application.

    // 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. Appelez RegisterUsage à partir de chaque image de conteneur payante dans votre offre de produit. ProductCode et PublicKeyVersion sont des paramètres obligatoires et toutes les autres entrées sont facultatives. Voici un exemple de charge utile pour 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 }
    Note

    Il est possible de rencontrer des problèmes transitoires lors de la connexion au AWS Marketplace Metering Service. AWS Marketplace recommande vivement d'implémenter des tentatives d'une durée maximale de 30 minutes, avec des interruptions exponentielles, afin d'éviter les pannes de courte durée ou les problèmes de réseau.

  6. RegisterUsagegénère une RSA signature PSS numérique à l'aide de SHA -256 que vous pouvez utiliser pour vérifier l'authenticité de la demande. La signature inclut les champs suivants : ProductCode, PublicKeyVersion, et Nonce. Pour vérifier la signature numérique, vous devez conserver ces champs à partir de la requête. Le code suivant est un exemple de réponse à un appel 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. Reconstruisez une nouvelle version de l'image de votre conteneur qui inclut l'RegisterUsageappel, balisez le conteneur et envoyez-la vers n'importe quel registre de conteneurs compatible avec Amazon ECS ou AmazonEKS, tel qu'Amazon ECR ou Amazon ECR Public. Si vous utilisez AmazonECR, assurez-vous que le compte qui lance la ECS tâche Amazon ou le EKS pod Amazon dispose d'autorisations sur le ECR référentiel Amazon. Dans le cas contraire, le lancement échoue.

  8. Créez un IAMrôle qui autorise votre conteneur à appelerRegisterUsage, comme défini dans le code suivant. Vous devez fournir ce IAM rôle dans le paramètre Task Role de la définition de la ECS tâche Amazon ou du EKS pod Amazon.

    { "Version": "2012-10-17", "Statement": [ { "Action": [ "aws-marketplace:RegisterUsage" ], "Effect": "Allow", "Resource": "*" } ] }
  9. Créez une définition de ECS tâche Amazon ou d'un EKS module Amazon qui fait référence au conteneur intégré AWS Marketplace et au IAM rôle que vous avez créé à l'étape 7. Vous devez activer la AWS CloudTrail journalisation dans la définition de tâche si vous souhaitez voir la journalisation.

  10. Créez un Amazon ECS ou un EKS cluster Amazon pour exécuter votre tâche ou votre pod. Pour plus d'informations sur la création d'un ECS cluster Amazon, consultez la section Création d'un cluster dans le manuel Amazon Elastic Container Service Developer Guide. Pour plus d'informations sur la création d'un EKS cluster Amazon (à l'aide de Kubernetes version 1.1.3.x ou ultérieure), consultez Création d'un cluster Amazon. EKS

  11. Configurez le EKS cluster Amazon ECS ou Amazon et lancez la définition de ECS tâche Amazon ou le EKS pod Amazon que vous avez créé, dans le us-east-1 Région AWS. Ce n'est que pendant ce processus de test, avant que le produit ne soit mis en service, que vous devez utiliser cette région.

  12. Lorsque vous recevez une réponse valide de RegisterUsage, vous pouvez commencer à créer votre produit de conteneur. Pour toute question, contactez l’équipe responsable des opérations vendeur AWS Marketplace.

RegisterUsage Exemple Java

L'exemple suivant utilise le service de AWS Marketplace mesure AWS SDK for Java et pour appeler l'RegisterUsageopération. La vérification de la signature est facultative, mais si vous souhaitez l'effectuer, vous devez inclure les bibliothèques de vérification de signatures numériques nécessaires. Cet exemple est donné uniquement à titre d'illustration.

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(); } } }