« Previous 1 2 3 Next »
Serverless run times with custom Bash AWS Lambda layers
A Code Bash
All Got A Role To Play
Before creating a function and attaching the Bash layer, you need an AWS IAM role to provide permissions for its execution ("invocation" in AWS Lambda-speak) and to allow it to write to CloudWatch logs correctly. Note that these permissions are created by default if you create a function inside the AWS Management Console, so re-use those if you get stuck. Also note that Elastic Network Interface creation, deletion, and description of VPC permissions are also needed if you plan to use a VPC with your Lambda function so it can access internal AWS resources (e.g., Elastic Compute Cloud (EC2) instances and the like).
Listing 2 shows the IAM permission policy to use with your role. You need to replace the XXXXX
entries with your own AWS account number to keep permissions tight. You can find the aforementioned account number by clicking the top-right, pull-down menu in the AWS Management Console and looking for Billing
in the options. Save Listing 2 to your filesystem as policy.json
. Note that bashFunction
under Resource
is the name of your function and needs to be changed if you change the function name.
Listing 2
policy.json
01 { 02 "Version": "2012-10-17", 03 "Statement": [ 04 { 05 "Effect": "Allow", 06 "Action": "logs:CreateLogGroup", 07 "Resource": "arn:aws:logs:eu-west-1:XXXXX:*" 08 }, 09 { 10 "Effect": "Allow", 11 "Action": [ 12 "logs:CreateLogStream", 13 "logs:PutLogEvents" 14 ], 15 "Resource": [ 16 "arn:aws:logs:eu-west-1:XXXXX:log-group:/aws/lambda/bashFunction:*" 17 ] 18 } 19 ] 20 }
For the IAM role, you will also need a trusted entity to tell AWS which services can use this role. Listing 3 names Lambda (!) as the service of choice. Call this file trust.json
.
Listing 3
trust.json
01 { 02 "Version": "2012-10-17", 03 "Statement": [ 04 { 05 "Effect": "Allow", 06 "Principal": { 07 "Service": "lambda.amazonaws.com" 08 }, 09 "Action": "sts:AssumeRole" 10 } 11 ] 12 }
You're almost there. You just need to create a role with that trust policy attached to it; then, you'll attach a permission policy. The command that creates the role with that trust policy is:
$ aws iam create-role --role-name bashFunctionRole --assume-role-policy-document file://trust.json
Any illegal character errors you receive might be caused by cut and paste errors [10], so check your input.
If that command is successful, you'll see lots of output, including a RoleId
. If you want to be certain that role does exist, check the IAM section of the AWS Management Console.
Next, create a permissions policy in AWS and attach it to your role (Listing 2). Listing 4 creates a permissions policy called bashFunctionPolicy
in AWS with the policy.json
code.
Listing 4
Permissions Policy (Redacted)
$ aws iam create-policy --policy-name bashFunctionPolicy --policy-document file://policy.json { "Policy": { "PolicyName": "bashFunctionPolicy", "PermissionsBoundaryUsageCount": 0, "CreateDate": "2001-11-11T11:11:11Z", "AttachmentCount": 0, "IsAttachable": true, "PolicyId": "ABCDEFGHIJKLMNOPQ", "DefaultVersionId": "v1", "Path": "/", "Arn": "arn:aws:iam::XXXXX:policy/bashFunctionPolicy", "UpdateDate": "2001-11-11T11:11:11Z" } }
The next command attaches the policy to your IAM role. (Note that I've replaced my AWS account number with Xs again for security reasons.)
$ aws iam attach-role-policy --policy-arn arn:aws:iam::XXXXX:policy/bashFunctionPolicy --role-name bashFunctionRole
You might be a little surprised to see that the successful execution of that command is a simple, empty newline with no output whatsoever. To verify, check in the IAM section of the AWS Management Console to see that it worked. Figure 1 proves, having looked up the role name in IAM, that it works as hoped.
So Close …
Now you can create a shiny new Lambda function and attach your Bash layer by using the AWS CLI to execute the long aws lambda create-function
command shown at the beginning of this article. When confronted with long commands, I can find them tricky to cut and paste, so I often just drop them into a script (adding #!/bin/bash
as the first line), which also makes them easier to tweak and reference later. To use this script, save it as a file called run.sh
(Listing 5) and make it executable with:
$ chmod +x run.sh
Listing 5
run.sh
01 #!/bin/bash 02 03 aws lambda create-function \ 04 --function-name bashFunction \ 05 --role arn:aws:iam::XXXXX:role/bashFunctionRole \ 06 --handler index.handler \ 07 --runtime provided \ 08 --layers arn:aws:lambda:eu-west-1:744348701589:layer:bash:8 \ 09 --zip-file fileb://list_buckets.zip
In my case, the only things I replace are the <region>
entry with eu-west-1
and function.zip
to the newly named ZIP payload with the filename list_buckets.zip
. To run that unwieldy command, enter:
$ ./run.sh
If you get stuck, you can copy and paste the code in Listing 5 (which is available on FTP [10]) and replace the Xs with your AWS account number, as usual.
The output from this relatively long command is shown in Listing 6, which shows that I've created a new Lambda function (in Dublin, Ireland), added a layer to it from another account, and given it permissions from a role with a policy attached to it. (Again, the output is redacted a bit.) The next step invokes the function and checks its output.
Listing 6
lambda create-function Output
01 { 02 "Layers": [ 03 { 04 "CodeSize": 26955425, 05 "Arn": "arn:aws:lambda:eu-west-1:744348701589:layer:bash:8" 06 } 07 ], 08 "FunctionName": "bashFunction", 09 "LastModified": "2001-11-11T11:11:11Z", 10 "RevisionId": "aa63-b5c0-4ec2-a5e99", 11 "MemorySize": 128, 12 "Version": "$LATEST", 13 "Role": "arn:aws:iam::XXXXX:role/bashFunctionRole", 14 "Timeout": 3, 15 "Runtime": "provided", 16 "TracingConfig": { 17 "Mode": "PassThrough" 18 }, 19 "CodeSha256": "37n/rzJz4o2lyvh4s2aet2aBlY=adc", 20 "Description": "", 21 "CodeSize": 432, 22 "FunctionArn": "arn:aws:lambda:eu-west-1:XXXXX:function:bashFunction", 23 "Handler": "index.handler" 24 }
Alrighty Then
Of course, you can send variables to the Lambda function to execute it from the AWS CLI, but you should look at the AWS Management Console, as well, so you can get used to how a function looks there. In my case, I would navigate to https://eu-west-1.console.aws.amazon.com/lambda/home?region=eu-west-1#/functions in my Browser, which should list, among my other functions, bashFunctionRole . The eagle-eyed also will spot Custom runtime , on which I'll click to enter its configuration.
Once on that screen (Figure 2), double-click on the index.sh
script. You can see that AWS Lambda has read the ZIP file payload as hoped and displays it on request.
Jump back up the page a moment, though, expand the little black menu arrow under the word Designer , and click on the attached layer. All in all, you should be able to see the config (Figure 3, blue highlight).
The next thing to check is whether the permissions are as intended. If you scroll down the very long page, you can see the attached role (Figure 4). Clicking on the link lets you see that your role has your policy attached.
The last stage requires invoking your new Lambda function's payload, written in the Bash scripting language and sitting atop your custom run time, to see what happens.
« Previous 1 2 3 Next »
Buy this article as PDF
(incl. VAT)
Buy ADMIN Magazine
Subscribe to our ADMIN Newsletters
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Most Popular
Support Our Work
ADMIN content is made possible with support from readers like you. Please consider contributing when you've found an article to be beneficial.