Writing Guardrails with Really
Authoring Your Own Guardrails
Really
Really is a policy language used to constrain configuration inputs in Resourcely. Instead of needing to write code, we have created Really to match as closely to plain English as possible, making it easier to both read and write policies that comply with your company's best practices.
With the structured and logical syntax of Really, anyone responsible for creating and maintaining security policies can:
Write policies faster than with alternatives such as Rego
Read, understand, and update policies quickly and easily
Below is an example of a Really policy that requires a specific prefix on an S3 bucket:
Overview
There are three components in a guardrail, which are grouped together by indentation.
Declaration
The first component is the declaration of the guardrail. In this line you use the keyword GUARDRAIL followed by a string that represents the name of the guardrail. Typically these names are a basic description of what the guardrail does.
Matcher
The second component is the matcher. The matcher lets you specify when a guardrail should be applied. It is specified using the keyword WHEN, and it is indented under the guardrail declaration. The statement can either be a direct resource name, or a logical operation to constrain the matcher even further.
For example the following will run the guardrail on all aws_s3_bucket resources that have a tag team with the value eng:
You can also use wildcards in matchers to match multiple resources.
Requirements
The third component of a guardrail is the requirements. This is where you actually specify what you expect to be true about the configuration. You specify this using the keyword REQUIRE and indent it under the matcher. A requirement can constrain the inputs to your configuration.
For example if you have a list of instance types you want developers to use, you can write a requirement that requires instance_type to match specific wildcard expressions:
A requirement with no operator constrains the property to be non-empty.
Example
Operators are used to further constrain the value.
Example
Context
Guardrails can reference context answers using the CONTEXT
keyword followed by the label of the context question: CONTEXT label
or CONTEXT "label"
.
The CONTEXT
keyword may be used on either side of an operation within WHEN
, but only on the right-hand side within REQUIRE
.
Examples
Here we use environment
from the global context.
All of the operators can be used with context answers. Here we use the MATCHES
glob operator to apply the guardrail to all production environments.
Context answers accommodate both single- and multi-select with the same guardrail syntax.
The two statements of each of the following guardrails are equivalent.
You can use EVERY
, SOME
and NO
with CONTEXT
on the left-hand side within WHEN
.
The two statements of the following guardrail are equivalent.
However, this guardrail only applies if every value in "environment" is "prod".
Optional Context
Guardrails fails safe by default when a context value is missing. That is, Resourcely will request approval from the approver group, the same as if the guardrail was violated.
Sometimes failing safe is too strong. Maybe you intentionally haven't added the context answers to all .resourcely.yaml
config roots yet. Or maybe you want to use the presence/absence of the context answer to condition the guardrail.
The OPTIONAL CONTEXT <foo>
syntax disables the fail safe behavior for that context answer.
will not require approval when the environment
context answer is missing.
This works in REQUIRE
statements as well.
will not require approval if the environment
context answer is missing.
The OPTIONAL
keyword disables the fail safe behavior only for that context answer.
will not require approval if team
is missing, but will if environment
is missing.
Reference
Operators
The following operator can be used in both the Matcher and Requirement components of a guardrail.
=
Equality
Example
!=
Inquality
Example
> / >=
Greater Than / Greater Than or Equal
Example
< / <=
Less Than / Less Than or Equal
Example
STARTS WITH
Check if a string property starts with a specified string.
Example
ENDS WITH
Check if a string property ends with a specified string.
Example
MATCHES
Check if a string property matches a wildcard pattern.
Example
MATCHES REGEX
Check if a string property matches a regex pattern.
Example
MATCHES ANY
Check if a string property matches at least one wildcard pattern in a list of wildcard patterns.
Example
MATCHES ANY REGEX
Check if a string property matches at least one regex pattern in a list of regex patterns.
Example
IN
Check if a string property matches at least one literal string value in a list of strings.
Example
EXISTS
Checks if the property is specified on a resource
Allows empty lists []
, the empty string ""
, etc. To require that the property is not empty, omit the operator entirely.
Example
NOT
Negates an operator (can be used on any operator) in the form NOT <operator>
Example
Connectors
You can string together operators with the connectors AND and OR. You can also use parentheses to separate multiple connectors.
AND
Requires that both operators on the left and right hand sides are satisfied.
Example
Note in this example that we could have used multiple REQUIRE statements in place of AND for better readability.
OR
Requires that at least one operator on the left and right hand sides are satisfied
Example
List Operators
In addition to the operators that evaluate against primitive properties, Really supports operators that can traverse over a list using EVERY
, SOME
, and NO
.
EVERY
Iterates over a list and ensures that all values of that list are satisfied. If the list is empty, EVERY will return true. However, if a guardrail specifies a list property without any list operator, we infer the EVERY operator, except that we require the list to be non-empty (so an empty list will return false)
Example: Explicit declaration of EVERY
In this example ingress.cidr_blocks can be empty
Example: Implicit declaration of EVERY
In this example ingress.cidr_blocks can not be empty
SOME
Iterates over a list and ensures that at least one value of that list is satisfied. If the list is empty, SOME will return false.
Example
NO
Iterates over a list and ensures that none of the values of the list are satisfied. If the list is empty, NO will return true.
Example
Special Syntax
HAS
Additional syntax used to change the scope inside a guardrail, usually used to enhance the human readability of a guardrail.
Example
Without HAS, a guardrail to check that a bunch of keys exist on the tags of an aws_instance would look like:
With HAS you can simplify it to be:
Last updated