The Dome9 GSL Language

In this topic:

    The Dome9 GSL (Governance Specification Language) is a syntax to define compliance rules, can be included in policies in the Dome9 Compliance Engine. GSL consists of a core language which, augmented by a set of functions that add domain specific functionality for different cloud providers (AWS, Azure, and GCP). These functions include IP addresses and networking, cloud entities such as instances, strings matching, date & time, etc.

    In this document will describe GSL syntax, to allow you to write or modify security, compliance and governance rules for your cloud environments.

    Rule Syntax

    A rule is in the form of:

    <Target> should <Condition>

    Target

    The Target is the cloud entity type we are checking (for example, an instance, SecurityGroup). One target can be checked in each rule.

    We can further qualify our target to match a smaller set of entities by adding the where keyword.

    The formal definition would be:

    <entity_type> where <expression>

    where

    • entity_type - the pivot cloud entity type we are checking (for example, Instance, SecurityGroup, ELB, etc.) See the Domain model section for a complete list of entities.

    • expression - can be any complex GSL expression to match on the target entity type.

    Examples

    SecurityGroup where name='default' should...
    Instance where (tags contain [key='env' and value='prod'] and not name='test') should ...
     

    Condition

    The condition is the actual rule, the attributes of the target that we wish to test. It could be a complex GSL expression, testing several attributes related to the target.

     
     

    Expressions

    Comparison expressions

    These expressions are of the form:

    <property_name> <comparison_operator> <expected_value>

    where

    • property_name - is the relevant property of the entity being tested

    • comparison_operator - one of the operators: = , < , >, !=, <=, >= , like

    • expected_value - is any expression you would like to test against (could be a string, number, another property or a function result)

    Examples:

    Instance should have inboundRules.length < 10
    Instance where image='ami-1234' should...
    Instance where name like '%db%' should...
     

    The 'like' comparison operator

    The GSL like operator is very similar to 'like' syntax in SQL. It allows you to match text with wildcards. Like works on string values.

    The like comparisons are case-insensitive, meaning that 'a' like 'A' is true.

     

    Wildcards

    The % wildcard indicates zero or more characters.

    For example, like '%er' will match the strings 'smarter', 'love', 'her', etc.

    The % wildcard can appear a number of times in an expression. For example, like '%DB%' matches 'MongoDB', 'DB123' and 'prodDB_111'

     

    The 'have' operator

    The keyword 'have' is not mandatory. It makes a rule more readable. The GSL parser actually removes it when processing the rule.

    This means we can write the 2nd example as Instance should image='ami-1234'

    It is provided as a way to write rules that are also human/auditor readable.

     

    Inclusion expressions (in)

    The 'in' built-in function verifies that a given object's property value is found in a list of user defined values.

    Syntax:

    <property_name> in (val1, val2, val3...)

    Examples:

    Instance should have image in ('ami-111','ami-222')
    Instance should have region in ('us_east1', 'us_west_2')
    Instance nics.length should be in (1,2)
     

    Contains expressions

    This rule will verify that a property of type list contains a specific item. The syntax allows you to build complex expressions to find/match an item.

    Syntax:

    <property_name> <containment-operator> [<expression>]

    where

    • property_name - is the property of the entity being tested.

    • containment-operator is one of the following:

      • contain or with or contain-any are syntactically identical.

        These options are provided so 'proper' English grammar can be accomplished. If any of the collection elements will satisfy the query expression, then the entire contain statement is considered as satisfied.

        contain-all requires all elements in the collection to satisfy the expression.

      • contain-none requires none of the elements in the collection to satisfy the expression.

    • Expression inside the [ ] block can be any complex GSL expression. It defines the query against which each collection item will be tested.

      If the list is empty, the expression will return false.

    Examples:

    Iterate over each rule in the SecurityGroups'sinboundRules collection. Each rule is matched against both port and scope properties:

    SecurityGroup should have inboundRules with [port=22 and scope='0.0.0.0/0']

    This example is a nested expression - the outer 'with' iterates over each nic in the nics collection, and the inner 'contain-any' iterates over each security group:

    Instance should not have nics with [securityGroups contain-any [name='default']]
     

    Existence expressions

    These expressions verify that a property exists and that it is not empty.

    The system is smart enough to understand 'emptiness' regarding each property type, ex: an empty collection is considered empty, as well as empty object, null, 0, empty string etc...

    Syntax:

    <property_name>

    Examples:

    Instance should have vpc 

    This is equivalent to

    Instance should vpc 

    or

    Instance should have not vpc isEmpty() 

    Another example:

    SecurityGroup where outboundRules... 

    This is equivalent to

    SecurityGroup where outboundRules.length >0 
     

    Regular expressions

    These are regular expressions that match text in an entity name or element.

    Syntax:

    <property_name> regexMatch /<regex pattern string>/

    Example:

    S3bucket should have name regexMatch /john.*/

    Complex logical expressions

    You can construct complex expressions from multiple simple ones, using the operators and, or, not, (<expr>)

    AND

    Verify that both sides of the and keyword are true.

    Syntax:

    <expr> and <expr>

    Examples:

    In this example, the instance should satisfy both the existence of property (name), and the existence of an element in a collection (tags). It could also be written as two separate rules.

    Instance should have name and tags with [key='owner']

    The next example shows a rule that cannot be logically split as each element is validated against both conditions:

    SecurityGroup should not have inboundRules with [port=22 and scope='0.0.0.0/0']

    OR

    Verify that either side of the or keyword is a true expression.

    Syntax:

    <expr> or <expr>

    Example:

    Instance should have name or tags with [key='owner']

    NOT

    Will satisfy (return true) if the following expression is false, and vice versa.

    Syntax:

    not <expression>

    Example:

    SecurityGroup where name='default' should not have inboundRules

    Parenthesis

    Use parenthesis "(", ")" or "[", "]" for complex expressions that contain multiple and and or expressions, to remove ambiguities.

    Syntax:

    (<expression>)

    Example:

    SecurityGroup where name='default' should not have (inboundRules or outboundRules)

    Note:

    Without the parenthesis the rule

    SecurityGroup should not have inboundRules or outboundRules 

    is ambiguous since it is not clear ifwe mean:

    • SecurityGroup should not (inboundRules or outboundRules)

    • SecurityGroup should (not inboundRules) or (outboundRules)

    The parser will use one of the options, but it is recommended not to rely upon an undocumented default implementation, and instead, use '( )' to make the expression unambiguous.

    List expressions

    This expression enumerates a list of items (defined by the following clauses in the GSL rule). The expression can be used with the ןitems and with keywords, after which additional expressions can then be added.

    List expressions can also be used with the groupBy keyword to evaluate the number of items in an enumerated list. Grouping aggregates items (in a list type data entity) by a specific attribute, which can then be used in logical expressions.

    Syntax:

    List<entity_type> should have/not have items with <expr>

    Example:

    List<Instance> should have items length() < 50

    This enumerates a list of instances, and checks that their number is less than a limit.

    List<Instance> should have items with [name like 'db'] length() < LIMIT
     
    In this example, the with keyword is used to filter the list for a specific name before it is enumerated, and then the result is checked with a condition.
    List<SecurityGroup> should have items groupBy [vpc.id] contain-all [values length() < 100]

    This enumerates the Security Groups in each VPC, and checks that there are less than 100 in each (the AWS limit).

     
     

    Data Types

    GSL has different syntax for strings (textual values) and for numericvalues

    Text

    Strings are surrounded by a single quote. For example,'my string value'.

     

    Numbers

    Numbers are written without quotes.

    For example, Instance should have inboundRules.length < 5

    Lists

    List entities have a length property (entity.length). For example, inboundRules, in the example above. Alternatively, use the length() function.

    For example,

    Instance should have inboundRules length() < 10

    or

    Instance should have inboundRules.length < 10
     
     

    Functions

    The core GSL syntax is enriched by internal functions that provide domain specific functionality in multiple areas such as: IP addresses, dates, string matching etc...

    Syntax:

    <property_name> <function_name> (<param1>,<param2>...)

    where:

    • property_name is the property/object we wish to operate on (similar to functions in object-oriented languages)

    • function_name is the name of the functions from the above list params the required parameters according to the type of the function, separated by

     

    General Functions

    isEmpty

    Check if the object / property is empty according to the property type. Will return false for empty collections and empty objects (as well as null values, 0 empty strings,etc...)

    Parameters: none

    Example

    Instance should not have vpc isEmpty()

    Note:

    This is equivalent to

    Instance should have vpc
     

    length

    Returns the length of a list. Follow this function with a comparator: >, <, =, >=, <=, !=.

    Parameters: none

    Example

    SecurityGroup should not have inboundRules length()>5
     

    in

    Returns true is the attribute value is contained in the provided list of values.

    Parameters:

    List of values to match.

    Example

    SecurityGroup should have region in ('us_east_1', 'us_east_2', 'us_west_1')
     

    split

    Splits a string based on a provided separator.

    Parameters:

    Position

    Description

    Values

    1

    Separator

    The separator to use when splitting the string

    Example

    Instance should have name split('-') length() = 3
    
    # make sure that the instance name format is x-y-z (further tests could be applied on x, y and z)
     

    join

    Concatenate multiple strings into a single string. This function can be useful to dynamically concatenate entity attributes.

    Parameters:

    Position

    Description

    Values

    1

    Separator

    The separator to use when concatenating the strings

    ...

    Strings

    The strings to concatenate

    Example

    Instance should have name like join('-', 'PROD', id)
    
    # make sure that instance name is in the format PROD-<Instance ID>, for example: PROD-i-a0b01c01
     
     

    Networking Functions - General

    isPublic

    Checks if this IP address or CIDR is an external/ public IP address /network, not within:rfc 1918

    Parameters: none

    Example

    Instance where tags contain [key='PCI'] should not have inboundRule with [scope isPublic()]
     

    isPrivate

    Checks if this IP address or CIDR is a private rfc 1918

    Parameters: none

    Example

     

    numberOfHosts

    Counts the number of possible IP addresses in the provided CIDR. It removes the broadcast address

    Parameters: none

    Example

    SecurityGroup should not have inboundRules with [port=22 and scope numberOfHosts() > 256]
     

    containedInNetworks

    Operating on an IP address or a CIDR network and testing if it is fully contained in any of the the provided networks.

    Parameters

    List of CIDRs representing networks to test

    Example

    SecurityGroup should not have inboundRules with [port=22 and scope isCIDR() and not scope containedInNetworks('10.0.0.0/8','172.16.0.0/12','192.168.0.0/16','1.2.3.4 /10','5.6.7.8/24')]
    
    # this rule checks that there is no SSH connection from non local or 'friendly' networks : '1.2.3.4/10','5.6.7.8/24'
     

    overlapWithNetworks

    Operating on an IP address or a CIDR network and test if it has some overlap with any of the the provided networks.

    Parameters

    List of CIDRs representing networks to test

    Example

    SecurityGroup should not have inboundRules with [port=22 and scope isCIDR() and scope overlapWithNetworks('10.1.2.0/24','192.168.100.0/24')]
    
    # In this example '10.1.2.0/24','192.168.100.0/24' (internal) networks belong to a 3rd party peered to our VPC. Let's verify we do not allow these networks to SSH into our servers

    isCIDR

    Check if field is in CIDR format.

    Parameters: none

    Example

    SecurityGroup should not have inboundRules with [ scope isCIDR() ]
     

    isSecurityGroupReference

    Checks if the attribute references to a Security Group.

    Some attributes can contain multiple type of objects (i.e. Security Group or a CIDR), this function is used to determine if the value is a Security Group.

    Parameters: none

    Example

    SecurityGroup should have inboundRules with [ scope isSecurityGroupReference() ]
    
    # This example makes sure that security groups should only allow traffic from another security group, and not a CIDR
     
     

    Networking Functions for AWS NACL and MS Azure NSG

    AWS NACL and MS Azure NSGs have different firewall semantics.

    The FW rules are ordered and may contain explicit 'DROP'. This makes the order of the rules critical.

    These functions operate on a list of rules.

    allowedHostsForPort

    Return the number of IP addresses (hosts) that can be connected to the relevant port protected by this Firewall

    Parameters

     
    Position Description Values
    1 Port number(mandatory) any valid port number, such as 22, 80 etc...

    Example

    VirtualMachine should not have nics with [networkSecurityGroup.inboundRules allowedHostsForPort(22) > 256 ]
    
    # this rule prevents from over permissive port 22 (that is allowed to more than 256 addresses). This is a rule for Azure VM
     

    areCIDRsAllowedForPort

    Return true if the provided IP addresses / CIDRs are allowed to connect to the specified port.

    This method will return true if any / some of the addresses in the provided CIDRs are allowed to connect.

    Parameters

    Position Description Values
    1 Port number (mandatory) any valid port number, such as 22, 80 etc...
    2 CIDR to test (at least 1 is mandatory) CIDR syntax like 1.2.3.4/24
    ... other optional CIDRs CIDR syntax like 1.2.3.4/24
     

    Example

    VirtualMachine should not have nics with [networkSecurityGroup.inboundRules areCIDRsAllowedForPort(22,'1.2.3.0/24','5.5.6.7/32') ]
    # this rule prevents SSH access from unauthorized 3rd party networks such as '1.2.3.0/24','5.5.6.7/32'
     

    isPortPrivate

    Return true if the specified port can only be accessed by internal IP addresses

    This method will return true if any / some of the addresses in the provided CIDRs are allowed to connect.

    Parameters

    Position Description Values
    1 Port number (mandatory) any valid port number, such as 22, 80 etc...
    ... Additional CIDR to mark as private (optional) CIDR syntax like 1.2.3.4/24
     

    Example

    VirtualMachine should have nics contain-all [networkSecurityGroup.inboundRules isPortPrivate(22) ]
    
    # this rule prevents SSH access from public IP addresses
     
     

    Time Functions

    before

    Test if the date property (in UNIX time format) is before (meaning smaller than) the desired relative time.

    Time is relative to real-time / evaluation time rather than the date of rule authorship, and can be defined using any of the supported time units.

    Parameters

    Name

    Description

    Values

    count

    The number of the units, negative numbers will resolve into past dates

    any positive or negative number such as: -5, 10, etc...

    unit

    The measurement unit

    'minutes','hours','days','months'

    (string)

    Example

    Instance should not have launchTime before(-3,'months')
    
    # will verify that no instance was launched more than 3 months ago
     

    after

    Test if the date property (in UNIX time format) equals or greater than the desired relative time.

    Time is relative to real-time / evaluation time rather than the date of writing the rule, and can be defined using any of the supported time units.

    Note Unlike before(), it also includes the desired time

    Parameters

    Name

    Description

    Values

    count

    The number of the units, negative numbers will resolve into past dates

    any positive or negative number such: -5,10,...

    unit

    The measurement unit

    'minutes','hours','days','months'

    (string)

    Example

    Instance where launchTime after(-2,'weeks') should...

    # do something about the instances that were launched in the last 2 weeks...

     

    Pro tip

    To use fixed (non-relative) time, you can use standard numeric comparison with the UNIX date/time format.

    For example, to do something with all instances that were created before 1/1/2016 (which translates into the UNIX time of: 1451606400), use:

    Instance where launchTime < 1451606400 should ...