Public and cross-account functions on Serverless platforms such as AWS Lambda offer compelling use-cases to build non-HTTP, non-RESTful web services that skip API Gateway and can be connected directly to event triggers on other user's accounts.

For instance, a function processing S3 uploads with AWS Rekognition could be connected to a number of S3 buckets across several accounts, with all image processing charges aggregated and billed under one account.

At  IOpipe we support creating alarms that execute Lambda functions. We also support webhooks, but to connect those with Lambda would demand using API Gateway, which demands configuration, adds latency, and incurs charges from AWS. By invoking Lambda directly, we offer a simpler and less expensive option, which also allows our user's Serverless applications to run more natively and inclusively in Lambda.

Here's how you configure it. You create a function on Lambda. This may be done via a framework, with the AWS cli, or via the web:

exports.handler = (event, context, callback) => {
  callback(null, 'Hello world.');
};

We save this as 'hello_world'. You may choose any name, but this is the name I will use as a reference.

Setting Permissions

Now, the magic! We must add permissions to the function to allow cross-account invocation. This may only be done using the AWS cli.

Allow invocations via API & CLI:

aws lambda add-permission --function-name hello_world --statement-id PublicAccess --action 'lambda:Invoke' --principal '*'

Allow configuration of event sources:

aws lambda add-permission --function-name hello_world --statement-id PublicAccessTrigger --action 'lambda:CreateEventSourceMapping' --principal '*'

Skip ahead to Invocations across accounts, unless you'd like to know more about fine-tuning these parameters!

Notes on 'add-permission' parameters

The statement-id is a name for this permission. You would reference this statement-id when removing permissions from the Lambda.

The action is any Lambda API call. The most appropriate one for this use-case is to Invoke, but other permissions could make sense, such as granting permission to a CI/CD system to  lambda:UpdateFunctionCode.

The principal argument accepts all origins by specifying '*', but can be restricted invocations from an AWS service id or an AWS account id. This allows restricting your Lambda to invocations originating from s3, or from specific AWS accounts.

When invocations originate from AWS services, their principal will not be an account ID, but an AWS service principal such as sns.amazon.com or s3.amazon.com, and you will need to specify that principal ('--principal s3.amazon.com') and then filter AWS accounts using the '--source-account' parameter.

Invocations across accounts

Amazon gives you a ARN, which for simplicity of explanation, we'll get from the AWS dashboard:

Using the ARN, we can simply invoke this from the CLI using another AWS account:

aws lambda invoke --function-name 'arn:aws:lambda:us-east-1:0000000000:function:hello_world' --invocation-type RequestResponse --log-type Tail

You can also specify '--invocation-type DryRun' to simply verify access to the function without invoking it, or specify type Event to asynchronously invoke (fire & forget).  The --log-type Tail option was specified to get stdout, but may be skipped if you do not desire to see "Hello World" printed.

Configuring event triggers

Cross-account Lambda functions are only useful if your application can trigger them! From an account with access to your Lambda function:

aws lambda create-event-source-mapping --event-source-arn <arn> --function-name arn:aws:lambda:us-east-1:0000000000:function:hello_world

Using this, one could connect their account’s S3 bucket to a shared Lambda, trigger on SNS messages, etc. This only works on “push-style” events such as those published by S3, and not “pull-based” events as used by Kinesis. 

Conclusion

I'd love to see your examples on what you're doing with this, what use-cases our community might have! Let us know in our Slack channel!

Did this answer your question?