Add a JSON Query for Build Policy Subtype

Policy rules to Secure Your Infrastructure Automation are written in JSON. So, you need to first convert your template file—CFT, Kubernetes or Terraform templates— to JSON and then parse the JSON structure to write the JSON query that correctly identifies the parameter and criteria on which you want to be alerted. See Build Policy Query Examples below.
  1. Convert your template file to JSON.
    You can also use any online tool to convert your CFT, Kubernetes or Terraform templates to JSON. In this workflow, you use the following sample Terraform template and upload the template file to Prisma Cloud.
    1. Get your template file.
      For example:
      Resources: myTrail: DependsOn: - BucketPolicy - TopicPolicy Type: AWS::CloudTrail::Trail Properties: S3BucketName: Ref: S3Bucket SnsTopicName: Fn::GetAtt: - Topic - TopicName IsLogging: true IsMultiRegionTrail: true myTrail2: DependsOn: - BucketPolicy - TopicPolicy Type: AWS::CloudTrail::Trail Properties: S3BucketName: Ref: S3Bucket SnsTopicName: Fn::GetAtt: - Topic - TopicName IsLogging: true IsMultiRegionTrail: true
    2. Select
      Policies
      and click
      New Policy
      Config
      .
    3. Enter a
      Policy Name
      .
      You can optionally add a
      Description
      and
      Labels
      .
    4. Select the
      Build
      policy subtype and click
      Next
      .
      The build subtype enables you to scan IaC templates that are used to deploy cloud resources. For Run policy subtype, see Create a Configuration Policy.
    5. Select the
      Severity
      for the policy and click
      Next
      .
    6. Build the query to define the match criteria for your policy.
      If your policy is for both
      Run
      and
      Build
      checks and you have added the RQL query, your cloud type for the build rule is automatically selected. It is based on the cloud type referenced in the RQL query. Otherwise, you must select the template type and the cloud type.
      1. Select the
        Template Type
        you want to scan—CloudFormation, Kubernetes, or Terraform. The supported files types are HCL, YAML, JSON.
        For scanning Terraform templates, you must select the Cloud Type and the Terraform version. See what versions of Terraform are supported.. For the other templates, you do not need to select the cloud type.
      2. Upload the template file for conversion to JSON in the JSON Template Validation section.
        In order to upload a file you must add a
        JSON query
        string. You can enter
        object exists
        to enable the ability to attach a file.
        Then, upload a single file or a .zip file.
        The sample template above when converted to JSON looks like this:
        { "Resources": { "myTrail": { "Type": "AWS::CloudTrail::Trail", "Properties": { "S3BucketName": { "Ref": "S3Bucket" }, "IsLogging": true, "IsMultiRegionTrail": true } }, "myTrail2": { "Type": "AWS::CloudTrail::Trail", "Properties": { "S3BucketName": { "Ref": "S3Bucket" }, "IsLogging": true, "IsMultiRegionTrail": true } } } }
  2. Use JSON path validators to write your
    JSON query
    in the policy.
    Use the following guidelines to parse the file structure and write the JSON query that specifies the properties or objects for which you want to apply policy checks:
    • $ - symbol refers to the root object or element.
    • @ – symbol refers to the current object or element.
    • . – operator is the dot-child operator, which you use to denote a child element of the current element.
    • [ ] – is the subscript operator, which you use to denote a child element of the current element (by name or index).
    • * – operator is a wildcard, that returns all objects or elements without regard of the name.
    • ? ( ) – to query all items that meet a certain criteria.
    For validating the JSON path, you can use validators such as https://jsonpath.com/ or others available on the internet. Each time you modify the query or upload a new template, Prisma Cloud revalidates your JSON query.
    Refer to the list of Prisma Cloud IAC Scan Policy Operators to define the operators for the match.
    If for example, you require that all AWS accounts across your organization have enabled AWS CloudTrail, you can check for violations where AWS CloudTrail is not enabled.
    • $.Resources.*[?(@.Type=='AWS::CloudTrail::Trail')]
      , enables filtering the Resources whose type is
      AWS::CloudTrail::Trail
    • and
      $.Resources.*[?(@.Type=='AWS::CloudTrail::Trail')].Properties.IsMultiRegionTrail ‘any null’
      or
      $.Resources.*[?(@.Type=='AWS::CloudTrail::Trail')].Properties.IsMultiRegionTrail anyFalse
      enables you to further filter for the value specified for the MultiRegionalTrail parameter.
      In this case, you are looking to identify a security issue when the value is missing or set to false. So, the match works as follows:If the Type: “AWS::CloudTrail::Trail”, then:
      Parameter
      Value
      Outcome
      IsMultiRegionalTrail
      missing
      Because the default is false, the rule will match.
      It means there a security issue detected.
      IsMultiRegionalTrail
      false
      The rule will match.
      It means there is a security issue detected.
      IsMultiRegionalTrail
      true
      The rule will not match.
      It means there is no security issue detected.
  3. Choose your next steps:
    Continue to Step 6if you want to add compliance standards to the policy rule or to 5.b. Otherwise,
    Save
    the policy rule.

Build Policy Query Examples

The following section shows you an example of a Terraform template and an AWS CloudFormation Template (CFT).
  • Sample JSON file (after being converted from Terraform)
    1. View the file contents.
      { "data": [ { "azurerm_client_config": [ { "current": [ {} ] } ] } ], "provider": [ { "azurerm": [ { "features": [ { "key_vault": [ { "purge_soft_delete_on_destroy": true } ] } ] } ] } ], "resource": [ { "azurerm_resource_group": [ { "example": [ { "location": "West US", "name": "resourceGroup1" } ] } ] }, { "azurerm_key_vault": [ { "example": [ { "access_policy": [ { "key_permissions": [ "list" ], "object_id": "11111111-2222-3333-4444-555555555555", "secret_permissions": [ "list" ], "storage_permissions": [ "get" ], "tenant_id": "2111-3333-4445-555" } ], "enabled_for_disk_encryption": true, "location": "azurerm_resource_group.example.location", "name": "testvault", "network_acls": [ { "bypass": "AzureServices", "default_action": "Deny" } ], "purge_protection_enabled": false, "resource_group_name": "def", "sku_name": "standard", "soft_delete_enabled": true, "tags": [ { "environment": "Testing" } ], "tenant_id": "2111-3333-4445-555" } ] } ] } ] }
    2. Define the match criteria for the policy.
      This following query checks that the template for an Object ID match. It checks whether the object ID of the user or service principal in Azure Active Directory that is granted permissions matches your organizational policy.
      $.resource[*].azurerm_key_vault.*[*].*.access_policy exists and $.resource[*].azurerm_key_vault.*[*].*.access_policy[*].object_id == "11111111-2222-3333-4444-555555555555"
  • Original CFT file that defines the security groups and the ports that allow ingress traffic.
    1. AWSTemplateFormatVersion: '2010-09-09' Parameters: testDescription: Description: Tests for blocked ports negative case in AWS Security Groups Type: String Resources: myELB: Type: AWS::ElasticLoadBalancing::LoadBalancer Properties: AvailabilityZones: - eu-west-1a Listeners: - LoadBalancerPort: '80' InstancePort: '80' Protocol: HTTP myELBIngressGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: ELB ingress group SecurityGroupIngress: - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0 SourceSecurityGroupOwnerId: Fn::GetAtt: - myELB - SourceSecurityGroup.OwnerAlias SourceSecurityGroupName: Fn::GetAtt: - myELB - SourceSecurityGroup.GroupName myELBIngressGroup2: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: ELB ingress group SecurityGroupIngress: - IpProtocol: tcp FromPort: '22' ToPort: '22' CidrIp6: "::/0" SourceSecurityGroupOwnerId: Fn::GetAtt: - myELB - SourceSecurityGroup.OwnerAlias SourceSecurityGroupName: Fn::GetAtt: - myELB - SourceSecurityGroup.GroupName
    2. Sample JSON file (after being converted from AWS CFT)
      { "AWSTemplateFormatVersion": "2010-09-09", "Parameters": { "testDescription": { "Description": "Tests for blocked ports negative case in AWS Security Groups", "Type": "String" } }, "Resources": { "myELB": { "Type": "AWS::ElasticLoadBalancing::LoadBalancer", "Properties": { "AvailabilityZones": [ "eu-west-1a" ], "Listeners": [ { "LoadBalancerPort": "80", "InstancePort": "80", "Protocol": "HTTP" } ] } }, "myELBIngressGroup": { "Type": "AWS::EC2::SecurityGroup", "Properties": { "GroupDescription": "ELB ingress group", "SecurityGroupIngress": [ { "IpProtocol": "tcp", "FromPort": 22, "ToPort": 22, "CidrIp": "0.0.0.0/0", "SourceSecurityGroupOwnerId": { "Fn::GetAtt": [ "myELB", "SourceSecurityGroup.OwnerAlias" ] }, "SourceSecurityGroupName": { "Fn::GetAtt": [ "myELB", "SourceSecurityGroup.GroupName" ] } } ] } }, "myELBIngressGroup2": { "Type": "AWS::EC2::SecurityGroup", "Properties": { "GroupDescription": "ELB ingress group", "SecurityGroupIngress": [ { "IpProtocol": "tcp", "FromPort": "22", "ToPort": "22", "CidrIp6": "::/0", "SourceSecurityGroupOwnerId": { "Fn::GetAtt": [ "myELB", "SourceSecurityGroup.OwnerAlias" ] }, "SourceSecurityGroupName": { "Fn::GetAtt": [ "myELB", "SourceSecurityGroup.GroupName" ] } } ] } } } }
    3. Define the policy match
      Check for any IPv4 or IPv6 CIDR range that allows unrestricted access for ingress traffic on port 22.
      $.Resources.*[?(@.Type == 'AWS::EC2::SecurityGroup')].Properties.SecurityGroupIngress[?(@.IpProtocol == 'tcp' && @.FromPort == '22' && @.ToPort == '22' && @.CidrIp == '0.0.0.0/0')] size greater than 0 or $.Resources.*[?(@.Type == 'AWS::EC2::SecurityGroup')].Properties.SecurityGroupIngress[?(@.IpProtocol == 'tcp' && @.FromPort == '22' && @.ToPort == '22' && @.CidrIp6 == '::/0')] size greater than 0
      This rule will match as follows:
      Parameter
      Value
      Outcome
      IpProtocol
      FromPort
      ToPort
      CidrIp
      tcp
      22
      22
      0.0.0.0/0
      The rule will match.
      Security issue found.
      IpProtocol
      FromPort
      ToPort
      CidrIp6
      tcp
      22
      22
      ::/0
      The rule will match.
      Security issue found.
      IpProtocol
      FromPort
      ToPort
      CidrIp6
      ftp
      23
      23
      0.0.0.0/0 or ::/0
      The rule will not match.
      No security issue found.
      IpProtocol
      FromPort
      ToPort
      CidrIp6
      tcp
      22
      22
      4.0.0.0/0 or ::/16
      The rule will not match because an IP address restriction is in place.
      No security issue found.
  • The JSON query on Prisma Cloud does not support the following cases:
    Embedded policies or similar structures that are represented as a JSON string instead of JSON elements.
    Example: If your resource template is like this:
    resource "aws_iam_role" "nat" { name = "${local.infra}-nat" path = "/" assume_role_policy =<<EOF { "Version": "2008-10-17", "Statement": [ { "Action": "sts:AssumeRole", "Principal": { "Service": "ec2.amazonaws.com" }, "Effect": "Allow", "Sid": "" } ] } EOF }
    When converted to JSON, the
    assume_role_policy
    is a json string within json. While Prisma Cloud can fetch the complete policy, it does not support the ability to filter the parameters inside it.
    { "aws_iam_role": [ { "nat": [ { "path": "/", "name": "${local.infra}-nat", "assume_role_policy": "{\n \"Version\": \"2008-10-17\",\n \"Statement\": [\n {\n \"Action\": \"sts:AssumeRole\",\n \"Principal\": {\n \"Service\": \"ec2.amazonaws.com\"\n },\n \"Effect\": \"Allow\",\n \"Sid\": \"\"\n }\n]\n}\n" } ] } ] },
  • Filtering with multiple criteria or with literal * matching.
    Example: An IAM policy that allows full administrative permissions, that is access to all AWS actions and resources, is a policy that contains a statement with
    "Effect": "Allow" for "Action": "*" over "Resource": "*", i.e. "Statement": [ { "Effect": "Allow", "Action": "*", "Resource": "*" } ].
    The following JSON equivalent for the policy above is not supported on Prisma Cloud:
    $.Resources.*[?(@.Type=='AWS::IAM::Policy')].Properties.PolicyDocument.Statement[?( @.Effect == 'Allow' && @.Action == '*' && @.Resource == '*' )] exists

Recommended For You