lambda:SourceFunctionArn
[Part 1]
AWS released support for lambad:SourceFunctionArn IAM condition key in mid 2022. When a function is invoked, this condition key is added to the request context of all AWS API calls made by the function. You can use this condition key in your IAM policy to implement advanced security controls, for example, grant permissions to those APIS calls only if they originate from inside a particular VPC or IP, grant API calls access to resources only if they are made by the function.
A few notes from AWS Lambda documentation:
You cannot use the lambda:SourceFunctionArn condition key in resource-based policies.
The lambda:SourceFunctionArn condition key is different from the lambda:FunctionArn and aws:SourceArn condition keys. The lambda:FunctionArn condition key applies only to event source mappings and helps define which functions your event source can invoke. The aws:SourceArn condition key applies only to policies where your Lambda function is the target resource, and helps define which other AWS services and resources can invoke that function. The lambda:SourceFunctionArn condition key can apply to any identity-based policy or SCP to define the specific Lambda functions that have permissions to make specific AWS API calls to other resources.
Exercise 1: Restrict access to resources from inside a function only
Summary
We will create an S3 bucket and store some sensitive files in there. We will create a Lambda function that will process those files. The S3 bucket will only be accessible when the API calls come from that lambda function, they will not be accessible if the API calls come from outside of the Lambda function. We will implement this using lambad:SourceFunctionArn IAM condition key in an identity-based policy.
Steps
Create an S3 bucket:
Create an S3 bucket (you may find these instructions helpful).
Bucket name: lsfa-test-s3-bucket
AWS region: us-west-2 (you can pick whichever closer to you)
Object ownership: ACLs disabled
Block Public Access settings for this bucket: Block all public access
Bucket Versioning: Enable
Default encryption: Server-side encryption with Amazon S3 managed keys (SSE-S3)
Upload two test data files to the bucket (you may find these instructions helpful).
File name: test-data-1.txt, content: Hello AWS
File name: test-data-2.txt, content: Hello Lambda
Create a Lambda function:
Create a Lambda function (you may follow these instructions)
Create function: Author from scratch
Function name: lsfa-test-funcion
Runtime: Python 3.9
Architecture: x86_64
Permissions: Create a new role with basic Lambda permissions
Advanced settings: Don't check anything for this exercise
Due to the above selection, the execution role will be automatically created with all the basic permissions. In my case, the following role was created:
Role name: lsfa-test-funcion-role-t7t0c5ob
name of the attached policy: AWSLambdaBasicExecutionRole-e7adbfa2-6abc-4372-841f-e27832d397c5
The policy AWSLambdaBasicExecutionRole-e7adbfa2-6abc-4372-841f-e27832d397c5 looks like this:
Add the following code to the lambda_function and deploy.
Create a test event.
Event name: lsfa-test-event
Event sharing settings: private
Event JSON: {}
Test the function by invoking.
Define a policy with lambda:sourceFunctionArn context key:
Create an identity-based policy named "lsfa-test-policy" (you may find these instructions helpful). Replace the region and account number with yours.
Attach the policy to the execution role of the Lambda function you created above.
Open your Lambda function "lsfa-test-funciton" from the lambda console (https://console.aws.amazon.com/lambda), go to the "Configuration" tab, click the role name under "Execution role", it will open up the role in IAM console. The role should be named as lsfa-test-function-role-xxxxxxxx.
Under "Permissions" tab, click "Add permissions" => "Attach policies", search for ""lsfa-test-policy" under "other permissions policies", select the policy by checking the box next it, and click "Add permissions".
Validate functionality of lambda:sourceFunctionArn:
Create an IAM user
From IAM Console (https://console.aws.amazon.com/iam), create a user "lsfa-test-function-role-assumer"
Add an inline policy to the user so that the user can assume the lambda-test-function-role-xxxxxxxx
From AWS CLI, create access keys for the user:
{ "AccessKey": { "UserName": "lfsa-test-function-role-assumer", "AccessKeyId": "RDUJKGKIAVQBLOK3UAR5", "Status": "Active", "SecretAccessKey": "sVADhVtiNQeRRtgayB6vCvlGTDPQ7TRb6fHrbGwu", "CreateDate": "2023-06-16T17:41:36Z" }}
Create a CLI profile for that assumer:
AWS Access Key ID [None]: RDUJKGKIAVQBLOK3UAR5AWS Secret Access Key [None]: sVADhVtiNQeRRtgayB6vCvlGTDPQ7TRb6fHrbGwu Default region name [None]: us-west-2Default output format [None]: json
Try listing the contents of the S3 bucket and you should see an Access Denied error:
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
Now open the function from Lambda Console (https://console.aws.amazon.com/lambda) and test invoke it. You should see the contents of the S3 bucket is being displayed in the output, which means calls from the function are being allowed.
Response{ "statusCode": 200, "body": "\"objects: test-data-1.txt,test-data-2.txt,\""}
Function LogsSTART RequestId: 09c30d2e-7094-493e-9c7c-957057828d5c Version: $LATESTinvoked_function_arn: arn:aws:lambda:us-west-2:123456789012:function:lsfa-test-funcionContents of bucket lsfa-test-s3-bucket:test-data-1.txt,test-data-2.txt,END RequestId: 09c30d2e-7094-493e-9c7c-957057828d5cREPORT RequestId: 09c30d2e-7094-493e-9c7c-957057828d5c Duration: 2698.32 ms Billed Duration: 2699 ms Memory Size: 128 MB Max Memory Used: 77 MB Init Duration: 260.71 ms
Request ID09c30d2e-7094-493e-9c7c-957057828d5c
Conclusion
In the above exercise, we have seen how lambda:sourceFucntionArn can be used to control access to resources. In large corporations, this can be useful as we can limit access to resources from a function only, no need to worry about someone else attaching the role to their function, and accessing the data.