├── .github └── FUNDING.yml ├── README.md ├── infrastructure.json ├── infrastructure.yaml ├── pipeline.yaml └── vpc-2azs.yaml /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: widdix 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Configure your CloudFormation managed infrastructure with Parameter Store and CodePipeline 2 | 3 | Code for my blog post: [Configure your CloudFormation managed infrastructure with Parameter Store and CodePipeline](https://cloudonaut.io/configure-your-cloudformation-managed-infrastructure-with-parameter-store-and-codepipeline/) 4 | 5 | ## Setup instructions 6 | 7 | > Have you [installed](https://docs.aws.amazon.com/cli/latest/userguide/installing.html) and [configured](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html) the AWS CLI? 8 | 9 | 1. Clone this repository `git clone https://github.com/widdix/parameter-store-cloudformation-codepipeline.git` download the ZIP file](https://github.com/widdix/parameter-store-cloudformation-codepipeline/archive/master.zip) 10 | 1. `cd parameter-store-cloudformation-codepipeline/` 11 | 1. Create parameter in Parameter Store: `aws ssm put-parameter --name '/application/stage/instancetype' --value 't2.micro' --type String` 12 | 1. Create pipeline stack with CloudFormation: `aws cloudformation create-stack --stack-name cloudonaut --template-body file://pipeline.yaml --capabilities CAPABILITY_IAM` 13 | 1. Wait until CloudFormation stack is created: `aws cloudformation wait stack-create-complete --stack-name cloudonaut` 14 | 1. Push files to the CodeCommit repository created by the pipeline stack (I don't use `git push` here to skip the git configuration): 15 | 1. `COMMIT_ID="$(aws codecommit put-file --repository-name cloudonaut --branch-name master --file-content file://infrastructure.yaml --file-path infrastructure.yaml --query commitId --output text)"` 16 | 1. `COMMIT_ID="$(aws codecommit put-file --repository-name cloudonaut --branch-name master --parent-commit-id $COMMIT_ID --file-content file://infrastructure.json --file-path infrastructure.json --query commitId --output text)"` 17 | 1. `COMMIT_ID="$(aws codecommit put-file --repository-name cloudonaut --branch-name master --parent-commit-id $COMMIT_ID --file-content file://vpc-2azs.yaml --file-path vpc-2azs.yaml --query commitId --output text)"` 18 | 1. Wait until the first pipeline run is finished: `open 'https://console.aws.amazon.com/codepipeline/home#/view/cloudonaut'` 19 | 1. Visit the website exposed by the EC2 instance: `open "http://$(aws cloudformation describe-stacks --stack-name cloudonaut-infrastructure --query "Stacks[0].Outputs[0].OutputValue" --output text)"` 20 | 1. Update the parameter value: `aws ssm put-parameter --name '/application/stage/instancetype' --value 't2.nano' --type String --overwrite` (`t2.nano` is outside th Free Tier, expect charges of a few cents) 21 | 1. Wait until the second pipeline run is finished: `open 'https://console.aws.amazon.com/codepipeline/home#/view/cloudonaut'` 22 | 1. Visit the website exposed by the EC2 instance: `open "http://$(aws cloudformation describe-stacks --stack-name cloudonaut-infrastructure --query "Stacks[0].Outputs[0].OutputValue" --output text)"` 23 | 24 | ## Clean up instructions 25 | 26 | 1. Remove CloudFormation stacks 27 | 1. `aws cloudformation delete-stack --stack-name cloudonaut-infrastructure` 28 | 1. `aws cloudformation wait stack-delete-complete --stack-name cloudonaut-infrastructure` 29 | 1. `aws cloudformation delete-stack --stack-name cloudonaut-vpc` 30 | 1. `aws cloudformation wait stack-delete-complete --stack-name cloudonaut-vpc` 31 | 1. `aws cloudformation delete-stack --stack-name cloudonaut` 32 | 1. `aws cloudformation wait stack-delete-complete --stack-name cloudonaut` 33 | 1. Remove S3 bucket prefixed with `cloudonaut-artifactsbucket-` including all files: `open "https://s3.console.aws.amazon.com/s3/home"` 34 | 1. Remove Parameter Store parameter: `aws ssm delete-parameter --name '/application/stage/instancetype'` 35 | -------------------------------------------------------------------------------- /infrastructure.json: -------------------------------------------------------------------------------- 1 | { 2 | "Parameters": { 3 | "ParentVPCStack": {"Fn::GetParam": ["VPC", "output.json", "StackName"]} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /infrastructure.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | AWSTemplateFormatVersion: '2010-09-09' 3 | Description: 'Infrastructure' 4 | Parameters: 5 | ParentVPCStack: 6 | Description: 'Stack name of parent VPC stack based on vpc/vpc-*azs.yaml template.' 7 | Type: String 8 | InstanceType: 9 | Description: 'Name of Parameter Store parameter to define the instance type.' 10 | Type: 'AWS::SSM::Parameter::Value' 11 | Default: '/application/stage/instancetype' 12 | Mappings: 13 | RegionMap: 14 | 'ap-south-1': 15 | AMI: 'ami-531a4c3c' 16 | 'eu-west-3': 17 | AMI: 'ami-8ee056f3' 18 | 'eu-west-2': 19 | AMI: 'ami-403e2524' 20 | 'eu-west-1': 21 | AMI: 'ami-d834aba1' 22 | 'ap-northeast-2': 23 | AMI: 'ami-863090e8' 24 | 'ap-northeast-1': 25 | AMI: 'ami-ceafcba8' 26 | 'sa-east-1': 27 | AMI: 'ami-84175ae8' 28 | 'ca-central-1': 29 | AMI: 'ami-a954d1cd' 30 | 'ap-southeast-1': 31 | AMI: 'ami-68097514' 32 | 'ap-southeast-2': 33 | AMI: 'ami-942dd1f6' 34 | 'eu-central-1': 35 | AMI: 'ami-5652ce39' 36 | 'us-east-1': 37 | AMI: 'ami-97785bed' 38 | 'us-east-2': 39 | AMI: 'ami-f63b1193' 40 | 'us-west-1': 41 | AMI: 'ami-824c4ee2' 42 | 'us-west-2': 43 | AMI: 'ami-f2d3638a' 44 | Resources: 45 | SecurityGroup: 46 | Type: 'AWS::EC2::SecurityGroup' 47 | Properties: 48 | GroupDescription: !Ref 'AWS::StackName' 49 | SecurityGroupIngress: 50 | - CidrIp: '0.0.0.0/0' 51 | FromPort: 80 52 | ToPort: 80 53 | IpProtocol: tcp 54 | VpcId: 55 | 'Fn::ImportValue': !Sub '${ParentVPCStack}-VPC' 56 | VirtualMachine: 57 | Type: 'AWS::EC2::Instance' 58 | Properties: 59 | ImageId: !FindInMap [RegionMap, !Ref 'AWS::Region', AMI] 60 | InstanceType: !Ref InstanceType 61 | SecurityGroupIds: 62 | - !Ref SecurityGroup 63 | UserData: 64 | 'Fn::Base64': !Sub | 65 | #!/bin/bash -ex 66 | trap '/opt/aws/bin/cfn-signal -e 1 --region ${AWS::Region} --stack ${AWS::StackName} --resource VirtualMachine' ERR 67 | 68 | # run UserData on every instance start, not only on first boot 69 | cat > /etc/cloud/cloud.cfg.d/15_run_every.cfg < /var/www/html/index.html 84 | service httpd start 85 | chkconfig httpd on 86 | /opt/aws/bin/cfn-signal -e 0 --region ${AWS::Region} --stack ${AWS::StackName} --resource VirtualMachine 87 | SubnetId: 88 | 'Fn::ImportValue': !Sub '${ParentVPCStack}-SubnetAPublic' 89 | CreationPolicy: 90 | ResourceSignal: 91 | Count: 1 92 | Timeout: PT10M 93 | Outputs: 94 | IPAddress: 95 | Description: 'The public IP address of the EC2 instance.' 96 | Value: !GetAtt 'VirtualMachine.PublicIp' 97 | -------------------------------------------------------------------------------- /pipeline.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | AWSTemplateFormatVersion: '2010-09-09' 3 | Description: 'Pipeline' 4 | Resources: 5 | CodeRepository: 6 | Type: 'AWS::CodeCommit::Repository' 7 | Properties: 8 | RepositoryName: !Ref 'AWS::StackName' 9 | ArtifactsBucket: 10 | DeletionPolicy: Retain 11 | Type: 'AWS::S3::Bucket' 12 | Properties: {} 13 | PipelineRole: 14 | Type: 'AWS::IAM::Role' 15 | Properties: 16 | AssumeRolePolicyDocument: 17 | Version: '2012-10-17' 18 | Statement: 19 | - Effect: Allow 20 | Principal: 21 | Service: 22 | - 'cloudformation.amazonaws.com' 23 | - 'codepipeline.amazonaws.com' 24 | Action: 25 | - 'sts:AssumeRole' 26 | ManagedPolicyArns: 27 | - 'arn:aws:iam::aws:policy/AdministratorAccess' 28 | Pipeline: 29 | Type: 'AWS::CodePipeline::Pipeline' 30 | Properties: 31 | ArtifactStore: 32 | Type: S3 33 | Location: !Ref ArtifactsBucket 34 | Name: !Ref 'AWS::StackName' 35 | RestartExecutionOnUpdate: true 36 | RoleArn: !GetAtt 'PipelineRole.Arn' 37 | Stages: 38 | - Name: Source 39 | Actions: 40 | - Name: FetchSource 41 | ActionTypeId: 42 | Category: Source 43 | Owner: AWS 44 | Provider: CodeCommit 45 | Version: 1 46 | Configuration: 47 | RepositoryName: !GetAtt 'CodeRepository.Name' 48 | BranchName: master 49 | PollForSourceChanges: false # see CodeCommitPipelineTriggerRule 50 | OutputArtifacts: 51 | - Name: Source 52 | RunOrder: 1 53 | - Name: VPC 54 | Actions: 55 | - Name: Deploy 56 | ActionTypeId: 57 | Category: Deploy 58 | Owner: AWS 59 | Provider: CloudFormation 60 | Version: 1 61 | Configuration: 62 | ActionMode: CREATE_UPDATE 63 | Capabilities: CAPABILITY_IAM 64 | RoleArn: !GetAtt 'PipelineRole.Arn' 65 | StackName: !Sub '${AWS::StackName}-vpc' 66 | TemplatePath: 'Source::vpc-2azs.yaml' 67 | OutputFileName: 'output.json' 68 | InputArtifacts: 69 | - Name: Source 70 | OutputArtifacts: 71 | - Name: VPC 72 | RunOrder: 1 73 | - Name: Production 74 | Actions: 75 | - Name: DeployInfrastructure 76 | ActionTypeId: 77 | Category: Deploy 78 | Owner: AWS 79 | Provider: CloudFormation 80 | Version: 1 81 | Configuration: 82 | ActionMode: CREATE_UPDATE 83 | Capabilities: CAPABILITY_IAM 84 | RoleArn: !GetAtt 'PipelineRole.Arn' 85 | StackName: !Sub '${AWS::StackName}-infrastructure' 86 | TemplatePath: 'Source::infrastructure.yaml' 87 | TemplateConfiguration: 'Source::infrastructure.json' 88 | InputArtifacts: 89 | - Name: VPC 90 | - Name: Source 91 | RunOrder: 1 92 | PipelineTriggerRole: 93 | Type: 'AWS::IAM::Role' 94 | Properties: 95 | AssumeRolePolicyDocument: 96 | Version: '2012-10-17' 97 | Statement: 98 | - Effect: Allow 99 | Principal: 100 | Service: 101 | - 'events.amazonaws.com' 102 | Action: 103 | - 'sts:AssumeRole' 104 | Policies: 105 | - PolicyName: 'codepipeline' 106 | PolicyDocument: 107 | Version: '2012-10-17' 108 | Statement: 109 | - Effect: Allow 110 | Action: 'codepipeline:StartPipelineExecution' 111 | Resource: !Sub 'arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${Pipeline}' 112 | CodeCommitPipelineTriggerRule: 113 | Type: 'AWS::Events::Rule' 114 | Properties: 115 | EventPattern: 116 | source: 117 | - 'aws.codecommit' 118 | 'detail-type': 119 | - 'CodeCommit Repository State Change' 120 | resources: 121 | - !GetAtt 'CodeRepository.Arn' 122 | detail: 123 | referenceType: 124 | - branch 125 | referenceName: 126 | - master 127 | State: ENABLED 128 | Targets: 129 | - Arn: !Sub 'arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${Pipeline}' 130 | Id: pipeline 131 | RoleArn: !GetAtt 'PipelineTriggerRole.Arn' 132 | ParameterStorePipelineTriggerRule: 133 | Type: 'AWS::Events::Rule' 134 | Properties: 135 | EventPattern: 136 | source: 137 | - 'aws.ssm' 138 | 'detail-type': 139 | - 'Parameter Store Change' 140 | resources: 141 | - !Sub 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/application/stage/instancetype' 142 | State: ENABLED 143 | Targets: 144 | - Arn: !Sub 'arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${Pipeline}' 145 | Id: pipeline 146 | RoleArn: !GetAtt 'PipelineTriggerRole.Arn' 147 | -------------------------------------------------------------------------------- /vpc-2azs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | AWSTemplateFormatVersion: '2010-09-09' 3 | Description: 'VPC: public and private subnets in two availability zones, a cloudonaut.io template' 4 | Metadata: 5 | 'AWS::CloudFormation::Interface': 6 | ParameterGroups: 7 | - Label: 8 | default: 'VPC Parameters' 9 | Parameters: 10 | - ClassB 11 | Parameters: 12 | ClassB: 13 | Description: 'Class B of VPC (10.XXX.0.0/16)' 14 | Type: Number 15 | Default: 0 16 | ConstraintDescription: 'Must be in the range [0-255]' 17 | MinValue: 0 18 | MaxValue: 255 19 | Resources: 20 | VPC: 21 | Type: 'AWS::EC2::VPC' 22 | Properties: 23 | CidrBlock: !Sub '10.${ClassB}.0.0/16' 24 | EnableDnsSupport: true 25 | EnableDnsHostnames: true 26 | InstanceTenancy: default 27 | Tags: 28 | - Key: Name 29 | Value: !Sub '10.${ClassB}.0.0/16' 30 | InternetGateway: 31 | Type: 'AWS::EC2::InternetGateway' 32 | Properties: 33 | Tags: 34 | - Key: Name 35 | Value: !Sub '10.${ClassB}.0.0/16' 36 | VPCGatewayAttachment: 37 | Type: 'AWS::EC2::VPCGatewayAttachment' 38 | Properties: 39 | VpcId: !Ref VPC 40 | InternetGatewayId: !Ref InternetGateway 41 | SubnetAPublic: 42 | Type: 'AWS::EC2::Subnet' 43 | Properties: 44 | AvailabilityZone: !Select [0, !GetAZs ''] 45 | CidrBlock: !Sub '10.${ClassB}.0.0/20' 46 | MapPublicIpOnLaunch: true 47 | VpcId: !Ref VPC 48 | Tags: 49 | - Key: Name 50 | Value: 'A public' 51 | - Key: Reach 52 | Value: public 53 | SubnetAPrivate: 54 | Type: 'AWS::EC2::Subnet' 55 | Properties: 56 | AvailabilityZone: !Select [0, !GetAZs ''] 57 | CidrBlock: !Sub '10.${ClassB}.16.0/20' 58 | VpcId: !Ref VPC 59 | Tags: 60 | - Key: Name 61 | Value: 'A private' 62 | - Key: Reach 63 | Value: private 64 | SubnetBPublic: 65 | Type: 'AWS::EC2::Subnet' 66 | Properties: 67 | AvailabilityZone: !Select [1, !GetAZs ''] 68 | CidrBlock: !Sub '10.${ClassB}.32.0/20' 69 | MapPublicIpOnLaunch: true 70 | VpcId: !Ref VPC 71 | Tags: 72 | - Key: Name 73 | Value: 'B public' 74 | - Key: Reach 75 | Value: public 76 | SubnetBPrivate: 77 | Type: 'AWS::EC2::Subnet' 78 | Properties: 79 | AvailabilityZone: !Select [1, !GetAZs ''] 80 | CidrBlock: !Sub '10.${ClassB}.48.0/20' 81 | VpcId: !Ref VPC 82 | Tags: 83 | - Key: Name 84 | Value: 'B private' 85 | - Key: Reach 86 | Value: private 87 | RouteTablePublic: # should be RouteTableAPublic, but logical id was not changed for backward compatibility 88 | Type: 'AWS::EC2::RouteTable' 89 | Properties: 90 | VpcId: !Ref VPC 91 | Tags: 92 | - Key: Name 93 | Value: 'A Public' 94 | RouteTablePrivate: # should be RouteTableAPrivate, but logical id was not changed for backward compatibility 95 | Type: 'AWS::EC2::RouteTable' 96 | Properties: 97 | VpcId: !Ref VPC 98 | Tags: 99 | - Key: Name 100 | Value: 'A Private' 101 | RouteTableBPublic: 102 | Type: 'AWS::EC2::RouteTable' 103 | Properties: 104 | VpcId: !Ref VPC 105 | Tags: 106 | - Key: Name 107 | Value: 'B Public' 108 | RouteTableBPrivate: 109 | Type: 'AWS::EC2::RouteTable' 110 | Properties: 111 | VpcId: !Ref VPC 112 | Tags: 113 | - Key: Name 114 | Value: 'B Private' 115 | RouteTableAssociationAPublic: 116 | Type: 'AWS::EC2::SubnetRouteTableAssociation' 117 | Properties: 118 | SubnetId: !Ref SubnetAPublic 119 | RouteTableId: !Ref RouteTablePublic 120 | RouteTableAssociationAPrivate: 121 | Type: 'AWS::EC2::SubnetRouteTableAssociation' 122 | Properties: 123 | SubnetId: !Ref SubnetAPrivate 124 | RouteTableId: !Ref RouteTablePrivate 125 | RouteTableAssociationBPublic: 126 | Type: 'AWS::EC2::SubnetRouteTableAssociation' 127 | Properties: 128 | SubnetId: !Ref SubnetBPublic 129 | RouteTableId: !Ref RouteTableBPublic 130 | RouteTableAssociationBPrivate: 131 | Type: 'AWS::EC2::SubnetRouteTableAssociation' 132 | Properties: 133 | SubnetId: !Ref SubnetBPrivate 134 | RouteTableId: !Ref RouteTableBPrivate 135 | RouteTablePublicInternetRoute: # should be RouteTablePublicAInternetRoute, but logical id was not changed for backward compatibility 136 | Type: 'AWS::EC2::Route' 137 | DependsOn: VPCGatewayAttachment 138 | Properties: 139 | RouteTableId: !Ref RouteTablePublic 140 | DestinationCidrBlock: '0.0.0.0/0' 141 | GatewayId: !Ref InternetGateway 142 | RouteTablePublicBInternetRoute: 143 | Type: 'AWS::EC2::Route' 144 | DependsOn: VPCGatewayAttachment 145 | Properties: 146 | RouteTableId: !Ref RouteTableBPublic 147 | DestinationCidrBlock: '0.0.0.0/0' 148 | GatewayId: !Ref InternetGateway 149 | NetworkAclPublic: 150 | Type: 'AWS::EC2::NetworkAcl' 151 | Properties: 152 | VpcId: !Ref VPC 153 | Tags: 154 | - Key: Name 155 | Value: Public 156 | NetworkAclPrivate: 157 | Type: 'AWS::EC2::NetworkAcl' 158 | Properties: 159 | VpcId: !Ref VPC 160 | Tags: 161 | - Key: Name 162 | Value: Private 163 | SubnetNetworkAclAssociationAPublic: 164 | Type: 'AWS::EC2::SubnetNetworkAclAssociation' 165 | Properties: 166 | SubnetId: !Ref SubnetAPublic 167 | NetworkAclId: !Ref NetworkAclPublic 168 | SubnetNetworkAclAssociationAPrivate: 169 | Type: 'AWS::EC2::SubnetNetworkAclAssociation' 170 | Properties: 171 | SubnetId: !Ref SubnetAPrivate 172 | NetworkAclId: !Ref NetworkAclPrivate 173 | SubnetNetworkAclAssociationBPublic: 174 | Type: 'AWS::EC2::SubnetNetworkAclAssociation' 175 | Properties: 176 | SubnetId: !Ref SubnetBPublic 177 | NetworkAclId: !Ref NetworkAclPublic 178 | SubnetNetworkAclAssociationBPrivate: 179 | Type: 'AWS::EC2::SubnetNetworkAclAssociation' 180 | Properties: 181 | SubnetId: !Ref SubnetBPrivate 182 | NetworkAclId: !Ref NetworkAclPrivate 183 | NetworkAclEntryInPublicAllowAll: 184 | Type: 'AWS::EC2::NetworkAclEntry' 185 | Properties: 186 | NetworkAclId: !Ref NetworkAclPublic 187 | RuleNumber: 99 188 | Protocol: -1 189 | RuleAction: allow 190 | Egress: false 191 | CidrBlock: '0.0.0.0/0' 192 | NetworkAclEntryOutPublicAllowAll: 193 | Type: 'AWS::EC2::NetworkAclEntry' 194 | Properties: 195 | NetworkAclId: !Ref NetworkAclPublic 196 | RuleNumber: 99 197 | Protocol: -1 198 | RuleAction: allow 199 | Egress: true 200 | CidrBlock: '0.0.0.0/0' 201 | NetworkAclEntryInPrivateAllowVPC: 202 | Type: 'AWS::EC2::NetworkAclEntry' 203 | Properties: 204 | NetworkAclId: !Ref NetworkAclPrivate 205 | RuleNumber: 99 206 | Protocol: -1 207 | RuleAction: allow 208 | Egress: false 209 | CidrBlock: '0.0.0.0/0' 210 | NetworkAclEntryOutPrivateAllowVPC: 211 | Type: 'AWS::EC2::NetworkAclEntry' 212 | Properties: 213 | NetworkAclId: !Ref NetworkAclPrivate 214 | RuleNumber: 99 215 | Protocol: -1 216 | RuleAction: allow 217 | Egress: true 218 | CidrBlock: '0.0.0.0/0' 219 | Outputs: 220 | TemplateID: 221 | Description: 'cloudonaut.io template id' 222 | Value: 'vpc/vpc-2azs' 223 | StackName: 224 | Description: 'Stack name' 225 | Value: !Sub '${AWS::StackName}' 226 | AZs: 227 | Description: 'AZs' 228 | Value: 2 229 | Export: 230 | Name: !Sub '${AWS::StackName}-AZs' 231 | AZA: 232 | Description: 'AZ of A' 233 | Value: !Select [0, !GetAZs ''] 234 | Export: 235 | Name: !Sub '${AWS::StackName}-AZA' 236 | AZB: 237 | Description: 'AZ of B' 238 | Value: !Select [1, !GetAZs ''] 239 | Export: 240 | Name: !Sub '${AWS::StackName}-AZB' 241 | ClassB: 242 | Description: 'Class B.' 243 | Value: !Ref ClassB 244 | Export: 245 | Name: !Sub '${AWS::StackName}-ClassB' 246 | VPC: 247 | Description: 'VPC.' 248 | Value: !Ref VPC 249 | Export: 250 | Name: !Sub '${AWS::StackName}-VPC' 251 | SubnetsPublic: 252 | Description: 'Subnets public.' 253 | Value: !Join [',', [!Ref SubnetAPublic, !Ref SubnetBPublic]] 254 | Export: 255 | Name: !Sub '${AWS::StackName}-SubnetsPublic' 256 | SubnetsPrivate: 257 | Description: 'Subnets private.' 258 | Value: !Join [',', [!Ref SubnetAPrivate, !Ref SubnetBPrivate]] 259 | Export: 260 | Name: !Sub '${AWS::StackName}-SubnetsPrivate' 261 | RouteTablePrivate: # deprecated in v4, will be removed in v5 262 | Description: 'Route table private (deprecated in v4, will be removed in v5).' 263 | Value: !Ref RouteTablePrivate 264 | Export: 265 | Name: !Sub '${AWS::StackName}-RouteTablePrivate' 266 | RouteTablePublic: # deprecated in v4, will be removed in v5 267 | Description: 'Route table public (deprecated in v4, will be removed in v5).' 268 | Value: !Ref RouteTablePublic 269 | Export: 270 | Name: !Sub '${AWS::StackName}-RouteTablePublic' 271 | RouteTablesPrivate: 272 | Description: 'Route tables private.' 273 | Value: !Join [',', [!Ref RouteTablePrivate, !Ref RouteTableBPrivate]] 274 | Export: 275 | Name: !Sub '${AWS::StackName}-RouteTablesPrivate' 276 | RouteTablesPublic: 277 | Description: 'Route tables public.' 278 | Value: !Join [',', [!Ref RouteTablePublic, !Ref RouteTableBPublic]] 279 | Export: 280 | Name: !Sub '${AWS::StackName}-RouteTablesPublic' 281 | SubnetAPublic: 282 | Description: 'Subnet A public.' 283 | Value: !Ref SubnetAPublic 284 | Export: 285 | Name: !Sub '${AWS::StackName}-SubnetAPublic' 286 | RouteTableAPublic: 287 | Description: 'Route table A public.' 288 | Value: !Ref RouteTablePublic 289 | Export: 290 | Name: !Sub '${AWS::StackName}-RouteTableAPublic' 291 | SubnetAPrivate: 292 | Description: 'Subnet A private.' 293 | Value: !Ref SubnetAPrivate 294 | Export: 295 | Name: !Sub '${AWS::StackName}-SubnetAPrivate' 296 | RouteTableAPrivate: 297 | Description: 'Route table A private.' 298 | Value: !Ref RouteTablePrivate 299 | Export: 300 | Name: !Sub '${AWS::StackName}-RouteTableAPrivate' 301 | SubnetBPublic: 302 | Description: 'Subnet B public.' 303 | Value: !Ref SubnetBPublic 304 | Export: 305 | Name: !Sub '${AWS::StackName}-SubnetBPublic' 306 | RouteTableBPublic: 307 | Description: 'Route table B public.' 308 | Value: !Ref RouteTableBPublic 309 | Export: 310 | Name: !Sub '${AWS::StackName}-RouteTableBPublic' 311 | SubnetBPrivate: 312 | Description: 'Subnet B private.' 313 | Value: !Ref SubnetBPrivate 314 | Export: 315 | Name: !Sub '${AWS::StackName}-SubnetBPrivate' 316 | RouteTableBPrivate: 317 | Description: 'Route table B private.' 318 | Value: !Ref RouteTableBPrivate 319 | Export: 320 | Name: !Sub '${AWS::StackName}-RouteTableBPrivate' 321 | --------------------------------------------------------------------------------