AWS Development - Chalice Framework - 5 minutes for Lambda and API Gateway
Published: 2020-09-07 22:06:00

Since first days in my IT career I was struggling between 2 choices to be infrastructure administrator or developer - I like both. Circumstances pushed me to be infrastructure administrator, and for some time development was just my hobby.
In recent years I was discovering more and more tools from AWS, which was bringing my dream to be developer and infrastructure administrator at the same time - tools making Infrastructure as code reality.

One of the tools is AWS Chalice framework  

Best definition of  [Chalice Framework](https://aws.amazon.com/blogs/developer/deploying-aws-chalice-application-using-aws-cloud-development-kit/) is:

   _AWS Chalice is a Python Serverless Microframework for AWS and allows you to quickly create and deploy applications that use Amazon API Gateway and AWS Lambda._

Chalice provides developers with the options:
1. Quick deploy resources using integrated deploy tool
2. Test code locally

Administrators can integrate and deploy Chalice application using CDK, Cloud Formation, Terraform . See AWS blog for [CDK deployment](https://aws.amazon.com/blogs/developer/deploying-aws-chalice-application-using-aws-cloud-development-kit/)

There is always question: Which tool to use - Chalice, SAM, CDK, Flask?

Chalice is suitable for small quick deployment:
1. Developer - to quick test applications.
2. Deployment in small environment

 The scenario #2 is why I exactly decided to use Chalice.
Talking to customer about his EC2 instance pricing, I got the requirements which  must be met:
- Windows Server with 2 remote users to login
- No Inbound open ports in Security group - *Y-e-e-h!*
- No VPN - *Guess - this is from Step above*
- Outgoing connections are allowed.
- Time zones PST/EST/CET - USA/Europe
- 5 min is ok to start server
- Server needs to be fast, and we need to save money - *Y-e-e-h!*
- No server management from customer

Solution:
1. Deploy Lambda and API Gateway which will start/stop instance when users connect to server - this will save cost, as total server usage is not expected to be more than 12 hours.
2. Configure customer side with SSM management plugin installed, and script to start server 
3. Stop EC2 instance when no user activity for an hour - script inside windows server

###Implementation: Step 1
* Docker container with Chalice installed - We are always using containers for Development environment. See Docker [file](https://github.com/virtiogroove/aws-helper-scripts/blob/master/Docker%20Chalice/Dockerfile)
* Start container
 
`docker run -v ~/chalice:/root/chalice -v /root/.aws:/root/.aws/ -it -p 2022:22 ubuntu:chalice  /bin/bash`
* In container:

 `cd  chalice`

 `chalice new-project control-ec2`

 `cd control-ec2`

 `python3 -m pip show boto3|grep Version|sed 's/Version: /boto3==/'>>requirements.txt`  _#this will add the latest boto3 version to requirements for local testing. You do not to do this if you are ok with code_

* Edit app.py file:

`from chalice import Chalice`
`import boto3`
`app = Chalice(app_name='control-ec2')`


`@app.authorizer(ttl_seconds=30)`
`def my_auth(auth_request):`
        `# Validate auth_request.token, and then:`
            `return AuthResponse(routes=['/'],` `principal_id='arn:aws:ec2:us-west-2:xxxxxxxxxx:root/*')`

`# Create route to start instance`
`@app.route('/start/{name}', authorizer=my_auth)`
`def instance(name):`
    `instances = [name]`
    `ec2 = boto3.client('ec2', region_name='us-west-2')`
    `ec2.start_instances(InstanceIds=instances)`
    `return {'InstanceId started': name}`


`# Create route to stop instance`
`@app.route('/stop/{name}', authorizer=my_auth)`
`def instance_stop(name):`
    `instances = [name]`
    `ec2 = boto3.client('ec2', region_name='us-west-2')`
    `ec2.stop_instances(InstanceIds=instances)`
    `return {'InstanceId stopped': name}`

What we are doing here:
* Creating Authorizer which allows only IAM user to invoke API method
* 2 functions to start/stop EC2 instances based on instance Id passed

*Note:* Change region in boto3 clients and principal id to whatever role/username you need
`principal_id='arn:aws:ec2:us-west-2:xxxxxxxxxx:root/*')`

* Next run
`chalice deploy` or
`chalice deploy --stage prod` _once dev stage is ok_

In less than 5 minutes you have it ready

How to invoke API?

*Method 1:
Python code

`import requests`
`from requests_aws_sign import AWSV4Sign`
`from boto3 import session`

`session = session.Session()`
`credentials = session.get_credentials()`
`region = session.region_name`
`service = 'execute-api'`

`url = "REPLACE_THIS_LINE_WITH_URI_AND_INSTANCE_ID"`
`auth = AWSV4Sign(credentials, region, service)`
`response = requests.get(url, auth=auth)`
`print(response.text)`

*Note:* you need to modify code to pass instance Id, or explicitly specify URLs with instance ID - e.g. 2 files to start and stop instance


* There is better method though:
use AWS CLI:

`aws apigateway test-invoke-method --rest-api-id API_ID --resource-id RESOURCE_ID --http-method GET --path-with-query-string /stop/<instanceId here>`

*--rest-api-id* - returned after chalice deploy or `cat .chalice/deployed/prod.json`
*--resource-id* -  find in console on particular method , or from
`aws apigateway get-resources --rest-api-id API_ID`  



From solution we implemented only Step 1.
Stay tune how to configure customer side for Steps 2 and 3