An updated version of this hack is now available:
Please follow the simpler instructions in the above article instead of the obsolete instructions listed below.
I spent the weekend learning just enough JavaScript and nodejs to hack together a Lambda function that runs arbitrary shell commands in the AWS Lambda environment.
This hack allows you to explore the current file system, learn what versions of Perl and Python are available, and discover what packages might be installed.
If you’re interested in seeing the results, then read following article which uses this AWS Lambda shell hack to examine the inside of the AWS Lambda run time environment.
Now on to the hack…
Setup
Define the basic parameters.
# Replace with your bucket name
bucket_name=lambdash.alestic.com
function=lambdash
lambda_execution_role_name=lambda-$function-execution
lambda_execution_access_policy_name=lambda-$function-execution-access
log_group_name=/aws/lambda/$function
IAM role that will be used by the Lambda function when it runs.
lambda_execution_role_arn=$(aws iam create-role \
--role-name "$lambda_execution_role_name" \
--assume-role-policy-document '{"Version": "2012-10-17","Statement": [{"Sid": "","Effect": "Allow","Principal": {"Service": "lambda.amazonaws.com"
},"Action": "sts:AssumeRole"
}]
}' \
--output text \
--query 'Role.Arn'
)
echo lambda_execution_role_arn=$lambda_execution_role_arn
What the Lambda function is allowed to do/access. Log to Cloudwatch and upload files to a specific S3 bucket/location.
aws iam put-role-policy \
--role-name "$lambda_execution_role_name" \
--policy-name "$lambda_execution_access_policy_name" \
--policy-document '{"Version": "2012-10-17","Statement": [{"Effect": "Allow","Action": [ "logs:*" ],"Resource": "arn:aws:logs:*:*:*"
}, {"Effect": "Allow","Action": [ "s3:PutObject" ],"Resource": "arn:aws:s3:::'$bucket_name'/'$function'/*"
}]
}'
Grab the current Lambda function JavaScript from the Alestic lambdash GitHub repository, create the ZIP file, and upload the new Lambda function.
wget -q -O$function.js \
https://raw.githubusercontent.com/alestic/lambdash/master/lambdash.js
npm install async fs tmp
zip -r $function.zip $function.js node_modules
aws lambda upload-function \
--function-name "$function" \
--function-zip "$function.zip" \
--runtime nodejs \
--mode event \
--handler "$function.handler" \
--role "$lambda_execution_role_arn" \
--timeout 60 \
--memory-size 256
Invoke the Lambda function with the desired command and S3 output locations. Adjust the command and repeat as desired.
cat > $function-args.json <<EOM
{"command": "ls -laiR /","bucket": "$bucket_name","stdout": "$function/stdout.txt","stderr": "$function/stderr.txt"
}
EOM
aws lambda invoke-async \
--function-name "$function" \
--invoke-args "$function-args.json"
Look at the Lambda function log output in CloudWatch.
log_stream_names=$(aws logs describe-log-streams \
--log-group-name "$log_group_name" \
--output text \
--query 'logStreams[*].logStreamName') &&
for log_stream_name in $log_stream_names; do
aws logs get-log-events \
--log-group-name "$log_group_name" \
--log-stream-name "$log_stream_name" \
--output text \
--query 'events[*].message'
done | less
Get the command output.
aws s3 cp s3://$bucket_name/$function/stdout.txt .
aws s3 cp s3://$bucket_name/$function/stderr.txt .
less stdout.txt stderr.txt
Clean up
If you are done with this example, you can delete the created resources. Or, you can leave the Lambda function in place ready for future use. After all, you aren’t charged unless you use it.
aws s3 rm s3://$bucket_name/$function/stdout.txt
aws s3 rm s3://$bucket_name/$function/stderr.txt
aws lambda delete-function \
--function-name "$function"
aws iam delete-role-policy \
--role-name "$lambda_execution_role_name" \
--policy-name "$lambda_execution_access_policy_name"
aws iam delete-role \
--role-name "$lambda_execution_role_name"
aws logs delete-log-group \
--log-group-name "$log_group_name"
Requests
What command output would you like to see in the Lambda environment?
Original article and comments: https://alestic.com/2014/11/aws-lambda-shell/