Skip to content
This repository was archived by the owner on Dec 18, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
The StartupKit-templates repo contains a collection of AWS [CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html) templates intended to help you set up common pieces of AWS infrastructure. Each template defines a [stack](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacks.html), which is a collection of related resources that can be created, updated, or deleted as a single unit. Templates are available for creating:

- A secure network inside a [VPC](https://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Introduction.html) ([jump](#vpc))
- A [bastion host](https://en.wikipedia.org/wiki/Bastion_host) to securely access instances inside the VPC ([jump](#bastion-host))
- AWS Session Manager to securely access inside the VPC ([jump](#aws-session-manager))
- A deployment environment using [AWS Elastic Beanstalk](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/Welcome.html) ([jump](#aws-elastic-beanstalk))
- A container-based environment using [AWS Fargate](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ECS_GetStarted.html) ([jump](#aws-fargate))
- A relational database using [Amazon RDS](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Welcome.html) ([jump](#amazon-rds))
Expand Down Expand Up @@ -76,10 +76,14 @@ Security groups act as firewalls at the instance level, to control inbound and o

</details>

### Bastion Host
### AWS Session Manager

It is preferable not to ssh into EC2 instances at all, instead monitoring instances by configuring them to send logs to [CloudWatch](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/WhatIsCloudWatchLogs.html) or other services, and managing instantiation, configuration, and termination of instances using devops tools.

Session Manager is a fully managed AWS Systems Manager capability that lets you manage your Amazon EC2 instances through an interactive one-click browser-based shell or through the AWS CLI. Session Manager provides secure and auditable instance management without the need to open inbound ports, maintain bastion hosts, or manage SSH keys. Session Manager also makes it easy to comply with corporate policies that require controlled access to instances, strict security practices, and fully auditable logs with instance access details, while still providing end users with simple one-click cross-platform access to your Amazon EC2 instances. You can read more of the [more of the benefits of using Session Manager in the documentation](https://docs.aws.amazon.com/systems-manager/latest/userguide/what-is-session-manager.html).

To use the AWS CLI to run session commands, you must be using version 1.16.12 of the CLI, and you must have [installed the Session Manager plugin on your local machine](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html).

If you do need to connect directly to instances, it's best (and for instances in a private subnets, a requirement) to use a bastion host, otherwise known as a jump box. A bastion host is an EC2 instance that is publicly accessible, and also has access to private resources, allowing it to function as a secure go-between. You configure your EC2 instances to only accept ssh traffic from the bastion host, then you can ssh into the bastion host, and from there connect to your private resources.

EC2 key pairs are required to ssh into any EC2 instance, including bastion hosts. If an attacker gains access to your key pair, they can use it to get into your bastion host, and thus your other resources. In order to prevent this kind of breach the bastion host template supports enabling [Multi-Factor Authentication (MFA)](https://en.wikipedia.org/wiki/Multi-factor_authentication), which is highly recommended
Expand Down
1 change: 1 addition & 0 deletions cmd.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
aws cloudformation create-stack --region=us-east-1 --stack-name startupkit-eb --template-body file://vpc-eb-rds.cfn.yml --capabilities CAPABILITY_IAM --parameters ParameterKey=DatabasePassword,ParameterValue=aquasush ParameterKey=TemplateBucket,ParameterValue=gjg-startupkit-templates ParameterKey=AppS3Bucket,ParameterValue=gjg-startupkit-testing ParameterKey=AppS3Key,ParameterValue=demoapp/1.zip ParameterKey=AvailabilityZone1,ParameterValue=us-east-1a ParameterKey=AvailabilityZone2,ParameterValue=us-east-1b ParameterKey=StackType,ParameterValue=rails
8 changes: 6 additions & 2 deletions templates/bastion.cfn.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ Parameters:

KeyName:
Description: EC2 key pair name for bastion host SSH access
Type: AWS::EC2::KeyPair::KeyName
Type: String
Default: ''

LogRetentionInDays:
Description: Number of days you would like your CloudWatch Logs to be retained
Expand All @@ -36,6 +37,9 @@ Parameters:
- true
- false

Conditions:
HasKeyName: !Not [ !Equals [ !Ref KeyName, '' ]]

Mappings:

# Amazon Linux AMI - https://aws.amazon.com/amazon-linux-ami/
Expand Down Expand Up @@ -211,7 +215,7 @@ Resources:

Properties:
InstanceType: t2.micro
KeyName: !Ref KeyName
KeyName: !If [ HasKeyName, !Ref KeyName, !Ref "AWS::NoValue" ]
NetworkInterfaces:
- NetworkInterfaceId: !Ref BastionNetworkInterface
DeviceIndex: 0
Expand Down
38 changes: 26 additions & 12 deletions templates/elastic-beanstalk.cfn.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ Parameters:
MaxLength: 255
AllowedPattern: "^[a-zA-Z][-a-zA-Z0-9]*$"

Bastion:
Description: Flag on whether to allow SSH access to instances via bastion instead of Session Manager
Type: String
Default: false
AllowedValues:
- true
- false

DatabaseStackName:
Description: Name of an active CloudFormation stack of database resources
Type: String
Expand Down Expand Up @@ -80,7 +88,8 @@ Parameters:

EC2KeyPairName:
Description: EC2 key pair name for SSH access
Type: AWS::EC2::KeyPair::KeyName
Type: String
Default: ''

DevInstanceType:
Description: The instance type for the dev environment
Expand Down Expand Up @@ -122,16 +131,19 @@ Parameters:
Conditions:

CreateProdEnv: !Equals [ !Ref EnvironmentName, prod ]
HasKeyName: !Not [ !Equals [ !Ref EC2KeyPairName, '' ]]

TlsEnabled: !Not [ !Equals [ !Ref SSLCertificateArn, "" ] ]

CreateBastion: !Equals [ !Ref Bastion, true ]

Mappings:
# Maps stack type parameter to solution stack name string
StackMap:
node:
stackName: 64bit Amazon Linux 2018.03 v4.5.3 running Node.js
rails:
stackName: 64bit Amazon Linux 2018.03 v2.8.3 running Ruby 2.4 (Puma)
stackName: 64bit Amazon Linux 2018.03 v2.8.7 running Ruby 2.4 (Puma)
spring:
stackName: 64bit Amazon Linux 2018.03 v3.0.3 running Tomcat 8 Java 8
python:
Expand Down Expand Up @@ -213,18 +225,20 @@ Resources:
Value: !Ref AutoScalingMaxInstanceCount

- Namespace: aws:autoscaling:launchconfiguration
OptionName: SecurityGroups
Value:
Fn::ImportValue: !Sub "${NetworkStackName}-AppSecurityGroupID"
OptionName: SSHSourceRestriction
Value: !If
- CreateBastion
- "Fn::Join":
- ','
- - 'tcp, 22, 22'
- !ImportValue
"Fn::Sub": "${NetworkStackName}-BastionGroupID"
- 'tcp, 22, 22, 127.0.0.1/32'

- Namespace: aws:autoscaling:launchconfiguration
OptionName: SSHSourceRestriction
OptionName: SecurityGroups
Value:
"Fn::Join":
- ','
- - 'tcp, 22, 22'
- !ImportValue
"Fn::Sub": "${NetworkStackName}-BastionGroupID"
Fn::ImportValue: !Sub "${NetworkStackName}-AppSecurityGroupID"

- Namespace: aws:autoscaling:launchconfiguration
OptionName: InstanceType
Expand All @@ -236,7 +250,7 @@ Resources:

- Namespace: aws:autoscaling:launchconfiguration
OptionName: EC2KeyName
Value: !Ref EC2KeyPairName
Value: !If [ HasKeyName, !Ref EC2KeyPairName, !Ref "AWS::NoValue" ]

- Namespace: aws:autoscaling:updatepolicy:rollingupdate
OptionName: RollingUpdateEnabled
Expand Down
23 changes: 17 additions & 6 deletions templates/vpc.cfn.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ AWSTemplateFormatVersion: 2010-09-09
Description: SASKV5N VPC

# This VPC stack should be created first before any other
# CloudFormation stacks, such as a bastion stack, database
# stack and application stack
# CloudFormation stacks, such as a database stack
# and application stack
Parameters:

AvailabilityZone1:
Expand All @@ -18,6 +18,14 @@ Parameters:
Type: AWS::EC2::AvailabilityZone::Name
ConstraintDescription: Must be a valid availability zone

Bastion:
Description: Flag on whether to allow SSH access to instances via bastion instead of Session Manager
Type: String
Default: false
AllowedValues:
- true
- false

SSHFrom:
Description: Limit SSH access to bastion hosts to a CIDR IP block
Type: String
Expand Down Expand Up @@ -76,6 +84,7 @@ Metadata:
Conditions:
CreateSingleNatGateway: !Equals [ !Ref SingleNatGateway, true ]
CreateMultipleNatGateways: !Not [ Condition: CreateSingleNatGateway ]
CreateBastion: !Equals [ !Ref Bastion, true ]

Mappings:

Expand Down Expand Up @@ -230,10 +239,6 @@ Resources:
IpProtocol: tcp
ToPort: !Ref AppIngressPort
FromPort: !Ref AppIngressPort
- SourceSecurityGroupId: !Ref BastionSecurityGroup
IpProtocol: tcp
ToPort: 22
FromPort: 22
Tags:
- Key: Name
Value: !Sub "${AWS::StackName}-AppSecurityGroup"
Expand All @@ -248,6 +253,7 @@ Resources:
SourceSecurityGroupId: !Ref ELBSecurityGroup

AppSecurityGroupFromBastionIngress:
Condition: CreateBastion
Type: AWS::EC2::SecurityGroupIngress # prevent security group circular references
Properties:
GroupId: !Ref AppSecurityGroup
Expand All @@ -257,6 +263,7 @@ Resources:
SourceSecurityGroupId: !Ref BastionSecurityGroup

BastionSecurityGroup:
Condition: CreateBastion
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Enable access to the bastion host
Expand Down Expand Up @@ -284,6 +291,7 @@ Resources:
Value: !Sub "${AWS::StackName}-BastionSecurityGroup"

BastionSecurityGroupToAppEgress:
Condition: CreateBastion
Type: AWS::EC2::SecurityGroupEgress # prevent security group circular references
Properties:
GroupId: !Ref BastionSecurityGroup
Expand All @@ -293,6 +301,7 @@ Resources:
DestinationSecurityGroupId: !Ref AppSecurityGroup

BastionSecurityGroupToDbEgress:
Condition: CreateBastion
Type: AWS::EC2::SecurityGroupEgress # prevent security group circular references
Properties:
GroupId: !Ref BastionSecurityGroup
Expand Down Expand Up @@ -320,6 +329,7 @@ Resources:
Value: !Sub "${AWS::StackName}-DbSecurityGroup"

DbSecurityGroupFromBastionIngress:
Condition: CreateBastion
Type: AWS::EC2::SecurityGroupIngress # prevent security group circular references
Properties:
GroupId: !Ref DbSecurityGroup
Expand Down Expand Up @@ -482,6 +492,7 @@ Outputs:

BastionSecurityGroup:
Description: Security group ID for bastion host
Condition: CreateBastion
Value: !GetAtt BastionSecurityGroup.GroupId
Export:
Name: !Sub "${AWS::StackName}-BastionGroupID"
Expand Down
Loading