Skip to content

Instantly share code, notes, and snippets.

@summersab
Last active March 12, 2019 04:39
Show Gist options
  • Save summersab/e55050b781c043439898bf66044359b3 to your computer and use it in GitHub Desktop.
Save summersab/e55050b781c043439898bf66044359b3 to your computer and use it in GitHub Desktop.
Notes for getting started with bref.sh

First follow one of these scripts (depending upon your dist): bref-config-debian.sh bref-config-fedora.sh

Then, follow bref-initialize-deploy.sh - these steps are the same regardless of the platform. Note that bref-initialize-deploy.sh references IAMCredentials.json (included in this Gist). Refer to template.yaml for notes on how to nest functions under the same API Gateway.

#### I'm using a LAMP stack on Debian 9 from TurnkeyLinux.org. It's easy, and things just work, so you should use it, too.
apt-get update
apt-get upgrade
apt-get install ca-certificates apt-transport-https python-pip gcc python2.7-dev
wget -q https://packages.sury.org/php/apt.gpg -O- | sudo apt-key add -
echo "deb https://packages.sury.org/php/ stretch main" | sudo tee /etc/apt/sources.list.d/php.list
apt-get update
apt-get upgrade
apt-get install php7.3-cli php7.3-common php7.3-curl php7.3-mbstring php7.3-mysql php7.3-xml php7.3
pip install setuptools
pip install awscli
pip install aws-sam-cli
#### This is assuming you're starting with a vanilla Amazon Linux AMI and will do things like setting up PHP from scratch
#### These commands complement https://bref.sh/docs/installation.html
# Update packages and install needed compilation dependencies
sudo yum update -y
sudo yum install autoconf bison gcc gcc-c++ libcurl-devel libxml2-devel -y
sudo pip install --upgrade pip
sudo pip install --upgrade awscli
sudo pip install --user setuptools
sudo pip install --user aws-sam-cli
#### The following is largely borrowed from https://aws.amazon.com/blogs/apn/aws-lambda-custom-runtime-for-php-a-practical-example/
# Compile OpenSSL v1.0.1 from source, as Amazon Linux uses a newer version than the Lambda Execution Environment, which
# would otherwise produce an incompatible binary.
curl -sL http://www.openssl.org/source/openssl-1.0.1k.tar.gz | tar -xvz
cd openssl-1.0.1k
./config && make && sudo make install
cd ~
# Download the PHP 7.3.0 source
mkdir ~/php-7-bin
curl -sL https://github.com/php/php-src/archive/php-7.3.0.tar.gz | tar -xvz
cd php-src-php-7.3.0
# Compile PHP 7.3.0 with OpenSSL 1.0.1 support, and install to /home/ec2-user/php-7-bin
./buildconf --force
./configure --prefix=/home/ec2-user/php-7-bin/ --with-openssl=/usr/local/ssl --with-curl --with-zlib
make install
sudo ln ~/php-7-bin/bin/php /usr/local/bin/php
####
#### These commands complement https://bref.sh/docs/first-steps.html
#### The following is borrowed from https://serverless.com/framework/docs/providers/aws/guide/credentials/#creating-aws-access-keys - I think this could probably be replaced with a "aws iam create-role" command, but I haven't figured that out, yet.
# Go to https://console.aws.amazon.com/iam/home?#/users
# Click on Users and then Add user. Enter a name in the first field to remind you this User is the Framework, like serverless-agent. Enable Programmatic access by clicking the checkbox. Click Next to go through to the Permissions page. Click on Create policy. Select the JSON tab, add the following JSON file you'll find in this gist*:
# https://gist.github.com/summersab/e55050b781c043439898bf66044359b3#file-iamcredentials-json
#
# When you are finished, select Review policy. You can assign this policy a Name and Description, then choose Create Policy. Check everything looks good and click Create user. Later, you can create different IAM Users for different apps and different stages of those apps. That is, if you don't use separate AWS accounts for stages/apps, which is most common.
#
# View and copy the API Key & Secret to a temporary place. You'll need it in the next step:
aws configure
####
# Install Composer
curl -sS https://getcomposer.org/installer -o composer-setup.php
sudo php composer-setup.php --install-dir=/usr/local/bin --filename=composer
rm composer-setup.php
# Create a folder for your project (rename this if you'd rather call it something to keep your projects organized)
cd ~/
mkdir bref
cd bref
composer require mnapoli/bref
# Initialize bref. You probably want to pick option 1 for an HTTP Application (this automagically creates an API gateway for your function)
vendor/bin/bref init
# Go ahead and edit index.php. Add more dependencies via Composer - go crazy! Treat this like a normal PHP project
#### These commands complement https://bref.sh/docs/deploy.html
# Create a new S3 Bucket
aws s3 mb s3://<bucket-name>
# Optimize your code:
composer install --optimize-autoloader --no-dev
# Upload the code and generate the stack configuration:
sam package \
--output-template-file .stack.yaml \
--s3-bucket <bucket-name>
# Deploy the generated stack (if this fails, you probably didn't edit the JSON for the IAM policy as noted in Part 1):
sam deploy \
--template-file .stack.yaml \
--capabilities CAPABILITY_IAM \
--stack-name <stack-name>
#### That's it!
#### I'm pretty sure the policy set-up can be automated, but I'm not having much luck with the "aws iam create-role" command. Maybe later . . .
# curl -sS https://gist.github.com/summersab/e55050b781c043439898bf66044359b3#file-iamcredentials-json -o /tmp/IAMCredentials.json
# aws iam create-role \
# --role-name LambdaPhpExample \
# --path "/service-role/" \
# --assume-role-policy-document file:///tmp/IAMCredentials.json
{
"Statement": [
{
"Action": [
"apigateway:*",
"cloudformation:CancelUpdateStack",
"cloudformation:ContinueUpdateRollback",
"cloudformation:CreateChangeSet",
"cloudformation:CreateStack",
"cloudformation:CreateUploadBucket",
"cloudformation:DeleteStack",
"cloudformation:Describe*",
"cloudformation:EstimateTemplateCost",
"cloudformation:ExecuteChangeSet",
"cloudformation:Get*",
"cloudformation:List*",
"cloudformation:UpdateStack",
"cloudformation:UpdateTerminationProtection",
"cloudformation:ValidateTemplate",
"ec2:AttachInternetGateway",
"ec2:AuthorizeSecurityGroupIngress",
"ec2:CreateInternetGateway",
"ec2:CreateNetworkAcl",
"ec2:CreateNetworkAclEntry",
"ec2:CreateRouteTable",
"ec2:CreateSecurityGroup",
"ec2:CreateSubnet",
"ec2:CreateTags",
"ec2:CreateVpc",
"ec2:DeleteInternetGateway",
"ec2:DeleteNetworkAcl",
"ec2:DeleteNetworkAclEntry",
"ec2:DeleteRouteTable",
"ec2:DeleteSecurityGroup",
"ec2:DeleteSubnet",
"ec2:DeleteVpc",
"ec2:Describe*",
"ec2:DetachInternetGateway",
"ec2:ModifyVpcAttribute",
"events:DeleteRule",
"events:DescribeRule",
"events:ListRuleNamesByTarget",
"events:ListRules",
"events:ListTargetsByRule",
"events:PutRule",
"events:PutTargets",
"events:RemoveTargets",
"iam:CreateRole",
"iam:DeleteRole",
"iam:DeleteRolePolicy",
"iam:GetRole",
"iam:PassRole",
"iam:PutRolePolicy",
"iam:AttachRolePolicy",
"lambda:*",
"logs:CreateLogGroup",
"logs:DeleteLogGroup",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams",
"logs:FilterLogEvents",
"logs:GetLogEvents",
"s3:CreateBucket",
"s3:DeleteBucket",
"s3:DeleteBucketPolicy",
"s3:DeleteObject",
"s3:DeleteObjectVersion",
"s3:GetObject",
"s3:GetObjectVersion",
"s3:ListAllMyBuckets",
"s3:ListBucket",
"s3:PutBucketNotification",
"s3:PutBucketPolicy",
"s3:PutBucketTagging",
"s3:PutBucketWebsite",
"s3:PutEncryptionConfiguration",
"s3:PutObject"
],
"Effect": "Allow",
"Resource": "*"
}
],
"Version": "2012-10-17"
}
# Say you have two scripts, hello and goodbye. They are in your project root like this:
# /project-root
# +-- /path
# | +-- /hello
# | +-- index.php
# +-- /different
# +-- /path
# +-- /goodbye
# +-- index.php
#
# You want them deployed so that they will be accessible as such:
# https://<host>.com/Prod/path/hello
# https://<host>.com/Prod/different/path/goodbye
#
# Below is how you would lay out your project's template.yaml to accomplish this structure when it is published to AWS.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: ''
Resources:
HelloFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: 'hello'
Description: ''
CodeUri: .
Handler: ./path/hello/index.php
Timeout: 30 # in seconds (API Gateway has a timeout of 30 seconds)
MemorySize: 1024 # The memory size is related to the pricing and CPU power
Runtime: provided
Layers:
- 'arn:aws:lambda:us-east-1:209497400698:layer:php-73-fpm:1'
Events:
# The function will match all HTTP URLs
HttpRoot:
Type: Api
Properties:
Path: /path/hello/
Method: ANY
HttpSubPaths:
Type: Api
Properties:
Path: /path/hello/{proxy+}
Method: ANY
GoodbyeFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: 'goodbye'
Description: ''
CodeUri: .
Handler: ./different/path/goodbye/index.php
Timeout: 30 # in seconds (API Gateway has a timeout of 30 seconds)
MemorySize: 1024 # The memory size is related to the pricing and CPU power
Runtime: provided
Layers:
- 'arn:aws:lambda:us-east-1:209497400698:layer:php-73-fpm:1'
Events:
# The function will match all HTTP URLs
HttpRoot:
Type: Api
Properties:
Path: /different/path/goodbye
Method: ANY
HttpSubPaths:
Type: Api
Properties:
Path: /different/goodbye/{proxy+}
Method: ANY
# Outputs show up in the CloudFormation dashboard
Outputs:
DemoHttpApi:
Description: 'URL of our function in the *Prod* environment'
Value: !Sub 'https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment