Using AWS Lambda’s New Attribute Based Access Control (ABAC) to Enforce Compliance of Lambda Functions

Attribute Based Access Control and New Lambda ABAC Support

Today AWS Lambda is announcing the general availability of Attribute Based Access Control (ABAC) for Lambda via new support for tag-related AWS IAM global condition keys. This means the advanced IAM condition keys used in this post, including aws:ResourceTag and aws:TagKeys, can be used with Lambda as of today. Vertical Relevance is proud to have partnered with AWS on this launch, and hopefully, this post will show the exciting possibilities of taking advantage of these new features.

Introduction

Vertical Relevance sees financial services organizations increasingly standardize around Infrastructure as Code (IaC) as the golden path to the cloud and especially to their production cloud environments. In most organizations, manual changes in the cloud are considered out-of-band and they must either be justified as special cases, or they are considered a breach of protocol.

Standardizing around IaC as the path to the cloud means that code must pass a security review, whether the review is automated using something like VR’s Control Broker or the result of a manual process.

One challenge in this compliance scheme is that created resources should be identifiable as having passed a security review. In other words, organizations need some way to look at a resource (e.g. a Lambda function) in the cloud and know definitively whether it has been reviewed by a trusted entity and approved for launch. If it has not been approved, it should be quarantined until it can be reviewed. This post demonstrates a simple way for organizations to use the new AWS Lambda ABAC support to allow trusted entities to mark Lambda Functions as compliant via a resource tag and automatically quarantine non-compliant Lambda Functions using only IAM features.

The Pieces

Figure 1 – Overview of the solution architecture with a numbered label for each piece.

Piece 1: The Service Control Policy (SCP)

The first component (Figure 1 Label 1) of our solution to label Lambda functions as compliant and quarantine those that are not is an SCP that defines the rules for how the tag is used within our Organizational Unit.

The SCP in our solution consists of two statements. The first statement in the SCP prohibits anyone but Compliance Officers from tagging Lambda Functions that have the tag “IsCompliant” with the value “true”:

{
            "Sid": "RestrictIsCompliantTagManagement",
            "Effect": "Deny",
            "Action": [
                "lambda:TagResource",
                "lambda:UntagResource"
],
            "Resource": "*",
            "Condition": {
                "StringNotEqualsIgnoreCaseIfExists": {
                    "aws:PrincipalTag/IsComplianceOfficer": "true"
                },
                "ForAnyValue:StringEqualsIgnoreCase": {
                    "aws:TagKeys": [
                        "IsCompliant"
                    ]
                }
            }
        },


We accomplish this with a Deny rule so that the statement will override any conflicting Allow statement within the account. We use the “aws:TagKeys” condition to scope this statement to only requests that set our special “IsCompliant” tag.

We then use the “aws:PrincipalTag” condition key with a “StringNotEqualsIgnoreCaseIfExists” operator to effectively create an exception to the rule for principals who have the special “IsComplianceOfficer” tag set to “true”. This exception allows us to delegate control over the “IsCompliant” tag to particular principals just by tagging them. For example, an organization could apply the “IsComplianceOfficer” tag to the IAM Roles trusted CI/CD pipelines use to launch their infrastructure via CloudFormation, Terraform, etc., thereby giving them permission to mark resources as compliant on launch if the IaC has passed review. Note that, for simplicity, no rules restricting the application of the “IsComplianceOfficer” tag are included in this example, but they would be essential in a real-life use case. Next, we must create an Organizational Unit-wide rule that prohibits invocation of Lambda functions unless they have the “IsCompliant” tag set to “true:`

{
            "Sid": "ProhibitInvocationOfNonCompliantFunctions",
            "Effect": "Deny",
            "Action": "lambda:Invoke*",
            "Resource": "*",
            "Condition": {
                "StringNotEqualsIgnoreCaseIfExists": {
                    "aws:ResourceTag/IsCompliant": "true"
                }
            }
        }

This second statement in the SCP simply prohibits the “lambda:Invoke*” actions on any resource if the resource does not have the “IsCompliant” tag set to “true”. This statement effectively means that any Lambda function not tagging with “IsCompliant” set to “true” will be quarantined (unable to be invoked).

Note that in this statement and the previous one, we use “StringNotEqualsIgnoreCaseIfExists,” a somewhat advanced IAM condition operator. This condition, when used with a Deny Effect, means that even requests on resources that do not have the “IsCompliant” tag set will be denied. This prevents a scenario where our rule is only in effect if the tag is set, but not in effect on resources that have not been tagged with “IsCompliant” at all. For more information about “…IfExists” operators, see the IAM Documentation on the subject.

 The “IgnoreCase” portion means this works even on tags with different casing. Casing is an important security concern with tags – if software gives out permissions based on tag values, users may be able to circumvent permission schemes by changing the casing of their tags. Ignoring casing in tag enforcement rules is a good way to mitigate this risk.

Pieces 2 and 3: In-Band and Out-of-Band Functions

The second component of this example is composed of two Lambda functions (Figure 1 Label 2), one called “in-band-function” and another called “out-of-band-function.” These names were chosen to represent one function being created via the organization’s approved IaC infrastructure creation and approval process (“in-band”) and the other being created outside that process (“out-of-band,” e.g. via the AWS console or API from a developer’s laptop).

We create these two functions and apply the “IsCompliant” tag with a value of “true” to only the “in-band” function (Figure 1 Label 3):

Figure 2 – The compliant function with the “IsCompliant” tag set to “true.”

Figure 3 – The non-compliant function without an “IsCompliant” tag.

Piece 4: Comparing the Results of Invoking the Two Functions

We need a principal to invoke these functions, so we create a role inside the account (Figure 1 Label 4) to demonstrate the different results when invoking them.

The role is called “compliant-function-invoker-role” and has all permissions on Lambda functions via the following attached IAM policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Resource": "arn:aws:lambda:*:*:function:*",
            "Action": [
                "lambda:*"
            ]
        }
    ]
}

We first assume the role and confirm our identity:

$ aws sts assume-role --role-arn arn:aws:iam::123456789012:role/compliant-function-invoker-role --role-session-name aws-blog

# Output and AWS_* environment variables redacted

$ aws sts get-caller-identity
{
    "UserId": "AROAWABCDEFGHIJKLMNOP:aws-blog",
    "Account": "123456789012",
    "Arn": "arn:aws:sts::123456789012:assumed-role/compliant-function-invoker-role/aws-blog"
}

Next, we invoke the “in-band-function,” which is successful since this function has the “IsCompliant” tag set to “true:`

$ aws lambda invoke --function-name in-band-function --payload file://payload.json --cli-binary-format raw-in-base64-out out.json
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}

And then we attempt to invoke the “out-of-band-function,” which fails since that function does not have the “IsCompliant” tag set to “true”.

$ aws --no-cli-pager lambda invoke --function-name out-of-band-function --payload '{"key1": "a", "key2": "b", "key3": "c"}' --cli-binary-format raw-in-base64-out out

An error occurred (AccessDeniedException) when calling the Invoke operation: User: arn:aws:sts::123456789012:assumed-role/compliant-function-invoker-role/Granted-aws-blog is not authorized to perform: lambda:InvokeFunction on resource: arn:aws:lambda:us-east-1:123456789012:function:out-of-band-function with an explicit deny in a service control policy

Note that the returned error message states that access was denied due to a service control policy and that the only difference between this call and the previous one is that this function is missing the “IsCompliant” tag.

We can also confirm that the special “IsCompliant” tag cannot be managed unless the calling principal is tagged with “IsComplianceOfficer” set to “true”.

For instance, if we try to use the “tag-resource” API as the “compliant-function-invoker-role” to mark the “out-of-band-function” so that we can invoke the function, we get an access error:

$ aws lambda tag-resource --resource arn:aws:lambda:us-east-1: 123456789012:function:out-of-band-function --tags 'IsCompliant=true' 

An error occurred (AccessDeniedException) when calling the TagResource operation: User: arn:aws:sts::123456789012:assumed-role/compliant-function-invoker-role/Granted-aws-blog is not authorized to perform: lambda:TagResource on resource: arn:aws:lambda:us-east-1:123456789012:function:out-of-band-function with an explicit deny in a service control policy

Changing Protected Tag Values with A Specially Tagged Role

If we want to delegate the ability to mark Lambda functions as compliant, all we must do under the above scheme is to tag the delegate role with the “IsComplianceOfficer” tag set to “true”.

For instance, we can apply this tag value to the same role (“compliant-function-invoker-role”) from above that was unable to set the “IsCompliant” tag on functions. Once the role has this tag attached, it will be able to set the “IsCompliant” tag on functions.

To designate the role as a Compliance Officer, we simply add the “IsComplianceOfficer” tag:

Figure-04

Now, we try managing the IsCompliant tag on the “out-of-band-function” to mark it as compliant:

$ aws lambda tag-resource --resource arn:aws:lambda:us-east-1:446960196218:function:out-of-band-function --tags 'IsCompliant=true'

Note that this same action was prohibited earlier.

And finally, we try to invoke the function. We are able to successfully invoke it since it is now marked as compliant:

$ aws --no-cli-pager lambda invoke --function-name out-of-band-function --payload '{"key1": "a", "key2": "b", "key3": "c"}' --cli-binary-format raw-in-base64-out out
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}

Summary

The above approach represents a powerful starting point toward ensuring all running resources have gone through an organization’s compliance process, and it has several advantages over other approaches. First, it requires almost no code to get started thanks to the always-improving support for ABAC in AWS. Secondly, it scales well since it does not require special actions to be taken when new resources are launched outside of the regular governance channels – these resources simply do not work by default.

Improvements to this system could be a mechanism for tracing launched resources back to their security and compliance reviews, effectively establishing an audit trail for how a resource got approved for launch. This could also be combined with a token system to allow developers to tag their resources with “IsCompliant” or similar tags so long as they got a token representing a successful review from the security and compliance team.

An important caveat to the system outlined above is that resources can change once deployed and drift from their original compliance status. If an organization is using IaC as its only path to deployment, this risk can be minimized, but a full solution would involve consideration of this risk so that mutated resources would not be trusted forever simply because they were compliant at the creation time.

Resources

About Vertical Relevance

Vertical Relevance is a Financial Services focused (Wealth Management, Asset Management, Banking, Insurance) consulting firm helping with the design & delivery of effective transformation programs across people, process, & systems. With 10+ years of AWS & 20+ years of Financial Services experience, we understand the business needs & build solutions to meet sales, marketing, & compliance goals.

Posted July 15, 2022 by The Vertical Relevance Team

Posted in: Insights, News

Tags: , , , , ,


Eddie Peters

Eddie Peters is a Principal Cloud Consultant at Vertical Relevance. He has led teams in Application Modernization, DevOps, and DevSecOps projects to automate application deployment and testing, troubleshoot performance issues in distributed systems, and automate security controls using industry best practices for Global Financial Services firms. Eddie currently holds the AWS Certified DevOps – Professional, AWS Certified Security – Specialty, and  AWS Certified Solutions Architect – Associate certification.


You may also be interested in:


Previous Post
Solution Spotlight – Data Pipeline Foundations
Next Post
Use Case: Building PCI Compliant Cloud Infrastructure 

About Vertical Relevance

Vertical Relevance was founded to help business leaders drive value through the design and delivery of effective transformation programs across people, processes, and systems. Our mission is to help Financial Services firms at any stage of their journey to develop solutions for success and growth.

Contact Us

Learn More