Integração de um produto AWS Marketplace for Containers Anywhere ao License Manager - AWS Marketplace

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Integração de um produto AWS Marketplace for Containers Anywhere ao License Manager

Siga estas instruções para fazer a integração do AWS License Manager a um produto AWS Marketplace for Containers Anywhere para Amazon EKS Anywhere, Amazon ECS Anywhere, Amazon EC2 ou infraestrutura on-premises.

Para obter informações gerais sobre a integração do License Manager ao AWS Marketplace, incluindo os modelos de licença disponíveis, consulte Preços contratuais para produtos de contêiner com o AWS License Manager. Para obter mais informações sobre o AWS License Manager, consulte o Guia do usuário do AWS License Manager e a Referência de comandos do AWS License Manager.

Integração de um produto AWS Marketplace for Containers Anywhere ao License Manager

Use as instruções a seguir para integrar o produto AWS Marketplace for Containers Anywhere ao AWS License Manager.

Para integrar o produto AWS Marketplace for Containers Anywhere ao License Manager
  1. Abra um navegador da web e faça login no Portal de gerenciamento do AWS Marketplace.

  2. Crie um ID para seu produto de contêiner realizando as etapas a seguir. Você usará esse ID na imagem do contêiner para verificações de licença em uma etapa posterior.

    1. Na barra de menus, expanda Assets (Ativos) e selecione Container (Contêiner).

    2. Insira um nome voltado ao cliente para o produto e selecione Criar. Você pode alterar esse nome depois.

    3. Anote o ID do produto. Você o usará ao criar ou atualizar os detalhes de preços do produto.

      dica

      Se você perder o ID do produto, poderá encontrá-lo no Portal de gerenciamento do AWS Marketplace escolhendo Contêiner no menu Ativos. A página Contêineres mostra uma lista dos produtos com os IDs associados.

  3. Baixe o SDK da AWS público mais recente e instale-o em seu aplicativo de contêiner. Você pode encontrar instruções de instalação para seu SDK da AWS preferido em Ferramentas para criar na AWS.

    nota

    Para chamar as operações de API do License Manager no Amazon EKS Anywhere ou em um cluster Kubernetes que não seja fornecido pela AWS, você deve usar um SDK da AWS compatível. Para ver uma lista de SDKs da AWS compatíveis, consulte Como usar um SDK da AWS compatível.

  4. Crie um cliente do AWS License Manager com um provedor de credenciais personalizado para que ele possa fornecer credenciais para o aplicativo de contêiner implantado na AWS e on-premises. Para obter o código-fonte completo de um provedor de credenciais personalizado, LicenseCredentialProvider, consulte as seções a seguir:

    LicenseCredentialsProvider estende a cadeia de provedores de credenciais padrão do SDK da AWS para uso on-premises adicionando LicenseManagerTokenCredentialsProvider. Isso fornece credenciais usando tokens de identidade emitidos pelo License Manager OIDC em ambientes on-premises. Você deve incluir o código-fonte do LicenseCredentialsProvider no caminho de classe do seu aplicativo.

    nota

    Estender o DefaultCredentialsProvider permite que o mesmo aplicativo de contêiner obtenha credenciais ao ser executado na AWS e quando executado em um ambiente on-premises. Se o aplicativo de contêiner já usa uma cadeia de provedores de credenciais personalizada em vez do padrão, ele também pode ser estendido adicionando LicenseManagerTokenCredentialsProvider à cadeia personalizada.

    O snippet de código a seguir é um exemplo de criação de um cliente do AWS License Manager usando Java.

    LicenseManagerClientBuilder clientBuilder = LicenseManagerClient.builder().credentialsProvider(LicenseCredentialsProvider.create());
  5. Chame a operação de API CheckoutLicense usando o comando aws license-manager checkout-license de cada imagem de contêiner paga na oferta de produto. Isso verifica se o comprador tem o direito de usar uma licença para o aplicativo. Se o comprador tiver direito ao aplicativo, CheckoutLicense obterá êxito e devolverá os direitos solicitados e os valores. Se o comprador não tiver direito ao aplicativo, CheckoutLicense lançará uma exceção.

    Os parâmetros a seguir são necessários ao chamar a operação de API CheckoutLicense:

    • CheckoutType: os valores válidos são PROVISIONAL ou PERPETUAL:

      • Use PERPETUAL quando a quantidade de direitos retirados será esgotada do conjunto.

        Exemplo: o comprador tem o direito de processar 500 GB de dados. À medida que continua processando os dados, a quantidade é retirada e esgotada do conjunto de 500 GB.

      • Use PROVISIONAL para direitos de licença flutuante, em que os direitos são retirados do conjunto e devolvidos após o uso.

        Exemplo: o usuário tem direito a 500 usuários simultâneos no aplicativo. Conforme os usuários fazem login ou se desconectam, eles são retirados ou retornados ao conjunto de 500 usuários. Para saber mais sobre direitos de licença flutuante, consulte Direitos de licença flutuante no License Manager.

    • ClientToken: um identificador exclusivo e que diferencia maiúsculas e minúsculas. Recomendamos usar um UUID aleatório para cada solicitação exclusiva.

    • Entitlements: uma lista de direitos a serem verificados.

      • Para direitos de recursos, forneça as propriedades Name e Unit assim.

        { "Name": "<Entitlement_Name>", "Unit": "None" }
      • Para direitos contados, forneça as propriedades Name, Unit e Count assim.

        { "Name": "<Entitlement_Name>", "Unit": "<Entitlement_Unit>", "Value": <Desired_Count> }
    • KeyFingerprint: a impressão digital de chave para licenças emitidas pelo AWS Marketplace é aws:294406891311:AWS/Marketplace:issuer-fingerprint. O uso dessa impressão digital de chave garante que a licença seja emitida pelo AWS Marketplace e não por uma entidade não confiável.

    • ProductSKU: o ID do produto gerado no Portal de gerenciamento do AWS Marketplace nas etapas anteriores.

    O snippet a seguir é um exemplo de uma chamada usando a operação de API CheckoutLicense usando a AWS CLI.

    aws license-manager checkout-license \ --product-sku "2205b290-19e6-4c76-9eea-377d6bf71a47" \ --checkout-type "PROVISIONAL" \ --client-token "79464194dca9429698cc774587a603a1" \ --entitlements "Name=AWS::Marketplace::Usage/Drawdown/DataConsumption, Value=10, Unit=Gigabytes" \ --key-fingerprint "aws:294406891311:AWS/Marketplace:issuer-fingerprint"
    nota

    Para verificar as licenças, os aplicativos de contêiner exigem acesso de saída à rede para usar o License Manager. Os aplicativos implantados on-premises podem ter acesso de saída lento ou não confiável à rede. Esses aplicativos devem incluir novas tentativas adequadas ao chamar o License Manager. Para obter mais informações, consulte Práticas recomendadas para integração com o License Manager para implantações on-premises.

  6. Chame a operação de API CheckoutLicense regularmente para identificar quaisquer alterações nas licenças dos clientes devido a renovações, atualizações ou cancelamentos feitos no AWS Marketplace. A cadência depende do aplicativo. Recomendamos verificar as licenças uma vez por dia para receber as alterações automaticamente sem a intervenção do comprador.

    Um aplicativo implantado on-premises pode ter acesso não confiável à rede de saída para verificar as licenças em um ritmo regular. Nesses casos, o aplicativo deve usar licenças em cache para obter resiliência suficiente. Para obter mais informações, consulte Práticas recomendadas para integração com o License Manager para implantações on-premises.

  7. Depois de integrar a chamada CheckoutLicense ao seu aplicativo de contêiner, crie uma nova versão da imagem de contêiner do Docker com as alterações.

  8. Atualize o chart do Helm do aplicativo para aceitar um segredo do Kubernetes como entrada opcional que contém a configuração para acessar licenças usando as APIs do License Manager. O segredo de configuração conterá um token de identidade emitido pelo License Manager e um perfil do AWS Identity and Access Management que será usado pelo provedor de credenciais personalizado descrito anteriormente para obter credenciais da AWS para chamar as APIs do License Manager quando o aplicativo de contêiner for implantado localmente. Além disso, adicione a Região da AWS como uma entrada com um valor padrão deus-east-1.

    Os compradores que implantam o aplicativo de contêiner on-premises podem criar o segredo do Kubernetes por meio da experiência do comprador do AWS Marketplace em produtos de contêiner. Forneça o nome do segredo do Kubernetes como entrada para o comando helm install. O segredo da configuração tem o seguinte formato:

    apiVersion: v1 kind: Secret metadata: name: aws-marketplace-license-config type: Opaque stringData: license_token: <token_value> // License Manager issued JWT token iam_role: <role_arn> // AWS Identity and Access Management role to assume with license token
  9. Atualize o modelo de implantação do aplicativo no chart do Helm para imagens de contêiner integradas ao AWS License Manager para incluir o seguinte:

    • Conta de serviço para pod: a conta de serviço é necessária para implantações do Helm no Amazon EKS. Ela é usada para obter permissões para chamar as operações de API do License Manager configurando perfis do IAM para a conta de serviço na imagem do contêiner. Para obter mais informações sobre perfis do IAM para contas de serviço, consulte Perfis do IAM para contas de serviço.

    • Acesso à licença para implantações on-premises: o segredo da configuração da licença é necessário para fornecer credenciais e permissões apropriadas para chamar as operações de API do License Manager para implantações do Helm em ambientes on-premises. Os compradores gerarão e fornecerão o segredo da licença ao Helm na experiência do comprador do AWS Marketplace.

    O snippet de código a seguir é um exemplo de especificação de implantação com a conta de serviço, a configuração da licença e o segredo de extração da imagem.

    apiVersion: apps/v1 kind: Deployment metadata: name: example-app spec: replicas: 1 selector: matchLabels: app: example-app template: metadata: labels: app: example-app spec: // Service account for pod serviceAccountName: {{ .Values.serviceAccountName }} containers: - name: example-app image: example-app ports: - containerPort: 8001 // Add the following conditional attributes {{ - if .Values.awsmp.licenseConfigSecretName }} //Mount the license volume to the container image volumeMounts: - name: awsmp-product-license mountPath: "/var/run/secrets/product-license" //Add following environment variable to container for credential provider env: - name: AWS_WEB_IDENTITY_REFRESH_TOKEN_FILE value: "/var/run/secrets/product-license/license_token" - name: AWS_ROLE_ARN valueFrom: secretKeyRef: name: {{ .Values.aws.licenseConfigSecretName }} key: iam_role //Mount the license secret as a volume to the pod volumes: - name: awsmp-product-license secret: secretName: {{ .Values.aws.licenseConfigSecretName }} optional: true {{ - end }}
    nota

    O segredo da configuração da licença é opcional. Os compradores usam o valor somente para implantações on-premises. Para implantações da AWS, a especificação de implantação deve incluir uma conta de serviço para as imagens integradas do License Manager.

  10. Teste a integração do License Manager localmente e no Amazon EKS realizando as etapas nas seguintes seções:

    1. Teste da integração do License Manager localmente

    2. Teste da integração do License Manager no Amazon EKS

  11. Depois de verificar com êxito a integração do License Manager ao AWS e on-premises, você pode criar a lista de produtos de contêiner seguindo as etapas em Criar um produto de contêiner.

Teste da integração do License Manager localmente

Você pode usar o minikube ou qualquer outra configuração para testar a integração do License Manager em qualquer cluster Kubernetes localmente. Certifique-se de que o cluster Kubernetes tenha acesso de saída à Internet para chamar as operações de API do License Manager.

Para testar uma integração do License Manager localmente
  1. Crie uma licença de teste em uma conta de vendedor de teste com os direitos desejados. Para configurar uma licença de teste, consulte CreateLicense na Referência da API do AWS License Manager. Ou use o script a seguir para criar uma licença de teste e, em seguida, criar uma concessão de licença para uma conta de comprador de teste para consumir a licença. O script a seguir usa as credenciais da conta de vendedor de teste.

    read -p 'AWS Account for test buyer: ' TEST_BUYER_ACCOUNT_ID read -p 'License entitlements: ' ENTITLEMENTS # TEST_SELLER_ACCOUNT_ID="109876543210" # ENTITLEMENTS="{\"Name\": \"ByData\",\"MaxCount\": 1000,\"Overage\":true,\"Unit\": \"Gigabits\",\"AllowCheckIn\": true}" # Create License NOW=$(date +"%Y-%m-%dT00:00:00+00:00") PRODUCT_NAME="My awesome product" PRODUCT_SKU="c97b7825-44c4-4f42-b025-12baa4c171e0" LICENSE_BENEFICIARY=" arn:aws:iam::$TEST_BUYER_ACCOUNT_ID:root " LICENSE_ISSUER_NAME="test-seller" LICENSE_NAME="test-seller-license" CLIENT_TOKEN="b3920968-a94f-4547-af07-3dd232319367" CONSUMPTION_TTL=180 CONSUMPTION_RENEW_TYPE="None" HOME_REGION="us-east-1" LICENSE_ARN=$(aws license-manager create-license --license-name "$LICENSE_NAME" --product-name "$PRODUCT_NAME" --product-sku "$PRODUCT_SKU" --issuer Name="$LICENSE_ISSUER_NAME" --home-region "$HOME_REGION" --validity Begin="$NOW" --entitlements "$ENTITLEMENTS" --beneficiary "$LICENSE_BENEFICIARY" --consumption-configuration RenewType="$CONSUMPTION_RENEW_TYPE",ProvisionalConfiguration={MaxTimeToLiveInMinutes=$CONSUMPTION_TTL} --client-token "$CLIENT_TOKEN" | jq -r ".LicenseArn" ) echo "License arn: $LICENSE_ARN" # Create Grant GRANT_TOKEN="e9a14140-4fca-4219-8230-57511a6ea6" GRANT_NAME="test-grant" GRANT_ARN=$(aws license-manager create-grant --grant-name "$GRANT_NAME" --license-arn "$LICENSE_ARN" --principals "$LICENSE_BENEFICIARY" --home-region "$HOME_REGION" --client-token "$GRANT_TOKEN" --allowed-operations "CheckoutLicense" "CheckInLicense" "ExtendConsumptionLicense" "CreateToken" | jq -r ".GrantArn") echo "Grant arn: $GRANT_ARN"
  2. Crie um segredo do Kubernetes com o token de licença e o perfil do IAM usando o formato do segredo definido anteriormente. Use a operação de API CreateToken do License Manager para gerar um token de licença. Em seguida, use a operação de API CreateRole do IAM para criar um perfil do IAM com permissões e uma política de confiança. Veja o exemplo no script seguinte. O script a seguir usa as credenciais da conta de comprador de teste.

    read -p 'AWS Account for test license: ' TEST_ACCOUNT_ID read -p 'License Arn' LICENSE_ARN # Create IAM Role ROLE_NAME="AWSLicenseManagerConsumptionTestRole" ROLE_DESCRIPTION="Role to test AWS License Manager integration on-prem" ROLE_POLICY_ARN="arn:aws:iam::aws:policy/service-role/AWSLicenseManagerConsumptionPolicy" ROLE_TRUST_POLICY="{\"Version\": \"2012-10-17\",\"Statement\": [{ \"Effect\":\"Allow\", \"Principal\": { \"Federated\": \"openid-license-manager.amazonaws.com\" }, \"Action\": \"sts:AssumeRoleWithWebIdentity\",\"Condition\": { \"ForAnyValue:StringLike\": { \"openid-license-manager.amazonaws.com:amr\": \"aws:license-manager:token-issuer-account-id:${TEST_ACCOUNT_ID}\" }}}]}" ROLE_SESSION_DURATION=3600 ROLE_ARN=$(aws iam create-role --role-name "$ROLE_NAME" --description "$ROLE_DESCRIPTION" --assume-role-policy-document "$ROLE_TRUST_POLICY" --max-session-duration $ROLE_SESSION_DURATION | jq ".Role" | jq -r ".Arn") aws iam attach-role-policy --role-name "$ROLE_NAME" --policy-arn "$ROLE_POLICY_ARN" echo "Role arn: $ROLE_ARN" # Create Token CLIENT_TOKEN="b3920968-a94f-4547-af07-3dd232319367" TOKEN=$(aws license-manager create-token --license-arn $LICENSE_ARN --role-arns $ROLE_ARN --client-token $CLIENT_TOKEN | jq '.Token') echo "License access token: $TOKEN"c
  3. Configure qualquer cluster Kubernetes hospedado fora da AWS. Use-o para testar se os aplicativos de contêiner podem se conectar à API AWS License Manager de ambientes diferentes da AWS e se o provedor de credenciais personalizadas está bem integrado ao aplicativo.

  4. Implante o token de licença e o perfil do IAM gerados anteriormente no cluster local do Kubernetes.

    kubectl create secret generic "awsmp-license-access-config" \ --from-literal=license_token=${TOKEN} \ --from-literal=iam_role=${ROLE_ARN}
  5. Implante seu aplicativo por meio do Helm com o nome do segredo como entrada e verifique se o aplicativo pode chamar as operações de API do License Manager para realizar verificações de direitos. Para alterações nas especificações do Helm e da implantação, consulte a Etapa 9 em Integração de um produto AWS Marketplace for Containers Anywhere ao License Manager.

Teste da integração do License Manager no Amazon EKS

Você também pode testar a integração do License Manager no Amazon EKS. Teste para garantir que o aplicativo possa chamar as operações de API do License Manager sem o segredo da configuração da licença. Além disso, certifique-se de que a conta de serviço possa ser usada para configurar perfis do IAM para contas de serviço (IRSA) e fornecer credenciais relevantes para o aplicativo.

Para testar a integração do License Manager no Amazon EKS
  1. Crie uma licença de teste em uma conta de vendedor de teste com os direitos desejados. Consulte a referência da API CreateLicense para configurar a licença de teste ou use o script a seguir para criar uma e criar uma concessão de licença para uma conta de comprador de teste para consumir a licença. O script a seguir usa as credenciais da conta de vendedor de teste.

    read -p 'AWS Account for test buyer: ' TEST_BUYER_ACCOUNT_ID read -p 'License entitlements: ' ENTITLEMENTS # TEST_SELLER_ACCOUNT_ID="109876543210" # ENTITLEMENTS="{\"Name\": \"ByData\",\"MaxCount\": 1000,\"Overage\": true,\"Unit\": \"Gigabits\",\"AllowCheckIn\": true}" # Create License NOW=$(date +"%Y-%m-%dT00:00:00+00:00") PRODUCT_NAME="My awesome product" PRODUCT_SKU="c97b7825-44c4-4f42-b025-12baa4c171e0" LICENSE_BENEFICIARY=" arn:aws:iam::$TEST_BUYER_ACCOUNT_ID:root " LICENSE_ISSUER_NAME="test-seller" LICENSE_NAME="test-seller-license" CLIENT_TOKEN="b3920968-a94f-4547-af07-3dd232319367" CONSUMPTION_TTL=180 CONSUMPTION_RENEW_TYPE="None" HOME_REGION="us-east-1" LICENSE_ARN=$(aws license-manager create-license --license-name "$LICENSE_NAME" --product-name "$PRODUCT_NAME" --product-sku "$PRODUCT_SKU" --issuer Name="$LICENSE_ISSUER_NAME" --home-region "$HOME_REGION" --validity Begin="$NOW" --entitlements "$ENTITLEMENTS" --beneficiary "$LICENSE_BENEFICIARY" --consumption-configuration RenewType="$CONSUMPTION_RENEW_TYPE",ProvisionalConfiguration={MaxTimeToLiveInMinutes=$CONSUMPTION_TTL} --client-token "$CLIENT_TOKEN" | jq -r ".LicenseArn" ) echo "License arn: $LICENSE_ARN" # Create Grant GRANT_TOKEN="e9a14140-4fca-4219-8230-57511a6ea6" GRANT_NAME="test-grant" GRANT_ARN=$(aws license-manager create-grant --grant-name "$GRANT_NAME" --license-arn "$LICENSE_ARN" --principals "$LICENSE_BENEFICIARY" --home-region "$HOME_REGION" --client-token "$GRANT_TOKEN" --allowed-operations "CheckoutLicense" "CheckInLicense" "ExtendConsumptionLicense" "CreateToken" | jq -r ".GrantArn") echo "Grant arn: $GRANT_ARN"
  2. Crie um cluster de teste do Amazon EKS com as configurações desejadas ou execute os seguintes comandos para usar uma configuração padrão.

    aws ec2 create-key-pair --region us-west-2 --key-name eks-key-pair
    eksctl create cluster \ --name awsmp-eks-test-example \ --region us-west-2 \ --with-oidc \ --ssh-access \ --ssh-public-key eks-key-pair
  3. Crie uma conta de serviço para um cluster existente e associe-o a um perfil do IAM. O comando a seguir cria um perfil do IAM com a AWSLicenseManagerConsumptionPolicy. Em seguida, o comando o anexa à conta de serviço test_sa do cluster do Amazon EKS em que as imagens integradas do License Manager devem ser implantadas. Como resultado, a conta de serviço pode obter as credenciais apropriadas para chamar as operações de API do License Manager.

    eksctl create iamserviceaccount \ --name test_sa \ --namespace test_namespace \ --cluster awsmp-eks-test-example \ --attach-policy-arn "arn:aws:iam::aws:policy/service-role/AWSLicenseManagerConsumptionPolicy" \ --approve \ --override-existing-serviceaccounts
  4. Implante o aplicativo por meio do Helm na conta de serviço em que o perfil do IAM está associado no comando anterior. Verifique se o aplicativo pode chamar as operações de API do License Manager para realizar verificações de direitos.

Direitos de licença flutuante no License Manager

Com licenças flutuantes, à medida que os usuários acessam o aplicativo, uma licença é retirada do conjunto de licenças disponíveis. À medida que os usuários se desconectam, as licenças são adicionadas novamente ao conjunto de licenças disponíveis.

Para licenças flutuantes, o aplicativo usa a operação de API CheckoutLicense para verificar os direitos do conjunto de direitos quando o recurso está sendo usado. A resposta da operação de API CheckoutLicense inclui um token de consumo de licença, que é um identificador exclusivo para o checkout. O token de consumo de licença pode realizar ações adicionais nos direitos que são retirados, como devolvê-los ao conjunto de licenças ou estender a finalização da compra.

Quando o recurso não está mais em uso, o aplicativo usa a operação de API CheckInLicense para verificar o direito de volta ao conjunto.

aws license-manager check-in-license \ --license-consumption-token "f1603b3c1f574b7284db84a9e771ee12"

Se a devolução de uma licença ao conjunto falhar, por exemplo, se o aplicativo falhar durante a operação, o direito será devolvido ao conjunto automaticamente após 60 minutos. Por esse motivo, se o recurso estiver em uso por mais de 60 minutos, é uma prática recomendada manter o direito retirado do conjunto. Para fazer isso, use a operação de API ExtendLicenseConsumption enquanto o recurso estiver sendo usado.

aws license-manager extend-license-consumption \ --license-consumption-token "f1603b3c1f574b7284db84a9e771ee12"

Práticas recomendadas para integração com o License Manager para implantações on-premises

Implantações de aplicativos de contêiner em um ambiente on-premises podem encontrar acesso não confiável à rede de saída. Use as práticas recomendadas a seguir para aumentar a resiliência e evitar a interrupção do serviço para os compradores devido a possíveis problemas causados pela baixa conectividade com a Internet:

  • Nova tentativa adequada: problemas transitórios de rede podem impedir que seu aplicativo se conecte ao AWS License Manager. Implemente novas tentativas por até 30 minutos, com recuo exponencial. Isso pode ajudar a evitar interrupções de curto prazo ou problemas de rede.

  • Evitar limites rígidos: os aplicativos implantados em clusters conectados podem verificar regularmente as licenças para identificar quaisquer alterações devido a atualizações ou renovações. Com o acesso externo não confiável, o aplicativo pode não conseguir identificar essas alterações. Sempre que possível, o aplicativo deve evitar a interrupção do serviço aos compradores devido à incapacidade de verificar as licenças por meio do License Manager. Os aplicativos podem recorrer a uma experiência de teste gratuito ou de código aberto quando a licença expirar e não podem verificar se a licença é válida.

  • Notificar os clientes: ao usar uma licença em cache, quaisquer alterações na licença (incluindo renovações ou upgrades) não são refletidas automaticamente na workload em execução. Notifique os clientes (que eles devem permitir o acesso externo ao aplicativo novamente temporariamente para que o aplicativo possa atualizar a licença em cache). Por exemplo, notifique os clientes por meio do próprio aplicativo ou da documentação. Da mesma forma, ao recorrer a um conjunto inferior de funcionalidades, notifique os clientes que os direitos estão esgotados ou que a licença expirou. Em seguida, eles podem optar por atualizar ou renovar.

LicenseManagerCredentialsProvider: implementação de Java

LicenseCredentialsProvider estende a cadeia de provedores de credenciais padrão do SDK da AWS para uso on-premises adicionando LicenseManagerTokenCredentialsProvider.

LicenseCredentialsProvider

package com.amazon.awsmp.license; import software.amazon.awssdk.auth.credentials.AwsCredentials; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.auth.credentials.AwsCredentialsProviderChain; import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; import software.amazon.awssdk.auth.credentials.internal.LazyAwsCredentialsProvider; import software.amazon.awssdk.utils.SdkAutoCloseable; public class LicenseCredentialsProvider implements AwsCredentialsProvider, SdkAutoCloseable { private static final LicenseCredentialsProvider CREDENTIALS_PROVIDER = new LicenseCredentialsProvider(); private final LazyAwsCredentialsProvider providerChain; private LicenseCredentialsProvider() { this.providerChain = createChain(); } public static LicenseCredentialsProvider create() { return CREDENTIALS_PROVIDER; } @Override public AwsCredentials resolveCredentials() { return this.providerChain.resolveCredentials(); } @Override public void close() { this.providerChain.close(); } private LazyAwsCredentialsProvider createChain() { return LazyAwsCredentialsProvider.create(() -> { AwsCredentialsProvider[] credentialsProviders = new AwsCredentialsProvider[]{ DefaultCredentialsProvider.create(), LicenseManagerTokenCredentialsProvider.create()}; return AwsCredentialsProviderChain.builder().reuseLastProviderEnabled(true) .credentialsProviders(credentialsProviders).build(); }); } }

LicenseManagerTokenCredentialsProvider

LicenseManagerTokenCredentialsProvider fornece credenciais usando tokens de identidade emitidos pelo License Manager OIDC em ambientes on-premises. Você deve incluir o código-fonte do LicenseCredentialsProvider no caminho de classe do seu aplicativo.

package com.amazon.awsmp.license; import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider; import software.amazon.awssdk.auth.credentials.AwsCredentials; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.core.SdkSystemSetting; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.core.retry.RetryPolicyContext; import software.amazon.awssdk.core.retry.conditions.OrRetryCondition; import software.amazon.awssdk.core.retry.conditions.RetryCondition; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.regions.providers.DefaultAwsRegionProviderChain; import software.amazon.awssdk.services.licensemanager.LicenseManagerClient; import software.amazon.awssdk.services.licensemanager.model.GetAccessTokenRequest; import software.amazon.awssdk.services.licensemanager.model.GetAccessTokenResponse; import software.amazon.awssdk.services.sts.StsClient; import software.amazon.awssdk.services.sts.auth.StsAssumeRoleWithWebIdentityCredentialsProvider; import software.amazon.awssdk.services.sts.model.AssumeRoleWithWebIdentityRequest; import software.amazon.awssdk.services.sts.model.IdpCommunicationErrorException; import software.amazon.awssdk.utils.IoUtils; import software.amazon.awssdk.utils.SdkAutoCloseable; import software.amazon.awssdk.utils.StringUtils; import software.amazon.awssdk.utils.SystemSetting; import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.time.Duration; import java.util.function.Supplier; public class LicenseManagerTokenCredentialsProvider implements AwsCredentialsProvider, SdkAutoCloseable { private final StsAssumeRoleWithWebIdentityCredentialsProvider credentialsProvider; private final RuntimeException loadException; private Path licenseAccessTokenFile; private String roleArn; private String roleSessionName; private StsClient stsClient; private LicenseManagerClient lmClient; public static LicenseManagerTokenCredentialsProvider create() { return new Builder().build(); } @Override public AwsCredentials resolveCredentials() { if (this.loadException != null) { throw this.loadException; } return this.credentialsProvider.resolveCredentials(); } @Override public void close() { IoUtils.closeQuietly(this.credentialsProvider, null); IoUtils.closeQuietly(this.stsClient, null); IoUtils.closeIfCloseable(this.lmClient, null); } private LicenseManagerTokenCredentialsProvider(Builder builder) { StsAssumeRoleWithWebIdentityCredentialsProvider credentialsProvider = null; RuntimeException loadException = null; try { this.licenseAccessTokenFile = Paths.get(StringUtils.trim(LicenseSystemSetting.AWS_WEB_IDENTITY_REFRESH_TOKEN_FILE.getStringValueOrThrow())); this.roleArn = SdkSystemSetting.AWS_ROLE_ARN.getStringValueOrThrow(); this.roleSessionName = SdkSystemSetting.AWS_ROLE_SESSION_NAME.getStringValue().orElse("aws-sdk-java-" + System.currentTimeMillis()); this.stsClient = builder.stsClient != null ? builder.stsClient : StsClientFactory.create(); this.lmClient = builder.lmClient != null ? builder.lmClient : LicenseManagerClientFactory.create(); AssumeRoleWithWebIdentityRequest request = AssumeRoleWithWebIdentityRequest.builder() .roleArn(this.roleArn).roleSessionName(this.roleSessionName).build(); Supplier<AssumeRoleWithWebIdentityRequest> supplier = new AssumeRoleRequestSupplier(request, this.licenseAccessTokenFile, this.lmClient); credentialsProvider = StsAssumeRoleWithWebIdentityCredentialsProvider.builder() .stsClient(this.stsClient).refreshRequest(supplier).build(); } catch (RuntimeException ex) { loadException = ex; } this.credentialsProvider = credentialsProvider; this.loadException = loadException; } public static final class Builder { private Path licenseAccessTokenFile; private String roleArn; private String roleSessionName; private StsClient stsClient; private LicenseManagerClient lmClient; public LicenseManagerTokenCredentialsProvider build() { return new LicenseManagerTokenCredentialsProvider(this); } public LicenseManagerTokenCredentialsProvider.Builder licenseAccessTokenFile(Path licenseAccessTokenFile) { this.licenseAccessTokenFile = licenseAccessTokenFile; return this; } public LicenseManagerTokenCredentialsProvider.Builder roleArn(String roleArn) { this.roleArn = roleArn; return this; } public LicenseManagerTokenCredentialsProvider.Builder roleSessionName(String roleSessionName) { this.roleSessionName = roleSessionName; return this; } public LicenseManagerTokenCredentialsProvider.Builder stsClient(StsClient stsClient) { this.stsClient = stsClient; return this; } public LicenseManagerTokenCredentialsProvider.Builder lmClient(LicenseManagerClient lmClient) { this.lmClient = lmClient; return this; } } private static final class AssumeRoleRequestSupplier implements Supplier { private final LicenseManagerClient lmClient; private final AssumeRoleWithWebIdentityRequest request; private final Path webIdentityRefreshTokenFile; AssumeRoleRequestSupplier(final AssumeRoleWithWebIdentityRequest request, final Path webIdentityRefreshTokenFile, final LicenseManagerClient lmClient) { this.lmClient = lmClient; this.request = request; this.webIdentityRefreshTokenFile = webIdentityRefreshTokenFile; } public AssumeRoleWithWebIdentityRequest get() { return this.request.toBuilder() .webIdentityToken(getIdentityToken()) .build(); } private String getIdentityToken() { return refreshIdToken(readRefreshToken(this.webIdentityRefreshTokenFile)); } private String readRefreshToken(Path file) { try (InputStream webIdentityRefreshTokenStream = Files.newInputStream(file)) { return IoUtils.toUtf8String(webIdentityRefreshTokenStream); } catch (IOException e) { throw new UncheckedIOException(e); } } private String refreshIdToken(String licenseRefreshToken) { final GetAccessTokenRequest request = GetAccessTokenRequest.builder() .token(licenseRefreshToken) .build(); GetAccessTokenResponse response = this.lmClient.getAccessToken(request); return response.accessToken(); } } private static final class LicenseManagerClientFactory { private static final Duration DEFAULT_API_TIMEOUT = Duration.ofSeconds(30); private static final Duration DEFAULT_API_ATTEMPT_TIMEOUT = Duration.ofSeconds(10); public static LicenseManagerClient create() { return getLicenseManagerClient(); } private static LicenseManagerClient getLicenseManagerClient() { ClientOverrideConfiguration configuration = ClientOverrideConfiguration.builder() .apiCallTimeout(DEFAULT_API_TIMEOUT) .apiCallAttemptTimeout(DEFAULT_API_ATTEMPT_TIMEOUT) .build(); LicenseManagerClient client = LicenseManagerClient.builder() .region(configureLicenseManagerRegion()) .credentialsProvider(AnonymousCredentialsProvider.create()) .overrideConfiguration(configuration).build(); return client; } private static Region configureLicenseManagerRegion() { Region defaultRegion = Region.US_EAST_1; Region region; try { region = (new DefaultAwsRegionProviderChain()).getRegion(); } catch (RuntimeException ex) { region = defaultRegion; } return region; } } private static final class StsClientFactory { private static final Duration DEFAULT_API_TIMEOUT = Duration.ofSeconds(30); private static final Duration DEFAULT_API_ATTEMPT_TIMEOUT = Duration.ofSeconds(10); public static StsClient create() { return getStsClient(); } private static StsClient getStsClient() { OrRetryCondition retryCondition = OrRetryCondition.create(new StsRetryCondition(), RetryCondition.defaultRetryCondition()); ClientOverrideConfiguration configuration = ClientOverrideConfiguration.builder() .apiCallTimeout(DEFAULT_API_TIMEOUT) .apiCallAttemptTimeout(DEFAULT_API_ATTEMPT_TIMEOUT) .retryPolicy(r -> r.retryCondition(retryCondition)) .build(); return StsClient.builder() .region(configureStsRegion()) .credentialsProvider(AnonymousCredentialsProvider.create()) .overrideConfiguration(configuration).build(); } private static Region configureStsRegion() { Region defaultRegion = Region.US_EAST_1; Region stsRegion; try { stsRegion = (new DefaultAwsRegionProviderChain()).getRegion(); } catch (RuntimeException ex) { stsRegion = defaultRegion; } return stsRegion; } private static final class StsRetryCondition implements RetryCondition { public boolean shouldRetry(RetryPolicyContext context) { return context.exception() instanceof IdpCommunicationErrorException; } } } private enum LicenseSystemSetting implements SystemSetting { AWS_WEB_IDENTITY_REFRESH_TOKEN_FILE("aws.webIdentityRefreshTokenFile"); private String systemProperty; private String defaultValue = null; LicenseSystemSetting(String systemProperty) { this.systemProperty = systemProperty; } @Override public String property() { return this.systemProperty; } @Override public String environmentVariable() { return this.name(); } @Override public String defaultValue() { return this.defaultValue; } } }

LicenseManagerCredentialsProvider: implementação do Golang

LicenseCredentialsProvider

LicenseCredentialsProvider estende a cadeia de provedores de credenciais padrão do SDK da AWS para uso on-premises adicionando LicenseManagerTokenCredentialsProvider.

package lib import ( "context" "fmt" "sync" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" ) // LicenseCredentialsProvider is the custom credential provider that can retrieve valid temporary aws credentials type LicenseCredentialsProvider struct { fallBackProvider aws.CredentialsProvider mux sync.RWMutex licenseCredentials aws.Credentials err error } // NewLicenseCredentialsProvider method will create a LicenseCredentialProvider Object which contains valid temporary aws credentials func NewLicenseCredentialsProvider() (*LicenseCredentialsProvider, error) { licenseCredentialProvider := &LicenseCredentialsProvider{} fallBackProvider, err := createCredentialProvider() if err != nil { return licenseCredentialProvider, fmt.Errorf("failed to create LicenseCredentialsProvider, %w", err) } licenseCredentialProvider.fallBackProvider = fallBackProvider return licenseCredentialProvider, nil } // Retrieve method will retrieve temporary aws credentials from the credential provider func (l *LicenseCredentialsProvider) Retrieve(ctx context.Context) (aws.Credentials, error) { l.mux.RLock() defer l.mux.RUnlock() l.licenseCredentials, l.err = l.fallBackProvider.Retrieve(ctx) return l.licenseCredentials, l.err } func createCredentialProvider() (aws.CredentialsProvider, error) { // LoadDefaultConfig will examine all "default" credential providers ctx := context.TODO() cfg, err := config.LoadDefaultConfig(ctx) if err != nil { return nil, fmt.Errorf("failed to create FallBackProvider, %w", err) } var useFallbackProvider bool if cfg.Credentials != nil { if _, err := cfg.Credentials.Retrieve(ctx); err != nil { // If the "default" credentials provider cannot retrieve credentials, enable fallback to customCredentialsProvider. useFallbackProvider = true } } else { useFallbackProvider = true } if useFallbackProvider { customProvider, err := newLicenseManagerTokenCredentialsProvider() if err != nil { return cfg.Credentials, fmt.Errorf("failed to create fallBackProvider, %w", err) } // wrap up customProvider with CredentialsCache to enable caching cfg.Credentials = aws.NewCredentialsCache(customProvider) } return cfg.Credentials, nil }

LicenseManagerTokenCredentialsProvider

LicenseManagerTokenCredentialsProvider fornece credenciais usando tokens de identidade emitidos pelo License Manager OIDC em ambientes on-premises. Você deve incluir o código-fonte do LicenseCredentialsProvider no caminho de classe do seu aplicativo.

package lib import ( "context" "fmt" "io/ioutil" "os" "sync" "time" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/sts" ) const awsRefreshTokenFilePathEnvVar = "AWS_LICENSE_ACCESS_FILE" // licenseManagerTokenCredentialsProvider defines and contains StsAssumeRoleWithWebIdentityProvider type licenseManagerTokenCredentialsProvider struct { stsCredentialProvider *stsAssumeRoleWithWebIdentityProvider mux sync.RWMutex licenseCredentials aws.Credentials err error } // Retrieve method will retrieve credentials from credential provider. // Make this method public to make this provider satisfies CredentialProvider interface func (a *licenseManagerTokenCredentialsProvider) Retrieve(ctx context.Context) (aws.Credentials, error) { a.mux.RLock() defer a.mux.RUnlock() a.licenseCredentials, a.err = a.stsCredentialProvider.Retrieve(ctx) return a.licenseCredentials, a.err } // newLicenseManagerTokenCredentialsProvider will create and return a LicenseManagerTokenCredentialsProvider Object which wraps up stsAssumeRoleWithWebIdentityProvider func newLicenseManagerTokenCredentialsProvider() (*licenseManagerTokenCredentialsProvider, error) { // 1. Retrieve variables From yaml environment envConfig, err := config.NewEnvConfig() if err != nil { return &licenseManagerTokenCredentialsProvider{}, fmt.Errorf("failed to create LicenseManagerTokenCredentialsProvider, %w", err) } roleArn := envConfig.RoleARN var roleSessionName string if envConfig.RoleSessionName == "" { roleSessionName = fmt.Sprintf("aws-sdk-go-v2-%v", time.Now().UnixNano()) } else { roleSessionName = envConfig.RoleSessionName } tokenFilePath := os.Getenv(awsRefreshTokenFilePathEnvVar) b, err := ioutil.ReadFile(tokenFilePath) if err != nil { return &licenseManagerTokenCredentialsProvider{}, fmt.Errorf("failed to create LicenseManagerTokenCredentialsProvider, %w", err) } refreshToken := aws.String(string(b)) // 2. Create stsClient cfg, err := config.LoadDefaultConfig(context.TODO()) if err != nil { return &licenseManagerTokenCredentialsProvider{}, fmt.Errorf("failed to create LicenseManagerTokenCredentialsProvider, %w", err) } stsClient := sts.NewFromConfig(cfg, func(o *sts.Options) { o.Region = configureStsClientRegion(cfg.Region) o.Credentials = aws.AnonymousCredentials{} }) // 3. Configure StsAssumeRoleWithWebIdentityProvider stsCredentialProvider := newStsAssumeRoleWithWebIdentityProvider(stsClient, roleArn, roleSessionName, refreshToken) // 4. Build and return return &licenseManagerTokenCredentialsProvider{ stsCredentialProvider: stsCredentialProvider, }, nil } func configureStsClientRegion(configRegion string) string { defaultRegion := "us-east-1" if configRegion == "" { return defaultRegion } else { return configRegion } }