The Threat Stack CloudTrail Base Ruleset has several out-of-the-box rules that alert users on activity within some of AWS’s most popular services (also the ones most prone to attack), including S3, IAM, Glacier, and Lambda. Given that AWS has over 100 services, we want to arm you with the ability to create custom CloudTrail rules in the Threat Stack Cloud Security Platform® based on the specific AWS services you leverage.
In this post, we cover three examples of one of Threat Stack’s most powerful capabilities — the ability to create, clone, and edit CloudTrail-specific rules. We briefly discuss the scenario that explains why we’re crafting the rule and why it’s important to our organization; we also look at the methodology for creating the rule; and finally we test the rule to make sure it works.
In the three examples that follow, we explain how to create custom rules for Route53, DynamoDB, and EBS Volumes.
Example 1: Creation or Deletion of Route53 Hosted Zones
In this example, imagine that you want to know when someone creates or deletes a Hosted Zone in Route53. Just like with a traditional DNS zone, it could be a cause for alarm when someone is tampering with your record sets.
In this example, we will configure a rule that will alert on the creation or deletion of a Hosted Zone in Route53.
We can take two approaches to create our rule.
One approach is to leverage the AWS API documentation. A quick Google search for “Route53 CloudTrail API” reveals the event names “CreateHostedZone” and “DeleteHostedZone”. Using CreateHostedZone and DeleteHostedZone as event names should be sufficient, but we’ll need to do some testing.
The second approach is to look at the events data in the Threat Stack platform, assuming that the data already exists. Under Events, let’s start by searching for the following:
event_type = “cloudtrail” and eventSource = “route53.amazonaws.com”
If you have event data related to the creation or deletion of Hosted Zones, it should look like this:
By looking at the result, it’s clear that the eventName needed is DeleteHostedZone. This is another way of discovering the index needed to construct our rule.
Now it’s time to create the actual rule. (For more information on creating rules, refer to our Rule Creation Overview.)
In the platform, go to the Rules tab and click + New Rule.
Fill out the Details section, and click Update Rule. Here’s an example of what my Details section looks like:
I chose to include aggregate fields that reference the event name, user, IP address, and Account ID. I considered it useful to see who created or deleted a Hosted Zone, the IP address they created it from, and the associated Account ID. Customize your Alert Title in a way that makes sense to you and your organization.
I left the default threshold for triggering the alert, because I wanted to know about every event that matched this rule.
Now we’ll create the Rule Filter.
The filter should include the event names for creating or deleting a Hosted Zone:
eventName = “DeleteHostedZone” or eventName = “CreateHostedZone”
It is good practice to also include the event source. In this case, it is unlikely that event names such as DeleteHostedZone and CreateHostedZone are used for other services, but we’ll include the event source just to be safe.
eventSource = “route53.amazonaws.com”
Combining the event names and event source, we have the following filter:
eventSource = “route53.amazonaws.com” and (eventName = “DeleteHostedZone” or eventName = “CreateHostedZone”)
It’s as simple as that! In this particular case, all we needed was the event name to create a rule that will alert us when a hosted zone is either created or deleted. We also included the event source just to guarantee that the alerts only pertain to Route53.
Of course, you can also update the rule or create any necessary suppressions. For more information on creating suppressions, refer to our documentation on how to Suppress or Unsuppress Vulnerabilities. As an example, a possible suppression might be to suppress a particular user that also has MFA enabled.
After creating the rule, it’s important to test it to make sure it’s working properly.
In AWS, simply create and delete a Hosted Zone in Route53, which should trigger two alerts.
From our testing, we can see the following results which confirm that our rule successfully captured both the creation and deletion of a Hosted Zone.
Example 2: Creation of an Unencrypted EBS Volume
Some organizations have a DevSecOps policy that states that every EBS volume needs to be encrypted. With the ease of spinning up instances comes the headache of tracking which volumes are encrypted and which ones aren’t.
In this example, we’ll configure a rule that will alert on the creation of any EBS volumes that are not encrypted.
As in Example 1, we have two options. If we believe we already have event data in the platform, we can search for the data and then use it to create the rule. Otherwise, we can resort to the AWS API documentation.
Through a bit of searching through the AWS API documentation, we discover that the CloudTrail event name for creating EBS volumes is, appropriately, CreateVolume.
But in this case, we don’t want to be alerted every time a volume is created — we only want to see alerts when unencrypted volumes are created. This requires a bit more research.
Our options are either to look at the JSON data in the events, or at the API documentation.
To see the JSON for a CloudTrail event, click on the Event and select the View JSON button seen here:
Here’s an excerpt from the JSON data:
You can see the event name CreateVolume, which we are already familiar with. Also, at the top level, we see requestParameters, and below that the key titled “encrypted” with a value of “false”. Based on the naming convention, it appears that we have found what we’re looking for, but it’s always best to confirm this by looking at the AWS documentation.
Here’s the information that we know we need in order to create the rule:
eventName = “CreateVolume”
requestParameters.encrypted != “true”
requestParameters.encrypted = “false”
We’ll also include the event source, which is “ec2.amazonaws.com”, so we don’t alert on any other services that might possess the same event names.
Create the rule by going to the Rules tab and clicking + New Rule.
Fill out the Details section, and click Update Rule. It should look similar to this:
Once again, use aggregates that are useful to you and your organization in the Alert Title. In mine, I specified the user, IP address, and the Account ID.
The Rule Filter should be as follows:
For testing binary/boolean scenarios such as this, I suggest creating two rules where the value is either true or false. That way, in either case, one of the rules will catch the event and create an alert, validating our logic and confirming that the rule works.
To make this workload easier, we can clone our newly created rule. Click + New Rule and select Clone Existing Rule. Click Next. Search for the rule we just created, and click Clone.
Change the Details and Rule Filter so that you now have a rule to catch the creation of Encrypted Volumes.
Details — EBS Encrypted Volumes
Rule Filter — EBS Encrypted Volumes
Note that we changed all instances of “unencrypted” to “encrypted” and changed the expression to requestParameters.encrypted = “true”.
As long as our logic is correct, and the elements are referenceable, then one of the two rules will create an alert.
I created both unencrypted and encrypted volumes, and both were caught by both the respective rules.
We can drill down further into the event data, and look at the JSON to confirm the differences.
JSON for the Encrypted Volume
JSON for the Unencrypted Volume
Now that we have confirmed that both the rules work, we can turn off or delete the rule that alerts us when encrypted volumes are created. If you still want to audit that information, you can leave that rule active and reduce the severity to a Sev 3.
Example 3: Creation of an Unencrypted DynamoDB Table
In February 2018, AWS announced server-side encryption at rest for DynamoDB.
In this example, we’re going to create a rule that alerts us when an unencrypted DynamoDB table is created. This is similar to the previous example, but the logic is a little more complex.
As with the previous two examples, we can leverage either the event data or AWS API documentation to help us craft the rule.
In this particular case, we want to compare the event data for both an encrypted DynamoDB table and an unencrypted DynamoDB table. We’ll see why that’s important shortly.
We can search through the event data with the following query:
event_type = “cloudtrail” and eventSource = “dynamodb.amazonaws.com”
In Events, we can see that there’s an event with the name CreateTable. Once again, you can also discover the event name through the AWS documentation.
Now, let’s compare the JSON event data associated with both an encrypted table and an unencrypted table.
Unencrypted DynamoDB Table — Event Data JSON
Encrypted DynamoDB Table — Event Data JSON
There are some slight, yet noticeable differences.
In the JSON related to the encrypted table, the object sSESpecification exists, and so does the key/value pair “enabled : true”. By referring to the AWS documentation, we can confirm that this is the property that specifies the setting to enable server-side encryption.
What’s interesting is that the object doesn’t exist at all in the JSON related to the unencrypted table.
Without noting this difference, we might be tempted to construct the rule to alert about an unencrypted table by setting enabled equal to false. Before we jump too far ahead, let’s enter the testing phase, and start constructing our rules.
Create Rule and Testing
As we did in Example 2, let’s create the two rules for testing purposes. We want one rule to alert us when an encrypted DynamoDB table is created, and one that alerts us when an unencrypted DynamoDB table is created.
Referencing the JSON above for an encrypted DynamoDB table, we create the following Details and Rule Filter sections.
Details — Encrypted DynamoDB Table
Rule Filter — Encrypted DynamoDB Table
Notice that we had to drill down into the JSON by using dot notation.
If we decide to test this (feel free to!), it will work. But our ultimate goal is to create a rule that alerts us when an unencrypted table is created.
Because sSESpecification doesn’t exist at all in the JSON associated with an unencrypted table, we can’t set requestParameters.sSESpecification.enabled = “false”. It’s not false: It simply doesn’t exist. Therefore, we need to set it to null. In other words, if requestParameters.sSESpecifcation doesn’t exist, then this must be an unencrypted table, and we want to be alerted.
Creating the rule for an unencrypted DynamoDB table should look similar to this:
Details — Unencrypted DynamoDB Table
Rule Filter — Unencrypted DynamoDB Table
We can test this rule by creating an encrypted DynamoDB table and an unencrypted DynamoDB table, and if we did everything correctly, both will trigger an alert in the respective rules.
After you have confirmed that the rules work, you can either delete or turn off the rule that related to encrypted tables, or you can change it to a Sev 3 for auditing purposes.
This post gives an excellent insight into one of Threat Stack’s powerful capabilities — the ability to create, clone, and edit rules in order to reflect the specific nature of your environment.
We just walked through three scenarios for creating custom CloudTrail rules in the Threat Stack platform. With over 100 AWS services, knowing how to create your own rules can help you secure and streamline your DevSecOps strategy.
Which additional rules would you like to see built into the Threat Stack platform?