Create the product
What are we going to do?
We have provisioned a detective control to look for AWS RDS Instances that have don't have encryption enabled. We can do better, and create an AWS Service Catalog product that meets the encryption requirement by default using service catalog tools. When users create a new RDS instance using this product, encryption at rest is enabled by default and no further configuration is required.
We are going to perform the following steps:
define a product with a version and a portfolio
add the source code for our product
share that portfolio with a spoke account
Step by step guide
Here are the steps you need to follow to “Create the product”
Define a product with a version and a portfolio
Add the following to the products section:
- Name : "rds-instance"
Owner : "data-governance@example.com"
Description : "A compliant RDS Instance you can use that meets data governance standards"
Distributor : "cloud-engineering"
SupportDescription : "Speak to data-governance@example.com about exceptions and speak to cloud-engineering@example.com about implementation issues"
SupportEmail : "cloud-engineering@example.com"
SupportUrl : "https://wiki.example.com/cloud-engineering/data-governance/rds-instance"
Options :
ShouldCFNNag : True
Tags :
- Key : "type"
Value : "governance"
- Key : "creator"
Value : "cloud-engineering"
Versions :
- Name : "v1"
Description : "v1 of rds-instance"
Active : True
Source :
Provider : "CodeCommit"
Configuration :
RepositoryName : "rds-instance"
BranchName : "main"
Portfolios :
- "cloud-engineering-self-service"
Add the following to the portfolios section:
- DisplayName : "cloud-engineering-self-service"
Description : "Portfolio containing products that you can use to ensure you meet the governance guidelines"
ProviderName : "cloud-engineering"
Associations :
- "arn:aws:iam::${AWS::AccountId}:role/TeamRole"
Tags :
- Key : "type"
Value : "governance"
- Key : "creator"
Value : "cloud-engineering"
Once completed it should like look this:
Schema : factory - 2019 - 04 - 01
Products :
- Name : "aws-config-desired-instance-types"
Owner : "budget-and-cost-governance@example.com"
Description : "Enables AWS Config rule - desired-instance-type with our RIs"
Distributor : "cloud-engineering"
SupportDescription : "Speak to budget-and-cost-governance@example.com about exceptions and speak to cloud-engineering@example.com about implementation issues"
SupportEmail : "cloud-engineering@example.com"
SupportUrl : "https://wiki.example.com/cloud-engineering/budget-and-cost-governance/aws-config-desired-instance-types"
Tags :
- Key : "type"
Value : "governance"
- Key : "creator"
Value : "cloud-engineering"
- Key : "cost-center"
Value : "governance"
Versions :
- Name : "v1"
Description : "v1 of aws-config-desired-instance-types"
Active : True
Source :
Provider : "CodeCommit"
Configuration :
RepositoryName : "aws-config-desired-instance-types"
BranchName : "main"
Portfolios :
- "cloud-engineering-governance"
- Name : "aws-config-rds-storage-encrypted"
Owner : "data-governance@example.com"
Description : "Enables AWS Config rule - aws-config-rds-storage-encrypted"
Distributor : "cloud-engineering"
SupportDescription : "Speak to data-governance@example.com about exceptions and speak to cloud-engineering@example.com about implementation issues"
SupportEmail : "cloud-engineering@example.com"
SupportUrl : "https://wiki.example.com/cloud-engineering/data-governance/aws-config-rds-storage-encrypted"
Tags :
- Key : "type"
Value : "governance"
- Key : "creator"
Value : "cloud-engineering"
- Key : "cost-center"
Value : "governance"
Versions :
- Name : "v1"
Description : "v1 of aws-config-rds-storage-encrypted"
Active : True
Source :
Provider : "CodeCommit"
Configuration :
RepositoryName : "aws-config-rds-storage-encrypted"
BranchName : "main"
Portfolios :
- "cloud-engineering-governance"
- Name : "rds-instance"
Owner : "data-governance@example.com"
Description : "A compliant RDS Instance you can use that meets data governance standards"
Distributor : "cloud-engineering"
SupportDescription : "Speak to data-governance@example.com about exceptions and speak to cloud-engineering@example.com about implementation issues"
SupportEmail : "cloud-engineering@example.com"
SupportUrl : "https://wiki.example.com/cloud-engineering/data-governance/rds-instance"
Options :
ShouldCFNNag : True
Tags :
- Key : "type"
Value : "governance"
- Key : "creator"
Value : "cloud-engineering"
Versions :
- Name : "v1"
Description : "v1 of rds-instance"
Active : True
Source :
Provider : "CodeCommit"
Configuration :
RepositoryName : "rds-instance"
BranchName : "main"
Portfolios :
- "cloud-engineering-self-service"
Portfolios :
- DisplayName : "cloud-engineering-governance"
Description : "Portfolio containing the products needed to govern AWS accounts"
ProviderName : "cloud-engineering"
Associations :
- "arn:aws:iam::${AWS::AccountId}:role/TeamRole"
Tags :
- Key : "type"
Value : "governance"
- Key : "creator"
Value : "cloud-engineering"
- Key : "cost-center"
Value : "governance"
- DisplayName : "cloud-engineering-self-service"
Description : "Portfolio containing products that you can use to ensure you meet the governance guidelines"
ProviderName : "cloud-engineering"
Associations :
- "arn:aws:iam::${AWS::AccountId}:role/TeamRole"
Tags :
- Key : "type"
Value : "governance"
- Key : "creator"
Value : "cloud-engineering"
Have a look at the highlighted lines. We are using this to turn on cfn-nag , an open source tool by Stelligent that looks for insecure configuration of resources. This will add an extra layer
of governance ensuring the AWS CloudFormation templates we are using meets the quality bar set by cfn-nag .
Set your Author name
Set your Email address
Set your Commit message
Using a good / unique commit message will help you understand what is going on later.
Click the Commit changes button:
What did we just do?
The YAML we pasted in the previous step told the framework to perform several actions:
create a product named rds-instance
add a v1 of our product
create a portfolio named cloud-engineering-self-service
add the product: rds-instance to the portfolio: cloud-engineering-self-service
Verify the change worked
Once you have made your changes the ServiceCatalogFactory Pipeline should have run. If you were very quick, the pipeline
may still be running. If it has not yet started feel free to the hit the Release change button.
Once it has completed it should show the Source and Build stages in green to indicate they have completed
successfully:
If this is failing please raise your hand for some assistance
Add the source code for our product
When you configured your product version, you specified the following version:
Versions :
- Name : "v1"
Description : "v1 of rds-instance"
Active : True
Source :
Provider : "CodeCommit"
Configuration :
RepositoryName : "rds-instance"
BranchName : "main"
This tells the framework the source code for the product comes from the main branch of a
CodeCommit repository of the name rds-instance .
We now need to create the CodeCommit repository and add the AWS CloudFormation template we are going to use for our
product.
Input the name rds-instance
Scroll down to the bottom of the page and hit the Create file button
Copy the following snippet into the main input field:
AWSTemplateFormatVersion : 2010 - 09 - 09
Description : "RDS Storage Encrypted"
Parameters :
RdsDbMasterUsername :
Description : RdsDbMasterUsername
Type : String
Default : someuser
RdsDbMasterUserPassword :
Description : RdsDbMasterUserPassword
Type : String
NoEcho : true
RdsDbDatabaseName :
Description : DbDatabaseName
Type : String
Default : mysql57_database
Resources :
VPC :
Type : AWS : : EC2 : : VPC
Properties :
CidrBlock : 10.0 .0 .0 / 16
EnableDnsSupport : 'false'
EnableDnsHostnames : 'false'
Subnet1 :
Type : AWS : : EC2 : : Subnet
Properties :
VpcId :
Ref : VPC
CidrBlock : 10.0 .0 .0 / 24
AvailabilityZone : ! Select [0 , ! GetAZs {Ref : 'AWS::Region' }]
Subnet2 :
Type : AWS : : EC2 : : Subnet
Properties :
VpcId :
Ref : VPC
CidrBlock : 10.0 .1 .0 / 24
AvailabilityZone : ! Select [1 , ! GetAZs {Ref : 'AWS::Region' }]
RdsDbSubnetGroup :
Type : AWS : : RDS : : DBSubnetGroup
Properties :
DBSubnetGroupDescription : Database subnets for RDS
SubnetIds :
- ! Ref Subnet1
- ! Ref Subnet2
RdsSecurityGroup :
Type : AWS : : EC2 : : SecurityGroup
Description : Used to grant access to and from the VPC
Properties :
VpcId : ! Ref VPC
GroupDescription : Allow MySQL (TCP3306 ) access to and from the VPC
SecurityGroupIngress :
- IpProtocol : tcp
FromPort : 3306
ToPort : 3306
CidrIp : 10.0 .0 .0 / 32
SecurityGroupEgress :
- IpProtocol : tcp
FromPort : 3306
ToPort : 3306
CidrIp : 10.0 .0 .0 / 32
RdsDbClusterParameterGroup :
Type : AWS : : RDS : : DBClusterParameterGroup
Properties :
Description : CloudFormation Aurora Cluster Parameter Group
Family : aurora - mysql5 .7
Parameters :
server_audit_logging : 0
server_audit_events : 'CONNECT,QUERY,QUERY_DCL,QUERY_DDL,QUERY_DML,TABLE'
RdsDbCluster :
Type : AWS : : RDS : : DBCluster
Properties :
DBSubnetGroupName : ! Ref RdsDbSubnetGroup
MasterUsername : ! Ref RdsDbMasterUsername
MasterUserPassword : ! Ref RdsDbMasterUserPassword
DatabaseName : ! Ref RdsDbDatabaseName
Engine : aurora - mysql
VpcSecurityGroupIds :
- ! Ref RdsSecurityGroup
DBClusterIdentifier : ! Sub '${AWS::StackName}-dbcluster'
DBClusterParameterGroupName : ! Ref RdsDbClusterParameterGroup
PreferredBackupWindow : 18 : 05 - 18 : 35
RdsDbParameterGroup :
Type : AWS : : RDS : : DBParameterGroup
Properties :
Description : CloudFormation Aurora Parameter Group
Family : aurora - mysql5 .7
Parameters :
aurora_lab_mode : 0
general_log : 1
slow_query_log : 1
long_query_time : 10
RdsDbInstance :
Type : AWS : : RDS : : DBInstance
Properties :
DBSubnetGroupName : ! Ref RdsDbSubnetGroup
DBParameterGroupName : ! Ref RdsDbParameterGroup
Engine : aurora - mysql
DBClusterIdentifier : ! Ref RdsDbCluster
AutoMinorVersionUpgrade : 'true'
PubliclyAccessible : 'false'
PreferredMaintenanceWindow : Thu : 19 : 05 - Thu : 19 : 35
AvailabilityZone : ! Select [0 , ! GetAZs {Ref : 'AWS::Region' }]
DBInstanceClass : 'db.t2.small'
Using a good / unique commit message will help you understand what is going on later.
Creating that file should trigger your
rds-instance-v1-pipeline .
Once the pipeline has completed it should show the Source stage in green to indicate it has completed successfully but
it should show the CFNNag action within the Tests stage as failing:
Clicking the Details link within the CFNNag box will bring you to the AWS CodeBuild project. When you scroll near to
the bottom of that page you should see an error:
·[ 0;31;49m| FAIL F26·[ 0m
·[ 0;31;49m|·[ 0m
·[ 0;31;49m| Resources: [ "RdsDbCluster" ] ·[ 0m
·[ 0;31;49m| Line Numbers: [ 84] ·[ 0m
·[ 0;31;49m|·[ 0m
·[ 0;31;49m| RDS DBCluster should have StorageEncrypted enabled·[ 0m
CFNNag has determined you are not applying encryption to your DBCluster. This is a violation of the data governance
guidelines and so we need to fix it.
Go to AWS CodeCommit
Click on the rds-instance repository
Click on product.template.yaml
Click on edit
Replace the contents with this:
AWSTemplateFormatVersion : 2010 - 09 - 09
Description : "RDS Storage Encrypted"
Parameters :
RdsDbMasterUsername :
Description : RdsDbMasterUsername
Type : String
Default : someuser
RdsDbMasterUserPassword :
Description : RdsDbMasterUserPassword
Type : String
NoEcho : true
RdsDbDatabaseName :
Description : DbDatabaseName
Type : String
Default : mysql57_database
Resources :
VPC :
Type : AWS : : EC2 : : VPC
Properties :
CidrBlock : 10.0 .0 .0 / 16
EnableDnsSupport : 'false'
EnableDnsHostnames : 'false'
Subnet1 :
Type : AWS : : EC2 : : Subnet
Properties :
VpcId :
Ref : VPC
CidrBlock : 10.0 .0 .0 / 24
AvailabilityZone : ! Select [0 , ! GetAZs {Ref : 'AWS::Region' }]
Subnet2 :
Type : AWS : : EC2 : : Subnet
Properties :
VpcId :
Ref : VPC
CidrBlock : 10.0 .1 .0 / 24
AvailabilityZone : ! Select [1 , ! GetAZs {Ref : 'AWS::Region' }]
RdsDbSubnetGroup :
Type : AWS : : RDS : : DBSubnetGroup
Properties :
DBSubnetGroupDescription : Database subnets for RDS
SubnetIds :
- ! Ref Subnet1
- ! Ref Subnet2
RdsSecurityGroup :
Type : AWS : : EC2 : : SecurityGroup
Description : Used to grant access to and from the VPC
Properties :
VpcId : ! Ref VPC
GroupDescription : Allow MySQL (TCP3306 ) access to and from the VPC
SecurityGroupIngress :
- IpProtocol : tcp
FromPort : 3306
ToPort : 3306
CidrIp : 10.0 .0 .0 / 32
SecurityGroupEgress :
- IpProtocol : tcp
FromPort : 3306
ToPort : 3306
CidrIp : 10.0 .0 .0 / 32
RdsDbClusterParameterGroup :
Type : AWS : : RDS : : DBClusterParameterGroup
Properties :
Description : CloudFormation Aurora Cluster Parameter Group
Family : aurora - mysql5 .7
Parameters :
server_audit_logging : 0
server_audit_events : 'CONNECT,QUERY,QUERY_DCL,QUERY_DDL,QUERY_DML,TABLE'
RdsDbCluster :
Type : AWS : : RDS : : DBCluster
Properties :
DBSubnetGroupName : ! Ref RdsDbSubnetGroup
MasterUsername : ! Ref RdsDbMasterUsername
MasterUserPassword : ! Ref RdsDbMasterUserPassword
DatabaseName : ! Ref RdsDbDatabaseName
Engine : aurora - mysql
VpcSecurityGroupIds :
- ! Ref RdsSecurityGroup
DBClusterIdentifier : ! Sub '${AWS::StackName}-dbcluster'
DBClusterParameterGroupName : ! Ref RdsDbClusterParameterGroup
PreferredBackupWindow : 18 : 05 - 18 : 35
StorageEncrypted : True
RdsDbParameterGroup :
Type : AWS : : RDS : : DBParameterGroup
Properties :
Description : CloudFormation Aurora Parameter Group
Family : aurora - mysql5 .7
Parameters :
aurora_lab_mode : 0
general_log : 1
slow_query_log : 1
long_query_time : 10
RdsDbInstance :
Type : AWS : : RDS : : DBInstance
Properties :
DBSubnetGroupName : ! Ref RdsDbSubnetGroup
DBParameterGroupName : ! Ref RdsDbParameterGroup
Engine : aurora - mysql
DBClusterIdentifier : ! Ref RdsDbCluster
AutoMinorVersionUpgrade : 'true'
PubliclyAccessible : 'false'
PreferredMaintenanceWindow : Thu : 19 : 05 - Thu : 19 : 35
AvailabilityZone : ! Select [0 , ! GetAZs {Ref : 'AWS::Region' }]
DBInstanceClass : 'db.t2.small'
StorageEncrypted : True
Please observe the highlighted lines showing where we have made a change. We have added:
Set your Author name
Set your Email address
Set your Commit message
Click Commit changes
Using a good / unique commit message will help you understand what is going on later.
Creating that file should trigger your
rds-instance-v1-pipeline .
Once the pipeline has completed it should show the Source and Tests stages in green to indicate they have completed
successfully:
You should see your commit message on this screen, it will help you know which version of ServiceCatalogFactory repository the
pipeline is processing.
If this is failing please raise your hand for some assistance
Once you have verified the pipeline has run you can go to Service Catalog products to view your newly
created version.
You should see the product you created listed:
Click on the product and verify v1 is there
If you cannot see your version please raise your hand for some assistance
You have now successfully created a version for your product!
Verify that the product was added to the portfolio
Now that you have verified the pipeline has run you can go to Service Catalog portfolios to view your
portfolio.
Click on cloud-engineering-self-service
Share portfolio with a spoke account
Append the following snippet to the YAML document in the main input field (be careful with your indentation):
spoke - local - portfolios :
cloud - engineering - self - service :
portfolio : "reinvent-cloud-engineering-self-service"
deploy_to :
tags :
- tag : "type:prod"
regions : "default_region"
The main input field should look like this:
accounts :
- account_id : "<YOUR_ACCOUNT_ID_WITHOUT_HYPHENS>"
name : "puppet-account"
default_region : "eu-west-1"
regions_enabled :
- "eu-west-1"
tags :
- "type:prod"
- "partition:eu"
launches :
aws - config - desired - instance - types :
portfolio : "reinvent-cloud-engineering-governance"
product : "aws-config-desired-instance-types"
version : "v1"
parameters :
InstanceType :
default : "t2.medium, t2.large, t2.xlarge"
deploy_to :
tags :
- tag : "type:prod"
regions : "default_region"
aws - config - rds - storage - encrypted :
portfolio : "reinvent-cloud-engineering-governance"
product : "aws-config-rds-storage-encrypted"
version : "v1"
deploy_to :
tags :
- tag : "type:prod"
regions : "default_region"
spoke - local - portfolios :
cloud - engineering - self - service :
portfolio : "reinvent-cloud-engineering-self-service"
deploy_to :
tags :
- tag : "type:prod"
regions : "default_region"
Committing the manifest file
Set your Author name
Set your Email address
Set your Commit message
Using a good / unique commit message will help you understand what is going on later.
Click the Commit changes button:
Verifying the sharing
Once you have made your changes the ServiceCatalogPuppet Pipeline should have run. If you were quick
may still be running. If it has not yet started feel free to the hit the Release change button.
Once it has completed it should show the Source and Build stages in green to indicate they have completed
successfully:
If this is failing please raise your hand for some assistance
Once you have verified the pipeline has run you can go to Service Catalog portfolios to view your
shared product.
When you share a portfolio the framework will decide if it should share the portfolio. If the target account is the same
as the factory account it will not share the portfolio as it is not needed.
If you cannot see your product please raise your hand for some assistance