lambda:SourceFunctionArn
[Part 1] 

June 16, 2023


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:


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

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)

File name: test-data-1.txt, content: Hello AWS

File name: test-data-2.txt, content: Hello Lambda

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

Role name: lsfa-test-funcion-role-t7t0c5ob
name of the attached policy: AWSLambdaBasicExecutionRole-e7adbfa2-6abc-4372-841f-e27832d397c5 

{    "Version": "2012-10-17",    "Statement": [        {            "Effect": "Allow",            "Action": "logs:CreateLogGroup",            "Resource": "arn:aws:logs:us-west-2:123456789012:*"        },        {            "Effect": "Allow",            "Action": [                "logs:CreateLogStream",                "logs:PutLogEvents"            ],            "Resource": [                "arn:aws:logs:us-west-2:123456789012:log-group:/aws/lambda/lsfa-test-funcion:*"            ]        },        {            "Effect": "Allow",            "Action": [                "s3:*"            ],            "Resource": [                "*"            ]        }    ]}
def lambda_handler(event, context):        print('invoked_function_arn: ' + context.invoked_function_arn)        bucket_name = "lsfa-test-s3-bucket"    s3 = boto3.resource(service_name='s3', region_name='us-west-2')    my_bucket = s3.Bucket(bucket_name)    bucket_objects = ''    print('Contents of bucket ' + bucket_name + ':')    for objects in my_bucket.objects.all():        bucket_objects += (objects.key + ',')    print(bucket_objects)        return {        'statusCode': 200,        'body': json.dumps('objects: ' + bucket_objects)    }

Event name: lsfa-test-event
Event sharing settings: private
Event JSON: {}

{    "Version": "2012-10-17",    "Statement": [        {            "Effect": "Allow",            "Action": [                "s3:*"            ],            "Resource": "arn:aws:s3:::lsfa-test-s3-bucket/*",            "Condition": {                "ArnNotEqualsIfExists": {                    "lambda:SourceFunctionArn": "arn:aws:lambda:us-west-2:123456789012:function:lsfa-test-funcion"                }            }        }    ]}
{    "Version": "2012-10-17",    "Statement": [        {            "Effect": "Allow",            "Action": "sts:AssumeRole",            "Resource": "arn:aws:iam::123456789012:role/aws:iam::123456789012:role/service-role/lsfa-test-funcion-role-t7t0c5ob"        }    ]}
aws iam create-access-key --user lfsa-test-function-role-assumer

{    "AccessKey": {        "UserName": "lfsa-test-function-role-assumer",        "AccessKeyId": "RDUJKGKIAVQBLOK3UAR5",        "Status": "Active",        "SecretAccessKey": "sVADhVtiNQeRRtgayB6vCvlGTDPQ7TRb6fHrbGwu",        "CreateDate": "2023-06-16T17:41:36Z"    }}
aws configure --profile lfsa-test-function-role-assumer-profile
AWS Access Key ID [None]: RDUJKGKIAVQBLOK3UAR5AWS Secret Access Key [None]: sVADhVtiNQeRRtgayB6vCvlGTDPQ7TRb6fHrbGwu    Default region name [None]: us-west-2Default output format [None]: json
aws s3 ls s3://lsfa-test-s3-bucket --profile lfsa-test-function-role-assumer-profile
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
Test Event Namelsfa-test-event
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.