The aws:lambda/permission:Permission resource, part of the Pulumi AWS provider, grants external AWS services or accounts permission to invoke Lambda functions. This guide focuses on three capabilities: EventBridge, SNS, and API Gateway integration; CloudWatch Logs subscription filters; and cross-account function URL access.
Lambda permissions reference existing functions and event sources. The examples are intentionally small. Combine them with your own Lambda functions, IAM roles, and event source infrastructure.
Allow EventBridge rules to invoke a function
Event-driven architectures use EventBridge to trigger Lambda on schedules or in response to AWS service events.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const iamForLambda = new aws.iam.Role("iam_for_lambda", {
name: "iam_for_lambda",
assumeRolePolicy: JSON.stringify({
Version: "2012-10-17",
Statement: [{
Action: "sts:AssumeRole",
Effect: "Allow",
Sid: "",
Principal: {
Service: "lambda.amazonaws.com",
},
}],
}),
});
const testLambda = new aws.lambda.Function("test_lambda", {
code: new pulumi.asset.FileArchive("lambdatest.zip"),
name: "lambda_function_name",
role: iamForLambda.arn,
handler: "exports.handler",
runtime: aws.lambda.Runtime.NodeJS20dX,
});
const testAlias = new aws.lambda.Alias("test_alias", {
name: "testalias",
description: "a sample description",
functionName: testLambda.name,
functionVersion: "$LATEST",
});
const allowCloudwatch = new aws.lambda.Permission("allow_cloudwatch", {
statementId: "AllowExecutionFromCloudWatch",
action: "lambda:InvokeFunction",
"function": testLambda.name,
principal: "events.amazonaws.com",
sourceArn: "arn:aws:events:eu-west-1:111122223333:rule/RunDaily",
qualifier: testAlias.name,
});
import pulumi
import json
import pulumi_aws as aws
iam_for_lambda = aws.iam.Role("iam_for_lambda",
name="iam_for_lambda",
assume_role_policy=json.dumps({
"Version": "2012-10-17",
"Statement": [{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Sid": "",
"Principal": {
"Service": "lambda.amazonaws.com",
},
}],
}))
test_lambda = aws.lambda_.Function("test_lambda",
code=pulumi.FileArchive("lambdatest.zip"),
name="lambda_function_name",
role=iam_for_lambda.arn,
handler="exports.handler",
runtime=aws.lambda_.Runtime.NODE_JS20D_X)
test_alias = aws.lambda_.Alias("test_alias",
name="testalias",
description="a sample description",
function_name=test_lambda.name,
function_version="$LATEST")
allow_cloudwatch = aws.lambda_.Permission("allow_cloudwatch",
statement_id="AllowExecutionFromCloudWatch",
action="lambda:InvokeFunction",
function=test_lambda.name,
principal="events.amazonaws.com",
source_arn="arn:aws:events:eu-west-1:111122223333:rule/RunDaily",
qualifier=test_alias.name)
package main
import (
"encoding/json"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iam"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lambda"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
tmpJSON0, err := json.Marshal(map[string]interface{}{
"Version": "2012-10-17",
"Statement": []map[string]interface{}{
map[string]interface{}{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Sid": "",
"Principal": map[string]interface{}{
"Service": "lambda.amazonaws.com",
},
},
},
})
if err != nil {
return err
}
json0 := string(tmpJSON0)
iamForLambda, err := iam.NewRole(ctx, "iam_for_lambda", &iam.RoleArgs{
Name: pulumi.String("iam_for_lambda"),
AssumeRolePolicy: pulumi.String(json0),
})
if err != nil {
return err
}
testLambda, err := lambda.NewFunction(ctx, "test_lambda", &lambda.FunctionArgs{
Code: pulumi.NewFileArchive("lambdatest.zip"),
Name: pulumi.String("lambda_function_name"),
Role: iamForLambda.Arn,
Handler: pulumi.String("exports.handler"),
Runtime: pulumi.String(lambda.RuntimeNodeJS20dX),
})
if err != nil {
return err
}
testAlias, err := lambda.NewAlias(ctx, "test_alias", &lambda.AliasArgs{
Name: pulumi.String("testalias"),
Description: pulumi.String("a sample description"),
FunctionName: testLambda.Name,
FunctionVersion: pulumi.String("$LATEST"),
})
if err != nil {
return err
}
_, err = lambda.NewPermission(ctx, "allow_cloudwatch", &lambda.PermissionArgs{
StatementId: pulumi.String("AllowExecutionFromCloudWatch"),
Action: pulumi.String("lambda:InvokeFunction"),
Function: testLambda.Name,
Principal: pulumi.String("events.amazonaws.com"),
SourceArn: pulumi.String("arn:aws:events:eu-west-1:111122223333:rule/RunDaily"),
Qualifier: testAlias.Name,
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var iamForLambda = new Aws.Iam.Role("iam_for_lambda", new()
{
Name = "iam_for_lambda",
AssumeRolePolicy = JsonSerializer.Serialize(new Dictionary<string, object?>
{
["Version"] = "2012-10-17",
["Statement"] = new[]
{
new Dictionary<string, object?>
{
["Action"] = "sts:AssumeRole",
["Effect"] = "Allow",
["Sid"] = "",
["Principal"] = new Dictionary<string, object?>
{
["Service"] = "lambda.amazonaws.com",
},
},
},
}),
});
var testLambda = new Aws.Lambda.Function("test_lambda", new()
{
Code = new FileArchive("lambdatest.zip"),
Name = "lambda_function_name",
Role = iamForLambda.Arn,
Handler = "exports.handler",
Runtime = Aws.Lambda.Runtime.NodeJS20dX,
});
var testAlias = new Aws.Lambda.Alias("test_alias", new()
{
Name = "testalias",
Description = "a sample description",
FunctionName = testLambda.Name,
FunctionVersion = "$LATEST",
});
var allowCloudwatch = new Aws.Lambda.Permission("allow_cloudwatch", new()
{
StatementId = "AllowExecutionFromCloudWatch",
Action = "lambda:InvokeFunction",
Function = testLambda.Name,
Principal = "events.amazonaws.com",
SourceArn = "arn:aws:events:eu-west-1:111122223333:rule/RunDaily",
Qualifier = testAlias.Name,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.iam.Role;
import com.pulumi.aws.iam.RoleArgs;
import com.pulumi.aws.lambda.Function;
import com.pulumi.aws.lambda.FunctionArgs;
import com.pulumi.aws.lambda.Alias;
import com.pulumi.aws.lambda.AliasArgs;
import com.pulumi.aws.lambda.Permission;
import com.pulumi.aws.lambda.PermissionArgs;
import com.pulumi.asset.FileArchive;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var iamForLambda = new Role("iamForLambda", RoleArgs.builder()
.name("iam_for_lambda")
.assumeRolePolicy(serializeJson(
jsonObject(
jsonProperty("Version", "2012-10-17"),
jsonProperty("Statement", jsonArray(jsonObject(
jsonProperty("Action", "sts:AssumeRole"),
jsonProperty("Effect", "Allow"),
jsonProperty("Sid", ""),
jsonProperty("Principal", jsonObject(
jsonProperty("Service", "lambda.amazonaws.com")
))
)))
)))
.build());
var testLambda = new Function("testLambda", FunctionArgs.builder()
.code(new FileArchive("lambdatest.zip"))
.name("lambda_function_name")
.role(iamForLambda.arn())
.handler("exports.handler")
.runtime("nodejs20.x")
.build());
var testAlias = new Alias("testAlias", AliasArgs.builder()
.name("testalias")
.description("a sample description")
.functionName(testLambda.name())
.functionVersion("$LATEST")
.build());
var allowCloudwatch = new Permission("allowCloudwatch", PermissionArgs.builder()
.statementId("AllowExecutionFromCloudWatch")
.action("lambda:InvokeFunction")
.function(testLambda.name())
.principal("events.amazonaws.com")
.sourceArn("arn:aws:events:eu-west-1:111122223333:rule/RunDaily")
.qualifier(testAlias.name())
.build());
}
}
resources:
allowCloudwatch:
type: aws:lambda:Permission
name: allow_cloudwatch
properties:
statementId: AllowExecutionFromCloudWatch
action: lambda:InvokeFunction
function: ${testLambda.name}
principal: events.amazonaws.com
sourceArn: arn:aws:events:eu-west-1:111122223333:rule/RunDaily
qualifier: ${testAlias.name}
testAlias:
type: aws:lambda:Alias
name: test_alias
properties:
name: testalias
description: a sample description
functionName: ${testLambda.name}
functionVersion: $LATEST
testLambda:
type: aws:lambda:Function
name: test_lambda
properties:
code:
fn::FileArchive: lambdatest.zip
name: lambda_function_name
role: ${iamForLambda.arn}
handler: exports.handler
runtime: nodejs20.x
iamForLambda:
type: aws:iam:Role
name: iam_for_lambda
properties:
name: iam_for_lambda
assumeRolePolicy:
fn::toJSON:
Version: 2012-10-17
Statement:
- Action: sts:AssumeRole
Effect: Allow
Sid: ""
Principal:
Service: lambda.amazonaws.com
The principal property identifies the AWS service (events.amazonaws.com for EventBridge). The sourceArn scopes the permission to a specific EventBridge rule. The qualifier property targets a function alias, allowing you to grant permissions to specific versions rather than $LATEST.
Allow SNS topics to trigger function execution
Pub/sub patterns use SNS to fan out messages to multiple subscribers, including Lambda functions.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const _default = new aws.sns.Topic("default", {name: "call-lambda-maybe"});
const defaultRole = new aws.iam.Role("default", {
name: "iam_for_lambda_with_sns",
assumeRolePolicy: JSON.stringify({
Version: "2012-10-17",
Statement: [{
Action: "sts:AssumeRole",
Effect: "Allow",
Sid: "",
Principal: {
Service: "lambda.amazonaws.com",
},
}],
}),
});
const func = new aws.lambda.Function("func", {
code: new pulumi.asset.FileArchive("lambdatest.zip"),
name: "lambda_called_from_sns",
role: defaultRole.arn,
handler: "exports.handler",
runtime: aws.lambda.Runtime.Python3d12,
});
const withSns = new aws.lambda.Permission("with_sns", {
statementId: "AllowExecutionFromSNS",
action: "lambda:InvokeFunction",
"function": func.name,
principal: "sns.amazonaws.com",
sourceArn: _default.arn,
});
const lambda = new aws.sns.TopicSubscription("lambda", {
topic: _default.arn,
protocol: "lambda",
endpoint: func.arn,
});
import pulumi
import json
import pulumi_aws as aws
default = aws.sns.Topic("default", name="call-lambda-maybe")
default_role = aws.iam.Role("default",
name="iam_for_lambda_with_sns",
assume_role_policy=json.dumps({
"Version": "2012-10-17",
"Statement": [{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Sid": "",
"Principal": {
"Service": "lambda.amazonaws.com",
},
}],
}))
func = aws.lambda_.Function("func",
code=pulumi.FileArchive("lambdatest.zip"),
name="lambda_called_from_sns",
role=default_role.arn,
handler="exports.handler",
runtime=aws.lambda_.Runtime.PYTHON3D12)
with_sns = aws.lambda_.Permission("with_sns",
statement_id="AllowExecutionFromSNS",
action="lambda:InvokeFunction",
function=func.name,
principal="sns.amazonaws.com",
source_arn=default.arn)
lambda_ = aws.sns.TopicSubscription("lambda",
topic=default.arn,
protocol="lambda",
endpoint=func.arn)
package main
import (
"encoding/json"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iam"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lambda"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/sns"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_default, err := sns.NewTopic(ctx, "default", &sns.TopicArgs{
Name: pulumi.String("call-lambda-maybe"),
})
if err != nil {
return err
}
tmpJSON0, err := json.Marshal(map[string]interface{}{
"Version": "2012-10-17",
"Statement": []map[string]interface{}{
map[string]interface{}{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Sid": "",
"Principal": map[string]interface{}{
"Service": "lambda.amazonaws.com",
},
},
},
})
if err != nil {
return err
}
json0 := string(tmpJSON0)
defaultRole, err := iam.NewRole(ctx, "default", &iam.RoleArgs{
Name: pulumi.String("iam_for_lambda_with_sns"),
AssumeRolePolicy: pulumi.String(json0),
})
if err != nil {
return err
}
_func, err := lambda.NewFunction(ctx, "func", &lambda.FunctionArgs{
Code: pulumi.NewFileArchive("lambdatest.zip"),
Name: pulumi.String("lambda_called_from_sns"),
Role: defaultRole.Arn,
Handler: pulumi.String("exports.handler"),
Runtime: pulumi.String(lambda.RuntimePython3d12),
})
if err != nil {
return err
}
_, err = lambda.NewPermission(ctx, "with_sns", &lambda.PermissionArgs{
StatementId: pulumi.String("AllowExecutionFromSNS"),
Action: pulumi.String("lambda:InvokeFunction"),
Function: _func.Name,
Principal: pulumi.String("sns.amazonaws.com"),
SourceArn: _default.Arn,
})
if err != nil {
return err
}
_, err = sns.NewTopicSubscription(ctx, "lambda", &sns.TopicSubscriptionArgs{
Topic: _default.Arn,
Protocol: pulumi.String("lambda"),
Endpoint: _func.Arn,
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var @default = new Aws.Sns.Topic("default", new()
{
Name = "call-lambda-maybe",
});
var defaultRole = new Aws.Iam.Role("default", new()
{
Name = "iam_for_lambda_with_sns",
AssumeRolePolicy = JsonSerializer.Serialize(new Dictionary<string, object?>
{
["Version"] = "2012-10-17",
["Statement"] = new[]
{
new Dictionary<string, object?>
{
["Action"] = "sts:AssumeRole",
["Effect"] = "Allow",
["Sid"] = "",
["Principal"] = new Dictionary<string, object?>
{
["Service"] = "lambda.amazonaws.com",
},
},
},
}),
});
var func = new Aws.Lambda.Function("func", new()
{
Code = new FileArchive("lambdatest.zip"),
Name = "lambda_called_from_sns",
Role = defaultRole.Arn,
Handler = "exports.handler",
Runtime = Aws.Lambda.Runtime.Python3d12,
});
var withSns = new Aws.Lambda.Permission("with_sns", new()
{
StatementId = "AllowExecutionFromSNS",
Action = "lambda:InvokeFunction",
Function = func.Name,
Principal = "sns.amazonaws.com",
SourceArn = @default.Arn,
});
var lambda = new Aws.Sns.TopicSubscription("lambda", new()
{
Topic = @default.Arn,
Protocol = "lambda",
Endpoint = func.Arn,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.sns.Topic;
import com.pulumi.aws.sns.TopicArgs;
import com.pulumi.aws.iam.Role;
import com.pulumi.aws.iam.RoleArgs;
import com.pulumi.aws.lambda.Function;
import com.pulumi.aws.lambda.FunctionArgs;
import com.pulumi.aws.lambda.Permission;
import com.pulumi.aws.lambda.PermissionArgs;
import com.pulumi.aws.sns.TopicSubscription;
import com.pulumi.aws.sns.TopicSubscriptionArgs;
import com.pulumi.asset.FileArchive;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var default_ = new Topic("default", TopicArgs.builder()
.name("call-lambda-maybe")
.build());
var defaultRole = new Role("defaultRole", RoleArgs.builder()
.name("iam_for_lambda_with_sns")
.assumeRolePolicy(serializeJson(
jsonObject(
jsonProperty("Version", "2012-10-17"),
jsonProperty("Statement", jsonArray(jsonObject(
jsonProperty("Action", "sts:AssumeRole"),
jsonProperty("Effect", "Allow"),
jsonProperty("Sid", ""),
jsonProperty("Principal", jsonObject(
jsonProperty("Service", "lambda.amazonaws.com")
))
)))
)))
.build());
var func = new Function("func", FunctionArgs.builder()
.code(new FileArchive("lambdatest.zip"))
.name("lambda_called_from_sns")
.role(defaultRole.arn())
.handler("exports.handler")
.runtime("python3.12")
.build());
var withSns = new Permission("withSns", PermissionArgs.builder()
.statementId("AllowExecutionFromSNS")
.action("lambda:InvokeFunction")
.function(func.name())
.principal("sns.amazonaws.com")
.sourceArn(default_.arn())
.build());
var lambda = new TopicSubscription("lambda", TopicSubscriptionArgs.builder()
.topic(default_.arn())
.protocol("lambda")
.endpoint(func.arn())
.build());
}
}
resources:
withSns:
type: aws:lambda:Permission
name: with_sns
properties:
statementId: AllowExecutionFromSNS
action: lambda:InvokeFunction
function: ${func.name}
principal: sns.amazonaws.com
sourceArn: ${default.arn}
default:
type: aws:sns:Topic
properties:
name: call-lambda-maybe
lambda:
type: aws:sns:TopicSubscription
properties:
topic: ${default.arn}
protocol: lambda
endpoint: ${func.arn}
func:
type: aws:lambda:Function
properties:
code:
fn::FileArchive: lambdatest.zip
name: lambda_called_from_sns
role: ${defaultRole.arn}
handler: exports.handler
runtime: python3.12
defaultRole:
type: aws:iam:Role
name: default
properties:
name: iam_for_lambda_with_sns
assumeRolePolicy:
fn::toJSON:
Version: 2012-10-17
Statement:
- Action: sts:AssumeRole
Effect: Allow
Sid: ""
Principal:
Service: lambda.amazonaws.com
The principal sns.amazonaws.com grants SNS permission to invoke your function. The sourceArn limits invocation to a specific topic. After creating the permission, the TopicSubscription resource connects the topic to your function, completing the integration.
Grant API Gateway permission to invoke functions
REST APIs route HTTP requests to Lambda for serverless API backends.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const myDemoAPI = new aws.apigateway.RestApi("MyDemoAPI", {
name: "MyDemoAPI",
description: "This is my API for demonstration purposes",
});
const lambdaPermission = new aws.lambda.Permission("lambda_permission", {
statementId: "AllowMyDemoAPIInvoke",
action: "lambda:InvokeFunction",
"function": "MyDemoFunction",
principal: "apigateway.amazonaws.com",
sourceArn: pulumi.interpolate`${myDemoAPI.executionArn}/*`,
});
import pulumi
import pulumi_aws as aws
my_demo_api = aws.apigateway.RestApi("MyDemoAPI",
name="MyDemoAPI",
description="This is my API for demonstration purposes")
lambda_permission = aws.lambda_.Permission("lambda_permission",
statement_id="AllowMyDemoAPIInvoke",
action="lambda:InvokeFunction",
function="MyDemoFunction",
principal="apigateway.amazonaws.com",
source_arn=my_demo_api.execution_arn.apply(lambda execution_arn: f"{execution_arn}/*"))
package main
import (
"fmt"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/apigateway"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lambda"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
myDemoAPI, err := apigateway.NewRestApi(ctx, "MyDemoAPI", &apigateway.RestApiArgs{
Name: pulumi.String("MyDemoAPI"),
Description: pulumi.String("This is my API for demonstration purposes"),
})
if err != nil {
return err
}
_, err = lambda.NewPermission(ctx, "lambda_permission", &lambda.PermissionArgs{
StatementId: pulumi.String("AllowMyDemoAPIInvoke"),
Action: pulumi.String("lambda:InvokeFunction"),
Function: pulumi.Any("MyDemoFunction"),
Principal: pulumi.String("apigateway.amazonaws.com"),
SourceArn: myDemoAPI.ExecutionArn.ApplyT(func(executionArn string) (string, error) {
return fmt.Sprintf("%v/*", executionArn), nil
}).(pulumi.StringOutput),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var myDemoAPI = new Aws.ApiGateway.RestApi("MyDemoAPI", new()
{
Name = "MyDemoAPI",
Description = "This is my API for demonstration purposes",
});
var lambdaPermission = new Aws.Lambda.Permission("lambda_permission", new()
{
StatementId = "AllowMyDemoAPIInvoke",
Action = "lambda:InvokeFunction",
Function = "MyDemoFunction",
Principal = "apigateway.amazonaws.com",
SourceArn = myDemoAPI.ExecutionArn.Apply(executionArn => $"{executionArn}/*"),
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.apigateway.RestApi;
import com.pulumi.aws.apigateway.RestApiArgs;
import com.pulumi.aws.lambda.Permission;
import com.pulumi.aws.lambda.PermissionArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var myDemoAPI = new RestApi("myDemoAPI", RestApiArgs.builder()
.name("MyDemoAPI")
.description("This is my API for demonstration purposes")
.build());
var lambdaPermission = new Permission("lambdaPermission", PermissionArgs.builder()
.statementId("AllowMyDemoAPIInvoke")
.action("lambda:InvokeFunction")
.function("MyDemoFunction")
.principal("apigateway.amazonaws.com")
.sourceArn(myDemoAPI.executionArn().applyValue(_executionArn -> String.format("%s/*", _executionArn)))
.build());
}
}
resources:
myDemoAPI:
type: aws:apigateway:RestApi
name: MyDemoAPI
properties:
name: MyDemoAPI
description: This is my API for demonstration purposes
lambdaPermission:
type: aws:lambda:Permission
name: lambda_permission
properties:
statementId: AllowMyDemoAPIInvoke
action: lambda:InvokeFunction
function: MyDemoFunction
principal: apigateway.amazonaws.com
sourceArn: ${myDemoAPI.executionArn}/*
The principal apigateway.amazonaws.com allows API Gateway to invoke your function. The sourceArn uses the API’s executionArn with a wildcard (/*) to permit all methods and resource paths. This broad permission simplifies initial setup; narrow it to specific paths for production.
Process CloudWatch Logs with Lambda subscriptions
Log processing pipelines stream CloudWatch Logs to Lambda for filtering, transformation, or forwarding.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const _default = new aws.cloudwatch.LogGroup("default", {name: "/default"});
const assumeRole = aws.iam.getPolicyDocument({
statements: [{
effect: "Allow",
principals: [{
type: "Service",
identifiers: ["lambda.amazonaws.com"],
}],
actions: ["sts:AssumeRole"],
}],
});
const defaultRole = new aws.iam.Role("default", {
name: "iam_for_lambda_called_from_cloudwatch_logs",
assumeRolePolicy: assumeRole.then(assumeRole => assumeRole.json),
});
const loggingFunction = new aws.lambda.Function("logging", {
code: new pulumi.asset.FileArchive("lamba_logging.zip"),
name: "lambda_called_from_cloudwatch_logs",
handler: "exports.handler",
role: defaultRole.arn,
runtime: aws.lambda.Runtime.Python3d12,
});
const logging = new aws.lambda.Permission("logging", {
action: "lambda:InvokeFunction",
"function": loggingFunction.name,
principal: "logs.eu-west-1.amazonaws.com",
sourceArn: pulumi.interpolate`${_default.arn}:*`,
});
const loggingLogSubscriptionFilter = new aws.cloudwatch.LogSubscriptionFilter("logging", {
destinationArn: loggingFunction.arn,
filterPattern: "",
logGroup: _default.name,
name: "logging_default",
}, {
dependsOn: [logging],
});
import pulumi
import pulumi_aws as aws
default = aws.cloudwatch.LogGroup("default", name="/default")
assume_role = aws.iam.get_policy_document(statements=[{
"effect": "Allow",
"principals": [{
"type": "Service",
"identifiers": ["lambda.amazonaws.com"],
}],
"actions": ["sts:AssumeRole"],
}])
default_role = aws.iam.Role("default",
name="iam_for_lambda_called_from_cloudwatch_logs",
assume_role_policy=assume_role.json)
logging_function = aws.lambda_.Function("logging",
code=pulumi.FileArchive("lamba_logging.zip"),
name="lambda_called_from_cloudwatch_logs",
handler="exports.handler",
role=default_role.arn,
runtime=aws.lambda_.Runtime.PYTHON3D12)
logging = aws.lambda_.Permission("logging",
action="lambda:InvokeFunction",
function=logging_function.name,
principal="logs.eu-west-1.amazonaws.com",
source_arn=default.arn.apply(lambda arn: f"{arn}:*"))
logging_log_subscription_filter = aws.cloudwatch.LogSubscriptionFilter("logging",
destination_arn=logging_function.arn,
filter_pattern="",
log_group=default.name,
name="logging_default",
opts = pulumi.ResourceOptions(depends_on=[logging]))
package main
import (
"fmt"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cloudwatch"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iam"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lambda"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_default, err := cloudwatch.NewLogGroup(ctx, "default", &cloudwatch.LogGroupArgs{
Name: pulumi.String("/default"),
})
if err != nil {
return err
}
assumeRole, err := iam.GetPolicyDocument(ctx, &iam.GetPolicyDocumentArgs{
Statements: []iam.GetPolicyDocumentStatement{
{
Effect: pulumi.StringRef("Allow"),
Principals: []iam.GetPolicyDocumentStatementPrincipal{
{
Type: "Service",
Identifiers: []string{
"lambda.amazonaws.com",
},
},
},
Actions: []string{
"sts:AssumeRole",
},
},
},
}, nil)
if err != nil {
return err
}
defaultRole, err := iam.NewRole(ctx, "default", &iam.RoleArgs{
Name: pulumi.String("iam_for_lambda_called_from_cloudwatch_logs"),
AssumeRolePolicy: pulumi.String(assumeRole.Json),
})
if err != nil {
return err
}
loggingFunction, err := lambda.NewFunction(ctx, "logging", &lambda.FunctionArgs{
Code: pulumi.NewFileArchive("lamba_logging.zip"),
Name: pulumi.String("lambda_called_from_cloudwatch_logs"),
Handler: pulumi.String("exports.handler"),
Role: defaultRole.Arn,
Runtime: pulumi.String(lambda.RuntimePython3d12),
})
if err != nil {
return err
}
logging, err := lambda.NewPermission(ctx, "logging", &lambda.PermissionArgs{
Action: pulumi.String("lambda:InvokeFunction"),
Function: loggingFunction.Name,
Principal: pulumi.String("logs.eu-west-1.amazonaws.com"),
SourceArn: _default.Arn.ApplyT(func(arn string) (string, error) {
return fmt.Sprintf("%v:*", arn), nil
}).(pulumi.StringOutput),
})
if err != nil {
return err
}
_, err = cloudwatch.NewLogSubscriptionFilter(ctx, "logging", &cloudwatch.LogSubscriptionFilterArgs{
DestinationArn: loggingFunction.Arn,
FilterPattern: pulumi.String(""),
LogGroup: _default.Name,
Name: pulumi.String("logging_default"),
}, pulumi.DependsOn([]pulumi.Resource{
logging,
}))
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var @default = new Aws.CloudWatch.LogGroup("default", new()
{
Name = "/default",
});
var assumeRole = Aws.Iam.GetPolicyDocument.Invoke(new()
{
Statements = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementInputArgs
{
Effect = "Allow",
Principals = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementPrincipalInputArgs
{
Type = "Service",
Identifiers = new[]
{
"lambda.amazonaws.com",
},
},
},
Actions = new[]
{
"sts:AssumeRole",
},
},
},
});
var defaultRole = new Aws.Iam.Role("default", new()
{
Name = "iam_for_lambda_called_from_cloudwatch_logs",
AssumeRolePolicy = assumeRole.Apply(getPolicyDocumentResult => getPolicyDocumentResult.Json),
});
var loggingFunction = new Aws.Lambda.Function("logging", new()
{
Code = new FileArchive("lamba_logging.zip"),
Name = "lambda_called_from_cloudwatch_logs",
Handler = "exports.handler",
Role = defaultRole.Arn,
Runtime = Aws.Lambda.Runtime.Python3d12,
});
var logging = new Aws.Lambda.Permission("logging", new()
{
Action = "lambda:InvokeFunction",
Function = loggingFunction.Name,
Principal = "logs.eu-west-1.amazonaws.com",
SourceArn = @default.Arn.Apply(arn => $"{arn}:*"),
});
var loggingLogSubscriptionFilter = new Aws.CloudWatch.LogSubscriptionFilter("logging", new()
{
DestinationArn = loggingFunction.Arn,
FilterPattern = "",
LogGroup = @default.Name,
Name = "logging_default",
}, new CustomResourceOptions
{
DependsOn =
{
logging,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cloudwatch.LogGroup;
import com.pulumi.aws.cloudwatch.LogGroupArgs;
import com.pulumi.aws.iam.IamFunctions;
import com.pulumi.aws.iam.inputs.GetPolicyDocumentArgs;
import com.pulumi.aws.iam.Role;
import com.pulumi.aws.iam.RoleArgs;
import com.pulumi.aws.lambda.Function;
import com.pulumi.aws.lambda.FunctionArgs;
import com.pulumi.aws.lambda.Permission;
import com.pulumi.aws.lambda.PermissionArgs;
import com.pulumi.aws.cloudwatch.LogSubscriptionFilter;
import com.pulumi.aws.cloudwatch.LogSubscriptionFilterArgs;
import com.pulumi.asset.FileArchive;
import com.pulumi.resources.CustomResourceOptions;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var default_ = new LogGroup("default", LogGroupArgs.builder()
.name("/default")
.build());
final var assumeRole = IamFunctions.getPolicyDocument(GetPolicyDocumentArgs.builder()
.statements(GetPolicyDocumentStatementArgs.builder()
.effect("Allow")
.principals(GetPolicyDocumentStatementPrincipalArgs.builder()
.type("Service")
.identifiers("lambda.amazonaws.com")
.build())
.actions("sts:AssumeRole")
.build())
.build());
var defaultRole = new Role("defaultRole", RoleArgs.builder()
.name("iam_for_lambda_called_from_cloudwatch_logs")
.assumeRolePolicy(assumeRole.json())
.build());
var loggingFunction = new Function("loggingFunction", FunctionArgs.builder()
.code(new FileArchive("lamba_logging.zip"))
.name("lambda_called_from_cloudwatch_logs")
.handler("exports.handler")
.role(defaultRole.arn())
.runtime("python3.12")
.build());
var logging = new Permission("logging", PermissionArgs.builder()
.action("lambda:InvokeFunction")
.function(loggingFunction.name())
.principal("logs.eu-west-1.amazonaws.com")
.sourceArn(default_.arn().applyValue(_arn -> String.format("%s:*", _arn)))
.build());
var loggingLogSubscriptionFilter = new LogSubscriptionFilter("loggingLogSubscriptionFilter", LogSubscriptionFilterArgs.builder()
.destinationArn(loggingFunction.arn())
.filterPattern("")
.logGroup(default_.name())
.name("logging_default")
.build(), CustomResourceOptions.builder()
.dependsOn(logging)
.build());
}
}
resources:
logging:
type: aws:lambda:Permission
properties:
action: lambda:InvokeFunction
function: ${loggingFunction.name}
principal: logs.eu-west-1.amazonaws.com
sourceArn: ${default.arn}:*
default:
type: aws:cloudwatch:LogGroup
properties:
name: /default
loggingLogSubscriptionFilter:
type: aws:cloudwatch:LogSubscriptionFilter
name: logging
properties:
destinationArn: ${loggingFunction.arn}
filterPattern: ""
logGroup: ${default.name}
name: logging_default
options:
dependsOn:
- ${logging}
loggingFunction:
type: aws:lambda:Function
name: logging
properties:
code:
fn::FileArchive: lamba_logging.zip
name: lambda_called_from_cloudwatch_logs
handler: exports.handler
role: ${defaultRole.arn}
runtime: python3.12
defaultRole:
type: aws:iam:Role
name: default
properties:
name: iam_for_lambda_called_from_cloudwatch_logs
assumeRolePolicy: ${assumeRole.json}
variables:
assumeRole:
fn::invoke:
function: aws:iam:getPolicyDocument
arguments:
statements:
- effect: Allow
principals:
- type: Service
identifiers:
- lambda.amazonaws.com
actions:
- sts:AssumeRole
The principal uses a region-specific format (logs.eu-west-1.amazonaws.com) to grant CloudWatch Logs permission. The LogSubscriptionFilter depends on the permission resource, ensuring the permission exists before CloudWatch attempts to invoke your function.
Allow cross-account access to function URLs
Function URLs provide HTTPS endpoints without API Gateway. Cross-account permissions let IAM principals from other accounts invoke your function URL.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const url = new aws.lambda.FunctionUrl("url", {
functionName: example.functionName,
authorizationType: "AWS_IAM",
});
const urlPermission = new aws.lambda.Permission("url", {
action: "lambda:InvokeFunctionUrl",
"function": example.functionName,
principal: "arn:aws:iam::444455556666:role/example",
sourceAccount: "444455556666",
functionUrlAuthType: "AWS_IAM",
});
import pulumi
import pulumi_aws as aws
url = aws.lambda_.FunctionUrl("url",
function_name=example["functionName"],
authorization_type="AWS_IAM")
url_permission = aws.lambda_.Permission("url",
action="lambda:InvokeFunctionUrl",
function=example["functionName"],
principal="arn:aws:iam::444455556666:role/example",
source_account="444455556666",
function_url_auth_type="AWS_IAM")
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lambda"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := lambda.NewFunctionUrl(ctx, "url", &lambda.FunctionUrlArgs{
FunctionName: pulumi.Any(example.FunctionName),
AuthorizationType: pulumi.String("AWS_IAM"),
})
if err != nil {
return err
}
_, err = lambda.NewPermission(ctx, "url", &lambda.PermissionArgs{
Action: pulumi.String("lambda:InvokeFunctionUrl"),
Function: pulumi.Any(example.FunctionName),
Principal: pulumi.String("arn:aws:iam::444455556666:role/example"),
SourceAccount: pulumi.String("444455556666"),
FunctionUrlAuthType: pulumi.String("AWS_IAM"),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var url = new Aws.Lambda.FunctionUrl("url", new()
{
FunctionName = example.FunctionName,
AuthorizationType = "AWS_IAM",
});
var urlPermission = new Aws.Lambda.Permission("url", new()
{
Action = "lambda:InvokeFunctionUrl",
Function = example.FunctionName,
Principal = "arn:aws:iam::444455556666:role/example",
SourceAccount = "444455556666",
FunctionUrlAuthType = "AWS_IAM",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.lambda.FunctionUrl;
import com.pulumi.aws.lambda.FunctionUrlArgs;
import com.pulumi.aws.lambda.Permission;
import com.pulumi.aws.lambda.PermissionArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var url = new FunctionUrl("url", FunctionUrlArgs.builder()
.functionName(example.functionName())
.authorizationType("AWS_IAM")
.build());
var urlPermission = new Permission("urlPermission", PermissionArgs.builder()
.action("lambda:InvokeFunctionUrl")
.function(example.functionName())
.principal("arn:aws:iam::444455556666:role/example")
.sourceAccount("444455556666")
.functionUrlAuthType("AWS_IAM")
.build());
}
}
resources:
url:
type: aws:lambda:FunctionUrl
properties:
functionName: ${example.functionName}
authorizationType: AWS_IAM
urlPermission:
type: aws:lambda:Permission
name: url
properties:
action: lambda:InvokeFunctionUrl
function: ${example.functionName}
principal: arn:aws:iam::444455556666:role/example
sourceAccount: '444455556666'
functionUrlAuthType: AWS_IAM
The action lambda:InvokeFunctionUrl specifically grants function URL access. The principal references an IAM role ARN from another account. The sourceAccount and functionUrlAuthType properties work together to enforce IAM authentication for cross-account invocations.
Beyond these examples
These snippets focus on specific permission features: event source integration (EventBridge, SNS, API Gateway, CloudWatch Logs), function URL access control, and cross-account permissions. They’re intentionally minimal rather than full event-driven applications.
The examples reference pre-existing infrastructure such as Lambda functions with IAM execution roles, EventBridge rules, SNS topics, API Gateway REST APIs, CloudWatch Log Groups, and Function URLs (for cross-account example). They focus on granting permissions rather than provisioning the event sources themselves.
To keep things focused, common permission patterns are omitted, including:
- Organization-wide permissions (principalOrgId)
- Alexa Skills integration (eventSourceToken)
- S3 bucket notifications
- Version and alias targeting (qualifier in most examples)
These omissions are intentional: the goal is to illustrate how each permission type is wired, not provide drop-in event-driven modules. See the Lambda Permission resource reference for all available configuration options.
Let's configure AWS Lambda Permissions
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Core Concepts
Service Integration
principal to events.amazonaws.com, action to lambda:InvokeFunction, and sourceArn to your EventBridge rule ARN.principal to sns.amazonaws.com, action to lambda:InvokeFunction, and sourceArn to your SNS topic ARN.principal to apigateway.amazonaws.com and sourceArn to your API Gateway execution ARN with a wildcard suffix like ${executionArn}/*.logs.eu-west-1.amazonaws.com and set sourceArn to your log group ARN with a :* suffix.dependsOn: [permissionResource] to the subscription filter.Configuration & Troubleshooting
statementId for an explicit identifier, or statementIdPrefix for auto-generation. You cannot use both simultaneously.${executionArn}/*), CloudWatch Logs needs :*, and most other services use the exact resource ARN.qualifier property to your version number or alias name.Cross-Account & Advanced Features
principal to the IAM principal ARN from the other account and specify sourceAccount with that account ID.lambda:InvokeFunction for standard invocations. Use lambda:InvokeFunctionUrl specifically for Function URL access, which requires setting functionUrlAuthType to AWS_IAM or NONE.principalOrgId to your AWS Organizations ID to grant permission to all member accounts.