├── .gitignore ├── README.md ├── samples ├── .gitignore ├── cloud9-go1.8 │ ├── Dockerfile │ ├── README.md │ └── task-def.json.template └── cloud9-go1.9 │ ├── Dockerfile │ ├── README.md │ └── task-def.json.template ├── serverless-bastion ├── README.md ├── cfn.yaml └── docker │ ├── .dockerignore │ ├── Dockerfile │ ├── README.md │ ├── entrypoint.sh │ ├── environment │ └── motd └── serverless-cloud9 ├── README.md ├── cfn.yaml └── docker ├── .dockerignore ├── Dockerfile ├── README.md ├── entrypoint.sh ├── environment └── motd /.gitignore: -------------------------------------------------------------------------------- 1 | id_rsa* 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | FargateShell 2 | --- 3 | 4 | # Serverless Cloud9 5 | 6 | Create a AWS Cloud9 remote host using AWS Fargate. 7 | https://github.com/pottava/fargate-shell/blob/master/serverless-cloud9/README.md 8 | 9 | # Serverless Bastion host 10 | 11 | Create a temporary bastion host using AWS Fargate. 12 | https://github.com/pottava/fargate-shell/blob/master/serverless-bastion/README.md 13 | -------------------------------------------------------------------------------- /samples/.gitignore: -------------------------------------------------------------------------------- 1 | task-def.json 2 | -------------------------------------------------------------------------------- /samples/cloud9-go1.8/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM pottava/fargate-cloud9:1.0 2 | 3 | ENV GOPATH=/home/fargate/go \ 4 | PATH=/home/fargate/go/bin:/usr/local/go/bin:$PATH 5 | 6 | # Install go 1.8 7 | RUN yum install -y go wget \ 8 | && mkdir -p $GOPATH \ 9 | && chmod -R 777 $GOPATH \ 10 | && echo "GOPATH=/home/fargate/go" >> /home/fargate/.ssh/environment \ 11 | && echo "PATH=$GOPATH/bin:$PATH" >> /home/fargate/.ssh/environment 12 | 13 | # Install gometalinter (goimports, golint, govet, ..) 14 | RUN go get github.com/alecthomas/gometalinter \ 15 | && cd $GOPATH/src/github.com/alecthomas/gometalinter \ 16 | && git checkout v2.0.2 \ 17 | && go install github.com/alecthomas/gometalinter \ 18 | && gometalinter --install \ 19 | && chmod -R 777 $GOPATH 20 | -------------------------------------------------------------------------------- /samples/cloud9-go1.8/README.md: -------------------------------------------------------------------------------- 1 | Cloud9 with go1.8.4 2 | --- 3 | 4 | ``` 5 | $ S3_BUCKET= 6 | $ S3_KEY= 7 | $ ECS_CLUSTER= 8 | $ FAGATE_SUBNET= 9 | $ FAGATE_SECURITYGROUP= 10 | $ FAGATE_EXEC_ROLEARN= 11 | $ FAGATE_TASK_ROLEARN= 12 | ``` 13 | 14 | ## Configure Cloud9 15 | 16 | ``` 17 | $ open https://console.aws.amazon.com/cloud9/home/create 18 | ``` 19 | 20 | ``` 21 | 1. Click `Create environment` button 22 | 2. Input the environment name 23 | 3. Click `Next step` button 24 | 4. Select `Connect and run in remote server (SSH)` as your environment type 25 | 5. Save `public SSH key` to your local disk as a `id_rsa.pub` 26 | 27 | * Do not click the `Next step` button for now 28 | ``` 29 | 30 | ## Upload the key to S3 31 | 32 | Set your S3 bucket name & key as environment variables 33 | 34 | ``` 35 | $ aws s3api put-object --bucket ${S3_BUCKET} --key ${S3_KEY} \ 36 | --body id_rsa.pub 37 | ``` 38 | 39 | ## Register a task definition with the FARGATE compatibility 40 | 41 | ``` 42 | $ sed -e 's/@S3_BUCKET/'${S3_BUCKET}'/' task-def.json.template > task-def.json 43 | $ sed -i -e 's/@S3_KEY/'${S3_KEY}'/' task-def.json 44 | $ aws --region us-east-1 ecs register-task-definition \ 45 | --family fagate-go18 \ 46 | --requires-compatibilities FARGATE \ 47 | --execution-role-arn ${FAGATE_EXEC_ROLEARN} \ 48 | --task-role-arn ${FAGATE_TASK_ROLEARN} \ 49 | --network-mode awsvpc \ 50 | --container-definitions "$( cat task-def.json )" \ 51 | --cpu 256 --memory 512 52 | ``` 53 | 54 | ## Run a fargate task & wait for its running 55 | 56 | ``` 57 | $ awsvpc='subnets=['${FAGATE_SUBNET}'],securityGroups=['${FAGATE_SECURITYGROUP}']' 58 | $ runtask_result=$( aws --region us-east-1 ecs run-task \ 59 | --cluster ${ECS_CLUSTER} \ 60 | --task-definition fagate-go18 \ 61 | --launch-type FARGATE \ 62 | --network-configuration awsvpcConfiguration="{${awsvpc},assignPublicIp=ENABLED}" \ 63 | --count 1 ) 64 | $ aws --region us-east-1 ecs wait tasks-running \ 65 | --cluster ${ECS_CLUSTER} \ 66 | --tasks $( echo ${runtask_result} | jq -r '.tasks[0].taskArn' ) 67 | ``` 68 | 69 | ## Retrieve its public IP address 70 | 71 | ``` 72 | $ eni_id=$( aws --region us-east-1 ecs describe-tasks \ 73 | --cluster ${ECS_CLUSTER} \ 74 | --tasks $( echo ${runtask_result} | jq -r '.tasks[0].taskArn' ) \ 75 | | jq '.tasks[0].attachments[0].details[]' \ 76 | | jq 'select( .name | contains("networkInterfaceId"))' \ 77 | | jq -r '.value' ) 78 | $ public_ip=$( aws ec2 --region us-east-1 describe-network-interfaces \ 79 | --network-interface-ids ${eni_id} \ 80 | | jq -r '.NetworkInterfaces[].Association.PublicIp' ) \ 81 | && echo ${public_ip} 82 | ``` 83 | 84 | ## Configure Cloud9 again 85 | 86 | Set $public_ip as a Coud9 remote host. 87 | Click the `Next step` button to complete the process! 88 | -------------------------------------------------------------------------------- /samples/cloud9-go1.8/task-def.json.template: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "cloud9", 4 | "image": "pottava/fargate-cloud9:with-go1.8", 5 | "portMappings": [ 6 | { 7 | "protocol": "tcp", 8 | "containerPort": 22, 9 | "hostPort": 22 10 | }, 11 | { 12 | "protocol": "tcp", 13 | "containerPort": 80, 14 | "hostPort": 80 15 | } 16 | ], 17 | "environment": [ 18 | { 19 | "name": "SSH_AUTHKEYS_S3_BUCKET", 20 | "value": "@S3_BUCKET" 21 | }, 22 | { 23 | "name": "SSH_AUTHKEYS_S3_KEY", 24 | "value": "@S3_KEY" 25 | } 26 | ], 27 | "essential": true 28 | } 29 | ] 30 | -------------------------------------------------------------------------------- /samples/cloud9-go1.9/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM pottava/fargate-cloud9:1.0 2 | 3 | ENV GOPATH=/home/fargate/go \ 4 | PATH=/home/fargate/go/bin:/usr/local/go/bin:$PATH 5 | 6 | # Install go 1.9 7 | RUN yum install -y go wget \ 8 | && GOLANG_VERSION=1.9.2 \ 9 | && GOLANG_SRC_URL=https://golang.org/dl/go$GOLANG_VERSION.src.tar.gz \ 10 | && GOLANG_SRC_SHA256=665f184bf8ac89986cfd5a4460736976f60b57df6b320ad71ad4cef53bb143dc \ 11 | && export GOROOT_BOOTSTRAP="$(go env GOROOT)" \ 12 | && wget -q "$GOLANG_SRC_URL" -O golang.tar.gz \ 13 | && echo "$GOLANG_SRC_SHA256 golang.tar.gz" | sha256sum -c - \ 14 | && tar -C /usr/local -xzf golang.tar.gz \ 15 | && rm -rf golang.tar.gz \ 16 | && cd /usr/local/go/src \ 17 | && ./make.bash \ 18 | && mkdir -p $GOPATH \ 19 | && chmod -R 777 $GOPATH \ 20 | && echo "GOPATH=/home/fargate/go" >> /home/fargate/.ssh/environment \ 21 | && echo "PATH=$GOPATH/bin:/usr/local/go/bin:$PATH" >> /home/fargate/.ssh/environment 22 | 23 | # Install gometalinter (goimports, golint, govet, ..) 24 | RUN go get github.com/alecthomas/gometalinter \ 25 | && cd $GOPATH/src/github.com/alecthomas/gometalinter \ 26 | && git checkout v2.0.2 \ 27 | && go install github.com/alecthomas/gometalinter \ 28 | && gometalinter --install \ 29 | && chmod -R 777 $GOPATH 30 | -------------------------------------------------------------------------------- /samples/cloud9-go1.9/README.md: -------------------------------------------------------------------------------- 1 | Cloud9 with go1.9.2 2 | --- 3 | 4 | ``` 5 | $ S3_BUCKET= 6 | $ S3_KEY= 7 | $ ECS_CLUSTER= 8 | $ FAGATE_SUBNET= 9 | $ FAGATE_SECURITYGROUP= 10 | $ FAGATE_EXEC_ROLEARN= 11 | $ FAGATE_TASK_ROLEARN= 12 | ``` 13 | 14 | ## Configure Cloud9 15 | 16 | ``` 17 | $ open https://console.aws.amazon.com/cloud9/home/create 18 | ``` 19 | 20 | ``` 21 | 1. Click `Create environment` button 22 | 2. Input the environment name 23 | 3. Click `Next step` button 24 | 4. Select `Connect and run in remote server (SSH)` as your environment type 25 | 5. Save `public SSH key` to your local disk as a `id_rsa.pub` 26 | 27 | * Do not click the `Next step` button for now 28 | ``` 29 | 30 | ## Upload the key to S3 31 | 32 | Set your S3 bucket name & key as environment variables 33 | 34 | ``` 35 | $ aws s3api put-object --bucket ${S3_BUCKET} --key ${S3_KEY} \ 36 | --body id_rsa.pub 37 | ``` 38 | 39 | ## Register a task definition with the FARGATE compatibility 40 | 41 | ``` 42 | $ sed -e 's/@S3_BUCKET/'${S3_BUCKET}'/' task-def.json.template > task-def.json 43 | $ sed -i -e 's/@S3_KEY/'${S3_KEY}'/' task-def.json 44 | $ aws --region us-east-1 ecs register-task-definition \ 45 | --family fagate-go19 \ 46 | --requires-compatibilities FARGATE \ 47 | --execution-role-arn ${FAGATE_EXEC_ROLEARN} \ 48 | --task-role-arn ${FAGATE_TASK_ROLEARN} \ 49 | --network-mode awsvpc \ 50 | --container-definitions "$( cat task-def.json )" \ 51 | --cpu 256 --memory 512 52 | ``` 53 | 54 | ## Run a fargate task & wait for its running 55 | 56 | ``` 57 | $ awsvpc='subnets=['${FAGATE_SUBNET}'],securityGroups=['${FAGATE_SECURITYGROUP}']' 58 | $ runtask_result=$( aws --region us-east-1 ecs run-task \ 59 | --cluster ${ECS_CLUSTER} \ 60 | --task-definition fagate-go19 \ 61 | --launch-type FARGATE \ 62 | --network-configuration awsvpcConfiguration="{${awsvpc},assignPublicIp=ENABLED}" \ 63 | --count 1 ) 64 | $ aws --region us-east-1 ecs wait tasks-running \ 65 | --cluster ${ECS_CLUSTER} \ 66 | --tasks $( echo ${runtask_result} | jq -r '.tasks[0].taskArn' ) 67 | ``` 68 | 69 | ## Retrieve its public IP address 70 | 71 | ``` 72 | $ eni_id=$( aws --region us-east-1 ecs describe-tasks \ 73 | --cluster ${ECS_CLUSTER} \ 74 | --tasks $( echo ${runtask_result} | jq -r '.tasks[0].taskArn' ) \ 75 | | jq '.tasks[0].attachments[0].details[]' \ 76 | | jq 'select( .name | contains("networkInterfaceId"))' \ 77 | | jq -r '.value' ) 78 | $ public_ip=$( aws ec2 --region us-east-1 describe-network-interfaces \ 79 | --network-interface-ids ${eni_id} \ 80 | | jq -r '.NetworkInterfaces[].Association.PublicIp' ) \ 81 | && echo ${public_ip} 82 | ``` 83 | 84 | ## Configure Cloud9 again 85 | 86 | Set $public_ip as a Coud9 remote host. 87 | Click the `Next step` button to complete the process! 88 | -------------------------------------------------------------------------------- /samples/cloud9-go1.9/task-def.json.template: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "cloud9", 4 | "image": "pottava/fargate-cloud9:with-go1.9", 5 | "portMappings": [ 6 | { 7 | "protocol": "tcp", 8 | "containerPort": 22, 9 | "hostPort": 22 10 | }, 11 | { 12 | "protocol": "tcp", 13 | "containerPort": 80, 14 | "hostPort": 80 15 | } 16 | ], 17 | "environment": [ 18 | { 19 | "name": "SSH_AUTHKEYS_S3_BUCKET", 20 | "value": "@S3_BUCKET" 21 | }, 22 | { 23 | "name": "SSH_AUTHKEYS_S3_KEY", 24 | "value": "@S3_KEY" 25 | } 26 | ], 27 | "essential": true 28 | } 29 | ] 30 | -------------------------------------------------------------------------------- /serverless-bastion/README.md: -------------------------------------------------------------------------------- 1 | Serverless Bastion 2 | --- 3 | 4 | # How to use 5 | 6 | ## Decide your SSH password 7 | 8 | ``` 9 | $ SSH_PASSWORD= 10 | ``` 11 | 12 | ## Create a base stack & retrieve the outputs 13 | 14 | ``` 15 | $ aws --region us-east-1 cloudformation create-stack \ 16 | --stack-name bastion --template-body file://cfn.yaml \ 17 | --parameters ParameterKey=Password,ParameterValue="${SSH_PASSWORD}" \ 18 | --capabilities CAPABILITY_IAM 19 | $ aws --region us-east-1 cloudformation wait stack-create-complete \ 20 | --stack-name bastion 21 | $ outputs=$( aws --region us-east-1 cloudformation describe-stacks \ 22 | --stack-name bastion | jq -r '.Stacks[0].Outputs[]' ) 23 | $ cluster=$( echo ${outputs} | jq -r 'select(.OutputKey=="Cluster").OutputValue' ) 24 | $ subnet1=$( echo ${outputs} | jq -r 'select(.OutputKey=="PublicSubnet1").OutputValue' ) 25 | $ subnet2=$( echo ${outputs} | jq -r 'select(.OutputKey=="PublicSubnet2").OutputValue' ) 26 | $ secgrp=$( echo ${outputs} | jq -r 'select(.OutputKey=="SecurityGroup").OutputValue' ) 27 | $ awsvpc='subnets=['${subnet1}','${subnet2}'],securityGroups=['${secgrp}']' 28 | ``` 29 | 30 | ## Run a fargate task & wait for its running 31 | 32 | ``` 33 | $ result=$( aws --region us-east-1 ecs run-task \ 34 | --cluster ${cluster} \ 35 | --task-definition bastion \ 36 | --launch-type FARGATE \ 37 | --network-configuration awsvpcConfiguration="{${awsvpc},assignPublicIp=ENABLED}" \ 38 | --count 1 ) 39 | $ aws --region us-east-1 ecs wait tasks-running \ 40 | --cluster ${cluster} \ 41 | --tasks $( echo ${result} | jq -r '.tasks[0].taskArn' ) 42 | ``` 43 | 44 | ## Retrieve its public IP address 45 | 46 | ``` 47 | $ eni_id=$( aws --region us-east-1 ecs describe-tasks \ 48 | --cluster ${cluster} \ 49 | --tasks $( echo ${result} | jq -r '.tasks[0].taskArn' ) \ 50 | | jq '.tasks[0].attachments[0].details[]' \ 51 | | jq 'select( .name | contains("networkInterfaceId"))' \ 52 | | jq -r '.value' ) 53 | $ public_ip=$( aws ec2 --region us-east-1 describe-network-interfaces \ 54 | --network-interface-ids ${eni_id} \ 55 | | jq -r '.NetworkInterfaces[].Association.PublicIp' ) \ 56 | && echo ${public_ip} 57 | ``` 58 | 59 | ## SSH 60 | 61 | ``` 62 | $ ssh fargate@${public_ip} 63 | ``` 64 | -------------------------------------------------------------------------------- /serverless-bastion/cfn.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Description: "Fargate for serverless bastion" 3 | 4 | Metadata: 5 | AWS::CloudFormation::Interface: 6 | ParameterGroups: 7 | - Label: 8 | default: SSH Configuration 9 | Parameters: 10 | - Password 11 | 12 | Parameters: 13 | Password: 14 | Description: SSH password 15 | Type: String 16 | 17 | Mappings: 18 | SubnetConfig: 19 | VPC: 20 | CIDR: 10.0.0.0/16 21 | Public1: 22 | CIDR: 10.0.10.0/24 23 | Public2: 24 | CIDR: 10.0.20.0/24 25 | 26 | Resources: 27 | VPC: 28 | Type: AWS::EC2::VPC 29 | Properties: 30 | EnableDnsSupport: true 31 | EnableDnsHostnames: true 32 | CidrBlock: 33 | Fn::FindInMap: 34 | - SubnetConfig 35 | - VPC 36 | - CIDR 37 | Tags: 38 | - Key: Application 39 | Value: !Ref AWS::StackName 40 | 41 | InternetGateway: 42 | Type: AWS::EC2::InternetGateway 43 | DependsOn: VPC 44 | Properties: 45 | Tags: 46 | - Key: Application 47 | Value: !Ref AWS::StackName 48 | 49 | AttachGateway: 50 | Type: AWS::EC2::VPCGatewayAttachment 51 | Properties: 52 | VpcId: !Ref VPC 53 | InternetGatewayId: !Ref InternetGateway 54 | 55 | PublicSubnet1: 56 | Type: AWS::EC2::Subnet 57 | DependsOn: AttachGateway 58 | Properties: 59 | VpcId: !Ref VPC 60 | MapPublicIpOnLaunch: true 61 | AvailabilityZone: 62 | Fn::Select: 63 | - 0 64 | - Fn::GetAZs: "" 65 | CidrBlock: 66 | Fn::FindInMap: 67 | - SubnetConfig 68 | - Public1 69 | - CIDR 70 | Tags: 71 | - Key: Name 72 | Value: "Public Subnet 1" 73 | - Key: Application 74 | Value: !Ref AWS::StackName 75 | 76 | PublicSubnet2: 77 | Type: AWS::EC2::Subnet 78 | DependsOn: AttachGateway 79 | Properties: 80 | VpcId: !Ref VPC 81 | MapPublicIpOnLaunch: true 82 | AvailabilityZone: 83 | Fn::Select: 84 | - 1 85 | - Fn::GetAZs: "" 86 | CidrBlock: 87 | Fn::FindInMap: 88 | - SubnetConfig 89 | - Public2 90 | - CIDR 91 | Tags: 92 | - Key: Name 93 | Value: "Public Subnet 2" 94 | - Key: Application 95 | Value: !Ref AWS::StackName 96 | 97 | PublicRouteTable: 98 | Type: AWS::EC2::RouteTable 99 | DependsOn: 100 | - VPC 101 | - AttachGateway 102 | Properties: 103 | VpcId: !Ref VPC 104 | Tags: 105 | - Key: Name 106 | Value: Public 107 | - Key: Application 108 | Value: !Ref AWS::StackName 109 | 110 | PublicRoute: 111 | Type: AWS::EC2::Route 112 | DependsOn: AttachGateway 113 | Properties: 114 | RouteTableId: !Ref PublicRouteTable 115 | DestinationCidrBlock: 0.0.0.0/0 116 | GatewayId: !Ref InternetGateway 117 | 118 | PublicSubnet1RouteTableAssociation: 119 | Type: AWS::EC2::SubnetRouteTableAssociation 120 | DependsOn: AttachGateway 121 | Properties: 122 | SubnetId: !Ref PublicSubnet1 123 | RouteTableId: !Ref PublicRouteTable 124 | 125 | PublicSubnet2RouteTableAssociation: 126 | Type: AWS::EC2::SubnetRouteTableAssociation 127 | DependsOn: AttachGateway 128 | Properties: 129 | SubnetId: !Ref PublicSubnet2 130 | RouteTableId: !Ref PublicRouteTable 131 | 132 | SecurityGroup: 133 | Type: AWS::EC2::SecurityGroup 134 | Properties: 135 | GroupDescription: SecurityGroup for Bastion host 136 | VpcId: !Ref VPC 137 | SecurityGroupIngress: 138 | - IpProtocol: tcp 139 | FromPort: 22 140 | ToPort: 22 141 | CidrIp: "0.0.0.0/0" 142 | Tags: 143 | - Key: Name 144 | Value: sg-for-bastion 145 | 146 | CloudWatchLogsGroup: 147 | Type: AWS::Logs::LogGroup 148 | Properties: 149 | RetentionInDays: 1 150 | 151 | BastionCluster: 152 | Type: AWS::ECS::Cluster 153 | Properties: 154 | ClusterName: !Ref AWS::StackName 155 | 156 | ExecutionRole: 157 | Type: AWS::IAM::Role 158 | Properties: 159 | AssumeRolePolicyDocument: 160 | Version: "2012-10-17" 161 | Statement: 162 | - Effect: Allow 163 | Principal: 164 | Service: ecs-tasks.amazonaws.com 165 | Action: sts:AssumeRole 166 | ManagedPolicyArns: 167 | - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy 168 | Path: / 169 | 170 | TaskRole: 171 | Type: AWS::IAM::Role 172 | Properties: 173 | AssumeRolePolicyDocument: 174 | Version: "2012-10-17" 175 | Statement: 176 | - Effect: Allow 177 | Principal: 178 | Service: ecs-tasks.amazonaws.com 179 | Action: sts:AssumeRole 180 | Policies: 181 | - PolicyName: deny-all 182 | PolicyDocument: 183 | Statement: 184 | - Effect: Deny 185 | Action: "*" 186 | Resource: "*" 187 | Path: / 188 | 189 | BastionTask: 190 | Type: AWS::ECS::TaskDefinition 191 | Properties: 192 | Family: !Ref AWS::StackName 193 | NetworkMode: awsvpc 194 | RequiresCompatibilities: 195 | - FARGATE 196 | TaskRoleArn: !Ref TaskRole 197 | ExecutionRoleArn: !Ref ExecutionRole 198 | Cpu: 256 199 | Memory: 512 200 | ContainerDefinitions: 201 | - Name: bastion 202 | Image: pottava/fargate-shell:1.0 203 | Command: 204 | - "-d" 205 | PortMappings: 206 | - ContainerPort: 22 207 | HostPort: 22 208 | Environment: 209 | - Name: SSH_PASSWORD 210 | Value: !Ref Password 211 | LogConfiguration: 212 | LogDriver: awslogs 213 | Options: 214 | awslogs-group: !Ref CloudWatchLogsGroup 215 | awslogs-region: !Ref AWS::Region 216 | awslogs-stream-prefix: bastion 217 | Essential: true 218 | 219 | BastionService: 220 | Type: AWS::ECS::Service 221 | Properties: 222 | LaunchType: FARGATE 223 | Cluster: !Ref BastionCluster 224 | DesiredCount: 1 225 | TaskDefinition: !Ref BastionTask 226 | NetworkConfiguration: 227 | AwsvpcConfiguration: 228 | AssignPublicIp: ENABLED 229 | Subnets: 230 | - !Ref PublicSubnet1 231 | - !Ref PublicSubnet2 232 | SecurityGroups: 233 | - !Ref SecurityGroup 234 | 235 | Outputs: 236 | PublicSubnet1: 237 | Value: !Ref PublicSubnet1 238 | 239 | PublicSubnet2: 240 | Value: !Ref PublicSubnet2 241 | 242 | SecurityGroup: 243 | Value: !Ref SecurityGroup 244 | 245 | Cluster: 246 | Value: !Ref BastionCluster 247 | -------------------------------------------------------------------------------- /serverless-bastion/docker/.dockerignore: -------------------------------------------------------------------------------- 1 | *.* 2 | !entrypoint.sh 3 | !environment 4 | !motd 5 | -------------------------------------------------------------------------------- /serverless-bastion/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.6 2 | 3 | # Python 2.7 4 | RUN apk --no-cache add python2=2.7.13-r1 5 | 6 | # AWS-CLI 1.14 7 | RUN apk --no-cache add less groff jq 8 | RUN apk --no-cache add --virtual build-deps py2-pip \ 9 | && pip install 'awscli == 1.14.7' \ 10 | && apk del --purge -r build-deps 11 | 12 | # OpenSSH server & client 13 | RUN apk --no-cache add openssh \ 14 | && sed -i s/#PermitRootLogin.*/PermitRootLogin\ no/ /etc/ssh/sshd_config \ 15 | && sed -i s/#PermitUserEnvironment.*/PermitUserEnvironment\ yes/ /etc/ssh/sshd_config 16 | 17 | # for better experience 18 | RUN apk --no-cache add tini bash sudo 19 | 20 | RUN addgroup fargate && adduser -s /bin/bash -D -G fargate fargate 21 | ADD environment /home/fargate/.ssh/environment 22 | WORKDIR /home/fargate/ 23 | 24 | ADD entrypoint.sh /entrypoint.sh 25 | RUN chmod +x /entrypoint.sh 26 | ADD motd /etc/motd 27 | 28 | EXPOSE 22 29 | 30 | ENTRYPOINT ["/sbin/tini", "--", "/entrypoint.sh"] 31 | -------------------------------------------------------------------------------- /serverless-bastion/docker/README.md: -------------------------------------------------------------------------------- 1 | Supported tags and respective `Dockerfile` links: 2 | 3 | ・latest ([docker/Dockerfile](https://github.com/pottava/fargate-shell/blob/master/serverless-bastion/docker/Dockerfile)) 4 | ・1.0 ([docker/Dockerfile](https://github.com/pottava/fargate-shell/blob/master/serverless-bastion/docker/Dockerfile)) 5 | 6 | ## Usage 7 | 8 | ### Launch a SSH server 9 | 10 | ``` 11 | $ docker run --rm -i -p 2222:22 -e SSH_PASSWORD=passw0rd \ 12 | -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_DEFAULT_REGION \ 13 | pottava/fargate-shell 14 | ``` 15 | 16 | ### SSH 17 | 18 | ``` 19 | $ ssh -p 2222 fargate@localhost 20 | ``` 21 | -------------------------------------------------------------------------------- /serverless-bastion/docker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | env | grep AWS_ >> /home/fargate/.ssh/environment 4 | 5 | if [ "x${SSH_AUTHKEYS_S3_BUCKET}" != "x" ] ; then 6 | if [ "x${SSH_AUTHKEYS_S3_KEY}" = "x" ] ; then 7 | echo "'SSH_AUTHKEYS_S3_KEY' should be specified." 1>&2 8 | exit 1 9 | fi 10 | aws sts get-caller-identity 11 | aws s3api get-object --bucket ${SSH_AUTHKEYS_S3_BUCKET} \ 12 | --key ${SSH_AUTHKEYS_S3_KEY} /home/fargate/.ssh/authorized_keys \ 13 | > /dev/null 14 | chown fargate:fargate /home/fargate/.ssh/authorized_keys 15 | chmod 600 /home/fargate/.ssh/authorized_keys 16 | cat /home/fargate/.ssh/authorized_keys 17 | 18 | passwd -u fargate 19 | sed -i s/#RSAAuthentication.*/RSAAuthentication\ yes/ /etc/ssh/sshd_config 20 | sed -i s/#PubkeyAuthentication.*/PubkeyAuthentication\ yes/ /etc/ssh/sshd_config 21 | sed -i s/#PasswordAuthentication.*/PasswordAuthentication\ no/ /etc/ssh/sshd_config 22 | sed -i s/#ChallengeResponse.*/ChallengeResponseAuthentication\ no/ /etc/ssh/sshd_config 23 | fi 24 | 25 | # generate host keys if not present 26 | ssh-keygen -A 27 | 28 | if [ "x${SSH_AUTHKEYS_S3_BUCKET}" = "x" ] ; then 29 | if [ "x${SSH_PASSWORD}" = "x" ] ; then 30 | echo "'SSH_PASSWORD' should be specified." 1>&2 31 | exit 1 32 | fi 33 | echo "fargate:${SSH_PASSWORD}" | chpasswd 34 | sed -i s/#PermitEmptyPasswords.*/PermitEmptyPasswords\ no/ /etc/ssh/sshd_config 35 | sed -i s/#PasswordAuthentication.*/PasswordAuthentication\ yes/ /etc/ssh/sshd_config 36 | fi 37 | 38 | if [ "${ENABLE_SUDO}" = "1" ] ; then 39 | echo 'Defaults visiblepw' >> /etc/sudoers 40 | echo 'fargate ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 41 | fi 42 | 43 | # do not detach (-D), log to stderr (-e), passthrough other arguments 44 | exec /usr/sbin/sshd -D -e "$@" 45 | -------------------------------------------------------------------------------- /serverless-bastion/docker/environment: -------------------------------------------------------------------------------- 1 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 2 | PAGER=less 3 | LESS=-eirMX 4 | -------------------------------------------------------------------------------- /serverless-bastion/docker/motd: -------------------------------------------------------------------------------- 1 | Welcome to FargateShell! 2 | 3 | -------------------------------------------------------------------------------- /serverless-cloud9/README.md: -------------------------------------------------------------------------------- 1 | Serverless Cloud9 2 | --- 3 | 4 | # How to use 5 | 6 | ## Configure Cloud9 7 | 8 | ``` 9 | $ open https://console.aws.amazon.com/cloud9/home/create 10 | ``` 11 | 12 | ``` 13 | 1. Click `Create environment` button 14 | 2. Input the environment name 15 | 3. Click `Next step` button 16 | 4. Select `Connect and run in remote server (SSH)` as your environment type 17 | 5. Save `public SSH key` to your local disk as a `id_rsa.pub` 18 | 19 | * Do not click the `Next step` button for now 20 | ``` 21 | 22 | ## Upload the key to S3 23 | 24 | Set your S3 bucket name & key as environment variables 25 | 26 | ``` 27 | $ S3_BUCKET= 28 | $ S3_KEY= 29 | $ aws s3api put-object --bucket ${S3_BUCKET} --key ${S3_KEY} \ 30 | --body id_rsa.pub 31 | ``` 32 | 33 | ## Create a base stack & retrieve the outputs 34 | 35 | ``` 36 | $ aws --region us-east-1 cloudformation create-stack \ 37 | --stack-name cloud9 --template-body file://cfn.yaml \ 38 | --parameters ParameterKey=AuthKeysS3Bucket,ParameterValue="${S3_BUCKET}" \ 39 | ParameterKey=AuthKeysS3Key,ParameterValue="${S3_KEY}" \ 40 | --capabilities CAPABILITY_IAM 41 | $ aws --region us-east-1 cloudformation wait stack-create-complete \ 42 | --stack-name cloud9 43 | $ outputs=$( aws --region us-east-1 cloudformation describe-stacks \ 44 | --stack-name cloud9 | jq -r '.Stacks[0].Outputs[]' ) 45 | $ cluster=$( echo ${outputs} | jq -r 'select(.OutputKey=="Cluster").OutputValue' ) 46 | $ subnet1=$( echo ${outputs} | jq -r 'select(.OutputKey=="PublicSubnet1").OutputValue' ) 47 | $ subnet2=$( echo ${outputs} | jq -r 'select(.OutputKey=="PublicSubnet2").OutputValue' ) 48 | $ secgrp=$( echo ${outputs} | jq -r 'select(.OutputKey=="SecurityGroup").OutputValue' ) 49 | $ awsvpc='subnets=['${subnet1}','${subnet2}'],securityGroups=['${secgrp}']' 50 | ``` 51 | 52 | ## Run a fargate task & wait for its running 53 | 54 | ``` 55 | $ result=$( aws --region us-east-1 ecs run-task \ 56 | --cluster ${cluster} \ 57 | --task-definition cloud9 \ 58 | --launch-type FARGATE \ 59 | --network-configuration awsvpcConfiguration="{${awsvpc},assignPublicIp=ENABLED}" \ 60 | --count 1 ) 61 | $ aws --region us-east-1 ecs wait tasks-running \ 62 | --cluster ${cluster} \ 63 | --tasks $( echo ${result} | jq -r '.tasks[0].taskArn' ) 64 | ``` 65 | 66 | ## Retrieve its public IP address 67 | 68 | ``` 69 | $ eni_id=$( aws --region us-east-1 ecs describe-tasks \ 70 | --cluster ${cluster} \ 71 | --tasks $( echo ${result} | jq -r '.tasks[0].taskArn' ) \ 72 | | jq '.tasks[0].attachments[0].details[]' \ 73 | | jq 'select( .name | contains("networkInterfaceId"))' \ 74 | | jq -r '.value' ) 75 | $ public_ip=$( aws ec2 --region us-east-1 describe-network-interfaces \ 76 | --network-interface-ids ${eni_id} \ 77 | | jq -r '.NetworkInterfaces[].Association.PublicIp' ) \ 78 | && echo ${public_ip} 79 | ``` 80 | 81 | ## Configure Cloud9 again 82 | 83 | Set $public_ip as a Coud9 remote host. 84 | Click the `Next step` button to complete the process! 85 | 86 | # Notice 87 | 88 | ## You cannot install `c9.ide.lambda.docker` though.. 89 | 90 | AWS Fargate is based on docker container itself. 91 | It seems that we are not allowed to run `docker in docker` on AWS Fargate :( 92 | 93 | # Don't forget to stop the container!!! 94 | 95 | Not like a serverless-bastion container, servereless-cloud9 container has to be stopped manually. 96 | -------------------------------------------------------------------------------- /serverless-cloud9/cfn.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Description: "Fargate for serverless Cloud9" 3 | 4 | Metadata: 5 | AWS::CloudFormation::Interface: 6 | ParameterGroups: 7 | - Label: 8 | default: SSH Configuration 9 | Parameters: 10 | - AuthKeysS3Bucket 11 | - AuthKeysS3Key 12 | 13 | Parameters: 14 | AuthKeysS3Bucket: 15 | Description: S3 bucket which stores .ssh/authorized_keys 16 | Type: String 17 | 18 | AuthKeysS3Key: 19 | Description: S3 object key of .ssh/authorized_keys 20 | Type: String 21 | 22 | Mappings: 23 | SubnetConfig: 24 | VPC: 25 | CIDR: 10.0.0.0/16 26 | Public1: 27 | CIDR: 10.0.10.0/24 28 | Public2: 29 | CIDR: 10.0.20.0/24 30 | 31 | Resources: 32 | VPC: 33 | Type: AWS::EC2::VPC 34 | Properties: 35 | EnableDnsSupport: true 36 | EnableDnsHostnames: true 37 | CidrBlock: 38 | Fn::FindInMap: 39 | - SubnetConfig 40 | - VPC 41 | - CIDR 42 | Tags: 43 | - Key: Application 44 | Value: !Ref AWS::StackName 45 | 46 | InternetGateway: 47 | Type: AWS::EC2::InternetGateway 48 | DependsOn: VPC 49 | Properties: 50 | Tags: 51 | - Key: Application 52 | Value: !Ref AWS::StackName 53 | 54 | AttachGateway: 55 | Type: AWS::EC2::VPCGatewayAttachment 56 | Properties: 57 | VpcId: !Ref VPC 58 | InternetGatewayId: !Ref InternetGateway 59 | 60 | PublicSubnet1: 61 | Type: AWS::EC2::Subnet 62 | DependsOn: AttachGateway 63 | Properties: 64 | VpcId: !Ref VPC 65 | MapPublicIpOnLaunch: true 66 | AvailabilityZone: 67 | Fn::Select: 68 | - 0 69 | - Fn::GetAZs: "" 70 | CidrBlock: 71 | Fn::FindInMap: 72 | - SubnetConfig 73 | - Public1 74 | - CIDR 75 | Tags: 76 | - Key: Name 77 | Value: "Public Subnet 1" 78 | - Key: Application 79 | Value: !Ref AWS::StackName 80 | 81 | PublicSubnet2: 82 | Type: AWS::EC2::Subnet 83 | DependsOn: AttachGateway 84 | Properties: 85 | VpcId: !Ref VPC 86 | MapPublicIpOnLaunch: true 87 | AvailabilityZone: 88 | Fn::Select: 89 | - 1 90 | - Fn::GetAZs: "" 91 | CidrBlock: 92 | Fn::FindInMap: 93 | - SubnetConfig 94 | - Public2 95 | - CIDR 96 | Tags: 97 | - Key: Name 98 | Value: "Public Subnet 2" 99 | - Key: Application 100 | Value: !Ref AWS::StackName 101 | 102 | PublicRouteTable: 103 | Type: AWS::EC2::RouteTable 104 | DependsOn: 105 | - VPC 106 | - AttachGateway 107 | Properties: 108 | VpcId: !Ref VPC 109 | Tags: 110 | - Key: Name 111 | Value: Public 112 | - Key: Application 113 | Value: !Ref AWS::StackName 114 | 115 | PublicRoute: 116 | Type: AWS::EC2::Route 117 | DependsOn: AttachGateway 118 | Properties: 119 | RouteTableId: !Ref PublicRouteTable 120 | DestinationCidrBlock: 0.0.0.0/0 121 | GatewayId: !Ref InternetGateway 122 | 123 | PublicSubnet1RouteTableAssociation: 124 | Type: AWS::EC2::SubnetRouteTableAssociation 125 | DependsOn: AttachGateway 126 | Properties: 127 | SubnetId: !Ref PublicSubnet1 128 | RouteTableId: !Ref PublicRouteTable 129 | 130 | PublicSubnet2RouteTableAssociation: 131 | Type: AWS::EC2::SubnetRouteTableAssociation 132 | DependsOn: AttachGateway 133 | Properties: 134 | SubnetId: !Ref PublicSubnet2 135 | RouteTableId: !Ref PublicRouteTable 136 | 137 | SecurityGroup: 138 | Type: AWS::EC2::SecurityGroup 139 | Properties: 140 | GroupDescription: SecurityGroup for Cloud9 remote server 141 | VpcId: !Ref VPC 142 | SecurityGroupIngress: 143 | - IpProtocol: tcp 144 | FromPort: 22 145 | ToPort: 22 146 | CidrIp: "0.0.0.0/0" 147 | - IpProtocol: tcp 148 | FromPort: 80 149 | ToPort: 80 150 | CidrIp: "0.0.0.0/0" 151 | Tags: 152 | - Key: Name 153 | Value: sg-for-cloud9 154 | 155 | CloudWatchLogsGroup: 156 | Type: AWS::Logs::LogGroup 157 | Properties: 158 | RetentionInDays: 1 159 | 160 | Cloud9Cluster: 161 | Type: AWS::ECS::Cluster 162 | Properties: 163 | ClusterName: !Ref AWS::StackName 164 | 165 | ExecutionRole: 166 | Type: AWS::IAM::Role 167 | Properties: 168 | AssumeRolePolicyDocument: 169 | Version: "2012-10-17" 170 | Statement: 171 | - Effect: Allow 172 | Principal: 173 | Service: ecs-tasks.amazonaws.com 174 | Action: sts:AssumeRole 175 | ManagedPolicyArns: 176 | - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy 177 | Path: / 178 | 179 | TaskRole: 180 | Type: AWS::IAM::Role 181 | Properties: 182 | AssumeRolePolicyDocument: 183 | Version: "2012-10-17" 184 | Statement: 185 | - Effect: Allow 186 | Principal: 187 | Service: ecs-tasks.amazonaws.com 188 | Action: sts:AssumeRole 189 | ManagedPolicyArns: 190 | - arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess 191 | Path: / 192 | 193 | Cloud9Task: 194 | Type: AWS::ECS::TaskDefinition 195 | Properties: 196 | Family: !Ref AWS::StackName 197 | NetworkMode: awsvpc 198 | RequiresCompatibilities: 199 | - FARGATE 200 | TaskRoleArn: !Ref TaskRole 201 | ExecutionRoleArn: !Ref ExecutionRole 202 | Cpu: 512 203 | Memory: 1024 204 | ContainerDefinitions: 205 | - Name: cloud9 206 | Image: pottava/fargate-cloud9:1.0 207 | PortMappings: 208 | - ContainerPort: 22 209 | HostPort: 22 210 | Environment: 211 | - Name: SSH_AUTHKEYS_S3_BUCKET 212 | Value: !Ref AuthKeysS3Bucket 213 | - Name: SSH_AUTHKEYS_S3_KEY 214 | Value: !Ref AuthKeysS3Key 215 | LogConfiguration: 216 | LogDriver: awslogs 217 | Options: 218 | awslogs-group: !Ref CloudWatchLogsGroup 219 | awslogs-region: !Ref AWS::Region 220 | awslogs-stream-prefix: cloud9 221 | Essential: true 222 | 223 | Outputs: 224 | PublicSubnet1: 225 | Value: !Ref PublicSubnet1 226 | 227 | PublicSubnet2: 228 | Value: !Ref PublicSubnet2 229 | 230 | SecurityGroup: 231 | Value: !Ref SecurityGroup 232 | 233 | Cluster: 234 | Value: !Ref Cloud9Cluster 235 | -------------------------------------------------------------------------------- /serverless-cloud9/docker/.dockerignore: -------------------------------------------------------------------------------- 1 | *.* 2 | !entrypoint.sh 3 | !environment 4 | !motd 5 | -------------------------------------------------------------------------------- /serverless-cloud9/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM amazonlinux:2017.09.0.20170930 2 | 3 | # AWS-CLI 1.14 4 | RUN yum install -y python27-pip groff \ 5 | && pip install 'awscli == 1.14.7' \ 6 | && yum remove -y python27-pip 7 | 8 | # Node 7.10 9 | RUN yum install -y epel-release \ 10 | && yum install -y --enablerepo=epel nodejs npm 11 | 12 | # for Cloud9 13 | RUN yum install -y glibc-static ncurses-devel which sudo git \ 14 | && echo 'Defaults visiblepw' >> /etc/sudoers 15 | 16 | # tini 17 | RUN curl -o /tini.asc -sL https://github.com/krallin/tini/releases/download/v0.16.1/tini.asc \ 18 | && curl -o /tini -sL https://github.com/krallin/tini/releases/download/v0.16.1/tini \ 19 | && gpg --keyserver hkp://p80.pool.sks-keyservers.net:80 \ 20 | --recv-keys 595E85A6B1B4779EA4DAAEC70B588DFF0527A9B7 \ 21 | && gpg --verify /tini.asc \ 22 | && chmod +x /tini 23 | 24 | # OpenSSH server 25 | RUN yum install -y openssh-server \ 26 | && sed -i s/#PermitRootLogin.*/PermitRootLogin\ no/ /etc/ssh/sshd_config \ 27 | && sed -i s/#PermitUserEnvironment.*/PermitUserEnvironment\ yes/ /etc/ssh/sshd_config \ 28 | && sed -i s/#PubkeyAuthentication.*/PubkeyAuthentication\ yes/ /etc/ssh/sshd_config \ 29 | && sed -i s/#PasswordAuthentication.*/PasswordAuthentication\ no/ /etc/ssh/sshd_config \ 30 | && sed -i s/#ChallengeResponse.*/ChallengeResponseAuthentication\ no/ /etc/ssh/sshd_config 31 | 32 | RUN groupadd -g 1000 fargate \ 33 | && useradd -g fargate -u 1000 -m -d /home/fargate -s /bin/bash fargate \ 34 | && chmod 755 /home/fargate 35 | ADD environment /home/fargate/.ssh/environment 36 | WORKDIR /home/fargate/ 37 | 38 | ADD entrypoint.sh /entrypoint.sh 39 | RUN chmod +x /entrypoint.sh 40 | ADD motd /etc/motd 41 | 42 | EXPOSE 22 43 | 44 | ENTRYPOINT ["/tini", "--", "/entrypoint.sh"] 45 | -------------------------------------------------------------------------------- /serverless-cloud9/docker/README.md: -------------------------------------------------------------------------------- 1 | Supported tags and respective `Dockerfile` links: 2 | 3 | ・latest ([docker/Dockerfile](https://github.com/pottava/fargate-shell/blob/master/serverless-cloud9/docker/Dockerfile)) 4 | ・1.0 ([docker/Dockerfile](https://github.com/pottava/fargate-shell/blob/master/serverless-cloud9/docker/Dockerfile)) 5 | -------------------------------------------------------------------------------- /serverless-cloud9/docker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | env | grep AWS_ >> /home/fargate/.ssh/environment 4 | 5 | if [ "x${SSH_AUTHKEYS_S3_BUCKET}" = "x" ] ; then 6 | echo "'SSH_AUTHKEYS_S3_BUCKET' should be specified." 1>&2 7 | exit 1 8 | fi 9 | if [ "x${SSH_AUTHKEYS_S3_KEY}" = "x" ] ; then 10 | echo "'SSH_AUTHKEYS_S3_KEY' should be specified." 1>&2 11 | exit 1 12 | fi 13 | 14 | aws sts get-caller-identity 15 | aws s3api get-object --bucket ${SSH_AUTHKEYS_S3_BUCKET} \ 16 | --key ${SSH_AUTHKEYS_S3_KEY} /home/fargate/.ssh/authorized_keys \ 17 | > /dev/null 18 | chown fargate:fargate /home/fargate/.ssh/authorized_keys 19 | chmod 600 /home/fargate/.ssh/authorized_keys 20 | cat /home/fargate/.ssh/authorized_keys 21 | 22 | # generate host keys if not present 23 | ssh-keygen -A 24 | 25 | if [ "x${USER_PASSWORD}" != "x" ] ; then 26 | echo "fargate:${USER_PASSWORD}" | chpasswd 27 | echo 'fargate ALL=(ALL) ALL' >> /etc/sudoers 28 | else 29 | echo 'fargate ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 30 | fi 31 | 32 | # do not detach (-D), log to stderr (-e), passthrough other arguments 33 | exec /usr/sbin/sshd -D -e "$@" 34 | -------------------------------------------------------------------------------- /serverless-cloud9/docker/environment: -------------------------------------------------------------------------------- 1 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 2 | PAGER=less 3 | LESS=-eirMX 4 | -------------------------------------------------------------------------------- /serverless-cloud9/docker/motd: -------------------------------------------------------------------------------- 1 | Welcome to FargateCloud9! 2 | 3 | --------------------------------------------------------------------------------