Configure AWS Lambda Permissions

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 FREE

Frequently Asked Questions

Core Concepts
What's the difference between a Lambda function's IAM role and a Permission resource?
The IAM role controls what AWS services your Lambda function can access (execution permissions). The Permission resource controls what external sources can invoke your Lambda function (invocation permissions).
What does the Permission resource do?
It grants external sources like EventBridge, SNS, S3, or API Gateway permission to invoke your Lambda function by adding resource-based policies.
Service Integration
How do I let EventBridge trigger my Lambda function?
Set principal to events.amazonaws.com, action to lambda:InvokeFunction, and sourceArn to your EventBridge rule ARN.
How do I let SNS invoke my Lambda function?
Set principal to sns.amazonaws.com, action to lambda:InvokeFunction, and sourceArn to your SNS topic ARN.
How do I let API Gateway invoke my Lambda function?
Set principal to apigateway.amazonaws.com and sourceArn to your API Gateway execution ARN with a wildcard suffix like ${executionArn}/*.
How do I let CloudWatch Logs invoke my Lambda function?
Use a regional principal like logs.eu-west-1.amazonaws.com and set sourceArn to your log group ARN with a :* suffix.
Why does my CloudWatch Logs subscription filter fail to create?
The subscription filter must wait for the Permission resource to be created first. Add dependsOn: [permissionResource] to the subscription filter.
Configuration & Troubleshooting
Can I change the principal or sourceArn after creating the permission?
No, these properties are immutable. Changing them forces resource replacement.
What's the difference between statementId and statementIdPrefix?
Use statementId for an explicit identifier, or statementIdPrefix for auto-generation. You cannot use both simultaneously.
What sourceArn format should I use for different services?
API Gateway requires a wildcard suffix (${executionArn}/*), CloudWatch Logs needs :*, and most other services use the exact resource ARN.
How do I grant permission to a specific Lambda version or alias?
Set the qualifier property to your version number or alias name.
Cross-Account & Advanced Features
How do I grant cross-account access to my Lambda function?
Set principal to the IAM principal ARN from the other account and specify sourceAccount with that account ID.
What's the difference between lambda:InvokeFunction and lambda:InvokeFunctionUrl actions?
Use lambda:InvokeFunction for standard invocations. Use lambda:InvokeFunctionUrl specifically for Function URL access, which requires setting functionUrlAuthType to AWS_IAM or NONE.
How do I grant permission to all accounts in my AWS Organization?
Set principalOrgId to your AWS Organizations ID to grant permission to all member accounts.

Using a different cloud?

Explore security guides for other cloud providers: