How to build a self-service for your tenant AWS accounts?

AWS Service Catalog + AWS Organizations


6 min read

How to build a self-service for your tenant AWS accounts?

Photo by John Morgan on Unsplash


Quite recently I got a great opportunity to speak at a community-led conference AWS Community Day as part of AWS Pop-up Hub Warsaw. In my brief presentation (in Polish) I've tried to show how to build a self-service for tenant AWS accounts, based on AWS Service Catalog and AWS Organizations. This article is a follow-up to my presentation on how to automate deployments of predefined AWS resources across multiple AWS accounts in your organization.

Service Catalog

AWS Service Catalog is a perfect service to build either a simple or more complex self-service for your AWS tenants. For example, you can prepare a well-designed 3-tier VPC, package it as a CF template and present it as an SC product, so your end users can simply kick off the VPC deployments in their AWS accounts by simply launching the SC product and providing some required parameters (i.e. CIDR block).


SC portfolios allow you to organize, manage, and distribute cloud resources for your end users. You can share the portfolios with other AWS accounts and allow the admins of those accounts to distribute the portfolios with additional restrictions.


SC products are version-friendly infrastructure-as-code templates added to portfolios for end users to provision and create AWS resources. A product can be either a single EC2 instance, S3 bucket, EKS cluster, full-blown VPC networking, multi-tier web application, or anything in between. It's simply a predefined CloudFormation template or a template imported from an existing CF stack.

Some sample CF templates for SC products:


SC constraints are certain limits that you can place on product-portfolio associations that allow you to manage minimal launch permissions or other optional actions that end users can perform on products. The most useful I usually find are:

  • launch constraints - for specifying a dedicated IAM role in the target account, which will be assumed by SC service to deploy CF stacks

  • template constraints - for limiting the values of CF parameters available to your end users, for example, a list of EC2 instance types

  • tag update constraints - used to allow/disallow end users to update tags on resources provisioned by the SC products


Your SC portfolios can be shared with users/roles inside a single AWS account, as well as with selected AWS accounts or a whole AWS organization. This also includes any external AWS accounts or other AWS organizations, so you can technically build a single self-service for multiple customers.

The following diagram shows a sample structure of related AWS accounts in a single organization: Management account (Organizations), Provisioning account (delegated Admin account for Service Catalog) and some Project accounts (spoke/tenant accounts). Additional IAM role(s) used as launch constraints need to be defined in the spoke accounts, which you can simply deploy with CloudFormation StackSets.

AWS Service Catalog sharing

CDK Constructs

To simplify the deployment of the Service Catalog resources in your Management or Provisioning account you can define them in a CDK application.

CloudFormation Product

Your products can be defined in CDK app in two ways. The first one is with the CloudFormationProduct construct: a CloudFormation template asset, stored either locally or remotely (S3, CodeCommit, GitHub). You have the template and you're providing its location. Easy, let's move on.

Product Stack

The second way is the ProductStack construct: a special CDK stack, where you define the resources you want to define for your SC product. This CDK stack will not be deployed as a CF stack, but rather only synthesized to a local JSON asset and consumed as a source template of the SC product. A pretty cool feature of CDK itself.

export class ScProductBucket extends ProductStack {

  constructor(scope: Construct, id: string) {
    super(scope, id);

    new s3.Bucket(this, 'PrivateBucket', {
      blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
      encryption: s3.BucketEncryption.KMS_MANAGED,
      enforceSSL: true,
      versioned: true

The full code for Product Stack:


Defining the Portfolio is pretty straightforward as well. The same applies to adding products and their versions to the portfolio. The sharing part is a bit more tricky.

AWS CDK and CloudFormation only support sharing with individual AWS accounts (by account ID) with the method shareWithAccount. Unfortunately, sharing with Organization or Organizational Unit is currently not supported (as of CDK release v2.60.0). However, there's always a workaround, more or less hacky.

This is a perfect opportunity to show you another interesting CDK construct, namely the AwsCustomResource. It's a singleton Lambda function, which can be used to extend the functionality of the CDK and/or CloudFormation. You can provide your code of course, but if you just need to get a response from some AWS API, the function code will be generated for you.

In my use case, I want to share the SC portfolio with my whole organization. To do this I'd need my organization's ID to create the portfolio share. I'm using here two AWS API calls to Organizations and Service Catalog services, respectively:

  • DescribeOrganization - to get dynamically the ID of my AWS Organization

  • CreatePortfolioShare - to share the portfolio with the whole Organization

Alternatively, I could provide my organization's ID statically, for example by using the CDK context file cdk.context.json. This would probably make more sense if I'd need to share the portfolio(s) with multiple external organizations and would need to have a list of IDs, then loop through them when creating the shares.

The code snippet below defines Custom Resource calling out AWS API call:

const describeOrg = new cr.AwsCustomResource(this, 'DescOrg', {
  onUpdate: {
    service: 'Organizations',
    action: 'describeOrganization',
    region: 'us-east-1',
  policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
    resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,

const orgId = describeOrg.getResponseField('Organization.Id');

The next important step is defining the products and their versions inside the portfolio and setting IAM role launch constraint, which can be simply done in the CDK with addProduct() and setLocalLaunchRoleName() methods, respectively. In my CDK stack, I'm building a list of products' CF templates with fromProductStack() method, which will be imported from the synthesized template produced by the ProductStack.

The full code for all SC-related resources is available here:

ITSM Integrations

Another interesting aspect of the AWS Service Catalog is integration with IT Service Management (ITSM) systems, which can be done with AWS Service Management Connectors (SMC). The connectors enable you to provision, manage, and operate native AWS resources directly from your ITSM system. Currently, supported integrations include ServiceNow Service Catalog and Atlassian Jira Service Management.

AWS Service Management Connector for ServiceNow:!/store/application/f0b117a3db32320093a7d7a0cf961912/

AWS Service Management Connector for JSM:


I hope this article will inspire you to build a self-service solution in your organization. It would be great if you'd share in the comments how have you organised your portfolios and what useful products have you designed for your end users in tenant AWS accounts. Have fun!


Self-Service (CDK Application)

IAM Roles (CDK Application)

AWS Service Catalog Construct Library (CDK)

AWS Service Catalog Administrator Guide

AWS Service Catalog User Guide

AWS Service Management Connectors

Did you find this article valuable?

Support Jakub Gaj by becoming a sponsor. Any amount is appreciated!