컨테이너 애니웨어 제품을 AWS Marketplace License Manager와 통합 - AWS Marketplace

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

컨테이너 애니웨어 제품을 AWS Marketplace License Manager와 통합

다음 지침에 따라 Amazon Anywhere, Amazon EKS Anywhere, Amazon 또는 온프레미스 AWS Marketplace 인프라용 컨테이너 ECS 애니웨어 제품과 AWS License Manager 통합하십시오. EC2

사용 가능한 라이선스 모델을 포함하여 License Manager 통합에 대한 일반적인 정보는 을 참조하십시오다음과 같은 컨테이너 제품의 계약 가격 AWS License Manager. AWS Marketplace AWS License Manager에 대한 자세한 내용은 AWS License Manager 사용 설명서AWS CLI 명령 참조의 AWS License Manager 섹션을 참조하세요.

컨테이너 애니웨어 제품을 AWS Marketplace License Manager와 통합

다음 지침에 따라 AWS Marketplace for Containers Anywhere 제품을 통합하십시오. AWS License Manager

컨테이너 애니웨어 제품을 License Manager와 통합하려면 AWS Marketplace
  1. 웹 브라우저를 열고 AWS Marketplace Management Portal에 로그인합니다.

  2. 다음 단계를 수행하여 컨테이너 제품의 제품 ID를 생성합니다. 이후 단계에서 라이선스 확인을 위해 컨테이너 이미지에서 이 ID를 사용하게 됩니다.

    1. 메뉴 모음에서 [Assets(자산)]를 확장하고 [Container(컨테이너)]를 선택합니다.

    2. 고객에게 표시되는 제품 이름을 입력하고 생성을 선택합니다. 이 이름은 나중에 변경할 수 있습니다.

    3. 제품 ID를 적어 둡니다. 제품 요금 세부 정보를 생성하거나 업데이트할 때 필요합니다.

      작은 정보

      제품 ID를 분실한 경우 자산 메뉴에서 컨테이너를 AWS Marketplace Management Portal 선택하여 제품 ID를 찾을 수 있습니다. 컨테이너 페이지에는 제품 목록과 관련 제품이 표시됩니다IDs.

  3. 최신 공개 AWS SDK 버전을 다운로드한 다음 컨테이너 애플리케이션에 설치하십시오. Tools to Build AWS SDK on에서 원하는 설치 지침을 찾을 수 AWS 있습니다.

    참고

    Amazon EKS Anywhere에서 제공하지 않는 쿠버네티스 클러스터 또는 Kubernetes 클러스터에서 License Manager API 작업을 호출하려면 AWS지원되는 버전을 사용해야 합니다. AWS SDK 지원되는 목록을 AWS SDKs 보려면 지원되는 항목 사용을 참조하십시오. AWS SDK

  4. 사용자 지정 자격 증명 공급자로 AWS License Manager 클라이언트를 생성하면 온프레미스뿐만 아니라 배포된 컨테이너 애플리케이션에 자격 증명을 제공할 수 있습니다. AWS 사용자 지정 보안 인증 정보 공급자 LicenseCredentialProvider에 대한 전체 소스 코드는 다음 섹션을 참조하세요.

    LicenseCredentialsProvider를 AWS SDK 추가하여 온프레미스에서 사용할 수 있도록 기본 자격 증명 공급자 체인을 확장합니다. LicenseManagerTokenCredentialsProvider 이는 온프레미스 환경에서 License Manager에서 OIDC 발급한 ID 토큰을 사용하여 자격 증명을 제공합니다. LicenseCredentialsProvider의 소스 코드를 애플리케이션 클래스 경로에 포함해야 합니다.

    참고

    DefaultCredentialsProvider 확장하면 온프레미스 환경에서 실행할 때와 실행할 때 동일한 컨테이너 응용 프로그램이 자격 증명을 얻을 수 있습니다. AWS 컨테이너 애플리케이션이 이미 기본값 대신 사용자 지정 보안 인증 정보 공급자 체인을 사용하는 경우 사용자 지정 체인에 LicenseManagerTokenCredentialsProvider를 추가하여 확장할 수도 있습니다.

    다음 코드 스니펫은 Java를 사용하여 클라이언트를 생성하는 예제입니다. AWS License Manager

    LicenseManagerClientBuilder clientBuilder = LicenseManagerClient.builder().credentialsProvider(LicenseCredentialsProvider.create());
  5. 제품 CheckoutLicense API 오퍼링의 각 유료 컨테이너 이미지에 있는 aws license-manager checkout-license 명령을 사용하여 오퍼레이션을 호출하십시오. 그러면 구매자가 애플리케이션의 라이선스를 사용할 권한이 있는지 확인됩니다. 구매자에게 애플리케이션에 대한 권한이 있으면 CheckoutLicense가 성공하고 요청된 권한과 해당 값을 반환합니다. 구매자에게 애플리케이션에 대한 권한이 없으면 CheckoutLicense가 예외를 throw합니다.

    CheckoutLicenseAPI오퍼레이션을 호출할 때는 다음 파라미터가 필요합니다.

    • CheckoutType - 유효한 값은 PROVISIONAL 또는 PERPETUAL입니다.

      • 체크아웃된 권한 수량이 풀에서 모두 소진되면 PERPETUAL을 사용합니다.

        예: 구매자에게 500GB의 데이터를 처리할 권한이 있습니다. 구매자가 데이터를 계속 처리하다 보면 수량이 감소하고 500GB 풀이 모두 소진됩니다.

      • 풀에서 권한을 체크아웃하고 사용 후 반환하는 플로팅 라이선스 권한에 PROVISIONAL을 사용합니다.

        예: 사용자는 애플리케이션에서 동시 사용자 500명을 이용할 수 있습니다. 사용자가 로그인 또는 로그아웃하면 사용자가 차감되거나 사용자 500명 풀로 반환됩니다. 플로팅 라이선스 권한에 대한 자세한 내용은 플로팅 라이선스 권한과 License Manager 섹션을 참조하세요.

    • ClientToken - 대/소문자를 구분하는 고유의 식별자입니다. 각 고유 요청에는 UUID 랜덤을 사용하는 것이 좋습니다.

    • Entitlements - 체크아웃할 권한 목록입니다.

      • 기능 권한의 경우 다음과 같이 NameUnit 속성을 제공합니다.

        { "Name": "<Entitlement_Name>", "Unit": "None" }
      • 집계된 권한의 경우 다음과 같이 Name, UnitCount 속성을 제공합니다.

        { "Name": "<Entitlement_Name>", "Unit": "<Entitlement_Unit>", "Value": <Desired_Count> }
    • KeyFingerprint - AWS Marketplace 에서 발급한 라이선스의 key fingerprint는 aws:294406891311:AWS/Marketplace:issuer-fingerprint입니다. 이 키 핑거프린트를 사용하면 신뢰할 수 없는 주체가 아닌 해당 기관이 AWS Marketplace 라이선스를 발급했는지 확인할 수 있습니다.

    • ProductSKU— 이전 AWS Marketplace Management Portal 단계에서 생성된 제품 ID.

    다음 스니펫은 를 사용한 CheckoutLicense API 작업을 사용하는 통화의 예입니다. 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"
    참고

    라이선스를 확인하려면 컨테이너 애플리케이션이 License Manager를 사용할 수 있도록 아웃바운드 네트워크 액세스가 필요합니다. 온프레미스에 배포된 애플리케이션은 아웃바운드 네트워크 액세스가 불안정하거나 느릴 수 있습니다. 이러한 애플리케이션에는 License Manager를 호출할 때 적절한 재시도 기능이 있어야 합니다. 자세한 내용은 온프레미스 배포를 위해 License Manager와 통합하는 모범 사례 단원을 참조하십시오.

  6. 정기적으로 CheckoutLicense API 영업팀에 전화하여 갱신, 업그레이드 또는 취소로 인한 고객 라이선스 변경 사항을 확인하십시오. AWS Marketplace주기는 애플리케이션에 따라 다릅니다. 하루에 한 번 라이선스를 확인하여 구매자의 개입 없이 변경 내용을 자동으로 적용하는 것이 좋습니다.

    온프레미스에 배포된 애플리케이션은 정기적으로 라이선스를 확인하기에는 아웃바운드 네트워크 액세스가 불안정할 수 있습니다. 이 경우 애플리케이션에서 충분한 복원력을 확보할 수 있도록 캐시된 라이선스를 사용해야 합니다. 자세한 내용은 온프레미스 배포를 위해 License Manager와 통합하는 모범 사례 단원을 참조하십시오.

  7. CheckoutLicense 호출을 컨테이너 애플리케이션과 통합한 후에는 변경 사항이 적용된 새 버전의 Docker 컨테이너 이미지를 빌드합니다.

  8. 애플리케이션의 헬름 차트를 업데이트하여 Kubernetes 시크릿을 License Manager를 사용하여 라이선스에 액세스하기 위한 구성을 포함하는 선택적 입력으로 받아들이십시오. APIs 구성 암호에는 License Manager에서 발급한 ID 토큰과 컨테이너 애플리케이션이 온프레미스로 배포될 APIs 때 앞서 설명한 사용자 지정 자격 증명 공급자가 License Manager를 호출하기 위한 AWS 자격 증명을 가져오는 데 사용할 AWS Identity and Access Management 역할이 포함됩니다. 또한 AWS 리전 을 기본값인 us-east-1로 하여 입력으로 추가합니다.

    컨테이너 애플리케이션을 온프레미스로 배포하는 구매자는 컨테이너 제품에 대한 구매자 경험을 통해 Kubernetes 시크릿을 생성할 수 있습니다. AWS Marketplace helm install 명령의 입력으로 Kubernetes 보안 암호 이름을 제공합니다. 구성 보안 암호는 다음 형식으로 구성됩니다.

    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. 와 통합된 컨테이너 이미지의 헬름 차트에 있는 애플리케이션 배포 템플릿을 업데이트하여 다음을 포함하세요. AWS License Manager

    • 포드 서비스 계정 — Amazon에서 Helm을 배포하려면 서비스 계정이 필요합니다. EKS 컨테이너 이미지에서 서비스 계정의 IAM 역할을 설정하여 License Manager API 작업을 호출할 권한을 얻는 데 사용됩니다. 서비스 계정의 IAM 역할에 대한 자세한 내용은 서비스 계정의 IAM역할을 참조하십시오.

    • 온프레미스 배포를 위한 라이선스 액세스 — 온프레미스 환경에서 Helm 배포를 위해 License Manager API 작업을 호출하려면 자격 증명과 적절한 권한을 제공하려면 라이선스 구성 암호가 필요합니다. 구매자는 구매자 경험을 바탕으로 라이선스 암호를 생성하여 헬름에 제공합니다. AWS Marketplace

    다음 코드 조각은 서비스 계정, 라이선스 구성 및 이미지 풀 보안 암호가 포함된 샘플 배포 사양입니다.

    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 }}
    참고

    라이선스 구성 보안 암호는 선택 사항입니다. 구매자는 이 값을 온프레미스 배포에만 사용합니다. AWS 배포의 경우 배포 사양에 License Manager 통합 이미지에 대한 서비스 계정이 포함되어야 합니다.

  10. 다음 섹션의 단계를 EKS 수행하여 로컬 및 Amazon에서 License Manager 통합을 테스트하십시오.

    1. 로컬로 License Manager 통합 테스트

    2. Amazon에서의 라이선스 관리자 통합 테스트 EKS

  11. AWS 온프레미스와 온프레미스 모두에서 License Manager 통합을 성공적으로 확인한 후에는 의 단계에 따라 컨테이너 제품 목록을 생성할 수 있습니다. 컨테이너 제품 생성

로컬로 License Manager 통합 테스트

minikube 또는 기타 설정을 사용하여 아무 Kubernetes 클러스터에서 로컬로 License Manager 통합을 테스트할 수 있습니다. 쿠버네티스 클러스터에 License Manager 작업을 호출할 수 있는 아웃바운드 인터넷 액세스 권한이 있는지 확인하십시오. API

로컬로 License Manager 통합을 테스트하는 방법
  1. 원하는 권한이 있는 테스트 판매자 계정에서 테스트 라이선스를 생성합니다. 테스트 라이선스를 설정하려면 레퍼런스를 참조하십시오 CreateLicense.AWS License Manager API 또는 다음 스크립트를 사용하여 테스트 라이선스를 생성한 다음, 테스트 구매자 계정에 라이선스를 부여하여 라이선스를 사용할 수 있습니다. 다음 스크립트는 테스트 판매자 계정 보안 인증 정보를 사용합니다.

    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. 이전에 정의한 시크릿 형식을 사용하여 라이선스 토큰과 IAM 역할을 포함하는 Kubernetes 시크릿을 생성하십시오. License Manager CreateToken API 작업을 사용하여 라이선스 토큰을 생성할 수 있습니다. 그런 다음 IAM CreateRole API 작업을 사용하여 권한 및 신뢰 정책이 있는 IAM 역할을 생성합니다. 다음 스크립트의 예시를 살펴보세요. 다음 스크립트는 테스트 구매자 계정 보안 인증 정보를 사용합니다.

    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. 외부에서 호스팅되는 모든 Kubernetes 클러스터를 설정합니다. AWS이를 사용하여 컨테이너 애플리케이션이 다른 AWS 환경에서 연결할 수 있는지, 사용자 지정 자격 증명 공급자가 애플리케이션에 잘 통합되어 있는지 테스트할 수 있습니다. AWS License Manager API

  4. 이전에 생성한 라이선스 토큰과 IAM 역할을 로컬 Kubernetes 클러스터에 배포합니다.

    kubectl create secret generic "awsmp-license-access-config" \ --from-literal=license_token=${TOKEN} \ --from-literal=iam_role=${ROLE_ARN}
  5. 비밀 이름을 입력으로 사용하여 Helm을 통해 애플리케이션을 배포하고 애플리케이션이 License Manager API 작업을 호출하여 권한 검사를 수행할 수 있는지 확인합니다. Helm 및 배포 사양 변경에 대한 내용은 컨테이너 애니웨어 제품을 AWS Marketplace License Manager와 통합의 9단계를 참조하세요.

Amazon에서의 라이선스 관리자 통합 테스트 EKS

Amazon에서 License Manager 통합을 테스트할 수도 EKS 있습니다. 애플리케이션이 라이선스 구성 암호 없이 License Manager API 작업을 호출할 수 있는지 테스트하십시오. 또한 서비스 계정을 사용하여 서비스 계정의 IAM 역할 (IRSA) 을 설정하고 애플리케이션에 관련 자격 증명을 제공할 수 있는지 확인하십시오.

Amazon에서 License Manager 통합을 테스트하려면 EKS
  1. 원하는 권한이 있는 테스트 판매자 계정에서 테스트 라이선스를 생성합니다. CreateLicense API참조를 참조하여 테스트 라이선스를 설정하거나 다음 스크립트를 사용하여 라이선스를 생성하고 테스트 구매자 계정에 라이선스 부여를 생성하여 라이선스를 사용하십시오. 다음 스크립트는 테스트 판매자 계정 보안 인증 정보를 사용합니다.

    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. 원하는 구성의 테스트 Amazon EKS 클러스터를 생성하거나 다음 명령을 실행하여 기본 구성을 사용하십시오.

    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. 기존 클러스터의 서비스 계정을 생성하고 이를 IAM 역할에 연결합니다. 다음 명령은 를 사용하여 IAM 역할을 생성합니다AWSLicenseManagerConsumptionPolicy. 그런 다음 이 명령은 License Manager 통합 이미지를 배포해야 하는 Amazon EKS 클러스터의 test_sa 서비스 계정에 해당 계정을 연결합니다. 따라서 서비스 계정은 License Manager API 작업을 호출하는 데 필요한 적절한 자격 증명을 얻을 수 있습니다.

    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. Helm을 통해 이전 명령에서 IAM 역할이 연결된 서비스 계정에 애플리케이션을 배포합니다. 애플리케이션이 License Manager API 작업을 호출하여 권한 검사를 수행할 수 있는지 확인합니다.

플로팅 라이선스 권한과 License Manager

플로팅 라이선스를 사용하면 사용자가 애플리케이션에 로그인할 때 사용 가능한 라이선스 풀에서 라이선스를 가져옵니다. 사용자가 로그아웃하면 라이선스가 사용 가능한 라이선스 풀에 다시 추가됩니다.

플로팅 라이선스의 경우 애플리케이션은 CheckoutLicense API 리소스를 사용할 때 작업을 사용하여 권한 풀에서 권한을 체크아웃합니다. CheckoutLicenseAPI작업 응답에는 체크아웃의 고유 식별자인 라이선스 소비 토큰이 포함됩니다. 라이선스 소비 토큰은 권한을 라이선스 풀로 다시 체크인하거나 체크아웃을 연장하는 등 체크아웃된 권한에 대한 추가 작업을 수행할 수 있습니다.

리소스가 더 이상 사용되지 않는 경우 애플리케이션은 CheckInLicense API 작업을 사용하여 권한을 다시 풀로 확인합니다.

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

라이선스를 다시 풀에 체크인하는 데 실패하면, 예를 들어 작업 중에 애플리케이션이 충돌하면 60분 후에 권한이 자동으로 다시 풀에 체크인됩니다. 따라서 리소스가 60분 넘게 사용 중이면 풀에서 권한을 체크아웃하는 것이 가장 좋습니다. 이렇게 하려면 리소스가 사용되는 동안 ExtendLicenseConsumption API 작업을 사용하십시오.

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

온프레미스 배포를 위해 License Manager와 통합하는 모범 사례

온프레미스 환경에서 컨테이너 애플리케이션을 배포할 때 아웃바운드 네트워크 액세스가 불안정할 수 있습니다. 인터넷 연결 불량으로 인한 잠재적 문제 때문에 구매자에게 제공되는 서비스가 중단되지 않도록 다음 모범 사례에 따라 복원력을 강화합니다.

  • 적절한 재시도 — 일시적인 네트워크 문제로 인해 애플리케이션이 연결되지 않을 수 있습니다. AWS License Manager지수 백오프를 사용하여 최대 30분 동안 재시도하도록 구현합니다. 이렇게 하면 단기적인 중단이나 네트워크 문제를 방지하는 데 도움이 될 수 있습니다.

  • 하드 제한 금지 - 연결된 클러스터에 배포된 애플리케이션은 정기적으로 라이선스를 확인하여 업그레이드 또는 갱신으로 인한 변경 사항을 식별할 수 있습니다. 아웃바운드 액세스가 불안정하면 애플리케이션이 이러한 변경 사항을 식별하지 못할 수 있습니다. 가급적이면 애플리케이션에서 License Manager를 통해 라이선스를 확인할 수 없어 구매자에게 제공되는 서비스가 중단되는 일이 없도록 해야 합니다. 라이선스가 만료되고 라이선스가 유효한지 확인할 수 없는 경우 애플리케이션이 무료 평가판 또는 오픈 소스 환경을 사용할 수 있습니다.

  • 고객 알림 - 캐시된 라이선스를 사용하는 경우 라이선스 변경 사항(갱신 또는 업그레이드 포함)이 실행 중인 워크로드에 자동으로 반영되지 않습니다. 애플리케이션이 캐시된 라이선스를 업데이트할 수 있도록 애플리케이션에 대한 아웃바운드 액세스를 일시적으로 다시 허용해야 한다고 고객에게 알려야 합니다. 예를 들어 애플리케이션 자체를 통해 또는 애플리케이션의 설명서를 통해 고객에게 알립니다. 마찬가지로, 기능 하위 세트로 대체하는 경우에도 권한이 모두 소진되었거나 라이선스가 만료되었다고 고객에게 알립니다. 그러면 고객은 업그레이드 또는 갱신을 선택할 수 있습니다.

LicenseManagerCredentialsProvider - Java 구현

LicenseCredentialsProvider를 추가하여 AWS SDK 온-프레미스에서 사용할 수 있도록 기본 자격 증명 공급자 체인을 확장합니다. 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온프레미스 환경에서 License Manager에서 OIDC 발급한 ID 토큰을 사용하여 자격 증명을 제공합니다. LicenseCredentialsProvider의 소스 코드를 애플리케이션 클래스 경로에 포함해야 합니다.

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 - Golang 구현

LicenseCredentialsProvider

LicenseCredentialsProvider를 AWS SDK 추가하여 온프레미스에서 사용할 수 있도록 기본 자격 증명 공급자 체인을 확장합니다. 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온프레미스 환경에서 License Manager에서 OIDC 발급한 ID 토큰을 사용하여 자격 증명을 제공합니다. LicenseCredentialsProvider의 소스 코드를 애플리케이션 클래스 경로에 포함해야 합니다.

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 } }