Object Constraint Language (OCL) grants immense flexibility within Turbot. While complex, there are some key points that can help aid in implimentation.
OCL is commonly used to define security group ingress and egress rules. In general, the psuedo-code for security group rule policy evaluation looks something like this:
For all security group rules for all OCL rules evaluate OCL against security group rule. note the result Combine results from all rule evaluations Take actions based on policy and APPROVE/REJECT status.
OCL is very useful for restricting permissions in policies such as IAM or a KMS Key policy.
OCL incorporates implicit logic. Items separated by a space is implicitly
AND, while commas indicate
OR. It must be noted that commas are only available in each condition and cannot be used to join rules. Let's take a look at some examples.
Turbot allows the use of OCL formatting for a variety of policies. Syntax is consistent across all policy types that accept OCL as an input. For more in depth information regarding how OCL rules work, check out our OCL reference page
Below are example policy settings using OCL:
Starting simple, we can reject the CIDR 0.0.0.0/0.
::/0 is the IPv6 version of IPv4's zero block, and Turbot policies allow us to also reject IPv6 addresses. Note how the comma is used to implicitly say if either
::/0 exists in the rules, it will alarm/ remediate.
### Reject the default route, always REJECT $.turbot.cidr:0.0.0.0/0,"::/0" ### Approve everything else APPROVE *
In this next example, not only are we restricting the
0.0.0.0/0 CIDR block, but also any block that IS NOT
192.168.0.0/16. Here we can see the use of the backslash,
\, implicitly denotes a space, which in turn denotes an AND operator.
### Reject if IP is outside (>) these CIDRs REJECT \ $.turbot.cidr:>10.0.0.0/8 \ $.turbot.cidr:>172.16.0.0/12 \ $.turbot.cidr:>192.168.0.0/16 ### Approve anything else APPROVE *
Logic can be stacked to create complex rules. In the below case, we are allowing the use of the default route (
0.0.0.0/0) IF AND ONLY IF using web ports 80 and 443. All other use of the default route will be flagged or removed by the
AWS > VPC > Security Group > Ingress Rules > Approved control, depending on the configuration. Any route outside of the above restriction is allowed.
### Approve use of default route if using web ports APPROVE \ $.turbot.ports.+:80,443 \ $.turbot.cidr:0.0.0.0/0,"::/0" ### Reject all other use of default route REJECT $.turbot.cidr:0.0.0.0/0,"::/0" ### Approve anything else APPROVE *
Again, we can stack the logic to reject specific ports (21 or 25), a specific port range (anything greater than 4, or -1. -1 is defined as the entire port range), and only allow the use of specific CIDR ranges.
### Reject if using port 25 or 21 REJECT $.turbot.ports.+:25,21 ### Reject if port range is > 4 or == -1 REJECT $.turbot.portRangeSize:>4,-1 ### Reject if IP is outside (>) these cidrs REJECT \ $.turbot.cidr:>10.0.0.0/8 \ $.turbot.cidr:>18.104.22.168/16 \ $.turbot.cidr:>192.168.0.0/24 ### Approve anything else APPROVE *
In this example, let's suppose we want to block a specific port (say, port
22) but at the same time, allow large ranges of ports. The key caveat is that the blocked port cannot be a part of the range. We saw in the above example that we can block a port using the OCL:
REJECT $.turbot.ports.+:25 APPROVE *
However, we can circumvent this restriction by defining a range that does not specifically mention port 25. To account for this possibility, we can tweak the rule:
REJECT $.turbot.fromPort:<=25 $.turbot.toPort:>=25 APPROVE *
This rule can be stacked in a similar manner to example 2 to restrict a number of ports, as well as restricting by CIDR (
REJECT $.turbot.cidr:0.0.0.0), IpProtocol (
REJECT $.IpProtocol:icmp), or any other metadata about the security group stored in the Turbot CMDB.
We can alarm on or remove any not approved rule using OCL. Often, KMS Key policies will have multiple entries, such as a user with access to kms:Encrypt, kms:Decrypt, and kms:DescribeKey. Using pipes (
|), we can concatenate the rules to be easier to create and read.
In this example, we are going to reject any action that is NOT kms:Encrypt, kms:Decrypt, or kms:DescribeKey.
Example without pipes:
REJECT !$.Action:kms:Encrypt REJECT !$.Action:kms:Decrypt REJECT !$.Action:kms:DescribeKey APPROVE *
Example with pipes:
REJECT !$.Action:/^kms:(Encrypt|Decrypt|DescribeKey)$/ APPROVE *
Much easier to read and write! Note the use of the
$/ at the end of the REJECT statement.
When setting this KMS rules policy, do not forget to also set AWS > KMS > Key > Policy Statements > Approved!
OCL logic can also be applied to IAM roles and users. Often, organizations will want to restrict the usage of the full access
AdministratorAccess policy in AWS IAM. This below example will trigger an alarm (and possible remediation) if the
AdministratorAccess policy is attached to any role.
### Reject administrator access policy attachments to an IAM role REJECT $.PolicyName:/^.+FullAccess.*$/ REJECT $.PolicyName:AdministratorAccess ### Approve anything else APPROVE *