Lambda Security covers the practices and configurations needed to run serverless functions securely. Each Lambda function has an execution role that defines what AWS services and resources the function can access.
AdministratorAccessAWS_IAM auth type, not NONE (which allows public, unauthenticated access)s3:* instead of s3:GetObject on a specific bucket)Access to a function URL is determined by two things together: the AuthType parameter and the function's resource-based policy. With AWS_IAM, Lambda authenticates and authorizes the caller using the principal's identity policy and the function's resource-based policy. With NONE, Lambda performs no authentication at all, but the resource-based policy is still in effect and must grant public access before requests are accepted. That is why a function URL with auth type NONE and no matching policy statement returns 403 Forbidden.
Two details worth internalizing. First, starting in October 2025, new function URLs require both lambda:InvokeFunctionUrl and lambda:InvokeFunction permissions, so older single-action policy examples are incomplete. Second, when you create a NONE function URL through the console or SAM, Lambda writes the public resource-based policy for you automatically; through the CLI, CloudFormation, or the API you must add it yourself. Deleting a NONE function URL does not remove that policy, so an old public grant can linger on a function long after the URL is gone.
The pattern I see repeatedly: a team enables a function URL with auth type NONE during development because signing requests with SigV4 from a browser or a curl test is annoying. The function is a small internal utility, so nobody thinks of it as an endpoint. Then the function's execution role is widened over time to read a DynamoDB table, then to write to S3, then to call Secrets Manager. What started as a throwaway is now an unauthenticated internet endpoint executing with meaningful permissions, and the URL is discoverable because it was pasted into a ticket, a README, or a client-side bundle. Anyone who has the URL can invoke the function.
The second recurring problem is confusing environment variable encryption with secrecy. Lambda encrypts environment variables at rest by default, but the plaintext values are visible to anyone who can call lambda:GetFunctionConfiguration, and they are visible to the function code and anything that can read the process environment. A database password in an environment variable is readable by every principal with function read permissions in the account. Use Secrets Manager or SSM Parameter Store and fetch at runtime, or at minimum use a customer managed KMS key with encryption helpers so that reading the configuration does not reveal the value.
Third, event injection. A Lambda triggered by S3, SQS, or API Gateway receives an event object built from data an outsider may control: object keys, message bodies, query strings, headers. Treating those fields as trusted input leads to the same classes of bugs as any other web application, including command injection and SSRF, except the credentials at risk are the execution role's.
To see whether a function has a URL and how it authenticates:
aws lambda get-function-url-config --function-name my-function
--function-name is required and --qualifier is optional for an alias. The output includes FunctionUrl, FunctionArn, AuthType (NONE or AWS_IAM), Cors, InvokeMode, and timestamps. Anything reporting NONE deserves a written justification.
To read the resource-based policy that actually decides who can invoke:
aws lambda get-policy --function-name my-function
The output is the policy document plus a RevisionId. Look for "Principal": "*" statements, and for statements conditioned on lambda:FunctionUrlAuthType equal to NONE. To block this class of mistake organization-wide, use an SCP that denies lambda:CreateFunctionUrlConfig and lambda:UpdateFunctionUrlConfig when lambda:FunctionUrlAuthType is not AWS_IAM.
Does putting a Lambda function in a VPC make it more secure?
It changes what the function can reach on the network, not who can invoke it. VPC placement lets a function talk to private resources and lets you apply security groups to its egress, which is genuinely useful for controlling outbound traffic. It does nothing about the invocation path, which is governed by the resource-based policy and the trigger configuration.
What is the difference between the execution role and the resource-based policy?
The execution role is what the function can do once it runs. The resource-based policy is who can make it run. They are independent, and both need to be tight: a narrow invoke policy with an admin execution role is still dangerous, and so is the reverse.
How do I make a function URL private but still callable from a browser?
Use AWS_IAM and put the function behind something that can sign requests or authenticate users, such as CloudFront with an origin access setup, API Gateway with a Cognito or Lambda authorizer, or an application that signs SigV4 server-side. Use the lambda:InvokedViaFunctionUrl condition key so the grant applies only to function URL calls and not to direct invocations.
The security principle of granting only the minimum permissions needed to perform a task - no more, no less.
An AWS identity with temporary credentials that can be assumed by users, services, or applications to perform actions without long-term access keys.
The practice of securely storing, accessing, and rotating sensitive data like API keys, database passwords, and tokens using services like AWS Secrets Manager.
An isolated virtual network within AWS where you launch resources, with full control over IP addressing, subnets, route tables, and network gateways.
Toc Consulting: AWS Security & Cloud Architecture
Our team helps engineering teams secure and architect AWS the right way: assessment in week one, a prioritized action plan in week two.