Skip to content

Commit

Permalink
Adding CloudFormation on ECS example (#78)
Browse files Browse the repository at this point in the history
* adding cloud formation example

* Update examples/cloudformation/README.md

Co-authored-by: Erik Osterman (CEO @ Cloud Posse) <[email protected]>

---------

Co-authored-by: Erik Osterman (CEO @ Cloud Posse) <[email protected]>
Co-authored-by: Max Lobur <[email protected]>
  • Loading branch information
3 people authored May 1, 2023
1 parent b0a4ff1 commit 622f819
Show file tree
Hide file tree
Showing 2 changed files with 355 additions and 0 deletions.
3 changes: 3 additions & 0 deletions examples/cloudformation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# CloudFormation Example

This cloudformation example was contributed by [dmcd](https://github.com/dmcd). Please see [Issue #24](https://github.com/cloudposse/bastion/issues/24) for more details.
352 changes: 352 additions & 0 deletions examples/cloudformation/cloudformation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,352 @@
AWSTemplateFormatVersion: 2010-09-09
Description: Bastion

Parameters:

KeyPairName:
Description: >-
Enter a Public/private key pair. If you do not have one in this region,
please create it before continuing
Type: 'AWS::EC2::KeyPair::KeyName'
NumBastionHosts:
AllowedValues:
- '1'
- '2'
- '3'
- '4'
Default: '1'
Description: Enter the number of bastion hosts to create
Type: String
NetworkStackName:
Description: Name of an active CloudFormation stack of networking resources
Type: String
MinLength: 1
MaxLength: 255
AllowedPattern: "^[a-zA-Z][-a-zA-Z0-9]*$"

Resources:

BastionAutoScalingGroup:
Type: 'AWS::AutoScaling::AutoScalingGroup'
Properties:
LaunchConfigurationName: !Ref BastionLaunchConfiguration
VPCZoneIdentifier:
- !ImportValue
Fn::Sub: "${NetworkStackName}-PublicSubnet1ID"
- !ImportValue
Fn::Sub: "${NetworkStackName}-PublicSubnet2ID"
- !ImportValue
Fn::Sub: "${NetworkStackName}-PublicSubnet3ID"
MinSize: 0
MaxSize: 3
Cooldown: '300'
DesiredCapacity: !Ref NumBastionHosts
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}
PropagateAtLaunch: 'true'
CreationPolicy:
ResourceSignal:
Count: !Ref NumBastionHosts
Timeout: PT30M

BastionECSCluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: !Sub ${AWS::StackName}

BastionEC2Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ec2.amazonaws.com]
Action: ['sts:AssumeRole']
Path: /
Policies:
- PolicyName: ecs-service
PolicyDocument:
Statement:
- Effect: Allow
Action: [
'ecs:CreateCluster',
'ecs:DeregisterContainerInstance',
'ecs:DiscoverPollEndpoint',
'ecs:Poll',
'ecs:RegisterContainerInstance',
'ecs:StartTelemetrySession',
'ecs:Submit*',
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
'logs:CreateLogStream',
'logs:PutLogEvents'
]
Resource: '*'

BastionEC2InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles: [!Ref 'BastionEC2Role']

BastionLaunchConfiguration:
Type: AWS::AutoScaling::LaunchConfiguration
Metadata:
AWS::CloudFormation::Init:
config:
files:
/usr/bin/github-authorized-keys:
content: |
#!/bin/sh
set -ue
API_URL="${API_URL:-http://github-authorized-keys:301/user/%s/authorized_keys}"
if [ -n "$1" ]; then
exec curl --silent --fail $(printf "$API_URL" "$1")
else
echo "Usage: $0 [github username]"
fi
mode: '000550'
owner: root
group: root
/etc/ssh/cloudposse_sshd_config:
content: |
Port 22
AddressFamily any
ListenAddress 0.0.0.0
ListenAddress ::
Protocol 2
HostKey /etc/ssh/ssh_host_rsa_key
# Lifetime and size of ephemeral version 1 server key
#KeyRegenerationInterval 1h
#ServerKeyBits 1024
# Ciphers and keying
#RekeyLimit default none
# Logging
# obsoletes QuietMode and FascistLogging
#SyslogFacility AUTH
#LogLevel INFO
# Authentication:
LoginGraceTime 2m
PermitRootLogin yes
PermitUserRC no
StrictModes no
MaxAuthTries 6
MaxSessions 10
PubkeyAuthentication yes
# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
# but this is overridden so installations will only check .ssh/authorized_keys
AuthorizedKeysFile .ssh/authorized_keys
#AuthorizedPrincipalsFile none
# Don't read the user's ~/.rhosts and ~/.shosts files
IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes
PermitEmptyPasswords no
# Change to no to disable s/key passwords
ChallengeResponseAuthentication yes
UsePAM yes
AuthenticationMethods publickey,keyboard-interactive
AllowAgentForwarding yes
AllowTcpForwarding no
GatewayPorts no
X11Forwarding no
PermitTTY yes
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes
#UseLogin no
UsePrivilegeSeparation sandbox
PermitUserEnvironment no
#Compression delayed
ClientAliveInterval 30
ClientAliveCountMax 3
UseDNS no
#PidFile /run/sshd.pid
PermitTunnel yes
ChrootDirectory none
VersionAddendum none
# no default banner path
Banner none
# override default of no subsystems
Subsystem sftp /usr/lib/ssh/sftp-server -l VERBOSE
# the following are HPN related configuration options
# tcp receive buffer polling. disable in non autotuning kernels
#TcpRcvBufPoll yes
# disable hpn performance boosts
#HPNDisabled no
# buffer size for hpn to non-hpn connections
#HPNBufferSize 2048
ForceCommand /usr/bin/fc
# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server
AuthorizedKeysCommand /usr/bin/github-authorized-keys
AuthorizedKeysCommandUser root
Properties:
ImageId: ami-0092e55c70015d8c3 # ECS AMI
InstanceType: t2.micro
IamInstanceProfile:
Ref: BastionEC2InstanceProfile
KeyName:
Ref: KeyPairName
SecurityGroups:
- !ImportValue
Fn::Sub: "${NetworkStackName}-BastionSecurityGroupID"
AssociatePublicIpAddress: true
UserData:
Fn::Base64: !Sub |
#!/bin/bash -xe

yum install -y aws-cfn-bootstrap

echo ECS_CLUSTER=${AWS::StackName} >> /etc/ecs/ecs.config

# Process the default configset from the CloudFormation::Init metadata
/opt/aws/bin/cfn-init -v \
--region ${AWS::Region} \
--stack ${AWS::StackName} \
--resource BastionLaunchConfiguration \
--configsets default

# Signal BastionAutoScalingGroup with the cfn-init exit status
/opt/aws/bin/cfn-signal -e $? \
--region ${AWS::Region} \
--stack ${AWS::StackName} \
--resource BastionAutoScalingGroup

TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
- Name: 'github-authorized-keys'
MountPoints:
- SourceVolume: "host"
ContainerPath: "/host"
Image: "cloudposse/github-authorized-keys"
Cpu: "100"
Memory: "64"
Essential: "true"
Environment:
- Name: GITHUB_API_TOKEN
Value: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- Name: GITHUB_ORGANIZATION
Value: xxxxxx
- Name: GITHUB_TEAM
Value: xxxxx
- Name: SYNC_USERS_SHELL
Value: /bin/bash
- Name: SYNC_USERS_ROOT
Value: /host
- Name: SYNC_USERS_INTERVAL
Value: 300
- Name: LISTEN
Value: :301
- Name: INTEGRATE_SSH
Value: 'false'
- Name: LINUX_USER_ADD_TPL
Value: 'adduser -s {shell} {username}'
- Name: LINUX_USER_ADD_WITH_GID_TPL
Value: 'adduser -s {shell} -G {group} {username}'
PortMappings:
- ContainerPort: 301
HostPort: 301
Protocol: tcp

- Name: 'bastion'
MountPoints:
- SourceVolume: "root"
ContainerPath: "/root"
- SourceVolume: "home"
ContainerPath: "/home"
- SourceVolume: "etc-shadow"
ContainerPath: "/etc/shadow"
- SourceVolume: "etc-passwd"
ContainerPath: "/etc/passwd"
- SourceVolume: "etc-group"
ContainerPath: "/etc/group"
- SourceVolume: "sshd_config"
ContainerPath: "/etc/ssh/sshd_config"
- SourceVolume: "usr-bin-github-authorized-keys"
ContainerPath: "/usr/bin/github-authorized-keys"
Image: "cloudposse/bastion"
Cpu: "100"
Memory: "128"
Essential: "true"
Links:
- github-authorized-keys
Environment:
- Name: DUO_IKEY
Value: xxxxxxxxxxxxxxxxxxx
- Name: DUO_SKEY
Value: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- Name: DUO_HOST
Value: api-xxxxx.duosecurity.com
- Name: SSH_AUDIT_ENABLED
Value: 'false'
PortMappings:
- ContainerPort: 22
HostPort: 1234
Protocol: tcp
Volumes:
- Name: "host"
Host:
SourcePath: "/"
- Name: "root"
Host:
SourcePath: "/root"
- Name: "home"
Host:
SourcePath: "/home"
- Name: "etc-shadow"
Host:
SourcePath: "/etc/shadow"
- Name: "etc-passwd"
Host:
SourcePath: "/etc/passwd"
- Name: "etc-group"
Host:
SourcePath: "/etc/group"
- Name: "sshd_config"
Host:
SourcePath: "/etc/ssh/cloudposse_sshd_config"
- Name: "usr-bin-github-authorized-keys"
Host:
SourcePath: "/usr/bin/github-authorized-keys"


ECSService:
Type: AWS::ECS::Service
Properties:
Cluster: !Sub ${AWS::StackName}
DesiredCount: !Ref NumBastionHosts
TaskDefinition: !Ref TaskDefinition
DeploymentConfiguration:
MinimumHealthyPercent: 0

0 comments on commit 622f819

Please sign in to comment.