Giter VIP home page Giter VIP logo

aws-marketplace-serverless-saas-integration's Introduction

AWS Marketplace - Serverless integration for SaaS products (Example)

This project provides example of serverless integration for SaaS products listed on the AWS Marketplace.

If you are a new seller on AWS Marketplace, we advise you to check the following resources:

Project Structure

The sample in this repository demonstrates how to use AWS SAM (Serverless application mode) to integrate your SaaS product with AWS Marketplace and how to perform:

Register new customers

With SaaS subscriptions and SaaS contracts, your customers subscribe to your products through AWS Marketplace, but access the product on environment you manage in your AWS account. After subscribing to the product, your customer is directed to a website you create and manage as a part of your SaaS product to register their account and configure the product.

When creating your product, you provide a URL to your registration landing page. AWS Marketplace uses that URL to redirect customers to your registration landing page after they subscribe. On your software's registration URL, you collect whatever information is required to create an account for the customer. AWS Marketplace recommends collecting your customer’s email addresses if you plan to contact them through email for usage notifications.

The registration landing page needs to be able to identify and accept the x-amzn-marketplace-token token in the form data from AWS Marketplace with the customer’s identifier for billing. It should then pass that token value to the AWS Marketplace Metering Service and AWS Marketplace Entitlement Service APIs to resolve for the unique customer identifier and corresponding product code.

NOTE: Deploying the static landing page is optional. You can choose to use your existing SaaS registration page, after collecting the data you should call the register new subscriber endpoint. Please see the deployment section.

Implementation

In this sample we created CloudFront Distribution, which can be configured to use domain/CNAME by your choice. The POST request coming from AWS Marketplace is intercepted by the Edge src/lambda-edge/edge-redirect.js, which transforms the POST request to GET request, and passes the x-amzn-marketplace-token in the query string. We have created static HTML page hosted on S3 which takes the users inputs defined in the html form and submits them to marketplace/customer endpoint.

The handler for the marketplace/customer endpoint is defined in the src/register-new-subscriber.js file, where we call the resolveCustomer and validate the token. If the token is valid the customer record is created in the AWSMarketplaceSubscribers DynamoDB table and the new customer data are stored.

Grant and revoke access to your product

Grant access to new subscribers

Once the resolveCustomer endpoint return successful response, the SaaS vendors must to provide access to the solution to the new subscriber. Based on the type of listing contract or subscription we have defined different conditions in the grant-revoke-access-to-product.js stream handler that is executed on adding new or updating existing rows.

In our implementation the Marketplace Tech Admin (The email address you have entered when deploying), will receive email when new environment needs to be provisioned or existing environment needs to be updated. AWS Marketplace strongly recommends automating the access and environment management which can be achieved by modifying the grant-revoke-access-to-product.js function.

The property successfully subscribed is set when successful response is returned from the SQS entitlement handler for SaaS Contract based listings or after receiving **subscribe-success message from the Subscription SNS Topic in the case of AWS SaaS subscriptions in the subscription-sqs-handler.js.

Update entitlement levels to new subscribers (SaaS Contracts only)

Each time the entitlement is update we receive message on the SNS topic. The lambda function entitlement-sqs.js on each message is calling the marketplaceEntitlementService and storing the response in the dynamoDB.

We are using the same DynamoDB stream to detect changes in the entailment for SaaS contracts. When the entitlement is update notification is sent to the MarketplaceTechAdmin.

Revoke access to customers with expired contracts and cancelled subscriptions

The revoke access logic is implemented in a similar manner as the grant access logic.

In our implementation the MarketplaceTechAdmin receives email when the contract expires or the subscription is cancelled. AWS Marketplace strongly recommends automating the access and environment management which can be achieved by modifying the grant-revoke-access-to-product.js function.

Metering for usage

For SaaS subscriptions, the SaaS provider must meter for all usage, and then customers are billed by AWS based on the metering records provided. For SaaS contracts, you only meter for usage beyond a customer’s contract entitlements. When your application meters usage for a customer, your application is providing AWS with a quantity of usage accrued. Your application meters for the pricing dimensions that you defined when you created your product, such as gigabytes transferred or hosts scanned in a given hour.

Implementation

We have created MeteringSchedule CloudWatch Event rule that is triggered every hour. The metering-hourly-job.js gets triggered by this rule and it's querying all of the pending/unreported metering records from the AWSMarketplaceMeteringRecords table using the PendingMeteringRecordsIndex. All of the pending records are aggregated based on the customerIdentifier and dimension name, and sent to the SQSMetering queue. The records in the AWSMarketplaceMeteringRecords table are expected to be inserted programmatically by your SaaS application. In this case you will have to give permissions to the service in charge of collecting usage data in your existing SaaS product to be able to write to AWSMarketplaceMeteringRecords table.

The lambda function metering-sqs.js is sending all of the queued metering records to the AWS Marketplace Metering service. After every call to the batchMeterUsage endpoint the rows are updated in the AWSMarketplaceMeteringRecords table, with the response returned from the Metering Service, which can be found in the metering_response field. If the request was unsuccessful the metering_failed value with be set to true and you will have to investigate the issue the error will be also stored in the metering_response field.

The new records in the AWSMarketplaceMeteringRecords table should be stored in the following format:

{
  "create_timestamp": {
    "N": "113123"
  },
  "customerIdentifier": {
    "S": "ifAPi5AcF3"
  },
  "dimension_usage": {
    "L": [
      {
        "M": {
          "dimension": {
            "S": "users"
          },
          "value": {
            "N": "3"
          }
        }
      },
      {
        "M": {
          "dimension": {
            "S": "admin_users"
          },
          "value": {
            "N": "1"
          }
        }
      }
    ]
  },
  "metering_pending": {
    "S": "true"
  }
}

Where the create_timestamp is the sort key and customerIdentifier is the partition key, and they are both forming the Primary key. Note:The new records format is in DynamoDB JSON format. It is different than JSON. The accepted time stamp is UNIX timestamp in UTC time.

After the record is submitted to AWS Marketplace BatchMeterUsage API, it will be updated and it will look like this:

{
  "create_timestamp": 113123,
  "customerIdentifier": "ifAPi5AcF3",
  "dimension_usage": [
    {
      "dimension": "admin_users",
      "value": 3
    }
  ],
  "metering_failed": false,
  "metering_response": "{\"Results\":[{\"UsageRecord\":{\"Timestamp\":\"2020-06-24T04:04:53.776Z\",\"CustomerIdentifier\":\"ifAPi5AcF3\",\"Dimension\":\"admin_users\",\"Quantity\":3},\"MeteringRecordId\":\"35155d37-56cb-423f-8554-5c4f3e3ff56d\",\"Status\":\"Success\"}],\"UnprocessedRecords\":[]}"
}

Deploy the sample application

The Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API.

To use the SAM CLI, you need the following tools.

To build and deploy your application, you must sign in to the AWS Management Console with IAM permissions for the resources that the templates deploy. For more information, see AWS managed policies for job functions. Your organization may choose to use a custom policy with more restrictions. These are the AWS services that you need permissions to create as part of the deployment:

  • AWS IAM role
  • Amazon CloudWatch Logs
  • Amazon CloudFront
  • Amazon S3 bucket
  • AWS CloudFormation stack
  • AWS Lambda function
  • Amazon API Gateway
  • Amazon DynamoDB database
  • Amazon SQS queue
  • Amazon SNS topic
  • Amazon EventBridge

To build and deploy your application for the first time, run the following in your shell:

#Replace all `<PLACEHOLDER_VALUES>` with their `actual values` (e.g. `<PROJECT_NAME>` with `My Cool Project`).
#Create non-public bucket for <DEPLOYMENT_ARTEFACT_S3_BUCKET> before running this script

sam build
sam package --output-template-file packaged.yaml --s3-bucket <DEPLOYMENT_ARTEFACT_S3_BUCKET>

sam deploy --template-file packaged.yaml --stack-name <STACK_NAME> --capabilities CAPABILITY_IAM \
--region us-east-1 \
--parameter-overrides \
ParameterKey=WebsiteS3BucketName,ParameterValue=<WEBSITE_BUCKET_NAME> \
ParameterKey=ProductCode,ParameterValue=<MARKETPLACE_PRODUCT_CODE> \
ParameterKey=EntitlementSNSTopic,ParameterValue=<MARKETPLACE_ENTITLEMENT_SNS_TOPIC> \
ParameterKey=SubscriptionSNSTopic,ParameterValue=<MARKETPLACE_SUBSCRIPTION_SNS_TOPIC> \
ParameterKey=MarketplaceTechAdminEmail,ParameterValue=<MARKETPLACE_TECH_ADMIN_EMAIL>

#If you want to notify your buyer of successful purchase then you can use the following to deploy your application
sam deploy --template-file packaged.yaml --stack-name <STACK_NAME> --capabilities CAPABILITY_IAM \
--region us-east-1 \
--parameter-overrides \
ParameterKey=WebsiteS3BucketName,ParameterValue=<WEBSITE_BUCKET_NAME> \
ParameterKey=ProductCode,ParameterValue=<MARKETPLACE_PRODUCT_CODE> \
ParameterKey=EntitlementSNSTopic,ParameterValue=<MARKETPLACE_ENTITLEMENT_SNS_TOPIC> \
ParameterKey=SubscriptionSNSTopic,ParameterValue=<MARKETPLACE_SUBSCRIPTION_SNS_TOPIC> \
ParameterKey=MarketplaceTechAdminEmail,ParameterValue=<MARKETPLACE_TECH_ADMIN_EMAIL> \
ParameterKey=MarketplaceSellerEmail,ParameterValue=<SELLERSESVERIFIEDEMAILADDRESS>

#Check the account for <MARKETPLACE_TECH_ADMIN_EMAIL> and approve the subscription to SNS

#Replace the baseUrl in web/script.js with the API Gateway endpoint URL 

aws s3 cp ./web/ s3://<WEBSITE_BUCKET_NAME>/ --recursive

#add a CNAME record to your DNS to route the url you put on your offering to the cloudformation endpoint

#add the domain used for your marketplace URL to the CNAME on the cloudformation config

List of parameters

Parameter name Description
WebsiteS3BucketName S3 bucket to store the HTML files; Mandatory if CreateRegistrationWebPage is set to true; will be created
NewSubscribersTableName Use customer name for the New Subscribers Table; Default value: AWSMarketplaceSubscribers
AWSMarketplaceMeteringRecordsTableName Use customer name for the Metering Records Table; Default value: AWSMarketplaceMeteringRecords
TypeOfSaaSListing allowed values: contracts_with_subscription, contracts, subscriptions; Default value: contracts_with_subscription
ProductCode Product code provided from AWS Marketplace
EntitlementSNSTopic SNS topic ARN provided from AWS Marketplace. Must exist.
SubscriptionSNSTopic SNS topic ARN provided from AWS Marketplace. Must exist.
CreateRegistrationWebPage true or false; Default value: true
MarketplaceTechAdminEmail Email to be notified on changes requiring action
MarketplaceSellerEmail Seller email address, verified in SES and in 'Production' mode

Diagram of created resources

Based on the value of the TypeOfSaaSListing parameter different set of resources will be created.

In the case of contracts_with_subscription all of the resources depicted on the diagram below will be created.

In the case of a contracts, the resources market with orange circles will not be created.

In the case of a subscriptions the resources market with purple circles will not be created.

The landing page is optional. Use the CreateRegistrationWebPage parameter.

Cleanup

To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following:

aws cloudformation delete-stack --stack-name app

Security

See CONTRIBUTING for more information.

License

This library is licensed under the MIT-0 License. See the LICENSE file.

aws-marketplace-serverless-saas-integration's People

Contributors

amazon-auto avatar chotafakir avatar dependabot[bot] avatar gargana avatar gitvchandra avatar gjoshevski avatar jcvalerio avatar jesusrod avatar jimzucker avatar joserolles avatar kumarpawan1 avatar kwwaikar avatar lenopip avatar linhlam-mp avatar lulzneko avatar mandusm avatar mbatchelor avatar ozzambra avatar sgawsmp avatar stian-a-johansen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aws-marketplace-serverless-saas-integration's Issues

SQS Policy code is incorrect with typos and not functional

Describe the bug
The create entitlement logic has SQSpolice instead of policy.

      - CreateEntitlementLogic
      - Statement:
        - Sid: SQSPolice <- typo 
          Effect: Allow
          Action:
            - sqs:SendMessage
          Resource: !GetAtt EntitlementSQSQueue.Arn
      - !Ref "AWS::NoValue"

ARN is used instead of Queuename:

SQSSendMessagePolicy requires a queueName.

More info here: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-policy-template-list.html#sqs-send-message-policy

email not working

We were able to get the stack working but when the website says you are getting an email it never comes.

Any hints on where to look will be welcome

API Gateway resource in the template

Hello, and thanks for the solution.
Am I missing something regarding the API Gateway resource? Where does the value for "${ServerlessRestApi}" come from and where is the trigger for the function "RegisterNewMarketplaceCustomer" defined?

Enable Subscription SNS topic for SaaS Contract pricing model

Is your feature request related to a problem? Please describe.
The Subscription SNS topic was not available for SaaS Contract model. This topic covers the subscription status of a marketplace customer. It is now available for all SaaS pricing models.

Describe the solution you'd like
Setup the logic to subscribe to Subscription SNS topic for SaaS contract product and send the message to the Seller via the Support SNS topic.

Additional context
https://docs.aws.amazon.com/marketplace/latest/userguide/saas-notification.html#saas-sns-subscription-message-body

SQS Infinite Loop with Empty Entitlements

Describe the bug

When the AWS Marketplace service returns empty entitlements the application errors and is thrown into an infinite loop.

To Reproduce
Steps to reproduce the behavior:

You can test this with an event that has empty entitlements:
Screen Shot 2022-08-01 at 9 13 38 AM

For a simple example. Comment out this line in entitlement-sqs.js:
const entitlementsResponse = await marketplaceEntitlementService.getEntitlements(entitlementParams).promise();

And replace it with something like:

const entitlementsResponse = {'Entitlements': []}

Then, trigger the function.

  1. The function will error as shown in the screenshot (Which happened because a response from AWS in that structure was returned when actually calling the entitlements service).

Expected behavior
Either the marketplace service API call doesn't return an empty entitlement, OR a DLQ and better error handling is added to this application so that events like this are sent to the DLQ instead of being retried.

Screenshots

Screen Shot 2022-08-01 at 8 48 43 AM

Desktop (please complete the following information):

  • OS: Mac
  • Browser: Chrome

Additional context
Also feel free to reach out: fernando.medina.corey(at)telcodr(dot)com to discuss.

Doing a resolveCustomer() call using temporary credentials.

This might be useful for sites that want to have unauthenticated users doing the resolveCustomer() call.

I am successfully generating an AccessKey, SecretKey, and SessionToken associated with a Role that permits the temporary user to make resolveCustomer() calls.

I can prove that these credentials can successfully do a resolveCustomer() call by setting env vars:
(without setting these, it can't find credentials).

export AWS_ACCESS_KEY_ID=xxxxx
export AWS_SECRET_ACCESS_KEY=yyyyy
export AWS_SESSION_TOKEN=zzzz

And then doing the relevant CLI call:

aws meteringmarketplace resolve-customer --registration-token asdfa --region us-west-2

This should return an "InvalidToken" error.

Works great. However, I want to do this using the JavaScript SDK v3.

My attempt looks like this:

const tempCredentials =  {
  accessKeyId: AccessKeyId,
  secretAccessKey: SecretAccessKey,
  sessionToken: SessionToken
};

 const marketplacemetering = new MarketplaceMeteringClient({
   region: 'us-west-2',
   credentials: tempCredentials
 });

 const resolveCustomerParams = {
     RegistrationToken: 'asdfa',
 };

 const resolve = new ResolveCustomerCommand(resolveCustomerParams);

 try {

    const data = await marketplacemetering.send(resolve);
    return data;

 } catch (error)  {

   return error;

 }

The call returns "TypeError: Failed to fetch" which usually means that the Api call is just not setup properly.
What I'm expecting is a 400 error of type InvalidToken.
Any thoughts?

Lambda@Edge function returns 502 error

Describe the bug
Upon filling the sample app form and submitting it, I get a generic cloudfront 502 error page.

Please see also: aws-ia/cloudformation-aws-marketplace-saas#54

To Reproduce
Steps to reproduce the behavior:

  1. Install the sample app as described
  2. try to buy the marketplace product

Expected behavior
The provided sample app should complete the way it should....

Apparently, the form sends the data as multipart/form-data, but the Lambda@edge function expects application/x-www-form-urlencoded.

Stack - Unlaunchable in other regions

Is your feature request related to a problem? Please describe.

We couldn't run the stack because it only supports the N. Virginia region today and we use Ohio, with strict guard rails in place to prevent notifications being received from other regions.

Describe the solution you'd like
Create the stack so that it can be deployed in any region that supports the services.

Describe alternatives you've considered
Manual integration and custom deployment.

Additional context
Add any other context or screenshots about the feature request here.

Enhance instructions to make amendments

The app is great, a quick start guide on how to make simple changes and update the stack would be great., ie I want to modify the registration lambda. Since it is not editable I have to learn how this stack works to re-deploy, can you give me some pointers?

Invalid parameter: TopicArn Reason: An ARN must have at least 6 elements

Describe the bug

We are deploying landing page for our Marketplace integration. While deploying facing following issues:
Invalid parameter: TopicArn Reason: An ARN must have at
least 6 elements, not 1 (Service: AmazonSNS; Status Code:
400; Error Code: InvalidParameter; Request ID:
98904f2c-9377-56e1-b024-17dcd6a302ad; Proxy: null)User: arn:aws:iam::xxxxxxx:user/xxxxxx is
not authorized to perform: SNS:Subscribe on resource:
arn:aws:sns:us-east-1:287250355862:aws-mp-entitlement-
notification-XXXXXXXX (Service: AmazonSNS;
Status Code: 403; Error Code: AuthorizationError; Request
ID: da0cfc82-d12a-5dfd-b1a6-a472cb4f9071; Proxy: null)
To resolve this issue we commented out EntitlementSQSHandler block from template.yaml.

We were able to deploy the landing page. However when we tried to access web page. It displays following error:

This XML file does not appear to have any style information associated with it. The document tree is shown below.

AccessDenied
Access Denied
Z9161D15XV37JFVH
zrlf9xukKblFljCwM3uMD0j60Vj54fQZrfoHNiXl7wvOVzMt7cwGzXJTN3CB/LJUE0fLVuDvGg0=

delete fails - lambda and s3

deleting gets these errors:

2021-05-20 17:28:05 UTC-0700 | ezops-saas-landing-page | DELETE_FAILED | The following resource(s) failed to delete: [LambdaEdgeRedirectPostRequests, WebsiteS3Bucket].

2021-05-20 17:28:00 UTC-0700 | LambdaEdgeRedirectPostRequests | DELETE_FAILED | Resource handler returned message: "Lambda was unable to delete arn:aws:lambda:us-east-1:865330066347:function:ezops-saas-landing-page-LambdaEdgeRedirectPostRequ-A1QyBSJhg0vw:1 because it is a replicated function. Please see our documentation for Deleting Lambda@Edge Functions and Replicas. (Service: Lambda, Status Code: 400, Request ID: 58deb957-2045-4ae0-b70a-df7de067f6ac, Extended Request ID: null)" (RequestToken: 9af66a2e-668d-959e-de3d-6012b95e0c8b, HandlerErrorCode: InvalidRequest)

2021-05-20 17:27:58 UTC-0700 | WebsiteS3Bucket | DELETE_FAILED | The bucket you tried to delete is not empty (Service: Amazon S3; Status Code: 409; Error Code: BucketNotEmpty; Request ID: FSJY3WDFDNFQK39A; S3 Extended Request ID: 9S/i72ctBdW2bXE0U+URCSLAAl0vMIIgFwRSPHi2P+YIE6oLOQhMc34HC2D6Nmvmt2DvWfPH8GE=; Proxy: null)
2021

template.yaml has typo

Describe the bug
Attempt to use sam deploy failed because SQSMeteringRecrods.Arn doesn't exist. It should be SQSMeteringRecords.Arn

To Reproduce
Steps to reproduce the behavior:

  1. Follow instructions
  2. Once you get to the sam deploy step, it will fail with the following error:
    Error: Failed to create changeset for the stack: my-stack, ex: Waiter ChangeSetCreateComplete failed: Waiter encountered a terminal failure state Status: FAILED. Reason: Template error: instance of Fn::GetAtt references undefined resource SQSMeteringRecrods

Expected behavior
It should succeed in deployment

Desktop (please complete the following information):
Using Cloud9 deployment following directions

QOL - improvement

Is your feature request related to a problem? Please describe.
The current quickstart template does not inform customers should enter a bucket with lower case characters.

Describe the solution you'd like
In the Quick-start template - s3 website bucket description should indicate that the bucket name should be lower case characters per s3 requirements.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

entitlement-sqs.js: Cannot read property 'ExpirationDate' of undefined

Describe the bug
After AWS Support deleted a test SaaS subscription (to cleanup internal testing), the serverless integration reported the following errors. The lambda function is invoked repeatedly ($$$) but fails to process the message

2022-10-28T17:24:25.283Z        b0ebcf90-1d41-5b3e-af18-94460ebaf1c0	INFO	entitlementsResponse { Entitlements: [] }

2022-10-28T17:24:25.283Z	6a4209b2-28b4-5344-a57a-52643ac848d8	ERROR	Invoke Error 	{"errorType":"TypeError","errorMessage":"Cannot read property 'ExpirationDate' of undefined","stack":["TypeError: Cannot read property 'ExpirationDate' of undefined","    at /var/task/entitlement-sqs.js:31:71","    at runMicrotasks (<anonymous>)","    at processTicksAndRejections (internal/process/task_queues.js:97:5)","    at async Promise.all (index 0)","    at async Runtime.exports.handler (/var/task/entitlement-sqs.js:10:3)"]}

suspect the problem is in the following line in entitlement-sqs.js

      const isExpired = new Date(entitlementsResponse.Entitlements[0].ExpirationDate) < new Date();

To Reproduce
Steps to reproduce the behavior:

  1. AWS Support deleted existing subscription (created from internal testing)

Expected behavior
{ Entitlements: [] } is handled gracefully by the serverless integration.

Enable "Vendor Metered Tagging" feature as part of SaaS CFT

Is your feature request related to a problem? Please describe.

The problem: customers does not have a clear visibility into their cost usage from SaaS provider if there is no tagging around the usage. Customers will only receive one bill that includes all the activities associated with the SaaS subscription.

Describe the solution you'd like

Enabling Vendor-metered tagging feature in the SaaS CFT solution would allow vendors to tag the usage that relevant to the customers, so customers can better understand their resource usage. The solution consist of adding the extra tagging field that SaaS vendors can supply, and support metering payload up to 1MB, because it is a new requirement after enabling tagging field.

Additional context

Documentation Link: https://docs.aws.amazon.com/marketplacemetering/latest/APIReference/API_BatchMeterUsage.html

This feature is especially important for SaaS product as we have limited information about SaaS user account. This will benefit both vendors and the customers for the long term, below are few value prepositions:

  1. Customers will be able to understand the breadth of the value the seller provide for their business units.
  2. This will directly reduce manual work for customers in terms of reconcile costs.
  3. Increase revenue for ISVs, because better tagging will help customers increase usage if they can understand and analyze allocation usage in detail.

Question on SaaS Contract registartion

This actually is a question and not a bug. In register-new-subscriber.js, on line 56, why are you sending a message yourself? From the documentation, it seems like Amazon would send a message with action = entitlement-updated and we are expected to process the SNS message. This confused me a bit. Can you help clarify?

Other than that, the code provided is top notch and helped us understand the marketplace workflow very clearly. Thanks a lot for putting in the efforts.

The template does not support cross-account access to the marketplace resources

The best practice for setting up our marketplace is to use a separate account for hosting this template.

We created and have an approved offering in our billing account and we have setup a cross-account role and tested it to access the marketplace sns topic.

How ever the Cloud formation template does not seem to support this.

we chatted with premium support but needhelp modifying the steps we are taking or the cloudformation to use our cross account role.

This is what support said:

You were having issues deploying the ‘Serverless integration for SaaS products’ sample CloudFormation stack [1]. You are receiving the following errors:


User: arn:aws:iam::232109169367:user/dilip-marketplace is not authorized to perform: SNS:Subscribe on resource: arn:aws:sns:us-east-1:287250355862:aws-mp-entitlement-notification-e4p71lg2jqw2dh4sjkxbcyuyo

Invalid parameter: TopicArn Reason: An ARN must have at least 6 elements, not 1

You are trying to subscribe to the SNS topic with an IAM role in another AWS Account which is whitelisted for the subscription. A previous Engineer Eman suggested to use a Lambda custom resource to first assume the whitelisted IAM role then subscribe to the SNS topic programmatically using the assumed role [2]. You mentioned in the chat that you had made changes in the stack to assume the role but you were still receiving the same errors. Please correct me if my understanding is wrong.

When deploying a CloudFormation stack, it will assume the IAM role that made the deploy API call (unless a Service Role is specified) to create the underlying CloudFormation resources. In this case, IAM user ‘dilip-marketplace’ is being assumed by CloudFormation to create the resources. However, when it attempts to create resource ‘SubscriptionSQSHandlerMySQSEvent’, the SNS topic sees that ‘dilip-marketplace’ role is in an AWS Account that has not been whitelisted and rejects the subscription attempt.

I can see you were working with an IAM Support Engineer to create the IAM role ‘arn:aws:iam::865330066347:role/marketplace-cross-account-role’ that should have cross account role access to subscribe to the SNS topic. With this in mind, we need a way of assuming the role ‘marketplace-cross-account-role’ in CloudFormation to perform the SNS subscription.

There is no native functionality in CloudFormation to individually assume roles for each resource. However, an ’AWS::CloudFormation::CustomResource’ [3] can be used to replace the ‘AWS::SNS::Subscription’ resource type with a Lambda function that first assumes the role ‘arn:aws:iam::865330066347:role/marketplace-cross-account-role’ then uses that assumed role to subscribe to the SNS topic using AWS SDK that calls the ‘subscribe’ API call [4].

Therefore, ‘SubscriptionSQSHandlerMySQSEvent’ resource needs to be replaced with a custom resource that uses a Lambda function to assume the role ‘arn:aws:iam::865330066347:role/marketplace-cross-account-role’ and make the subscribe API call.

It’s likely that the ‘EntitlementSNSTopic’ will also need to be replaced with a custom Lambda resource so it can assume the ‘marketplace-cross-account-role’ IAM role and subscribe to the SNS topic.

Request to define an IAM policy for this solution

Is your feature request related to a problem? Please describe.
Please define a IAM policy that can be attached to a IAM user and provide restricted access to the seller AWS account to deploy the serverless solution.

This is a top ask from seller teams to manage their seller AWS account permissions.

The Metering record sample format provided in the doc is invalid

Describe the bug
The Readme file provides a sample metering record format to submit the records to the Metering Records DynamoDB table created by the application. The below provided record format is invalid.

{
"create_timestamp": 113123,
"customerIdentifier": "ifAPi5AcF3",
"dimension_usage": [
{
"dimension": "users",
"value": 3
},
{
"dimension": "admin_users",
"value": 1
}
],
"metering_pending": "true"
}

To Reproduce
Steps to reproduce the behavior:
1.Deploy the serverless application with SaaS CCP or subscription model
2. Try to submit a dummy metering record in the format provided
3.

Expected behavior
The document should provide the correct metering record format to be accepted by the metering DynamoDB table.

Screenshots
If applicable, add screenshots to help explain your problem.
image

Desktop (please complete the following information):

  • OS: [e.g. iOS] Windows
  • Browser [e.g. chrome, safari] Firefox

Additional context
Add any other context about the problem here.

Specifying a long stack name causes and error while creating the SQSMetering Queue

Describe the bug
Specifying a long stack name causes and error while creating the SQSMetering Queue

To Reproduce
Steps to reproduce the behavior:

  1. Launch the solution with a long stack name. (80 Chars)

Expected behavior
SQSMetering Queue resource fails to create.

The name of a FIFO queue can only include alphanumeric characters, hyphens, or underscores, must end with .fifo suffix and be 1 to 80 in length.

Additional context
We are consuming the project as part of an automation:
aws-ia/cloudformation-aws-marketplace-saas#6

Empty entitleResponse object within the entitlement-sqs.js script

Describe the bug
Running into a runtime error on the entitlementService script with the following log:
`2022-03-14T21:05:27.152Z 60da1f47-10a8-5a34-adc1-45eea0e044ea INFO entitlementsResponse
{}

2022-03-14T21:05:27.152Z 60da1f47-10a8-5a34-adc1-45eea0e044ea ERROR Invoke Error
{
"errorType": "TypeError",
"errorMessage": "Cannot read property '0' of undefined",
"stack": [
"TypeError: Cannot read property '0' of undefined",
" at /var/task/entitlement-sqs.js:33:67",
" at runMicrotasks ()",
" at processTicksAndRejections (internal/process/task_queues.js:97:5)",
" at async Promise.all (index 0)",
" at async Runtime.exports.handler (/var/task/entitlement-sqs.js:8:3)"
]
}`

To Reproduce
Steps to reproduce the behavior:

  1. Follow the AWS recommended quick start guide to deploy the stack
  2. Test creating a contract subscription
  3. The email to seller was never received, after investigation, determined that the entitlement-sqs.js is generating the fatal error with the log above, hence the record was never pushed onto the SNS queue.

Expected behavior
This line in the entitlement-sqs.js, const entitlementsResponse = await marketplaceEntitlementService.getEntitlements(entitlementParams).promise(); should not be returning an empty object.

Desktop (please complete the following information):

  • OS: iOS
  • Browser: chrome

Additional context
Add any other context about the problem here.

SAM deployment fails when `CreateRegistrationWebPage` is set to `false`

Describe the bug
When parameter CreateRegistrationWebPage is set to false deployment fails due to the fact that the Output - LandingPageUrl references CloudfrontDistribution which is only created when CreateRegistrationWebPage is true .

To Reproduce
Deploy the app with CreateRegistrationWebPage set to false

Expected behavior
The stack will fail complaining about an unresolvable reference

Screenshots
If applicable, add screenshots to help explain your problem.
Screen Shot 2022-08-17 at 11 15 00 AM

Desktop (please complete the following information):
n/a

Smartphone (please complete the following information):
n/a

Additional context
Add any other context about the problem here.

Documentation Improvements

Some notes on the documentation that may help others:

You have to create these manually before executing the CLI Commands:

  <DEPLOYMENT_ARTEFACT_S3_BUCKET>
  <MARKETPLACE_ENTITLEMENT_SNS_TOPIC>  - This must be the full topic ARN (FIFO does not work - use STANDARD)
  <MARKETPLACE_SUBSCRIPTION_SNS_TOPIC>  - This must be the full topic ARN (FIFO does not work - use STANDARD)

You provide these strings before executing the CLI Commands:

<STACK_NAME>
<MARKETPLACE_PRODUCT_CODE>
<MARKETPLACE_TECH_ADMIN_EMAIL>

This is created BY CLOUDFORMATION on your behalf:

<WEBSITE_BUCKET_NAME> - Make sure you supply a valid and unique name

Your stack may take 30 minutes to finish because it deploys a new Cloudfront distribution
which takes 15-30 minutes to deploy.

Go to Cloudfront to get your "website" URL. It will look something like: https://d2foiuiyrqbfrhj.cloudfront.net
You should be able to load it into any web browser and get a registration page.

Question on design for Marketplace metering

Very helpful repo, thank you. I had a question regarding the motivation behind the design of how metering records are submitted to Marketplace.

What is the motivation/reason for having the metering-hourly-job.js function send records to a SQS queue, and having another function to read records from this queue and submit to Marketplace? Would it still work to have the metering-hourly-job.js function both aggregate the records and submit to Marketplace and record the response in the table? Are there any downsides about using this approach?

Thank you.

Upgrade runtimes to nodeJS16

Is your feature request related to a problem? Please describe.
The nodeJS12 runtime is being deprecated and the stack will need upgrading to ensure that it's valid after support has ended

Describe the solution you'd like
Node16 is in active LTS so this would be ideal to implement
https://github.com/nodejs/Release#release-schedule

Describe alternatives you've considered
Node14 would work but require a replacement again in the near future.

Additional context
N/A

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.