Skip to content

Instantly share code, notes, and snippets.

@094459
Created May 17, 2024 14:15
Show Gist options
  • Save 094459/0dc0eefcffbbc2c843e11e96940c2011 to your computer and use it in GitHub Desktop.
Save 094459/0dc0eefcffbbc2c843e11e96940c2011 to your computer and use it in GitHub Desktop.
This is a Cloudformation template that will deploy a VSCode server running on an EC2 instance with Python, Node, Java, .NET, Rust installed, as well as Amazon Q Developer. Ready to go.
Description: Create a VSCode code-server instance with an Amazon CloudFront distribution.
Parameters:
EC2KeyPair:
Type: AWS::EC2::KeyPair::KeyName
Description: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/create-key-pairs.html
Default: ws-default-keypair
InstanceVolumeSize:
Type: Number
Description: The volume size in GB
Default: 30
InstanceType:
Description: Type of EC2 instance to launch
Type: String
Default: c7i.xlarge
AllowedValues: [
c4.large, c4.xlarge, c4.2xlarge, c4.4xlarge, c4.8xlarge,
c5.large, c5.xlarge, c5.2xlarge, c5.4xlarge, c5.9xlarge, c5.12xlarge, c5.18xlarge, c5.24xlarge,
c5a.large, c5a.xlarge, c5a.2xlarge, c5a.4xlarge, c5a.8xlarge, c5a.12xlarge, c5a.16xlarge, c5a.24xlarge,
c5ad.large, c5ad.xlarge, c5ad.2xlarge, c5ad.4xlarge, c5ad.8xlarge, c5ad.12xlarge, c5ad.16xlarge, c5ad.24xlarge,
c5d.large, c5d.xlarge, c5d.2xlarge, c5d.4xlarge, c5d.9xlarge, c5d.12xlarge, c5d.18xlarge, c5d.24xlarge,
c5n.large, c5n.xlarge, c5n.2xlarge, c5n.4xlarge, c5n.9xlarge, c5n.18xlarge,
c6a.large, c6a.xlarge, c6a.2xlarge, c6a.4xlarge, c6a.8xlarge, c6a.12xlarge, c6a.16xlarge, c6a.24xlarge, c6a.32xlarge, c6a.48xlarge,
c6g.medium, c6g.large, c6g.xlarge, c6g.2xlarge, c6g.4xlarge, c6g.8xlarge, c6g.12xlarge, c6g.16xlarge,
c6gd.medium, c6gd.large, c6gd.xlarge, c6gd.2xlarge, c6gd.4xlarge, c6gd.8xlarge, c6gd.12xlarge, c6gd.16xlarge,
c6gn.medium, c6gn.large, c6gn.xlarge, c6gn.2xlarge, c6gn.4xlarge, c6gn.8xlarge, c6gn.12xlarge, c6gn.16xlarge,
c6i.large, c6i.xlarge, c6i.2xlarge, c6i.4xlarge, c6i.8xlarge, c6i.12xlarge, c6i.16xlarge, c6i.24xlarge, c6i.32xlarge,
c7g.medium, c7g.large, c7g.xlarge, c7g.2xlarge, c7g.4xlarge, c7g.8xlarge, c7g.12xlarge, c7g.16xlarge,
c7gd.medium, c7gd.large, c7gd.xlarge, c7gd.2xlarge, c7gd.4xlarge, c7gd.8xlarge, c7gd.12xlarge, c7gd.16xlarge,
c7gn.medium, c7gn.large, c7gn.xlarge, c7gn.2xlarge, c7gn.4xlarge, c7gn.8xlarge, c7gn.12xlarge, c7gn.16xlarge,
c7i.large, c7i.xlarge, c7i.2xlarge, c7i.4xlarge, c7i.8xlarge, c7i.12xlarge, c7i.16xlarge, c7i.24xlarge, c7i.48xlarge,
m4.large, m4.xlarge, m4.2xlarge, m4.4xlarge, m4.10xlarge, m4.16xlarge,
m5.large, m5.xlarge, m5.2xlarge, m5.4xlarge, m5.8xlarge, m5.12xlarge, m5.16xlarge, m5.24xlarge,
m5a.large, m5a.xlarge, m5a.2xlarge, m5a.4xlarge, m5a.8xlarge, m5a.12xlarge, m5a.16xlarge, m5a.24xlarge,
m6a.large, m6a.xlarge, m6a.2xlarge, m6a.4xlarge, m6a.8xlarge, m6a.12xlarge, m6a.16xlarge, m6a.24xlarge, m6a.32xlarge, m6a.48xlarge,
m7a.medium, m7a.large, m7a.xlarge, m7a.2xlarge, m7a.4xlarge, m7a.8xlarge, m7a.12xlarge, m7a.16xlarge, m7a.24xlarge, m7a.32xlarge, m7a.48xlarge,
t2.nano, t2.micro, t2.small, t2.medium, t2.large, t2.xlarge, t2.2xlarge,
t3.nano, t3.micro, t3.small, t3.medium, t3.large, t3.xlarge, t3.2xlarge,
t3a.nano, t3a.micro, t3a.small, t3a.medium, t3a.large, t3a.xlarge, t3a.2xlarge,
t4g.nano, t4g.micro, t4g.small, t4g.medium, t4g.large, t4g.xlarge, t4g.2xlarge
]
HomeFolder:
Type: String
Description: The home folder in the VSCodeInstance
Default: /Workshop
DevServerBasePath:
Type: String
Description: The base path for the application to be added to nginx sites-available list for code-server
Default: app
DevServerPort:
Type: Number
Description: The port for the DevServer
Default: 8081
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Instance Configuration
Parameters:
- InstanceVolumeSize
- EC2KeyPair
- Label:
default: Code Server Configuration
Parameters:
- HomeFolder
- DevServerBasePath
- DevServerPort
ParameterLabels:
InstanceVolumeSize:
default: Attached volume size
EC2KeyPair:
default: EC2 key pair name
HomeFolder:
default: Folder to open in code server when launching
DevServerBasePath:
default: BasePath where the application runs
DevServerPort:
default: Port where the application runs
Mappings:
Subnets:
VPC:
CIDR: 10.0.0.0/16
PublicOne:
CIDR: 10.0.1.0/24
PublicTwo:
CIDR: 10.0.2.0/24
PrivateOne:
CIDR: 10.0.3.0/24
PrivateTwo:
CIDR: 10.0.4.0/24
# aws ec2 describe-managed-prefix-lists --region <REGION> | jq -r '.PrefixLists[] | select (.PrefixListName == "com.amazonaws.global.cloudfront.origin-facing") | .PrefixListId'
AWSRegions2PrefixListID:
ap-northeast-1:
PrefixList: pl-58a04531
ap-northeast-2:
PrefixList: pl-22a6434b
ap-south-1:
PrefixList: pl-9aa247f3
ap-southeast-1:
PrefixList: pl-31a34658
ap-southeast-2:
PrefixList: pl-b8a742d1
ca-central-1:
PrefixList: pl-38a64351
eu-central-1:
PrefixList: pl-a3a144ca
eu-north-1:
PrefixList: pl-fab65393
eu-west-1:
PrefixList: pl-4fa04526
eu-west-2:
PrefixList: pl-93a247fa
eu-west-3:
PrefixList: pl-75b1541c
sa-east-1:
PrefixList: pl-5da64334
us-east-1:
PrefixList: pl-3b927c52
us-east-2:
PrefixList: pl-b6a144df
us-west-1:
PrefixList: pl-4ea04527
us-west-2:
PrefixList: pl-82a045eb
Resources:
########### VPC Resources ###########
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !FindInMap [Subnets, VPC, CIDR]
EnableDnsSupport: true
EnableDnsHostnames: true
InternetGateway:
Type: AWS::EC2::InternetGateway
GatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
PublicSubnetOne:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: !FindInMap [Subnets, PublicOne, CIDR]
VpcId: !Ref VPC
MapPublicIpOnLaunch: true
AvailabilityZone: !Select [0, !GetAZs '']
PublicOneRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
PublicOneRoute:
Type: AWS::EC2::Route
DependsOn: GatewayAttachment
Properties:
RouteTableId: !Ref PublicOneRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicOneRouteTableAssoc:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicOneRouteTable
SubnetId: !Ref PublicSubnetOne
PublicSubnetTwo:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: !FindInMap [Subnets, PublicTwo, CIDR]
VpcId: !Ref VPC
MapPublicIpOnLaunch: true
AvailabilityZone: !Select [1, !GetAZs '']
PublicTwoRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
PublicTwoRoute:
Type: AWS::EC2::Route
DependsOn: GatewayAttachment
Properties:
RouteTableId: !Ref PublicTwoRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicTwoRouteTableAssoc:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicTwoRouteTable
SubnetId: !Ref PublicSubnetTwo
PrivateSubnetOne:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: !FindInMap [Subnets, PrivateOne, CIDR]
VpcId: !Ref VPC
MapPublicIpOnLaunch: true
AvailabilityZone: !Select [0, !GetAZs '']
PrivateSubnetTwo:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: !FindInMap [Subnets, PrivateTwo, CIDR]
VpcId: !Ref VPC
MapPublicIpOnLaunch: true
AvailabilityZone: !Select [1, !GetAZs '']
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: SG for Developer Machine - only allow CloudFront ingress
SecurityGroupIngress:
- Description: Allow HTTP from com.amazonaws.global.cloudfront.origin-facing
IpProtocol: tcp
FromPort: 80
ToPort: 80
SourcePrefixListId: !FindInMap [AWSRegions2PrefixListID, !Ref 'AWS::Region', PrefixList]
SecurityGroupEgress:
- Description: Allow all outbound traffic
IpProtocol: -1
CidrIp: 0.0.0.0/0
VpcId: !Ref VPC
########### SSM Resources ###########
SSMLogBucket:
Type: AWS::S3::Bucket
Metadata:
cfn_nag:
rules_to_suppress:
- id: W35
reason: Access logs aren't needed for this bucket
DeletionPolicy: Delete
Properties:
AccessControl: Private
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
VSCodeInstanceSSMDoc:
Type: AWS::SSM::Document
Properties:
DocumentType: Command
Content:
schemaVersion: '2.2'
description: Bootstrap VSCode code-server instance
parameters:
architecture:
type: String
default: amd64
description: Instance architecture type
allowedValues:
- arm64
- amd64
ubuntuVersion:
type: String
default: jammy
allowedValues:
- focal
- bionic
- jammy
nodeVersion:
type: String
default: node_20.x
allowedValues:
- node_21.x
- node_20.x
- node_19.x
dotNetVersion:
type: String
default: dotnet-sdk-8.0
allowedValues:
- dotnet-sdk-8.0
- dotnet-sdk-7.0
- dotnet-sdk-8.0
mainSteps:
- action: aws:runShellScript
name: InstallAWSCLI
inputs:
runCommand:
- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y curl unzip
- curl -fsSL https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m).zip -o /tmp/aws-cli.zip
- unzip -q -d /tmp /tmp/aws-cli.zip
- sudo /tmp/aws/install
- rm -rf /tmp/aws
- aws --version
- action: aws:runShellScript
name: InstallGit
inputs:
runCommand:
- add-apt-repository ppa:git-core/ppa
- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y software-properties-common
- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y git
- sudo -u ubuntu git config --global user.email "participant@workshops.aws"
- sudo -u ubuntu git config --global user.name "Workshop Participant"
- sudo -u ubuntu git config --global init.defaultBranch "main"
- git --version
- action: aws:runShellScript
name: InstallNode
inputs:
runCommand:
- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y curl
- curl -fsSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | gpg --dearmor -o /usr/share/keyrings/nodesource-keyring.gpg
- echo "deb [arch={{ architecture }} signed-by=/usr/share/keyrings/nodesource-keyring.gpg] https://deb.nodesource.com/{{ nodeVersion }} {{ ubuntuVersion }} main" >> /etc/apt/sources.list.d/nodesource.list
- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y nodejs
- action: aws:runShellScript
name: InstallPython
inputs:
runCommand:
- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y python3-pip python3.10-venv python3-boto3 python3-pytest
- echo 'alias pytest=pytest-3' >> /home/ubuntu/.bashrc
- ln -s /usr/bin/python3 /usr/bin/python
- python3 --version
- pip3 --version
- action: aws:runShellScript
name: InstallPythonRequirements
inputs:
runCommand:
- '#!/bin/bash'
- !Sub mkdir -p ${HomeFolder} # should already exist!
- !Sub sudo chown ubuntu:ubuntu ${HomeFolder} -R
- !Sub | # move to the directory of the repository if it's there
cd ${HomeFolder}
- python3 -m venv .venv # create a virtual environment
- source .venv/bin/activate
- |
- deactivate
- sudo chown ubuntu:ubuntu .venv -R
- action: aws:runShellScript
name: UpdateProfile
inputs:
runCommand:
- '#!/bin/bash'
- echo LANG=en_US.utf-8 >> /etc/environment
- echo LC_ALL=en_US.UTF-8 >> /etc/environment
- echo 'PATH=$PATH:/home/ubuntu/.local/bin' >> /home/ubuntu/.bashrc
- echo 'export PATH' >> /home/ubuntu/.bashrc
- !Sub echo 'export AWS_REGION=${AWS::Region}' >> /home/ubuntu/.bashrc
- !Sub echo 'export AWS_ACCOUNTID=${AWS::AccountId}' >> /home/ubuntu/.bashrc
- echo 'export NEXT_TELEMETRY_DISABLED=1' >> /home/ubuntu/.bashrc
- action: aws:runShellScript
name: ConfigureCodeServer
inputs:
runCommand:
- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y curl nginx
- '#!/bin/bash'
- export HOME=/home/ubuntu
- curl -fsSL https://code-server.dev/install.sh | sh
- sudo systemctl enable --now code-server@ubuntu
- !Sub |
sudo tee /etc/nginx/sites-available/code-server <<EOF
server {
listen 80;
listen [::]:80;
server_name ${CloudFrontDistribution.DomainName};
location / {
proxy_pass http://localhost:8080/;
proxy_set_header Host \$host;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection upgrade;
proxy_set_header Accept-Encoding gzip;
}
location /${DevServerBasePath} {
proxy_pass http://localhost:${DevServerPort}/${DevServerBasePath};
proxy_set_header Host \$host;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection upgrade;
proxy_set_header Accept-Encoding gzip;
}
}
EOF
- |
sudo tee /home/ubuntu/.config/code-server/config.yaml <<EOF
cert: false
auth: password
hashed-password: "$(echo -n $(aws sts get-caller-identity --query "Account" --output text) | sudo npx argon2-cli -e)"
EOF
- sudo -u ubuntu --login mkdir -p /home/ubuntu/.local/share/code-server/User/
- sudo -u ubuntu --login touch /home/ubuntu/.local/share/code-server/User/settings.json
- !Sub |
sudo tee /home/ubuntu/.local/share/code-server/User/settings.json <<EOF
{
"extensions.autoUpdate": false,
"extensions.autoCheckUpdates": false,
"terminal.integrated.cwd": "${HomeFolder}",
"telemetry.telemetryLevel": "off",
"security.workspace.trust.startupPrompt": "never",
"security.workspace.trust.enabled": false,
"security.workspace.trust.banner": "never",
"security.workspace.trust.emptyWindow": false,
"editor.indentSize": "tabSize",
"editor.tabSize": 2,
"python.testing.pytestEnabled": true,
"auto-run-command.rules": [
{
"command": "workbench.action.terminal.new"
}
]
}
EOF
- sudo systemctl restart code-server@ubuntu
- sudo ln -s ../sites-available/code-server /etc/nginx/sites-enabled/code-server
- sudo systemctl restart nginx
- sudo -u ubuntu --login code-server --install-extension AmazonWebServices.aws-toolkit-vscode --force
# - sudo -u ubuntu --login code-server --install-extension AmazonWebServices.aws-toolkit-vscode --force
# - sudo -u ubuntu --login code-server --install-extension AmazonWebServices.amazon-q-vscode --force
- sudo -u ubuntu --login code-server --install-extension synedra.auto-run-command --force
- sudo chown ubuntu:ubuntu /home/ubuntu -R
- action: aws:runShellScript
name: InstallQDeveloperExtension
inputs:
runCommand:
- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y curl jq
- |
Q_URL=$(curl -sL https://api.github.com/repos/aws/aws-toolkit-vscode/releases/latest | jq -r '.assets[] | select(.name? | match("amazon-q-vscode-[0-9].[0-9].[0-9]*.vsix$";"g")) | .browser_download_url')
if [ -z "$Q_URL" ];
then
echo 'No Q url found, using default'
Q_URL=https://github.com/aws/aws-toolkit-vscode/releases/download/amazonq/v1.3.0/amazon-q-vscode-1.3.0.vsix
fi
echo 'Hardcoding add-in version'
Q_URL=https://github.com/aws/aws-toolkit-vscode/releases/download/amazonq/v1.3.0/amazon-q-vscode-1.3.0.vsix
echo $Q_URL
curl -fsSL $Q_URL -o /tmp/AmazonWebServices.amazon-q-vscode.vsix
sudo -u ubuntu --login code-server --install-extension /tmp/AmazonWebServices.amazon-q-vscode.vsix --force
- action: aws:runShellScript
name: InstallAWSToolkit
inputs:
runCommand:
- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y curl jq
- |
TOOLKIT_URL=$(curl -sL https://api.github.com/repos/aws/aws-toolkit-vscode/releases/latest | jq -r '.assets[] | select(.name? | match("aws-toolkit-vscode-[0-9].[0-9].[0-9]*.vsix$";"g")) | .browser_download_url')
if [ -z "$TOOLKIT_URL" ];
then
echo 'No toolkit url found, using default'
TOOLKIT_URL=https://github.com/aws/aws-toolkit-vscode/releases/download/toolkit/v3.2.0/aws-toolkit-vscode-3.2.0.vsix
fi
echo $TOOLKIT_URL
curl -fsSL $TOOLKIT_URL -o /tmp/AmazonWebServices.amazon-toolkit-vscode.vsix
sudo -u ubuntu --login code-server --install-extension /tmp/AmazonWebServices.amazon-toolkit-vscode.vsix --force
- action: aws:runShellScript
name: InstallCDK
inputs:
runCommand:
- npm install -g aws-cdk
- cdk --version
- action: aws:runShellScript
name: InstallGo
inputs:
runCommand:
- add-apt-repository ppa:longsleep/golang-backports
- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y golang-go
- sudo chown ubuntu:ubuntu /home/ubuntu -R
- go version
- action: aws:runShellScript
name: InstallRust
inputs:
runCommand:
- add-apt-repository ppa:ubuntu-mozilla-security/rust-next
- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y rustc cargo
- sudo chown ubuntu:ubuntu /home/ubuntu -R
- rustc --version
- action: aws:runShellScript
name: InstallDocker
inputs:
runCommand:
- apt-get update && apt-get install -y apt-transport-https ca-certificates curl software-properties-common curl gnupg lsb-release
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
- add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu jammy stable"
- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y docker-ce libpq-dev
- mkdir -p ~/.docker/cli-plugins/
- curl -SL https://github.com/docker/compose/releases/download/v2.3.3/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose
- chmod +x ~/.docker/cli-plugins/docker-compose
- docker compose version
- usermod -aG docker ubuntu
- action: aws:runShellScript
name: InstallAmazonCorretto
inputs:
runCommand:
- wget -O - https://apt.corretto.aws/corretto.key | sudo gpg --dearmor -o /usr/share/keyrings/corretto-keyring.gpg
- echo "deb [signed-by=/usr/share/keyrings/corretto-keyring.gpg] https://apt.corretto.aws stable main" | tee /etc/apt/sources.list.d/corretto.list
- apt-get update && sudo apt-get install -y java-17-amazon-corretto-jdk maven
- echo 'export JAVA_HOME=$(dirname $(dirname $(readlink -f $(which java))))' >> /home/ubuntu/.bashrc
- echo 'export PATH=$PATH:/usr/share/maven/bin' >> /home/ubuntu/.bashrc
- action: aws:runShellScript
name: InstallDotnet
inputs:
runCommand:
- apt-get update && DEBIAN_FRONTEND=noninteractive sudo apt-get install -y {{ dotNetVersion }}
- dotnet tool install -g Microsoft.Web.LibraryManager.Cli
- export PATH="$PATH:/home/ubuntu/.dotnet/tools"
- chown ubuntu:ubuntu /home/ubuntu -R
- dotnet --list-sdks
- action: aws:runShellScript
name: InstallVite
inputs:
runCommand:
- apt-get update && DEBIAN_FRONTEND=noninteractive sudo apt-get install -y vite create-vite
VSCodeInstanceSSMAssociation:
Type: AWS::SSM::Association
Properties:
Name: !Ref VSCodeInstanceSSMDoc
OutputLocation:
S3Location:
OutputS3BucketName: !Ref SSMLogBucket
OutputS3KeyPrefix: bootstrap
Targets:
- Key: tag:SSMBootstrap
Values: [True]
### Empty S3 bucket resources ###
EmptyS3BucketExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: !Sub EmptyS3BucketPolicy-${AWS::Region}
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- s3:ListBucket
- s3:DeleteObject
Resource: '*'
EmptyS3Bucket:
Type: AWS::Lambda::Function
Metadata:
cfn_nag:
rules_to_suppress:
- id: W58
reason: EmptyS3BucketExecutionRole has the AWSLambdaBasicExecutionRole managed policy attached, allowing writing to CloudWatch logs
- id: W89
reason: Bootstrap function does not need the scaffolding of a VPC or provisioned concurrency
- id: W92
reason: Bootstrap function does not need provisioned concurrency
Properties:
Description: Empty S3 bucket CloudFormation custom resource
Handler: index.lambda_handler
Role:
Fn::GetAtt:
- EmptyS3BucketExecutionRole
- Arn
Runtime: python3.11
MemorySize: 1024
Timeout: 400
Code:
ZipFile: |
import boto3
import cfnresponse
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
logger.info('event: {}'.format(event))
logger.info('context: {}'.format(context))
if event['RequestType'] == 'Delete':
try:
AssetsBucketName = (event['ResourceProperties']['S3Bucket'])
s3 = boto3.resource('s3')
logger.info('S3 Object initialized')
bucket = s3.Bucket(AssetsBucketName)
logger.info('S3 bucket: ' + AssetsBucketName)
bucket.objects.all().delete()
cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData={}, reason='S3 bucket emptied: ' + AssetsBucketName )
except Exception as e:
logger.error(e, exc_info=True)
cfnresponse.send(event, context, cfnresponse.FAILED, responseData={}, reason=str(e))
else:
cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData={}, reason='No action to take')
EmptyS3BucketLogGroup:
Metadata:
cfn_nag:
rules_to_suppress:
- id: W84
reason: KMS Key not required for encrypting this non sensitive data
Type: AWS::Logs::LogGroup
DeletionPolicy: Delete
UpdateReplacePolicy: Delete
Properties:
LogGroupName: !Sub /aws/lambda/${EmptyS3Bucket}
RetentionInDays: 7
EmptyS3BucketCustomResource:
Type: Custom::EmptyS3Bucket
Properties:
ServiceToken: !GetAtt EmptyS3Bucket.Arn
S3Bucket: !Ref SSMLogBucket
########### EC2 Resources ###########
VSCodeInstanceRole:
Metadata:
cfn_nag:
rules_to_suppress:
- id: W11
reason: CodeWhisperer requires '*' as a resource, reference https://docs.aws.amazon.com/codewhisperer/latest/userguide/cloud9-setup.html#codewhisperer-IAM-policies
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
- ssm.amazonaws.com
- codecommit.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- !Sub arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess
Policies:
- PolicyName: !Sub CDKAssumeRolePolicy-${AWS::Region}
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- sts:AssumeRole
Resource:
- !Sub arn:${AWS::Partition}:iam::*:role/cdk-*
- PolicyName: !Sub Codewhisperer-${AWS::Region}
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- codewhisperer:GenerateRecommendations
Resource: '*'
VSCodeInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Roles:
- !Ref VSCodeInstanceRole
VSCodeInstanceEC2Instance:
Type: AWS::EC2::Instance
Properties:
KeyName: !Ref EC2KeyPair
BlockDeviceMappings:
- Ebs:
VolumeSize: !Ref InstanceVolumeSize
VolumeType: gp3
DeleteOnTermination: true
Encrypted: true
DeviceName: /dev/sda1
Monitoring: true
SubnetId: !Ref PublicSubnetOne
ImageId: >-
{{resolve:ssm:/aws/service/canonical/ubuntu/server/22.04/stable/current/amd64/hvm/ebs-gp2/ami-id}}
InstanceType: !Ref InstanceType
SecurityGroupIds:
- !Ref SecurityGroup
IamInstanceProfile: !Ref VSCodeInstanceProfile
UserData:
Fn::Base64: !Sub |
#cloud-config
hostname: dev
runcmd:
- mkdir -p ${HomeFolder} && chown ubuntu:ubuntu ${HomeFolder}
Tags:
- Key: SSMBootstrap
Value: True
########### CloudFront Resources ###########
VSCodeInstanceCachePolicy:
Type: AWS::CloudFront::CachePolicy
Properties:
CachePolicyConfig:
DefaultTTL: 86400
MaxTTL: 31536000
MinTTL: 1
Name: !Join ['-', ['VSCodeServer', !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]]]
ParametersInCacheKeyAndForwardedToOrigin:
CookiesConfig:
CookieBehavior: all
EnableAcceptEncodingGzip: False
HeadersConfig:
HeaderBehavior: whitelist
Headers:
- Accept-Charset
- Authorization
- Origin
- Accept
- Referer
- Host
- Accept-Language
- Accept-Encoding
- Accept-Datetime
QueryStringsConfig:
QueryStringBehavior: all
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: True
HttpVersion: http2
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
- OPTIONS
- PUT
- PATCH
- POST
- DELETE
CachePolicyId: !Ref VSCodeInstanceCachePolicy
OriginRequestPolicyId: 216adef6-5c7f-47e4-b989-5492eafa07d3 # Managed-AllViewer - see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-origin-request-policies.html#:~:text=When%20using%20AWS,47e4%2Db989%2D5492eafa07d3
TargetOriginId: !Sub CloudFront-${AWS::StackName}
ViewerProtocolPolicy: allow-all
Origins:
- DomainName: !GetAtt VSCodeInstanceEC2Instance.PublicDnsName
Id: !Sub CloudFront-${AWS::StackName}
CustomOriginConfig:
OriginProtocolPolicy: http-only
Outputs:
Password:
Description: VSCode-Server Password
Value: !Ref AWS::AccountId
Export:
Name: !Sub ${AWS::StackName}-Password
URL:
Description: VSCode-Server URL
Value: !Sub https://${CloudFrontDistribution.DomainName}/?folder=${HomeFolder}
Export:
Name: !Sub ${AWS::StackName}-URL
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment